bloomy 0.10.0 → 0.11.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,112 +3,96 @@
3
3
  require "json"
4
4
  require "bloomy/utils/get_user_id"
5
5
 
6
- # Class to handle all the operations related to issues
7
- class Issue
8
- include Bloomy::Utilities::UserIdUtility
9
- # Initializes a new Issue instance
10
- #
11
- # @param conn [Object] the connection object to interact with the API
12
- def initialize(conn)
13
- @conn = conn
14
- end
15
-
16
- # Retrieves details of a specific issue
17
- #
18
- # @param issue_id [Integer] the ID of the issue
19
- # @return [Hash] a hash containing issue details
20
- # @example
21
- # issue.details(123)
22
- # #=> { id: 123, title: "Issue Title", notes_url: "http://details.url", ... }
23
- def details(issue_id)
24
- response = @conn.get("issues/#{issue_id}").body
25
- {
26
- id: response["Id"],
27
- title: response["Name"],
28
- notes_url: response["DetailsUrl"],
29
- created_at: response["CreateTime"],
30
- completed_at: response["CloseTime"],
31
- meeting_details: {
32
- id: response["OriginId"],
33
- title: response["Origin"]
34
- },
35
- owner_details: {
36
- id: response["Owner"]["Id"],
37
- name: response["Owner"]["Name"]
38
- }
39
- }
40
- end
6
+ module Bloomy
7
+ # Handles CRUD operations for issues in the system.
8
+ # Provides functionality to create, retrieve, list, and solve issues
9
+ # associated with meetings and users.
10
+ class Issue
11
+ include Bloomy::Utilities::UserIdUtility
41
12
 
42
- # Lists issues for a specific user or meeting
43
- #
44
- # @param user_id [Integer, nil] the ID of the user (defaults to initialized user_id)
45
- # @param meeting_id [Integer, nil] the ID of the meeting
46
- # @raise [ArgumentError] if both `user_id` and `meeting_id` are provided
47
- # @return [Array<Hash>] an array of hashes containing issues details
48
- # @example
49
- # # Fetch issues for the current user
50
- # issue.list
51
- #
52
- # # Fetch issues for a specific user
53
- # issue.list(user_id: 42)
54
- #
55
- # # Fetch issues for a specific meeting
56
- # issue.list(meeting_id: 99)
57
- def list(user_id: nil, meeting_id: nil)
58
- if user_id && meeting_id
59
- raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both."
13
+ # Initializes a new Issue instance
14
+ #
15
+ # @param conn [Faraday::Connection] Connection object for making API requests
16
+ # @return [Issue] New instance of Issue
17
+ def initialize(conn)
18
+ @conn = conn
60
19
  end
61
20
 
62
- if meeting_id
63
- response = @conn.get("l10/#{meeting_id}/issues").body
64
- else
65
- user_id ||= self.user_id
66
- response = @conn.get("issues/users/#{user_id}").body
21
+ # Retrieves detailed information about a specific issue
22
+ #
23
+ # @param issue_id [Integer] Unique identifier of the issue
24
+ # @return [Types::IssueDetails] Detailed information about the issue
25
+ # @raise [ApiError] When the API request fails or returns invalid data
26
+ def details(issue_id)
27
+ response = @conn.get("issues/#{issue_id}").body
28
+ Types::IssueItem.new(
29
+ id: response["Id"],
30
+ title: response["Name"],
31
+ notes_url: response["DetailsUrl"],
32
+ created_at: response["CreateTime"],
33
+ completed_at: response["CloseTime"],
34
+ meeting_id: response["OriginId"],
35
+ meeting_title: response["Origin"],
36
+ user_id: response["Owner"]["Id"],
37
+ user_name: response["Owner"]["Name"]
38
+ )
67
39
  end
68
40
 
