camper 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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