checkoff 0.161.0 → 0.163.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f83187f80678558975069a3181a34814c3859b81a9a19f0d29606e9ba37e62c4
4
- data.tar.gz: 8e53186cd5ac43fa6b2fb6f9f4f13a4da3259ab75d8792a43459657e8dcaf8bc
3
+ metadata.gz: 4e069f1f67cf8145e42254912651cb575323ca8c5ec0b2e94e8929b6c2e1cb33
4
+ data.tar.gz: 6e0f8039d9e956c0918b03807cc04cf65853232e4b3a97f7d6d5cca72b38b593
5
5
  SHA512:
6
- metadata.gz: 4e4415a477513de35f11579dd45544071ca1b223a5b7a646c2bba0adb2b3becddf7409d4bd69cf0c14d2f0e8fcf55b10014f7d1b90f33d0b667b442aa25dba63
7
- data.tar.gz: 823f046f8f55e05be6d3368cd878abbb02e9632c9bdc7bf5ca5e46160155bee5845ff742550579c55cd1c5013de7e632c828e84c3861ada4998feca0ef29c34a
6
+ metadata.gz: 9f696c01862a1febb0f973bf90a39ce8afbc3be48d0b7df2a57494f9333c8894c2b17a0b3c2c4954fd2014c572d8e6bc78fdbb128e197f9714809e64e5207d45
7
+ data.tar.gz: 0d2d8a45685bf264c00dee9e7fedfbfb7974c0a0e3dcd580618dafb99e936ef52d621411fa462a9a75bc4a54a0290c143cea459b549305131d8c8de02a36c253
data/Gemfile.lock CHANGED
@@ -12,12 +12,13 @@ GIT
12
12
  PATH
13
13
  remote: .
14
14
  specs:
15
- checkoff (0.161.0)
15
+ checkoff (0.163.0)
16
16
  activesupport
17
17
  asana (> 0.10.0)
18
18
  cache_method
19
19
  dalli
20
20
  gli
21
+ mime-types
21
22
 
22
23
  GEM
23
24
  remote: https://rubygems.org/
@@ -110,6 +111,9 @@ GEM
110
111
  mixlib-config (>= 2.2.1, < 4)
111
112
  mixlib-shellout
112
113
  method_source (1.0.0)
114
+ mime-types (3.5.1)
115
+ mime-types-data (~> 3.2015)
116
+ mime-types-data (3.2023.1205)
113
117
  minitest (5.20.0)
114
118
  minitest-profile (0.0.2)
115
119
  minitest-reporters (1.6.1)
data/Makefile CHANGED
@@ -49,7 +49,6 @@ clear_metrics: ## remove or reset result artifacts created by tests and quality
49
49
 
50
50
  clean: clear_metrics ## remove all built artifacts
51
51
 
52
-
53
52
  citest: test ## Run unit tests from CircleCI
54
53
 
55
54
  overcommit: ## run precommit quality checks
@@ -69,6 +68,14 @@ repl: ## Load up checkoff in pry
69
68
  clean-coverage:
70
69
  @bundle exec rake clear_metrics
71
70
 
71
+ clean-typecheck: ## Refresh information that type checking depends on
72
+ bundle install
73
+ bundle exec solargraph clear
74
+ rm -fr .yardoc/
75
+ bundle exec yard gems
76
+ bundle exec solargraph scan
77
+ echo all clear
78
+
72
79
  coverage: test report-coverage ## check code coverage
73
80
  @bundle exec rake undercover
74
81
 
data/checkoff.gemspec CHANGED
@@ -29,6 +29,7 @@ Gem::Specification.new do |spec|
29
29
  spec.add_runtime_dependency 'cache_method'
30
30
  spec.add_runtime_dependency 'dalli'
31
31
  spec.add_runtime_dependency 'gli'
32
+ spec.add_runtime_dependency 'mime-types'
32
33
 