69
- response.map do |issue|
70
- {
71
- id: issue["Id"],
72
- title: issue["Name"],
73
- notes_url: issue["DetailsUrl"],
74
- created_at: issue["CreateTime"],
75
- meeting_id: issue["OriginId"],
76
- meeting_title: issue["Origin"]
77
- }
41
+ # Lists issues filtered by user or meeting
42
+ #
43
+ # @param user_id [Integer, nil] Unique identifier of the user (optional)
44
+ # @param meeting_id [Integer, nil] Unique identifier of the meeting (optional)
45
+ # @return [Array<Types::IssueItem>] List of issues matching the filter criteria
46
+ # @raise [ArgumentError] When both user_id and meeting_id are provided
47
+ # @raise [ApiError] When the API request fails or returns invalid data
48
+ def list(user_id: nil, meeting_id: nil)
49
+ if user_id && meeting_id
50
+ raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both."
51
+ end
52
+
53
+ response = meeting_id ? @conn.get("l10/#{meeting_id}/issues").body : @conn.get("issues/users/#{user_id || self.user_id}").body
54
+
55
+ response.map do |issue|
56
+ Types::IssueItem.new(
57
+ id: issue["Id"],
58
+ title: issue["Name"],
59
+ notes_url: issue["DetailsUrl"],
60
+ created_at: issue["CreateTime"],
61
+ meeting_id: issue["OriginId"],
62
+ meeting_title: issue["Origin"]
63
+ )
64
+ end
78
65
  end
79
- end
80
66
 
81
- # Marks an issue as solved
82
- #
83
- # @param issue_id [Integer] the ID of the issue
84
- # @return [Boolean] true if the operation was successful, false otherwise
85
- # @example
86
- # issue.solve(123)
87
- # #=> true
88
- def solve(issue_id)
89
- response = @conn.post("issues/#{issue_id}/complete", {complete: true}.to_json)
90
- response.success?
91
- end
67
+ # Marks an issue as completed/solved
68
+ #
69
+ # @param issue_id [Integer] Unique identifier of the issue to be solved
70
+ # @return [Boolean] true if issue was successfully solved, false otherwise
71
+ # @raise [ApiError] When the API request fails
72
+ def solve(issue_id)
73
+ response = @conn.post("issues/#{issue_id}/complete", {complete: true}.to_json)
74
+ response.success?
75
+ end
92
76
 
93
- # Creates a new issue
94
- #
95
- # @param meeting_id [Integer] the ID of the meeting associated with the issue
96
- # @param title [String] the title of the new issue
97
- # @param user_id [Integer] the ID of the user responsible for the issue (default: initialized user ID)
98
- # @param notes [String, nil] the notes for the issue (optional)
99
- # @return [Hash] a hash containing the new issue's ID and title
100
- # @example
101
- # issue.create(meeting_id: 123, title: "New Issue")
102
- # #=> { id: 789, title: "New Issue" }
103
- def create(meeting_id:, title:, user_id: self.user_id, notes: nil)
104
- response = @conn.post("issues/create", {title: title, meetingid: meeting_id, ownerid: user_id, notes: notes}.to_json)
105
- {
106
- id: response.body["Id"],
107
- meeting_id: response.body["OriginId"],
108
- meeting_title: response.body["Origin"],
109
- title: response.body["Name"],
110
- user_id: response.body["Owner"]["Id"],
111
- notes_url: response.body["DetailsUrl"]
112
- }
77
+ # Creates a new issue in the system
78
+ #
79
+ # @param meeting_id [Integer] Unique identifier of the associated meeting
80
+ # @param title [String] Title/name of the issue
81
+ # @param user_id [Integer] Unique identifier of the issue owner (defaults to current user)
82
+ # @param notes [String, nil] Additional notes or description for the issue (optional)
83
+ # @return [Types::IssueItem] Newly created issue details
84
+ # @raise [ApiError] When the API request fails or returns invalid data
85
+ # @raise [ArgumentError] When required parameters are missing or invalid
86
+ def create(meeting_id:, title:, user_id: self.user_id, notes: nil)
87
+ response = @conn.post("issues/create", {title: title, meetingid: meeting_id, ownerid: user_id, notes: notes}.to_json)
88
+ Types::IssueItem.new(
89
+ id: response.body["Id"],
90
+ meeting_id: response.body["OriginId"],
91
+ meeting_title: response.body["Origin"],
92
+ title: response.body["Name"],
93
+ user_id: response.body["Owner"]["Id"],
94
+ notes_url: response.body["DetailsUrl"]
95
+ )
96
+ end
113
97
  end
