camper 0.0.7 → 0.1.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.
@@ -6,7 +6,9 @@ require 'rack/oauth2'
6
6
  require 'camper/version'
7
7
  require 'camper/logging'
8
8
  require 'camper/error'
9
+ require 'camper/recording_types'
9
10
  require 'camper/configuration'
11
+ require 'camper/url_utils'
10
12
  require 'camper/authorization'
11
13
  require 'camper/resource'
12
14
  require 'camper/pagination_data'
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Camper
4
+ class Client
5
+ # Defines methods related to comments.
6
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/comments.md
7
+ module CommentsAPI
8
+ # Get a paginated list of active comments for a given resource
9
+ #
10
+ # @example
11
+ # client.comments(todo)
12
+ #
13
+ # @param resource [Resource] resource to gets the comments from
14
+ # @return [PaginatedResponse<Resource>]
15
+ # @raise [Error::ResourceCannotBeCommented] if the resource doesn't support comments
16
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/comments.md#get-comments
17
+ def comments(resource)
18
+ raise Error::ResourceCannotBeCommented, resource unless resource.can_be_commented?
19
+
20
+ get(resource.comments_url, override_path: true)
21
+ end
22
+
23
+ # Get a comment within a resource
24
+ #
25
+ # @example
26
+ # client.comment(todo, 10)
27
+ # @example
28
+ # client.comment(my_message, '23')
29
+ #
30
+ # @param resource [Resource] resource to get the comment from
31
+ # @param comment_id [Integer|String] id of comment ot retrieve
32
+ # @return [Resource]
33
+ # @raise [Error::ResourceCannotBeCommented] if the resource doesn't support comments
34
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/comments.md#get-a-comment
35
+ def comment(resource, comment_id)
36
+ raise Error::ResourceCannotBeCommented, resource unless resource.can_be_commented?
37
+
38
+ bucket_id = resource.bucket.id
39
+
40
+ get("/buckets/#{bucket_id}/comments/#{comment_id}")
41
+ end
42
+
43
+ # Create a new comment for a given resource
44
+ #
45
+ # @example
46
+ # client.create_comment(my_message, 'We are ready to start the project')
47
+ #
48
+ # @param resource [Resource] resource to create the comment on
49
+ # @param content [String] content of the comment
50
+ # @return [Resource]
51
+ # @raise [Error::ResourceCannotBeCommented] if the resource doesn't support comments
52
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/comments.md#create-a-comment
53
+ def create_comment(resource, content)
54
+ raise Error::ResourceCannotBeCommented, resource unless resource.can_be_commented?
55
+
56
+ post(resource.comments_url, override_path: true, body: { content: content })
57
+ end
58
+
59
+ # Update the content in a comment
60
+ #
61
+ # @example
62
+ # client.update_comment(comment, 'Fixed grammar mistakes')
63
+ #
64
+ # @param comment [Resource] comment to modify
65
+ # @param content [String] new content of the comment
66
+ # @return [Resource]
67
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/comments.md#update-a-comment
68
+ def update_comment(comment, content)
69
+ bucket_id = comment.bucket.id
70
+
71
+ put("/buckets/#{bucket_id}/comments/#{comment.id}", body: { content: content })
72
+ end
73
+
74
+ # Trash a comment
75
+ # it calls the trash_recording endpoint under the hood
76
+ #
77
+ # @example
78
+ # client.trash_comment(current_comment)
79
+ #
80
+ # @param comment [Resource] the comment to be trashed
81
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/recordings.md#trash-a-recording
82
+ def trash_comment(comment)
83
+ trash_recording(comment)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Camper
4
+ class Client
5
+ # Defines methods related to message boards.
6
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_boards.md
7
+ module MessageBoardsAPI
8
+ # Get a message board for a given project
9
+ #
10
+ # @example
11
+ # client.message_board(project)
12
+ #
13
+ # @param project [Project] project to get the associated message board on
14
+ # @return [Resource]
15
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_boards.md#message-boards
16
+ def message_board(project)
17
+ board = project.message_board
18
+
19
+ get(board.url, override_path: true)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Camper
4
+ class Client
5
+ # Defines methods related to message types.
6
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_types.md
7
+ module MessageTypesAPI
8
+ # Get a paginated list of all messages types in a given project
9
+ #
10
+ # @example
11
+ # client.messages_types(my_project)
12
+ #
13
+ # @param project [Project] project to get the messages types from
14
+ # @return [PaginatedResponse<Resource>]
15
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_types.md#get-message-types
16
+ def message_types(project)
17
+ get("/buckets/#{project.id}/categories")
18
+ end
19
+
20
+ # Get a messages type in a given project
21
+ #
22
+ # @example
23
+ # client.message_type(my_project, '10')
24
+ # @example
25
+ # client.message_type(my_project, 64926)
26
+ #
27
+ # @param project [Project] project to get the messages type from
28
+ # @param message_type_id [Integer|String] id of the message type to retrieve
29
+ # @return [Resource]
30
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_types.md#get-a-message-type
31
+ def message_type(project, message_type_id)
32
+ get("/buckets/#{project.id}/categories/#{message_type_id}")
33
+ end
34
+
35
+ # Create a messages type in a given project
36
+ #
37
+ # @example
38
+ # client.create_message_type(my_project, 'Farewell', '👋')
39
+ #
40
+ # @param project [Project] project where the message type belongs to
41
+ # @param name [String] name of the new message type
42
+ # @param icon [String] icon to associate with the new message type
43
+ # @return [Resource]
44
+ # @raise [Error::InvalidParameter] if either name or icon is blank
45
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_types.md#create-a-message-type
46
+ def create_message_type(project, name, icon)
47
+ raise Error::InvalidParameter, 'Name and icon parameters cannot be blank' if name.blank? || icon.blank?
48
+
49
+ post("/buckets/#{project.id}/categories", body: { name: name, icon: icon })
50
+ end
51
+
52
+ # Update a message type in a given project
53
+ #
54
+ # @example
55
+ # client.update_message_type(my_project, type, name: 'Quick Update')
56
+ # @example
57
+ # client.update_message_type(my_project, type, icon: '🤙')
58
+ #
59
+ # @param project [Project] project where the message type belongs to
60
+ # @param type [Resource|Integer|String] resource or id representing a message type
61
+ # @param options [Hash] hash containing the name and/or icon to modify
62
+ # @return [Resource]
63
+ # @raise [Error::InvalidParameter] if options parameter is empty
64
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_types.md#destroy-a-message-type
65
+ def update_message_type(project, type, options = {})
66
+ raise Error::InvalidParameter, 'options cannot be empty' if options.empty?
67
+
68
+ type_id = type.respond_to?(:id) ? type.id : type
69
+
70
+ put("/buckets/#{project.id}/categories/#{type_id}", body: options)
71
+ end
72
+
73
+ # Delete a message type in a given project
74
+ #
75
+ # @example
76
+ # client.delete_message_type(my_project, type)
77
+ #
78
+ # @param project [Project] project where the message type belongs to
79
+ # @param type [Resource|Integer|String] resource or id representing a message type
80
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/message_types.md#destroy-a-message-type
81
+ def delete_message_type(project, type)
82
+ type_id = type.respond_to?(:id) ? type.id : type
83
+
84
+ delete("/buckets/#{project.id}/categories/#{type_id}")
85
+ end
86
+
87
+ alias trash_message_type delete_message_type
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Camper
4
+ class Client
5
+ # Defines methods related to messages.
6
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/messages.md
7
+ module MessagesAPI
8
+ # Get a paginated list of active messages under the given message board or project
9
+ #
10
+ # @example
11
+ # client.messages(message_board)
12
+ # @example
13
+ # client.messages(my_project)
14
+ #
15
+ # @param parent [Project|Resource] either a project or message board resource
16
+ # @return [PaginatedResponse<Resource>]
17
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/messages.md#get-messages
18
+ def messages(parent)
19
+ if parent.is_a?(Project)
20
+ bucket_id, board_id = parent.id, parent.message_board.id
21
+ else
22
+ bucket_id, board_id = parent.bucket.id, parent.id
23
+ end
24
+
25
+ get("/buckets/#{bucket_id}/message_boards/#{board_id}/messages")
26
+ end
27
+
28
+ # Get a paginated list of active messages under the given message board or project
29
+ #
30
+ # @example
31
+ # client.message(my_project, '2343')
32
+ # @example
33
+ # client.message(message_board, 234)
34
+ #
35
+ # @param parent [Project|Resource] either a project or message board resource
36
+ # @param message_id [Integer|String] id of the message to retrieve
37
+ # @return [Resource]
38
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/messages.md#get-a-message
39
+ def message(parent, message_id)
40
+ bucket_id = parent.is_a?(Project) ? parent.id : parent.bucket.id
41
+
42
+ get("/buckets/#{bucket_id}/messages/#{message_id}")
43
+ end
44
+
45
+ # Create a message
46
+ #
47
+ # @example
48
+ # client.create_message(my_project, 'New Infrastructure')
49
+ # @example
50
+ # client.create_message(message_board, 'New Launch',
51
+ # content: 'This launch will be awesome',
52
+ # category_id: '23'
53
+ # )
54
+ #
55
+ # @param parent [Project|Resource] either a project or message board resource
56
+ # @param subject [String] subject of the new message
57
+ # @param options [Hash] hash containing the content and/or category id for the new message
58
+ # @return [Resource]
59
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/messages.md#create-a-message
60
+ def create_message(parent, subject, options = {})
61
+ if parent.is_a?(Project)
62
+ bucket_id, board_id = parent.id, parent.message_board.id
63
+ else
64
+ bucket_id, board_id = parent.bucket.id, parent.id
65
+ end
66
+
67
+ post(
68
+ "/buckets/#{bucket_id}/message_boards/#{board_id}/messages",
69
+ body: options.merge({ subject: subject, status: 'active' })
70
+ )
71
+ end
72
+
73
+ # Update a message
74
+ #
75
+ # @example
76
+ # client.update_message(message, subject: 'New Infrastructure')
77
+ # @example
78
+ # client.update_message(message, content: 'This launch will be awesome')
79
+ # @example
80
+ # client.update_message(message, category_id: '6918641') # message type id
81
+ #
82
+ # @param message [Resource] message to update
83
+ # @param options [Hash] subject of the new message
84
+ # @param options [Hash] hash containing subject, content and/or category_id to update
85
+ # @return [Resource]
86
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/messages.md#update-a-message
87
+ def update_message(message, options = {})
88
+ raise Error::InvalidParameter, 'options cannot be empty' if options.empty?
89
+
90
+ update("/buckets/#{message.bucket.id}/messages/#{message.id}", body: options)
91
+ end
92
+
93
+ # Trash message
94
+ # it calls the trash_recording endpoint under the hood
95
+ #
96
+ # @example
97
+ # client.trash_message(message)
98
+ #
99
+ # @param todo [Resource] the message to be trashed
100
+ # @raise [Error::InvalidParameter] if url field in todo param
101
+ # is not a valid basecamp url
102
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/recordings.md#trash-a-recording
103
+ def trash_message(message)
104
+ trash_recording(message)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Camper
4
+ class Client
5
+ # Defines methods related to people.
6
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md
7
+ module PeopleAPI
8
+ # Get all people visible to the current user
9
+ #
10
+ # @example
11
+ # client.people
12
+ #
13
+ # @return [PaginatedResponse<Resource>]
14
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md#get-all-people
15
+ def people
16
+ get('/people')
17
+ end
18
+
19
+ # Get all active people on the project with the given ID
20
+ #
21
+ # @example
22
+ # client.people_in_project(10)
23
+ # @example
24
+ # client.people_in_project("20")
25
+ # @example
26
+ # client.people_in_project(my_project)
27
+ #
28
+ # @param project [Resource|Integer|String] A project resource or a project id
29
+ # @return [PaginatedResponse<Resource>]
30
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md#get-people-on-a-project
31
+ def people_in_project(project)
32
+ id = project.respond_to?(:id) ? project.id : project
33
+
34
+ get("/projects/#{id}/people")
35
+ end
36
+
37
+ # Allows granting new and existing people access to a project, and revoking access from existing people.
38
+ #
39
+ # @example
40
+ # client.update_access_in_project(10, { grant: [102, 127] })
41
+ # @example
42
+ # client.update_access_in_project("8634", { revoke: [300, 12527] })
43
+ # @example
44
+ # client.update_access_in_project(my_project, {
45
+ # create: [{
46
+ # name: "Victor Copper",
47
+ # email_address: "victor@hanchodesign.com"
48
+ # }]
49
+ # })
50
+ #
51
+ # @param project [Resource|Integer|String] A project resource or a project id
52
+ # @param options [Hash] options to update access, either grant, revoke or create new people
53
+ # @return [Resource]
54
+ # @raise [Error::InvalidParameter] if no option is specified
55
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md#update-who-can-access-a-project
56
+ def update_access_in_project(project, options = {})
57
+ raise Camper::Error::InvalidParameter, 'options cannot be empty' if options.empty?
58
+
59
+ id = project.respond_to?(:id) ? project.id : project
60
+
61
+ put("/projects/#{id}/people/users", body: { **options })
62
+ end
63
+
64
+ # Get all people on this Basecamp account who can be pinged
65
+ #
66
+ # @example
67
+ # client.pingable_people
68
+ #
69
+ # @return [PaginatedResponse<Resource>]
70
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md#get-pingable-people
71
+ def pingable_people
72
+ get('/circles/people')
73
+ end
74
+
75
+ # Get the profile for the user with the given ID
76
+ #
77
+ # @example
78
+ # client.person(234790)
79
+ #
80
+ # @param id [Integer|String] A user id
81
+ # @return [Resource]
82
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md#get-person
83
+ def person(id)
84
+ get("/people/#{id}")
85
+ end
86
+
87
+ # Get the current user's personal info.
88
+ #
89
+ # @example
90
+ # client.profile
91
+ #
92
+ # @return [Resource]
93
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/people.md#get-my-personal-info
94
+ def profile
95
+ get('/my/profile')
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Camper
4
+ class Client
5
+ # Defines methods related to projects.
6
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/projects.md
7
+ module ProjectsAPI
8
+ # Get the projects visible to the current user
9
+ #
10
+ # @example
11
+ # client.projects
12
+ # @example
13
+ # client.projects(status: 'trashed')
14
+ #
15
+ # @param options [Hash] extra options to filter the list of todolist
16
+ # @return [PaginatedResponse<Project>]
17
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/projects.md#get-all-projects
18
+ def projects(options = {})
19
+ get('/projects', query: options)
20
+ end
21
+
22
+ # Get a project with a given id, granted they have access to it
23
+ #
24
+ # @example
25
+ # client.project(82564)
26
+ # @example
27
+ # client.project('7364183')
28
+ #
29
+ # @param id [Integet|String] id of the project to retrieve
30
+ # @return [Project]
31
+ # @raise [Error::InvalidParameter] if id is blank (nil or empty string)
32
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/projects.md#get-a-project
33
+ def project(id)
34
+ raise Error::InvalidParameter, id if id.blank?
35
+
36
+ get("/projects/#{id}")
37
+ end
38
+
39
+ # Create a project
40
+ #
41
+ # @example
42
+ # client.create_project("Marketing Campaign")
43
+ # @example
44
+ # client.create_project('Better Marketing Campaign', "For Client: XYZ")
45
+ #
46
+ # @param name [String] name of the project to create
47
+ # @param description [String] description of the project
48
+ # @return [Project]
49
+ # @raise [Error::InvalidParameter] if name is blank (nil or empty string)
50
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/projects.md#create-a-project
51
+ def create_project(name, description = '')
52
+ raise Error::InvalidParameter, name if name.blank?
53
+
54
+ post('/projects', body: { name: name, description: description })
55
+ end
56
+
57
+ # Update a project
58
+ # description can be set to empty by passing an empty string
59
+ #
60
+ # @example
61
+ # client.update_project(12324, name: 'Retros')
62
+ # @example
63
+ # client.update_project('157432', description: 'A new description')
64
+ # @example
65
+ # client.update_project('157432', description: '')
66
+ # @example
67
+ # client.update_project(my_project, name: 'A new name', description: 'A new description')
68
+ #
69
+ # @param project [Integer|String|Project] either a project object or a project id
70
+ # @param name [String] optional new name of the project
71
+ # @param description [String] optinal new description of the project
72
+ # @return [Project]
73
+ # @raise [Error::InvalidParameter] if both name and description are blank (nil or empty strings)
74
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/projects.md#update-a-project
75
+ def update_project(project, name: '', description: nil)
76
+ # rubocop:disable Style/IfUnlessModifier:
77
+ if name.blank? && description.blank?
78
+ raise Error::InvalidParameter, 'name and description cannot both be blank'
79
+ end
80
+
81
+ # rubocop:enable Style/IfUnlessModifier
82
+
83
+ id = project.respond_to?(:id) ? project.id : project
84
+
85
+ options = {}
86
+ options[:name] = name unless name.blank?
87
+ options[:description] = description unless description.nil?
88
+
89
+ put("/projects/#{id}", body: { **options })
90
+ end
91
+
92
+ # Delete a project
93
+ #
94
+ # @example
95
+ # client.delete_project(12324)
96
+ # @example
97
+ # client.delete_project('157432')
98
+ # @example
99
+ # client.delete_project(my_project)
100
+ #
101
+ # @param project [Integer|String|Project] either a project object or a project id
102
+ # @raise [Error::InvalidParameter] if project param is blank
103
+ # @see https://github.com/basecamp/bc3-api/blob/master/sections/projects.md#trash-a-project
104
+ def delete_project(project)
105
+ raise Error::InvalidParameter, 'project cannot be blank' if project.blank?
106
+
107
+ id = project.respond_to?(:id) ? project.id : project
108
+
109
+ delete("/projects/#{id}")
110
+ end
111
+
112
+ alias trash_project delete_project
113
+
114
+ def todoset(project)
115
+ todoset = project.todoset
116
+ get(todoset.url, override_path: true)
117
+ end
118
+ end
119
+ end
120
+ end