33
34
  spec.metadata = {
34
35
  'rubygems_mfa_required' => 'false',
@@ -0,0 +1,204 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'faraday'
6
+ require 'forwardable'
7
+ require 'cache_method'
8
+ require 'mime/types'
9
+ require 'net/http'
10
+ require 'net/http/response'
11
+ require 'net/http/responses'
12
+ require 'tempfile'
13
+ require_relative 'internal/config_loader'
14
+ require_relative 'internal/logging'
15
+ require_relative 'workspaces'
16
+ require_relative 'tasks'
17
+ require_relative 'clients'
18
+
19
+ # https://developers.asana.com/reference/attachments
20
+
21
+ module Checkoff
22
+ # Manage attachments in Asana
23
+ class Attachments
24
+ # @!parse
25
+ # extend CacheMethod::ClassMethods
26
+
27
+ include Logging
28
+
29
+ MINUTE = 60
30
+ private_constant :MINUTE
31
+ HOUR = MINUTE * 60
32
+ private_constant :HOUR
33
+ DAY = 24 * HOUR
34
+ private_constant :DAY
35
+ REALLY_LONG_CACHE_TIME = HOUR * 1
36
+ private_constant :REALLY_LONG_CACHE_TIME
37
+ LONG_CACHE_TIME = MINUTE * 15
38
+ private_constant :LONG_CACHE_TIME
39
+ SHORT_CACHE_TIME = MINUTE
40
+ private_constant :SHORT_CACHE_TIME
41
+
42
+ # @param config [Hash]
43
+ # @param workspaces [Checkoff::Workspaces]
44
+ # @param clients [Checkoff::Clients]
45
+ # @param client [Asana::Client]
46
+ def initialize(config: Checkoff::Internal::ConfigLoader.load(:asana),
47
+ workspaces: Checkoff::Workspaces.new(config: config),
48
+ clients: Checkoff::Clients.new(config: config),
49
+ client: clients.client)
50
+ @workspaces = workspaces
51
+ @client = client
52
+ end
53
+
54
+ # @param url [String]
55
+ # @param resource [Asana::Resources::Resource]
56
+ # @param attachment_name [String,nil]
57
+ # @param just_the_url [Boolean]
58
+ #
59
+ # @return [Asana::Resources::Attachment]
60
+ def create_attachment_from_url!(url,
61
+ resource,
62
+ attachment_name: nil,
63
+ just_the_url: false)
64
+ if just_the_url
65
+ create_attachment_from_url_alone!(url, resource, attachment_name: attachment_name)
66
+ else
67
+ create_attachment_from_downloaded_url!(url, resource, attachment_name: attachment_name)
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ # Writes contents of URL to a temporary file with the same
74
+ # extension as the URL using Net::HTTP, raising an exception if
75
+ # not succesful
76
+ #
77
+ # @param uri [URI]
78
+ #
79
+ # @return [Object]
80
+ # @sg-ignore
81
+ def download_uri(uri, &block)
82
+ out = nil
83
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
84
+ # @sg-ignore
85
+ request = Net::HTTP::Get.new(uri)
86
+ http.request(request) do |response|
87
+ # use a block to ensure the file is closed after we're done with it
88
+ raise("Unexpected response code: #{response.code}") unless response.code == '200'
89
+
90
+ write_tempfile_from_response(response) do |tempfile|
91
+ out = block.yield tempfile
92
+ end
93
+ end
94
+ end
95
+ out
96
+ end
97
+
98
+ # @sg-ignore
99
+ # @param response [Net::HTTPResponse]
100
+ #
101
+ # @yields [IO]
102
+ #
103
+ # @return [Object]
104
+ def write_tempfile_from_response(response)
105
+ Tempfile.create('checkoff') do |tempfile|
106
+ tempfile.binmode
107
+ # @sg-ignore
108
+ response.read_body do |chunk|
109
+ tempfile.write(chunk)
110
+ end
111
+ tempfile.rewind
112
+
113
+ yield tempfile
114
+ end
115
+ end
116
+
117
+ # @param url [String]
118
+ # @param resource [Asana::Resources::Resource]
119
+ # @param attachment_name [String,nil]
120
+ #
121
+ # @return [Asana::Resources::Attachment]
122
+ def create_attachment_from_downloaded_url!(url, resource, attachment_name:)
123
+ uri = URI(url)
124
+ attachment_name ||= File.basename(uri.path)
125
+ download_uri(uri) do |tempfile|
126
+ content_type ||= content_type_from_filename(attachment_name)
127
+ content_type ||= content_type_from_filename(uri.path)
128
+
129
+ resource.attach(filename: attachment_name, mime: content_type,
130
+ io: tempfile)
131
+ end
132
+ end
133
+
134
+ # @param url [String]
135
+ # @param resource [Asana::Resources::Resource]
136
+ # @param attachment_name [String,nil]
137
+ #
138
+ # @return [Asana::Resources::Attachment,nil]
139
+ def create_attachment_from_url_alone!(url, resource, attachment_name:)
140
+ with_params = {
141
+ 'parent' => resource.gid,
142
+ 'url' => url,
143
+ 'resource_subtype' => 'external',
144
+ 'name' => attachment_name,
145
+ }
146
+ options = {}
147
+ Asana::Resource.new(parse(client.post('/attachments', body: with_params, options: options)).first,
148
+ client: client)
149
+ end
150
+
151
+ # @param filename [String]
152
+ #
153
+ # @return [String,nil]
154
+ # @sg-ignore
155
+ def content_type_from_filename(filename)
156
+ # @sg-ignore
157
+ MIME::Types.type_for(filename)&.first&.content_type
158
+ end
159
+
160
+ # https://github.com/Asana/ruby-asana/blob/master/lib/asana/resource_includes/response_helper.rb#L7
161
+ # @param response [Faraday::Response]
162
+ #
163
+ # @return [Array<Hash, Hash>]
164
+ def parse(response)
165
+ data = response.body.fetch('data') do
166
+ raise("Unexpected response body: #{response.body}")
167
+ end
168
+ extra = response.body.except('data')
169
+ [data, extra]
170
+ end
171
+
172
+ # @return [Checkoff::Workspaces]
173
+ attr_reader :workspaces
174
+
175
+ # @return [Asana::Client]
176
+ attr_reader :client
177
+
178
+ # bundle exec ./attachments.rb
179
+ # :nocov:
180
+ class << self
181
+ # @return [void]
182
+ def run
183
+ # @sg-ignore
184
+ # @type [String]
185
+ gid = ARGV[0] || raise('Please pass task gid as first argument')
186
+ # @sg-ignore
187
+ # @type [String]
188
+ url = ARGV[1] || raise('Please pass attachment URL as second argument')
189
+
190
+ tasks = Checkoff::Tasks.new
191
+ attachments = Checkoff::Attachments.new
192
+ task = tasks.task_by_gid(gid)
193
+ attachment = attachments.create_attachment_from_url!(url, task)
194
+ puts "Results: #{attachment.inspect}"
195
+ end
196
+ end
197
+ # :nocov:
198
+ end
199
+ end
200
+
201
+ # :nocov:
202
+ abs_program_name = File.expand_path($PROGRAM_NAME)
203
+ Checkoff::Attachments.run if abs_program_name == File.expand_path(__FILE__)
204
+ # :nocov:
@@ -3,5 +3,5 @@
3
3
  # Command-line and gem client for Asana (unofficial)
4
4
  module Checkoff
5
5
  # Version of library
6
- VERSION = '0.161.0'
6
+ VERSION = '0.163.0'
7
7
  end
data/lib/checkoff.rb CHANGED
@@ -17,3 +17,4 @@ require 'checkoff/task_selectors'
17
17
  require 'checkoff/project_selectors'
18
18
  require 'checkoff/section_selectors'
19
19
  require 'checkoff/task_searches'
20
+ require 'checkoff/attachments'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: checkoff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.161.0
4
+ version: 0.163.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vince Broz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-26 00:00:00.000000000 Z
11
+ date: 2023-12-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mime-types
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description:
84
98
  email:
85
99
  - vince@broz.cc
@@ -129,6 +143,7 @@ files:
129
143
  - exe/checkoff
130
144
  - fix.sh
131
145
  - lib/checkoff.rb
146
+ - lib/checkoff/attachments.rb
132
147
  - lib/checkoff/cli.rb
133
148
  - lib/checkoff/clients.rb
134
149
  - lib/checkoff/create-entity.sh