114
98
  end
@@ -2,171 +2,173 @@
2
2
 
3
3
  require "bloomy/utils/get_user_id"
4
4
 
5
- # Class to handle all the operations related to meeting
6
- # @note
7
- # This class is already initialized via the client and usable as `client.measurable.method`
8
- class Meeting
9
- include Bloomy::Utilities::UserIdUtility
10
- # Initializes a new Meeting instance
11
- #
12
- # @param conn [Object] the connection object to interact with the API
13
- def initialize(conn)
14
- @conn = conn
15
- end
5
+ module Bloomy
6
+ # Class to handle all the operations related to meeting
7
+ # @note
8
+ # This class is already initialized via the client and usable as `client.meeting.method`
9
+ class Meeting
10
+ include Bloomy::Utilities::UserIdUtility
11
+ # Initializes a new Meeting instance
12
+ #
13
+ # @param conn [Object] the connection object to interact with the API
14
+ def initialize(conn)
15
+ @conn = conn
16
+ end
16
17
 
17
- # Lists all meetings for a specific user
18
- #
19
- # @param user_id [Integer] the ID of the user (default is the initialized user ID)
20
- # @return [Array<Hash>] an array of hashes containing meeting details
21
- # @example
22
- # client.meeting.list
23
- # #=> [{ id: 123, name: "Team Meeting" }, ...]
24
- def list(user_id = self.user_id)
25
- response = @conn.get("L10/#{user_id}/list").body
26
- response.map { |meeting| {id: meeting["Id"], name: meeting["Name"]} }
27
- end
18
+ # Lists all meetings for a specific user
19
+ #
20
+ # @param user_id [Integer] the ID of the user (default is the initialized user ID)
21
+ # @return [Array<Hash>] an array of hashes containing meeting details
22
+ # @example
23
+ # client.meeting.list
24
+ # #=> [{ id: 123, name: "Team Meeting" }, ...]
25
+ def list(user_id = self.user_id)
26
+ response = @conn.get("L10/#{user_id}/list").body
27
+ response.map { |meeting| Types::MeetingItem.new(id: meeting["Id"], title: meeting["Name"]) }
28
+ end
28
29
 
29
- # Lists all attendees for a specific meeting
30
- #
31
- # @param meeting_id [Integer] the ID of the meeting
32
- # @return [Array<Hash>] an array of hashes containing attendee details
33
- # @example
34
- # client.meeting.attendees(1)
35
- # #=> [{ name: "John Doe", id: 1 }, ...]
36
- def attendees(meeting_id)
37
- response = @conn.get("L10/#{meeting_id}/attendees").body
38
- response.map { |attendee| {name: attendee["Name"], id: attendee["Id"]} }
39
- end
30
+ # Lists all attendees for a specific meeting
31
+ #
32
+ # @param meeting_id [Integer] the ID of the meeting
33
+ # @return [Array<Hash>] an array of hashes containing attendee details
34
+ # @example
35
+ # client.meeting.attendees(1)
36
+ # #=> [{ name: "John Doe", id: 1 }, ...]
37
+ def attendees(meeting_id)
38
+ response = @conn.get("L10/#{meeting_id}/attendees").body
39
+ response.map { |attendee| Types::UserItem.new(id: attendee["Id"], name: attendee["Name"]) }
40
+ end
40
41
 
