timely-app 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6e93ac9511c215489f329d2a464a85ee094ddadb88b41710298fd6e7aeca1d48
4
+ data.tar.gz: '0888c32a76cfabc24b32a74c5745f5fdc0252b2a9e28d395cadc6888eb52b1c9'
5
+ SHA512:
6
+ metadata.gz: 765f0d5cd8a1bdbdbb84b4d22cc60702d61547e4de445d13ac76d1b642cca88a82d9478e83566a75c1ba14bd021c8bc717fb4e5042b1c734480f3199da37b98f
7
+ data.tar.gz: 8003b4a414f1b39a828fdfa3434d50a6f803bdc9c0a181ed4a544e131c44131ff3bc9836508c522d776fd2c767105e87dc8ff520d968a1af5862efd00c32dd3a
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 1.0.0
2
+
3
+ * Initial version
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 amkisko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # timely-app
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/timely-app.svg)](https://badge.fury.io/rb/timely-app) [![Test Status](https://github.com/amkisko/timely-app/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/timely-app/actions/workflows/test.yml)
4
+
5
+ Ruby client for the [Timely API](https://dev.timelyapp.com).
6
+
7
+ ## Install
8
+
9
+ Using Bundler:
10
+ ```sh
11
+ bundle add timely-app
12
+ ```
13
+
14
+ Using RubyGems:
15
+ ```sh
16
+ gem install timely-app
17
+ ```
18
+
19
+ ## Getting started
20
+
21
+ Implement link to Timely OAuth authorization page:
22
+
23
+ ```ruby
24
+ <%= link_to "Sign in with Timely", TimelyApp::Client.new.get_oauth_authorize_url(client_id: ENV.fetch("TIMELY_CLIENT_ID"), redirect_uri: ENV.fetch("TIMELY_REDIRECT_URI")) %>
25
+ ```
26
+
27
+ Implement callback action to get access token:
28
+
29
+ ```ruby
30
+ def timely_auth_callback
31
+ skip_verify_authorized!
32
+
33
+ client = TimelyApp::Client.new
34
+ token = client.post_oauth_token(client_id: ENV.fetch("TIMELY_CLIENT_ID"), client_secret: ENV.fetch("TIMELY_CLIENT_SECRET"), code: params["code"], redirect_uri: ENV.fetch("TIMELY_REDIRECT_URI"), grant_type: "authorization_code")
35
+
36
+ if token["access_token"].present?
37
+ client.access_token = token["access_token"]
38
+ timely_user = client.get_current_user
39
+
40
+ user = User.find_or_create_by(email: timely_user["email"])
41
+ user.update!(timely_id: timely_user["id"], timely_access_token: token["access_token"], timely_refresh_token: token["refresh_token"])
42
+
43
+ sign_in(user)
44
+
45
+ redirect_to "/authorized"
46
+ else
47
+ redirect_to "/not-authorized"
48
+ end
49
+ rescue TimelyApp::Error => _e
50
+ redirect_to "/not-authorized"
51
+ end
52
+ ```
53
+
54
+ Use client:
55
+
56
+ ```ruby
57
+ timely = TimelyApp::Client.new(access_token: <USER_TOKEN_AFTER_OAUTH>, account_id: <ACCOUNT_ID>)
58
+
59
+ timely.get_projects.each do |project|
60
+ puts project.name
61
+ end
62
+ ```
63
+
64
+ ## How to test callbacks
65
+
66
+ You can use [localhost.run](https://localhost.run/) to test callbacks locally.
67
+
68
+ There are large list of available tools for tunneling: [awesome-tunneling](https://github.com/anderspitman/awesome-tunneling)
69
+
70
+ ## Contributing
71
+
72
+ Bug reports and pull requests are welcome on GitHub at https://github.com/amkisko/timely-app
73
+
74
+ ## License
75
+
76
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#accounts
4
+ module TimelyApp
5
+ class Client
6
+ def get_accounts
7
+ get('/1.1/accounts')
8
+ end
9
+
10
+ def get_account_activities(account_id, **params)
11
+ get("/1.1/#{account_id}/activities", params)
12
+ end
13
+
14
+ def get_account(id)
15
+ get("/1.1/accounts/#{id}")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#authentication
4
+ module TimelyApp
5
+ class Client
6
+ def get_oauth_authorize_url(client_id:, redirect_uri:)
7
+ host_uri_join(
8
+ "/1.1/oauth/authorize",
9
+ response_type: 'code',
10
+ redirect_uri: redirect_uri,
11
+ client_id: client_id
12
+ )
13
+ end
14
+
15
+ def post_oauth_token(client_id:, client_secret:, code:, redirect_uri:, grant_type: "authorization_code")
16
+ post("/1.1/oauth/token", body: {
17
+ redirect_uri: redirect_uri,
18
+ code: code,
19
+ client_id: client_id,
20
+ client_secret: client_secret,
21
+ grant_type: grant_type
22
+ }, params: {})
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#clients
4
+ module TimelyApp
5
+ class Client
6
+ def create_client(name:, **params)
7
+ post("/1.1/#{account_id}/clients", client: params.merge(name: name))
8
+ end
9
+
10
+ def get_clients(**params)
11
+ get('/1.1/accounts', params)
12
+ end
13
+
14
+ def get_client(id)
15
+ get("/1.1/#{account_id}/clients/#{id}")
16
+ end
17
+
18
+ def update_client(id, name:, **params)
19
+ put("/1.1/#{account_id}/clients/#{id}", client: params.merge(name: name))
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#events
4
+ module TimelyApp
5
+ class Client
6
+ def create_event(day:, hours:, minutes:, **params)
7
+ post("/1.1/#{account_id}/events", event: params.merge(day: day, hours: hours, minutes: minutes))
8
+ end
9
+
10
+ def create_project_event(project_id:, day:, hours:, minutes:, **params)
11
+ post("/1.1/#{account_id}/projects/#{project_id}/events", event: params.merge(day: day, hours: hours, minutes: minutes))
12
+ end
13
+
14
+ def create_user_event(user_id:, day:, hours:, minutes:, **params)
15
+ post("/1.1/#{account_id}/users/#{user_id}/events", event: params.merge(day: day, hours: hours, minutes: minutes))
16
+ end
17
+
18
+ def create_bulk_events(create)
19
+ post("/1.1/#{account_id}/bulk/events", create: create)
20
+ end
21
+
22
+ def delete_event(id)
23
+ delete("/1.1/#{account_id}/events/#{id}")
24
+ end
25
+
26
+ def delete_bulk_events(delete)
27
+ post("/1.1/#{account_id}/bulk/events", delete: delete)
28
+ end
29
+
30
+ def get_events(**params)
31
+ get("/1.1/#{account_id}/events", params)
32
+ end
33
+
34
+ def get_project_events(project_id:, **params)
35
+ get("/1.1/#{account_id}/projects/#{project_id}/events", params)
36
+ end
37
+
38
+ def get_user_events(user_id:, **params)
39
+ get("/1.1/#{account_id}/users/#{user_id}/events", params)
40
+ end
41
+
42
+ def update_user_event(id, user_id:, day:, hours:, minutes:, **params)
43
+ put("/1.1/#{account_id}/users/#{user_id}/events/#{id}", event: params.merge(day: day, hours: hours, minutes: minutes))
44
+ end
45
+
46
+ def update_project_event(id, project_id:, day:, hours:, minutes:, **params)
47
+ put("/1.1/#{account_id}/projects/#{project_id}/events/#{id}", event: params.merge(day: day, hours: hours, minutes: minutes))
48
+ end
49
+
50
+ def get_event(id)
51
+ get("/1.1/#{account_id}/events/#{id}")
52
+ end
53
+
54
+ def start_event_timer(id)
55
+ put("/1.1/#{account_id}/events/#{id}/start")
56
+ end
57
+
58
+ def stop_event_timer(id)
59
+ put("/1.1/#{account_id}/events/#{id}/stop")
60
+ end
61
+
62
+ def update_event(id, day:, hours:, minutes:, **params)
63
+ put("/1.1/#{account_id}/events/#{id}", event: params.merge(day: day, hours: hours, minutes: minutes))
64
+ end
65
+
66
+ def update_bulk_events(update)
67
+ post("/1.1/#{account_id}/bulk/events", update: update)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#forecasts
4
+ module TimelyApp
5
+ class Client
6
+ def create_forecast(project_id:, **params)
7
+ post("/1.1/#{account_id}/forecasts", forecast: params.merge(project_id: project_id))
8
+ end
9
+
10
+ def delete_forecast(id)
11
+ delete("/1.1/#{account_id}/forecasts/#{id}")
12
+ end
13
+
14
+ def get_forecasts(**params)
15
+ get("/1.1/#{account_id}/forecasts", params)
16
+ end
17
+
18
+ def update_forecast(id, project_id:, estimated_minutes:, **params)
19
+ put("/1.1/#{account_id}/forecasts/#{id}", forecast: params.merge(project_id: project_id, estimated_minutes: estimated_minutes))
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#labels
4
+ module TimelyApp
5
+ class Client
6
+ def create_label(name:, **params)
7
+ post("/1.1/#{account_id}/labels", label: params.merge(name: name))
8
+ end
9
+
10
+ def delete_label(id)
11
+ delete("/1.1/#{account_id}/labels/#{id}")
12
+ end
13
+
14
+ def get_child_labels(parent_id)
15
+ get("/1.1/#{account_id}/labels", parent_id: parent_id)
16
+ end
17
+
18
+ def get_labels(**params)
19
+ get("/1.1/#{account_id}/labels", params)
20
+ end
21
+
22
+ def get_label(id)
23
+ get("/1.1/#{account_id}/labels/#{id}")
24
+ end
25
+
26
+ def update_label(id, name:, **params)
27
+ put("/1.1/#{account_id}/labels/#{id}", label: params.merge(name: name))
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#permissions
4
+ module TimelyApp
5
+ class Client
6
+ def get_current_user_permissions
7
+ get("/1.1/#{account_id}/users/current/permissions")
8
+ end
9
+
10
+ def get_user_permissions(user_id:)
11
+ get("/1.1/#{account_id}/users/#{user_id}/permissions")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#projects
4
+ module TimelyApp
5
+ class Client
6
+ def create_project(name:, color:, client_id:, users:, **params)
7
+ post("/1.1/#{account_id}/projects", project: params.merge(name: name, color: color, client_id: client_id, users: users))
8
+ end
9
+
10
+ def delete_project(id)
11
+ delete("/1.1/#{account_id}/projects/#{id}")
12
+ end
13
+
14
+ def get_projects(**params)
15
+ get("/1.1/#{account_id}/projects", params)
16
+ end
17
+
18
+ def get_project(id)
19
+ get("/1.1/#{account_id}/projects/#{id}")
20
+ end
21
+
22
+ def update_project(id, name:, color:, client_id:, users:, **params)
23
+ put("/1.1/#{account_id}/projects/#{id}", project: params.merge(name: name, color: color, client_id: client_id, users: users))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#reports
4
+ module TimelyApp
5
+ class Client
6
+ def get_reports(**params)
7
+ post("/1.1/#{account_id}/reports", params)
8
+ end
9
+
10
+ def get_filter_reports(**params)
11
+ post("/1.1/#{account_id}/reports/filter", params)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#roles
4
+ module TimelyApp
5
+ class Client
6
+ def get_roles
7
+ get("/1.1/#{account_id}/roles")
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#teams
4
+ module TimelyApp
5
+ class Client
6
+ def create_team(name:, users:, **params)
7
+ post("/1.1/#{account_id}/teams", team: params.merge(name: name, users: users))
8
+ end
9
+
10
+ def delete_team(id)
11
+ delete("/1.1/#{account_id}/teams/#{id}")
12
+ end
13
+
14
+ def get_teams(**params)
15
+ get("/1.1/#{account_id}/teams", params)
16
+ end
17
+
18
+ def get_team(id)
19
+ get("/1.1/#{account_id}/teams/#{id}")
20
+ end
21
+
22
+ def update_team(id, name:, users:, **params)
23
+ put("/1.1/#{account_id}/teams/#{id}", team: params.merge(name: name, users: users))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#user_capacities
4
+ module TimelyApp
5
+ class Client
6
+ def get_users_capacities(**params)
7
+ get("/1.1/#{account_id}/users/capacities", params)
8
+ end
9
+
10
+ def get_user_capacities(user_id:)
11
+ get("/1.1/#{account_id}/users/#{user_id}/capacities")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#users
4
+ module TimelyApp
5
+ class Client
6
+ def create_user(name:, email:, role_id:, **params)
7
+ post("/1.1/#{account_id}/users", user: params.merge(name: name, email: email, role_id: role_id))
8
+ end
9
+
10
+ def delete_user(id)
11
+ delete("/1.1/#{account_id}/users/#{id}")
12
+ end
13
+
14
+ def get_users(**params)
15
+ get("/1.1/#{account_id}/users", params)
16
+ end
17
+
18
+ def get_user(id)
19
+ get("/1.1/#{account_id}/users/#{id}")
20
+ end
21
+
22
+ def get_current_user
23
+ get("/1.1/#{account_id}/users/current")
24
+ end
25
+
26
+ def update_user(id, name:, email:, role_id:, **params)
27
+ put("/1.1/#{account_id}/users/#{id}", user: params.merge(name: name, email: email, role_id: role_id))
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # https://dev.timelyapp.com/#webhooks
4
+ module TimelyApp
5
+ class Client
6
+ def create_webhook(url:, **params)
7
+ post("/1.1/#{account_id}/webhooks", webhook: params.merge(url: url))
8
+ end
9
+
10
+ def delete_webhook(id)
11
+ delete("/1.1/#{account_id}/webhooks/#{id}")
12
+ end
13
+
14
+ def get_webhooks(**params)
15
+ get("/1.1/#{account_id}/webhooks", params)
16
+ end
17
+
18
+ def get_webhook(id)
19
+ get("/1.1/#{account_id}/webhooks/#{id}")
20
+ end
21
+
22
+ def update_webhook(id, url:, **params)
23
+ put("/1.1/#{account_id}/webhooks/#{id}", webhook: params.merge(url: url))
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ require 'timely-app/version'
3
+ require 'timely-app/errors'
4
+ require 'timely-app/link_header'
5
+ require 'timely-app/params'
6
+ require 'timely-app/record'
7
+ require 'timely-app/response'
8
+ require 'net/http'
9
+ require 'json'
10
+
11
+ module TimelyApp
12
+ class Client
13
+ attr_accessor :account_id
14
+
15
+ def initialize(options = {})
16
+ @auth_header, @auth_value = 'Authorization', "Bearer #{options[:access_token]}"
17
+ @user_agent = options.fetch(:user_agent) { "timely-app/#{VERSION} ruby/#{RUBY_VERSION}" }
18
+
19
+ @host = 'api.timelyapp.com'
20
+
21
+ @http = Net::HTTP.new(@host, Net::HTTP.https_default_port)
22
+ @http.use_ssl = true
23
+
24
+ @account_id = options[:account_id]
25
+ end
26
+
27
+ def get(path, params = nil)
28
+ request(Net::HTTP::Get.new(Params.join(path, params)))
29
+ end
30
+
31
+ private
32
+
33
+ def host_uri_join(path, params)
34
+ URI::join("https://#{@host}", Params.join(path, params)).to_s
35
+ end
36
+
37
+ def post(path, attributes)
38
+ request(Net::HTTP::Post.new(path), attributes)
39
+ end
40
+
41
+ def put(path, attributes = nil)
42
+ request(Net::HTTP::Put.new(path), attributes)
43
+ end
44
+
45
+ def delete(path)
46
+ request(Net::HTTP::Delete.new(path))
47
+ end
48
+
49
+ def request(http_request, body_object = nil)
50
+ http_request['User-Agent'] = @user_agent
51
+ http_request[@auth_header] = @auth_value
52
+
53
+ if body_object
54
+ http_request['Content-Type'] = 'application/json'
55
+ http_request.body = JSON.generate(body_object)
56
+ end
57
+
58
+ response = @http.request(http_request)
59
+
60
+ if response.is_a?(Net::HTTPSuccess)
61
+ Response.parse(response)
62
+ else
63
+ raise Response.error(response)
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,21 @@
1
+ module TimelyApp
2
+ class Error < StandardError
3
+ attr_reader :response, :errors
4
+
5
+ def initialize(message = nil, response:, errors: nil)
6
+ @response = response
7
+ @errors = errors
8
+
9
+ super(message)
10
+ end
11
+ end
12
+
13
+ ClientError = Class.new(Error)
14
+
15
+ ServerError = Class.new(Error)
16
+
17
+ UnauthorizedError = Class.new(ClientError)
18
+
19
+ NotFound = Class.new(ClientError)
20
+ ForbiddenError = Class.new(ClientError)
21
+ end
@@ -0,0 +1,18 @@
1
+ require 'timely-app/record'
2
+ require 'uri'
3
+
4
+ module TimelyApp
5
+ module LinkHeader
6
+ extend self
7
+
8
+ REGEXP = /<([^>]+)>; rel="(\w+)"/
9
+
10
+ def parse(string)
11
+ string.scan(REGEXP).each_with_object(Record.new) do |(uri, rel), record|
12
+ record[rel.to_sym] = URI.parse(uri).request_uri
13
+ end
14
+ end
15
+ end
16
+
17
+ private_constant :LinkHeader
18
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'cgi'
3
+
4
+ module TimelyApp
5
+ module Params
6
+ extend self
7
+
8
+ def join(path, params = nil)
9
+ return path if params.nil? || params.empty?
10
+
11
+ path + '?' + encode(params)
12
+ end
13
+
14
+ def encode(params)
15
+ params.map { |k, v| "#{escape(k)}=#{array_escape(v)}" }.join('&')
16
+ end
17
+
18
+ private
19
+
20
+ def array_escape(object)
21
+ Array(object).map { |value| escape(value) }.join(',')
22
+ end
23
+
24
+ def escape(component)
25
+ CGI.escape(component.to_s)
26
+ end
27
+ end
28
+
29
+ private_constant :Params
30
+ end
@@ -0,0 +1,31 @@
1
+ module TimelyApp
2
+ class Record
3
+ def initialize(attributes = {})
4
+ @attributes = attributes
5
+ end
6
+
7
+ def [](name)
8
+ @attributes[name]
9
+ end
10
+
11
+ def []=(name, value)
12
+ @attributes[name] = value
13
+ end
14
+
15
+ def method_missing(name, *args, &block)
16
+ if @attributes.has_key?(name) && args.empty? && block.nil?
17
+ return @attributes[name]
18
+ else
19
+ super name, *args, &block
20
+ end
21
+ end
22
+
23
+ def respond_to_missing?(name, include_private = false)
24
+ @attributes.has_key?(name)
25
+ end
26
+
27
+ def to_h
28
+ @attributes
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ module TimelyApp
6
+ module Response
7
+ extend self
8
+
9
+ def parse(response)
10
+ if response.is_a?(Net::HTTPNoContent)
11
+ return :no_content
12
+ end
13
+
14
+ if response.content_type == 'application/json'
15
+ object = JSON.parse(response.body, symbolize_names: true, object_class: Record)
16
+
17
+ if response['Link']
18
+ object.singleton_class.module_eval { attr_accessor :link }
19
+ object.link = LinkHeader.parse(response['Link'])
20
+ end
21
+
22
+ return object
23
+ end
24
+
25
+ response.body
26
+ end
27
+
28
+ def error(response)
29
+ if response.content_type == "application/json"
30
+ body = JSON.parse(response.body)
31
+ error_class(response).new(body&.dig("errors", "message"), response: response, errors: body&.dig("errors"))
32
+ else
33
+ error_class(response).new(response: response)
34
+ end
35
+ end
36
+
37
+ def error_class(object)
38
+ case object
39
+ when Net::HTTPBadRequest then TimelyApp::ClientError
40
+ when Net::HTTPUnauthorized then TimelyApp::UnauthorizedError
41
+ when Net::HTTPForbidden then TimelyApp::ForbiddenError
42
+ when Net::HTTPNotFound then TimelyApp::NotFoundError
43
+ when Net::HTTPClientError then TimelyApp::ClientError
44
+ when Net::HTTPServerError then TimelyApp::ServerError
45
+ else
46
+ TimelyApp::Error
47
+ end
48
+ end
49
+ end
50
+
51
+ private_constant :Response
52
+ end
@@ -0,0 +1,3 @@
1
+ module TimelyApp
2
+ VERSION = '1.0.0'
3
+ end
data/lib/timely-app.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'timely-app/client'
2
+ require 'timely-app/client/accounts'
3
+ require 'timely-app/client/auth'
4
+ require 'timely-app/client/clients'
5
+ require 'timely-app/client/events'
6
+ require 'timely-app/client/forecasts'
7
+ require 'timely-app/client/labels'
8
+ require 'timely-app/client/permissions'
9
+ require 'timely-app/client/projects'
10
+ require 'timely-app/client/reports'
11
+ require 'timely-app/client/roles'
12
+ require 'timely-app/client/teams'
13
+ require 'timely-app/client/user_capacities'
14
+ require 'timely-app/client/users'
15
+ require 'timely-app/client/webhooks'
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'timely-app'
3
+ s.version = '1.0.0'
4
+ s.license = 'MIT'
5
+ s.platform = Gem::Platform::RUBY
6
+ s.authors = ['Andrei Makarov']
7
+ s.email = ['andrei@kiskolabs.com']
8
+ s.homepage = 'https://github.com/amkisko/timely-app'
9
+ s.description = 'Ruby client for the Timely API'
10
+ s.summary = 'See description'
11
+ s.files = Dir.glob('lib/**/*.rb') + %w(CHANGELOG.md LICENSE.md README.md timely-app.gemspec)
12
+ s.required_ruby_version = '>= 1.9.3'
13
+ s.require_path = 'lib'
14
+ s.metadata = {
15
+ 'homepage' => 'https://github.com/amkisko/timely-app',
16
+ 'source_code_uri' => 'https://github.com/amkisko/timely-app',
17
+ 'bug_tracker_uri' => 'https://github.com/amkisko/timely-app/issues',
18
+ 'changelog_uri' => 'https://github.com/amkisko/timely-app/blob/main/CHANGES.md'
19
+ }
20
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timely-app
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrei Makarov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby client for the Timely API
14
+ email:
15
+ - andrei@kiskolabs.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - CHANGELOG.md
21
+ - LICENSE.md
22
+ - README.md
23
+ - lib/timely-app.rb
24
+ - lib/timely-app/client.rb
25
+ - lib/timely-app/client/accounts.rb
26
+ - lib/timely-app/client/auth.rb
27
+ - lib/timely-app/client/clients.rb
28
+ - lib/timely-app/client/events.rb
29
+ - lib/timely-app/client/forecasts.rb
30
+ - lib/timely-app/client/labels.rb
31
+ - lib/timely-app/client/permissions.rb
32
+ - lib/timely-app/client/projects.rb
33
+ - lib/timely-app/client/reports.rb
34
+ - lib/timely-app/client/roles.rb
35
+ - lib/timely-app/client/teams.rb
36
+ - lib/timely-app/client/user_capacities.rb
37
+ - lib/timely-app/client/users.rb
38
+ - lib/timely-app/client/webhooks.rb
39
+ - lib/timely-app/errors.rb
40
+ - lib/timely-app/link_header.rb
41
+ - lib/timely-app/params.rb
42
+ - lib/timely-app/record.rb
43
+ - lib/timely-app/response.rb
44
+ - lib/timely-app/version.rb
45
+ - timely-app.gemspec
46
+ homepage: https://github.com/amkisko/timely-app
47
+ licenses:
48
+ - MIT
49
+ metadata:
50
+ homepage: https://github.com/amkisko/timely-app
51
+ source_code_uri: https://github.com/amkisko/timely-app
52
+ bug_tracker_uri: https://github.com/amkisko/timely-app/issues
53
+ changelog_uri: https://github.com/amkisko/timely-app/blob/main/CHANGES.md
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.9.3
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubygems_version: 3.3.3
70
+ signing_key:
71
+ specification_version: 4
72
+ summary: See description
73
+ test_files: []