camper 0.0.6 → 0.0.11
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 +4 -4
- data/.gitignore +1 -1
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +48 -2
- data/Gemfile.lock +10 -11
- data/README.md +14 -0
- data/camper.gemspec +1 -0
- data/examples/people.rb +11 -0
- data/examples/projects.rb +12 -0
- data/examples/recordings.rb +13 -0
- data/examples/todolists.rb +50 -0
- data/examples/todos.rb +21 -6
- data/lib/camper.rb +2 -0
- data/lib/camper/api/{comment.rb → comments.rb} +3 -1
- data/lib/camper/api/{message.rb → messages.rb} +1 -1
- data/lib/camper/api/people.rb +97 -0
- data/lib/camper/api/projects.rb +120 -0
- data/lib/camper/api/recordings.rb +84 -0
- data/lib/camper/api/todolists.rb +103 -0
- data/lib/camper/api/todos.rb +198 -0
- data/lib/camper/client.rb +7 -4
- data/lib/camper/core_extensions/object.rb +156 -0
- data/lib/camper/error.rb +6 -0
- data/lib/camper/recording_types.rb +22 -0
- data/lib/camper/request.rb +2 -13
- data/lib/camper/url_utils.rb +26 -0
- data/lib/camper/version.rb +1 -1
- metadata +31 -7
- data/lib/camper/api/project.rb +0 -24
- data/lib/camper/api/todo.rb +0 -80
data/lib/camper/client.rb
CHANGED
@@ -12,12 +12,15 @@ module Camper
|
|
12
12
|
|
13
13
|
# Keep in alphabetical order
|
14
14
|
include Authorization
|
15
|
-
include
|
15
|
+
include CommentsAPI
|
16
16
|
include Logging
|
17
|
-
include
|
18
|
-
include
|
17
|
+
include MessagesAPI
|
18
|
+
include PeopleAPI
|
19
|
+
include ProjectsAPI
|
20
|
+
include RecordingsAPI
|
19
21
|
include ResourceAPI
|
20
|
-
include
|
22
|
+
include TodolistsAPI
|
23
|
+
include TodosAPI
|
21
24
|
|
22
25
|
# Creates a new Client instance.
|
23
26
|
# @raise [Error:MissingCredentials]
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copied from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/blank.rb
|
3
|
+
|
4
|
+
require 'concurrent/map'
|
5
|
+
|
6
|
+
class Object
|
7
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
8
|
+
# For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
|
9
|
+
#
|
10
|
+
# This simplifies
|
11
|
+
#
|
12
|
+
# !address || address.empty?
|
13
|
+
#
|
14
|
+
# to
|
15
|
+
#
|
16
|
+
# address.blank?
|
17
|
+
#
|
18
|
+
# @return [true, false]
|
19
|
+
def blank?
|
20
|
+
respond_to?(:empty?) ? !!empty? : !self
|
21
|
+
end
|
22
|
+
|
23
|
+
# An object is present if it's not blank.
|
24
|
+
#
|
25
|
+
# @return [true, false]
|
26
|
+
def present?
|
27
|
+
!blank?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the receiver if it's present otherwise returns +nil+.
|
31
|
+
# <tt>object.presence</tt> is equivalent to
|
32
|
+
#
|
33
|
+
# object.present? ? object : nil
|
34
|
+
#
|
35
|
+
# For example, something like
|
36
|
+
#
|
37
|
+
# state = params[:state] if params[:state].present?
|
38
|
+
# country = params[:country] if params[:country].present?
|
39
|
+
# region = state || country || 'US'
|
40
|
+
#
|
41
|
+
# becomes
|
42
|
+
#
|
43
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
44
|
+
#
|
45
|
+
# @return [Object]
|
46
|
+
def presence
|
47
|
+
self if present?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class NilClass
|
52
|
+
# +nil+ is blank:
|
53
|
+
#
|
54
|
+
# nil.blank? # => true
|
55
|
+
#
|
56
|
+
# @return [true]
|
57
|
+
def blank?
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class FalseClass
|
63
|
+
# +false+ is blank:
|
64
|
+
#
|
65
|
+
# false.blank? # => true
|
66
|
+
#
|
67
|
+
# @return [true]
|
68
|
+
def blank?
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class TrueClass
|
74
|
+
# +true+ is not blank:
|
75
|
+
#
|
76
|
+
# true.blank? # => false
|
77
|
+
#
|
78
|
+
# @return [false]
|
79
|
+
def blank?
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Array
|
85
|
+
# An array is blank if it's empty:
|
86
|
+
#
|
87
|
+
# [].blank? # => true
|
88
|
+
# [1,2,3].blank? # => false
|
89
|
+
#
|
90
|
+
# @return [true, false]
|
91
|
+
alias_method :blank?, :empty?
|
92
|
+
end
|
93
|
+
|
94
|
+
class Hash
|
95
|
+
# A hash is blank if it's empty:
|
96
|
+
#
|
97
|
+
# {}.blank? # => true
|
98
|
+
# { key: 'value' }.blank? # => false
|
99
|
+
#
|
100
|
+
# @return [true, false]
|
101
|
+
alias_method :blank?, :empty?
|
102
|
+
end
|
103
|
+
|
104
|
+
class String
|
105
|
+
BLANK_RE = /\A[[:space:]]*\z/
|
106
|
+
ENCODED_BLANKS = Concurrent::Map.new do |h, enc|
|
107
|
+
h[enc] = Regexp.new(BLANK_RE.source.encode(enc), BLANK_RE.options | Regexp::FIXEDENCODING)
|
108
|
+
end
|
109
|
+
|
110
|
+
# A string is blank if it's empty or contains whitespaces only:
|
111
|
+
#
|
112
|
+
# ''.blank? # => true
|
113
|
+
# ' '.blank? # => true
|
114
|
+
# "\t\n\r".blank? # => true
|
115
|
+
# ' blah '.blank? # => false
|
116
|
+
#
|
117
|
+
# Unicode whitespace is supported:
|
118
|
+
#
|
119
|
+
# "\u00a0".blank? # => true
|
120
|
+
#
|
121
|
+
# @return [true, false]
|
122
|
+
def blank?
|
123
|
+
# The regexp that matches blank strings is expensive. For the case of empty
|
124
|
+
# strings we can speed up this method (~3.5x) with an empty? call. The
|
125
|
+
# penalty for the rest of strings is marginal.
|
126
|
+
empty? ||
|
127
|
+
begin
|
128
|
+
BLANK_RE.match?(self)
|
129
|
+
rescue Encoding::CompatibilityError
|
130
|
+
ENCODED_BLANKS[self.encoding].match?(self)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class Numeric #:nodoc:
|
136
|
+
# No number is blank:
|
137
|
+
#
|
138
|
+
# 1.blank? # => false
|
139
|
+
# 0.blank? # => false
|
140
|
+
#
|
141
|
+
# @return [false]
|
142
|
+
def blank?
|
143
|
+
false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class Time #:nodoc:
|
148
|
+
# No Time is blank:
|
149
|
+
#
|
150
|
+
# Time.now.blank? # => false
|
151
|
+
#
|
152
|
+
# @return [false]
|
153
|
+
def blank?
|
154
|
+
false
|
155
|
+
end
|
156
|
+
end
|
data/lib/camper/error.rb
CHANGED
@@ -13,6 +13,12 @@ module Camper
|
|
13
13
|
|
14
14
|
class MissingBody < Error; end
|
15
15
|
|
16
|
+
class ResourceCannotBeCommented < Error; end
|
17
|
+
|
18
|
+
class RequestIsMissingParameters < Error; end
|
19
|
+
|
20
|
+
class InvalidParameter < Error; end
|
21
|
+
|
16
22
|
# Raised when impossible to parse response body.
|
17
23
|
class Parsing < Error; end
|
18
24
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Camper
|
4
|
+
class RecordingTypes
|
5
|
+
COMMENT = 'Comment'
|
6
|
+
DOCUMENT = 'Document'
|
7
|
+
MESSAGE = 'Message'
|
8
|
+
QUESTION_ANSWER = 'Question::Answer'
|
9
|
+
SCHEDULE_ENTRY = 'Schedule::Entry'
|
10
|
+
TODO = 'Todo'
|
11
|
+
TODOLIST = 'Todolist'
|
12
|
+
UPLOAD = 'Upload'
|
13
|
+
|
14
|
+
# rubocop:disable Style/ClassVars
|
15
|
+
def self.all
|
16
|
+
@@recordings ||= constants(false).map { |c| const_get(c) }.sort
|
17
|
+
|
18
|
+
@@recordings
|
19
|
+
end
|
20
|
+
# rubocop:enable Style/ClassVars
|
21
|
+
end
|
22
|
+
end
|
data/lib/camper/request.rb
CHANGED
@@ -93,7 +93,7 @@ module Camper
|
|
93
93
|
|
94
94
|
full_endpoint = override_path ? @path : @client.api_endpoint + @path
|
95
95
|
|
96
|
-
full_endpoint =
|
96
|
+
full_endpoint = UrlUtils.transform(full_endpoint)
|
97
97
|
|
98
98
|
return full_endpoint, params
|
99
99
|
end
|
@@ -138,19 +138,8 @@ module Camper
|
|
138
138
|
{ 'Authorization' => "Bearer #{@client.access_token}" }
|
139
139
|
end
|
140
140
|
|
141
|
-
# Utility method for transforming Basecamp Web URLs into API URIs
|
142
|
-
# e.g 'https://3.basecamp.com/1/buckets/2/todos/3' will be
|
143
|
-
# converted into 'https://3.basecampapi.com/1/buckets/2/todos/3.json'
|
144
|
-
#
|
145
|
-
# @return [String]
|
146
|
-
def url_transform(url)
|
147
|
-
api_url = url.gsub('3.basecamp.com', '3.basecampapi.com')
|
148
|
-
api_url.gsub!('.json', '')
|
149
|
-
"#{api_url}.json"
|
150
|
-
end
|
151
|
-
|
152
141
|
def body_to_json?(params)
|
153
|
-
@method
|
142
|
+
%w[post put].include?(@method) && params.key?(:body)
|
154
143
|
end
|
155
144
|
end
|
156
145
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Camper
|
4
|
+
# Defines methods related to url operations.
|
5
|
+
module UrlUtils
|
6
|
+
def self.basecamp_url?(url)
|
7
|
+
return false if url.nil? || !url.is_a?(String) || url == ''
|
8
|
+
|
9
|
+
transformed_url = UrlUtils.transform(url)
|
10
|
+
|
11
|
+
transformed_url.match?(%r{#{Configuration.base_api_endpoint}/\d+/.*})
|
12
|
+
end
|
13
|
+
|
14
|
+
# Utility method for transforming Basecamp Web URLs into API URIs
|
15
|
+
# e.g 'https://3.basecamp.com/1/buckets/2/todos/3' will be
|
16
|
+
# converted into 'https://3.basecampapi.com/1/buckets/2/todos/3.json'
|
17
|
+
#
|
18
|
+
# @param url [String] url to test
|
19
|
+
# @return [String]
|
20
|
+
def self.transform(url)
|
21
|
+
api_url = url.gsub('3.basecamp.com', '3.basecampapi.com')
|
22
|
+
api_url.gsub!('.json', '')
|
23
|
+
"#{api_url}.json"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/camper/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: camper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- renehernandez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: concurrent-ruby
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.1'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,23 +126,33 @@ files:
|
|
112
126
|
- examples/messages.rb
|
113
127
|
- examples/oauth.rb
|
114
128
|
- examples/obtain_acces_token.rb
|
129
|
+
- examples/people.rb
|
130
|
+
- examples/projects.rb
|
131
|
+
- examples/recordings.rb
|
132
|
+
- examples/todolists.rb
|
115
133
|
- examples/todos.rb
|
116
134
|
- lib/camper.rb
|
117
|
-
- lib/camper/api/
|
118
|
-
- lib/camper/api/
|
119
|
-
- lib/camper/api/
|
135
|
+
- lib/camper/api/comments.rb
|
136
|
+
- lib/camper/api/messages.rb
|
137
|
+
- lib/camper/api/people.rb
|
138
|
+
- lib/camper/api/projects.rb
|
139
|
+
- lib/camper/api/recordings.rb
|
120
140
|
- lib/camper/api/resource.rb
|
121
|
-
- lib/camper/api/
|
141
|
+
- lib/camper/api/todolists.rb
|
142
|
+
- lib/camper/api/todos.rb
|
122
143
|
- lib/camper/authorization.rb
|
123
144
|
- lib/camper/client.rb
|
124
145
|
- lib/camper/configuration.rb
|
146
|
+
- lib/camper/core_extensions/object.rb
|
125
147
|
- lib/camper/error.rb
|
126
148
|
- lib/camper/logging.rb
|
127
149
|
- lib/camper/paginated_response.rb
|
128
150
|
- lib/camper/pagination_data.rb
|
151
|
+
- lib/camper/recording_types.rb
|
129
152
|
- lib/camper/request.rb
|
130
153
|
- lib/camper/resource.rb
|
131
154
|
- lib/camper/resources/project.rb
|
155
|
+
- lib/camper/url_utils.rb
|
132
156
|
- lib/camper/version.rb
|
133
157
|
homepage: https://github.com/renehernandez/camper
|
134
158
|
licenses:
|
@@ -152,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
176
|
- !ruby/object:Gem::Version
|
153
177
|
version: '0'
|
154
178
|
requirements: []
|
155
|
-
rubygems_version: 3.1.
|
179
|
+
rubygems_version: 3.1.4
|
156
180
|
signing_key:
|
157
181
|
specification_version: 4
|
158
182
|
summary: Ruby client for Basecamp 3 API
|
data/lib/camper/api/project.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Camper::Client
|
4
|
-
module ProjectAPI
|
5
|
-
|
6
|
-
def projects(options = {})
|
7
|
-
get("/projects", options)
|
8
|
-
end
|
9
|
-
|
10
|
-
def project(id)
|
11
|
-
get("/projects/#{id}")
|
12
|
-
end
|
13
|
-
|
14
|
-
def message_board(project)
|
15
|
-
board = project.message_board
|
16
|
-
get(board.url, override_path: true)
|
17
|
-
end
|
18
|
-
|
19
|
-
def todoset(project)
|
20
|
-
todoset = project.todoset
|
21
|
-
get(todoset.url, override_path: true)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/camper/api/todo.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Camper::Client
|
4
|
-
module TodoAPI
|
5
|
-
|
6
|
-
# Get the todolists associated with the todoset
|
7
|
-
#
|
8
|
-
# @example
|
9
|
-
# client.todolists(todoset)
|
10
|
-
# @example
|
11
|
-
# client.todolists(todoset, status: 'archived')
|
12
|
-
#
|
13
|
-
# @param todoset [Resource] the parent todoset resource
|
14
|
-
# @param options [Hash] extra options to filter the list of todolist
|
15
|
-
# @return [Array<Resource>]
|
16
|
-
# @see https://github.com/basecamp/bc3-api/blob/master/sections/todolists.md#get-to-do-lists
|
17
|
-
def todolists(todoset, options={})
|
18
|
-
get(todoset.todolists_url, options.merge(override_path: true))
|
19
|
-
end
|
20
|
-
|
21
|
-
# Get a todolist with a given id
|
22
|
-
#
|
23
|
-
# @example
|
24
|
-
# client.todolist(todoset, '2345')
|
25
|
-
#
|
26
|
-
# @param todoset [Resource] the parent todoset resource
|
27
|
-
# @param id [Integer, String] the id of the todolist to get
|
28
|
-
# @return [Resource]
|
29
|
-
# @see https://github.com/basecamp/bc3-api/blob/master/sections/todolists.md#get-a-to-do-list
|
30
|
-
def todolist(todoset, id)
|
31
|
-
get("/buckets/#{todoset.bucket.id}/todolists/#{id}")
|
32
|
-
end
|
33
|
-
|
34
|
-
# Get the todos in a todolist
|
35
|
-
#
|
36
|
-
# @example
|
37
|
-
# client.todos(todolist)
|
38
|
-
# @example
|
39
|
-
# client.todos(todolist, completed: true)
|
40
|
-
#
|
41
|
-
# @param todolist [Resource] the parent todoset resource
|
42
|
-
# @param options [Hash] options to filter the list of todos
|
43
|
-
# @return [Resource]
|
44
|
-
# @see https://github.com/basecamp/bc3-api/blob/master/sections/todos.md#get-to-dos
|
45
|
-
def todos(todolist, options={})
|
46
|
-
get(todolist.todos_url, options.merge(override_path: true))
|
47
|
-
end
|
48
|
-
|
49
|
-
# Create a todo within a todolist
|
50
|
-
#
|
51
|
-
# @example
|
52
|
-
# client.create_todo(todolist, 'First Todo')
|
53
|
-
# @example
|
54
|
-
# client.create_todo(
|
55
|
-
# todolist,
|
56
|
-
# 'Program it',
|
57
|
-
# description: "<div><em>Try that new language!</em></div>, due_on: "2016-05-01"
|
58
|
-
# )
|
59
|
-
#
|
60
|
-
# @param todolist [Resource] the todolist where the todo is going to be created
|
61
|
-
# @param content [String] what the to-do is for
|
62
|
-
# @param options [Hash] extra configuration for the todo such as due_date and description
|
63
|
-
# @return [Resource]
|
64
|
-
# @see https://github.com/basecamp/bc3-api/blob/master/sections/todos.md#create-a-to-do
|
65
|
-
def create_todo(todolist, content, options={})
|
66
|
-
post(todolist.todos_url, body: { content: content, **options }, override_path: true)
|
67
|
-
end
|
68
|
-
|
69
|
-
# Complete a todo
|
70
|
-
#
|
71
|
-
# @example
|
72
|
-
# client.complete_todo(todo)
|
73
|
-
#
|
74
|
-
# @param todo [Resource] the todo to be marked as completed
|
75
|
-
# @see https://github.com/basecamp/bc3-api/blob/master/sections/todos.md#complete-a-to-do
|
76
|
-
def complete_todo(todo)
|
77
|
-
post("#{todo.url}/completion", override_path: true)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|