41
- # Lists all issues for a specific meeting
42
- #
43
- # @param meeting_id [Integer] the ID of the meeting
44
- # @param include_closed [Boolean] whether to include closed issues (default: false)
45
- # @return [Array<Hash>] an array of hashes containing issue details
46
- # @example
47
- # client.meeting.issues(1)
48
- # #=> [{ id: 1, title: "Issue Title", created_at: "2024-06-10", ... }, ...]
49
- def issues(meeting_id, include_closed: false)
50
- response = @conn.get("L10/#{meeting_id}/issues?include_resolved=#{include_closed}").body
51
- response.map do |issue|
52
- {
53
- id: issue["Id"],
54
- title: issue["Name"],
55
- created_at: issue["CreateTime"],
56
- closed_at: issue["CloseTime"],
57
- details_url: issue["DetailsUrl"],
58
- owner: {
59
- id: issue["Owner"]["Id"],
60
- name: issue["Owner"]["Name"]
61
- }
62
- }
42
+ # Lists all issues for a specific meeting
43
+ #
44
+ # @param meeting_id [Integer] the ID of the meeting
45
+ # @param include_closed [Boolean] whether to include closed issues (default: false)
46
+ # @return [Array<Hash>] an array of hashes containing issue details
47
+ # @example
48
+ # client.meeting.issues(1)
49
+ # #=> [{ id: 1, title: "Issue Title", created_at: "2024-06-10", ... }, ...]
50
+ def issues(meeting_id, include_closed: false)
51
+ response = @conn.get("L10/#{meeting_id}/issues?include_resolved=#{include_closed}").body
52
+ response.map do |issue|
53
+ Types::IssueItem.new(
54
+ id: issue["Id"],
55
+ title: issue["Name"],
56
+ notes_url: issue["DetailsUrl"],
57
+ created_at: issue["CreateTime"],
58
+ completed_at: issue["CloseTime"],
59
+ user_id: issue.dig("Owner", "Id"),
60
+ user_name: issue.dig("Owner", "Name"),
61
+ meeting_id: meeting_id,
62
+ meeting_title: issue["Origin"]
63
+ )
64
+ end
63
65
  end
64
- end
65
66
 
66
- # Lists all todos for a specific meeting
67
- #
68
- # @param meeting_id [Integer] the ID of the meeting
69
- # @param include_closed [Boolean] whether to include closed todos (default: false)
70
- # @return [Array<Hash>] an array of hashes containing todo details
71
- # @example
72
- # client.meeting.todos(1)
73
- # #=> [{ id: 1, title: "Todo Title", due_date: "2024-06-12", ... }, ...]
74
- def todos(meeting_id, include_closed: false)
75
- response = @conn.get("L10/#{meeting_id}/todos?INCLUDE_CLOSED=#{include_closed}").body
76
- response.map do |todo|
77
- {
78
- id: todo["Id"],
79
- title: todo["Name"],
80
- due_date: todo["DueDate"],
81
- details_url: todo["DetailsUrl"],
82
- completed_at: todo["CompleteTime"],
83
- owner: {
84
- id: todo["Owner"]["Id"],
85
- name: todo["Owner"]["Name"]
86
- }
87
- }
67
+ # Lists all todos for a specific meeting
68
+ #
69
+ # @param meeting_id [Integer] the ID of the meeting
70
+ # @param include_closed [Boolean] whether to include closed todos (default: false)
71
+ # @return [Array<Hash>] an array of hashes containing todo details
72
+ # @example
73
+ # client.meeting.todos(1)
74
+ # #=> [{ id: 1, title: "Todo Title", due_date: "2024-06-12", ... }, ...]
75
+ def todos(meeting_id, include_closed: false)
76
+ response = @conn.get("L10/#{meeting_id}/todos?INCLUDE_CLOSED=#{include_closed}").body
77
+ response.map do |todo|
78
+ Types::TodoItem.new(
79
+ {
80
+ id: todo["Id"],
81
+ title: todo["Name"],
82
+ due_date: todo["DueDate"],
83
+ notes_url: todo["DetailsUrl"],
84
+ status: todo["Complete"] ? "Complete" : "Incomplete",
85
+ created_at: todo["CreateTime"],
86
+ completed_at: todo["CompleteTime"],
87
+ user_id: todo.dig("Owner", "Id"),
88
+ user_name: todo.dig("Owner", "Name")
89
+ }
90
+ )
91
+ end
88
92
  end
89
- end
90
93
 
91
- # Lists all metrics for a specific meeting
92
- #
93
- # @param meeting_id [Integer] the ID of the meeting
94
- # @return [Array<Hash>] an array of hashes containing metric details
95
- # @example
96
- # client.meeting.metrics(1)
97
- # #=> [{ id: 1, name: "Sales", target: 100, operator: ">", format: "currency", ... }, ...]
98
- def metrics(meeting_id)
99
- response = @conn.get("L10/#{meeting_id}/measurables").body
100
- response.map do |measurable|
101
- {
102
- id: measurable["Id"],
103
- title: measurable["Name"].strip,
104
- target: measurable["Target"],
105
- operator: measurable["Direction"],
106
- format: measurable["Modifiers"],
107
- owner: {
108
- id: measurable["Owner"]["Id"],
109
- name: measurable["Owner"]["Name"]
110
- },
111
- admin: {
112
- id: measurable["Admin"]["Id"],
113
- name: measurable["Admin"]["Name"]
114
- }
115
- }
94
+ # Lists all metrics for a specific meeting
95
+ #
96
+ # @param meeting_id [Integer] the ID of the meeting
97
+ # @return [Array<Hash>] an array of hashes containing metric details
98
+ # @example
99
+ # client.meeting.metrics(1)
100
+ # #=> [{ id: 1, name: "Sales", target: 100, operator: ">", format: "currency", ... }, ...]
101
+ def metrics(meeting_id)
102
+ response = @conn.get("L10/#{meeting_id}/measurables").body
103
+ return [] if response.nil? || !response.is_a?(Array)
104
+
105
+ response.map do |measurable|
106
+ next unless measurable["Id"] && measurable["Name"]
107
+
108
+ Types::MetricItem.new(
109
+ id: measurable["Id"],
110
+ title: measurable["Name"].to_s.strip,
111
+ target: measurable["Target"].to_f,
112
+ operator: measurable["Direction"].to_s,
113
+ format: measurable["Modifiers"].to_s,
114
+ user_id: measurable.dig("Owner", "Id"),
115
+ user_name: measurable.dig("Owner", "Name"),
116
+ admin_id: measurable.dig("Admin", "Id"),
117
+ admin_name: measurable.dig("Admin", "Name")
118
+ )
119
+ end.compact
116
120
  end
117
- end
118
121
 
119
- # Retrieves details of a specific meeting
120
- #
121
- # @param meeting_id [Integer] the ID of the meeting
122
- # @param include_closed [Boolean] whether to include closed issues and todos (default: false)
123
- # @return [Hash] a hash containing detailed information about the meeting
124
- # @example
125
- # client.meeting.details(1)
126
- # #=> { id: 1, name: "Team Meeting", attendees: [...], issues: [...], todos: [...], metrics: [...] }
127
- def details(meeting_id, include_closed: false)
128
- meeting = list.find { |m| m[:id] == meeting_id }
129
- attendees = attendees(meeting_id)
130
- issues = issues(meeting_id, include_closed: include_closed)
131
- todos = todos(meeting_id, include_closed: include_closed)
132
- measurables = metrics(meeting_id)
133
- {
134
- id: meeting[:id],
135
- title: meeting[:name],
136
- attendees: attendees,
137
- issues: issues,
138
- todos: todos,
139
- metrics: measurables
140
- }
141
- end
122
+ # Retrieves details of a specific meeting
123
+ #
124
+ # @param meeting_id [Integer] the ID of the meeting
125
+ # @param include_closed [Boolean] whether to include closed issues and todos (default: false)
126
+ # @return [Hash] a hash containing detailed information about the meeting
127
+ # @example
128
+ # client.meeting.details(1)
129
+ # #=> { id: 1, name: "Team Meeting", attendees: [...], issues: [...], todos: [...], metrics: [...] }
130
+ def details(meeting_id, include_closed: false)
131
+ meeting = list.find { |m| m.id == meeting_id }
132
+ Types::MeetingDetails.new(
133
+ id: meeting.id,
134
+ title: meeting.title,
135
+ attendees: attendees(meeting_id),
136
+ issues: issues(meeting_id, include_closed: include_closed),
137
+ todos: todos(meeting_id, include_closed: include_closed),
138
+ metrics: metrics(meeting_id)
139
+ )
140
+ end
142
141
 
143
- # Creates a new meeting
144
- #
145
- # @param title [String] the title of the new meeting
146
- # @param add_self [Boolean] whether to add the current user as an attendee (default: true)
147
- # @param attendees [Array<Integer>] a list of user IDs to add as attendees
148
- # @return [Hash] a hash containing the new meeting's ID and title, and the list of attendees
149
- # @example
150
- # client.meeting.create(title: "New Meeting", attendees: [2, 3])
151
- # #=> { meeting_id: 1, title: "New Meeting", attendees: [2, 3] }
152
- def create(title, add_self: true, attendees: [])
153
- payload = {title: title, addSelf: add_self}.to_json
154
- response = @conn.post("L10/create", payload).body
155
- meeting_id = response["meetingId"]
156
- meeting_details = {meeting_id: meeting_id, title: title}
157
- attendees.each do |attendee|
158
- @conn.post("L10/#{meeting_id}/attendees/#{attendee}")
142
+ # Creates a new meeting
143
+ #
144
+ # @param title [String] the title of the new meeting
145
+ # @param add_self [Boolean] whether to add the current user as an attendee (default: true)
146
+ # @param attendees [Array<Integer>] a list of user IDs to add as attendees
147
+ # @return [Hash] a hash containing meeting_id, title and attendees array
148
+ # @example
149
+ # client.meeting.create("New Meeting", attendees: [2, 3])
150
+ # #=> { meeting_id: 1, title: "New Meeting", attendees: [2, 3] }
151
+ def create(title, add_self: true, attendees: [])
152
+ payload = {title: title, addSelf: add_self}.to_json
153
+ response = @conn.post("L10/create", payload).body
154
+ meeting_id = response["meetingId"]
155
+ meeting_details = {meeting_id: meeting_id, title: title}
156
+ attendees.each do |attendee|
157
+ @conn.post("L10/#{meeting_id}/attendees/#{attendee}")
158
+ end
159
+ meeting_details.merge(attendees: attendees)
159
160
  end
160
- meeting_details.merge(attendees: attendees)
161
- end
162
161
 
163
- # Deletes a meeting
164
- #
165
- # @param meeting_id [Integer] the ID of the meeting to delete
166
- # @example
167
- # client.meeting.delete(1)
168
- def delete(meeting_id)
169
- response = @conn.delete("L10/#{meeting_id}")
170
- response.success?
162
+ # Deletes a meeting
163
+ #
164
+ # @param meeting_id [Integer] the ID of the meeting to delete
165
+ # @return [Boolean] true if deletion was successful
166
+ # @example
167
+ # client.meeting.delete(1)
168
+ # #=> true
169
+ def delete(meeting_id)
170
+ response = @conn.delete("L10/#{meeting_id}")
171
+ response.success?
172
+ end
171
173
  end
172
174
  end