bloomy 0.10.0 → 0.11.4
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/CONTRIBUTING.md +7 -4
- data/lib/bloomy/client.rb +10 -8
- data/lib/bloomy/operations/goals.rb +140 -123
- data/lib/bloomy/operations/headlines.rb +122 -104
- data/lib/bloomy/operations/issues.rb +83 -99
- data/lib/bloomy/operations/meetings.rb +156 -154
- data/lib/bloomy/operations/scorecard.rb +91 -93
- data/lib/bloomy/operations/todos.rb +123 -128
- data/lib/bloomy/operations/users.rb +100 -85
- data/lib/bloomy/types/items.rb +119 -0
- data/lib/bloomy/version.rb +1 -1
- metadata +3 -2
@@ -3,108 +3,106 @@
|
|
3
3
|
require "json"
|
4
4
|
require "bloomy/utils/get_user_id"
|
5
5
|
|
6
|
-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
class
|
10
|
-
|
6
|
+
module Bloomy
|
7
|
+
# Class to handle all the operations related to scorecards
|
8
|
+
# @note
|
9
|
+
# This class is already initialized via the client and usable as `client.scorecard.method`
|
10
|
+
class Scorecard
|
11
|
+
include Bloomy::Utilities::UserIdUtility
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
# Initializes a new Scorecard instance
|
14
|
+
#
|
15
|
+
# @param conn [Object] the connection object to interact with the API
|
16
|
+
def initialize(conn)
|
17
|
+
@conn = conn
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
20
|
+
# Retrieves the current week details
|
21
|
+
#
|
22
|
+
# @return [Types::WeekItem] an object containing current week details
|
23
|
+
# @example
|
24
|
+
# client.scorecard.current_week
|
25
|
+
# #=> #<Types::WeekItem @id=123, @week_number=24, @week_start="2024-06-10", @week_end="2024-06-16">
|
26
|
+
def current_week
|
27
|
+
response = @conn.get("weeks/current").body
|
28
|
+
Types::WeekItem.new(
|
29
|
+
id: response["Id"],
|
30
|
+
week_number: response["ForWeekNumber"],
|
31
|
+
week_start: response["LocalDate"]["Date"],
|
32
|
+
week_end: response["ForWeek"]
|
33
|
+
)
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
36
|
+
# Retrieves the scorecards for a user or a meeting.
|
37
|
+
#
|
38
|
+
# @param user_id [Integer, nil] the ID of the user (defaults to initialized user_id)
|
39
|
+
# @param meeting_id [Integer, nil] the ID of the meeting
|
40
|
+
# @param show_empty [Boolean] whether to include scores with nil values (default: false)
|
41
|
+
# @param week_offset [Integer, nil] offset for the week number to filter scores
|
42
|
+
# @raise [ArgumentError] if both `user_id` and `meeting_id` are provided
|
43
|
+
# @return [Array<Types::ScorecardItem>] an array of scorecard items
|
44
|
+
# @example
|
45
|
+
# # Fetch scorecards for the current user
|
46
|
+
# client.scorecard.list
|
47
|
+
#
|
48
|
+
# # Fetch scorecards for a specific user
|
49
|
+
# client.scorecard.list(user_id: 42)
|
50
|
+
#
|
51
|
+
# # Fetch scorecards for a specific meeting
|
52
|
+
# client.scorecard.list(meeting_id: 99)
|
53
|
+
# @note
|
54
|
+
# The `week_offset` parameter is useful when fetching scores for previous or future weeks.
|
55
|
+
# For example, to fetch scores for the previous week, you can set `week_offset` to -1.
|
56
|
+
# To fetch scores for a future week, you can set `week_offset` to a positive value.
|
57
|
+
def list(user_id: nil, meeting_id: nil, show_empty: false, week_offset: nil)
|
58
|
+
raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both." if user_id && meeting_id
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
if meeting_id
|
61
|
+
response = @conn.get("scorecard/meeting/#{meeting_id}").body
|
62
|
+
else
|
63
|
+
user_id ||= self.user_id
|
64
|
+
response = @conn.get("scorecard/user/#{user_id}").body
|
65
|
+
end
|
66
|
+
|
67
|
+
scorecards = response["Scores"].map do |scorecard|
|
68
|
+
Types::ScorecardItem.new(
|
69
|
+
id: scorecard["Id"],
|
70
|
+
measurable_id: scorecard["MeasurableId"],
|
71
|
+
accountable_user_id: scorecard["AccountableUserId"],
|
72
|
+
title: scorecard["MeasurableName"],
|
73
|
+
target: scorecard["Target"],
|
74
|
+
value: scorecard["Measured"],
|
75
|
+
week: scorecard["Week"],
|
76
|
+
week_id: scorecard["ForWeek"],
|
77
|
+
updated_at: scorecard["DateEntered"]
|
78
|
+
)
|
79
|
+
end
|
65
80
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
week: scorecard["Week"],
|
75
|
-
week_id: scorecard["ForWeek"],
|
76
|
-
updated_at: scorecard["DateEntered"]
|
77
|
-
}
|
81
|
+
if week_offset
|
82
|
+
week_data = current_week
|
83
|
+
week_id = week_data.week_number + week_offset
|
84
|
+
scorecards.select! { |scorecard| scorecard.week_id == week_id }
|
85
|
+
end
|
86
|
+
|
87
|
+
scorecards.select! { |scorecard| scorecard.value || show_empty } unless show_empty
|
88
|
+
scorecards
|
78
89
|
end
|
79
90
|
|
80
|
-
|
91
|
+
# Updates the score for a measurable item for a specific week.
|
92
|
+
#
|
93
|
+
# @param measurable_id [Integer] the ID of the measurable item
|
94
|
+
# @param score [Numeric] the score to be assigned to the measurable item
|
95
|
+
# @param week_offset [Integer] the number of weeks to offset from the current week (default: 0)
|
96
|
+
# @return [Boolean] true if the score was successfully updated
|
97
|
+
# @example
|
98
|
+
# client.scorecard.score(measurable_id: 123, score: 5)
|
99
|
+
# #=> true
|
100
|
+
def score(measurable_id:, score:, week_offset: 0)
|
81
101
|
week_data = current_week
|
82
102
|
week_id = week_data[:week_number] + week_offset
|
83
|
-
scorecards.select! { |scorecard| scorecard[:week_id] == week_id }
|
84
|
-
end
|
85
|
-
|
86
|
-
scorecards.select! { |scorecard| scorecard[:value] || show_empty } unless show_empty
|
87
|
-
scorecards
|
88
|
-
end
|
89
103
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
# @param score [Numeric] the score to be assigned to the measurable item.
|
94
|
-
# @param week_offset [Integer] the number of weeks to offset from the current week (default is 0).
|
95
|
-
# @return [Boolean] true if the score was successfully updated, false otherwise.
|
96
|
-
# @example
|
97
|
-
# client.scorecard.score(measurable_id: 123, score: 5)
|
98
|
-
# #=> true
|
99
|
-
# @note
|
100
|
-
# The `week_offset` parameter is useful when updating scores for previous weeks.
|
101
|
-
# For example, to update the score for the previous week, you can set `week_offset` to -1.
|
102
|
-
# To update a future week's score, you can set `week_offset` to a positive value.
|
103
|
-
def score(measurable_id:, score:, week_offset: 0)
|
104
|
-
week_data = current_week
|
105
|
-
week_id = week_data[:week_number] + week_offset
|
106
|
-
|
107
|
-
response = @conn.put("measurables/#{measurable_id}/week/#{week_id}", {value: score}.to_json)
|
108
|
-
response.success?
|
104
|
+
response = @conn.put("measurables/#{measurable_id}/week/#{week_id}", {value: score}.to_json)
|
105
|
+
response.success?
|
106
|
+
end
|
109
107
|
end
|
110
108
|
end
|
@@ -1,148 +1,143 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "date"
|
4
|
-
|
4
|
+
require "bloomy/utils/get_user_id"
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
module Bloomy
|
7
|
+
# Class to handle all the operations related to todos
|
8
|
+
class Todo
|
9
|
+
include Bloomy::Utilities::UserIdUtility
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
# Initializes a new Todo 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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
# client.todo.list(user_id: 42)
|
30
|
-
# # => [{ id: 1, title: "New Todo", due_date: "2024-06-15", ... }]
|
31
|
-
#
|
32
|
-
# # Fetch todos for a specific meeting
|
33
|
-
# client.todo.list(meeting_id: 99)
|
34
|
-
# # => [{ id: 1, title: "New Todo", due_date: "2024-06-15", ... }]
|
35
|
-
def list(user_id: nil, meeting_id: nil)
|
36
|
-
raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both." if user_id && meeting_id
|
18
|
+
# Lists all todos for a specific user or meeting
|
19
|
+
#
|
20
|
+
# @param user_id [Integer, nil] the ID of the user (default is the initialized user ID)
|
21
|
+
# @param meeting_id [Integer, nil] the ID of the meeting
|
22
|
+
# @return [Array<TodoItem>] an array of TodoItem objects
|
23
|
+
# @raise [ArgumentError] if both `user_id` and `meeting_id` are provided
|
24
|
+
# @example
|
25
|
+
# # Fetch todos for the current user
|
26
|
+
# client.todo.list
|
27
|
+
# #=> [#<TodoItem id: 1, title: "New Todo", due_date: "2024-06-15", ...>]
|
28
|
+
def list(user_id: nil, meeting_id: nil)
|
29
|
+
raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both." if user_id && meeting_id
|
37
30
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
31
|
+
if meeting_id
|
32
|
+
response = @conn.get("l10/#{meeting_id}/todos").body
|
33
|
+
else
|
34
|
+
user_id ||= self.user_id
|
35
|
+
response = @conn.get("todo/user/#{user_id}").body
|
36
|
+
end
|
44
37
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
38
|
+
response.map do |todo|
|
39
|
+
Types::TodoItem.new(
|
40
|
+
id: todo["Id"],
|
41
|
+
title: todo["Name"],
|
42
|
+
notes_url: todo["DetailsUrl"],
|
43
|
+
due_date: todo["DueDate"],
|
44
|
+
created_at: todo["CreateTime"],
|
45
|
+
completed_at: todo["CompleteTime"],
|
46
|
+
status: todo["Complete"] ? "Complete" : "Incomplete"
|
47
|
+
)
|
48
|
+
end
|
55
49
|
end
|
56
|
-
end
|
57
50
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
51
|
+
# Creates a new todo
|
52
|
+
#
|
53
|
+
# @param title [String] the title of the new todo
|
54
|
+
# @param meeting_id [Integer] the ID of the meeting associated with the todo
|
55
|
+
# @param due_date [String, nil] the due date of the todo (optional)
|
56
|
+
# @param user_id [Integer] the ID of the user responsible for the todo (default: initialized user ID)
|
57
|
+
# @param notes [String, nil] additional notes for the todo (optional)
|
58
|
+
# @return [TodoItem] the newly created todo item
|
59
|
+
# @example
|
60
|
+
# client.todo.create(title: "New Todo", meeting_id: 1, due_date: "2024-06-15")
|
61
|
+
# #=> #<TodoItem id: 1, title: "New Todo", due_date: "2024-06-15", ...>
|
62
|
+
def create(title:, meeting_id:, due_date: nil, user_id: self.user_id, notes: nil)
|
63
|
+
payload = {title: title, accountableUserId: user_id, notes: notes}
|
64
|
+
payload[:dueDate] = due_date if due_date
|
65
|
+
response = @conn.post("/api/v1/L10/#{meeting_id}/todos", payload.to_json).body
|
73
66
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
67
|
+
Types::TodoItem.new(
|
68
|
+
id: response["Id"],
|
69
|
+
title: response["Name"],
|
70
|
+
notes_url: response["DetailsUrl"],
|
71
|
+
due_date: response["DueDate"],
|
72
|
+
created_at: DateTime.now.to_s,
|
73
|
+
status: "Incomplete"
|
74
|
+
)
|
75
|
+
end
|
83
76
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
77
|
+
# Marks a todo as complete
|
78
|
+
#
|
79
|
+
# @param todo_id [Integer] the ID of the todo to complete
|
80
|
+
# @return [Boolean] true if the operation was successful
|
81
|
+
# @example
|
82
|
+
# todo.complete(1)
|
83
|
+
# #=> true
|
84
|
+
def complete(todo_id)
|
85
|
+
response = @conn.post("/api/v1/todo/#{todo_id}/complete?status=true")
|
86
|
+
response.success?
|
87
|
+
end
|
95
88
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
89
|
+
# Updates an existing todo
|
90
|
+
#
|
91
|
+
# @param todo_id [Integer] the ID of the todo to update
|
92
|
+
# @param title [String, nil] the new title of the todo (optional)
|
93
|
+
# @param due_date [String, nil] the new due date of the todo (optional)
|
94
|
+
# @return [TodoItem] the updated todo item
|
95
|
+
# @raise [ArgumentError] if no update fields are provided
|
96
|
+
# @raise [RuntimeError] if the update request fails
|
97
|
+
# @example
|
98
|
+
# todo.update(todo_id: 1, title: "Updated Todo", due_date: "2024-11-01")
|
99
|
+
# #=> #<TodoItem id: 1, title: "Updated Todo", due_date: "2024-11-01", ...>
|
100
|
+
def update(todo_id:, title: nil, due_date: nil)
|
101
|
+
payload = {}
|
102
|
+
payload[:title] = title if title
|
103
|
+
payload[:dueDate] = due_date if due_date
|
109
104
|
|
110
|
-
|
105
|
+
raise ArgumentError, "At least one field must be provided" if payload.empty?
|
111
106
|
|
112
|
-
|
113
|
-
|
107
|
+
response = @conn.put("/api/v1/todo/#{todo_id}", payload.to_json)
|
108
|
+
raise "Failed to update todo. Status: #{response.status}" unless response.status == 200
|
114
109
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
110
|
+
Types::TodoItem.new(
|
111
|
+
id: todo_id,
|
112
|
+
title: title,
|
113
|
+
due_date: due_date,
|
114
|
+
created_at: nil,
|
115
|
+
status: "Incomplete"
|
116
|
+
)
|
117
|
+
end
|
122
118
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
119
|
+
# Retrieves the details of a specific todo item by its ID.
|
120
|
+
#
|
121
|
+
# @param todo_id [Integer] The ID of the todo item to retrieve.
|
122
|
+
# @return [TodoItem] The requested todo item
|
123
|
+
# @raise [RuntimeError] If the request to retrieve the todo details fails.
|
124
|
+
# @example
|
125
|
+
# client.todo.details(1)
|
126
|
+
# #=> #<TodoItem id: 1, title: "Updated Todo", due_date: "2024-11-01", ...>
|
127
|
+
def details(todo_id)
|
128
|
+
response = @conn.get("/api/v1/todo/#{todo_id}")
|
129
|
+
raise "Failed to get todo details. Status: #{response.status}" unless response.success?
|
134
130
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
}
|
131
|
+
todo = response.body
|
132
|
+
Types::TodoItem.new(
|
133
|
+
id: todo["Id"],
|
134
|
+
title: todo["Name"],
|
135
|
+
notes_url: todo["DetailsUrl"],
|
136
|
+
due_date: todo["DueDate"],
|
137
|
+
created_at: todo["CreateTime"],
|
138
|
+
completed_at: todo["CompleteTime"],
|
139
|
+
status: todo["Complete"] ? "Complete" : "Incomplete"
|
140
|
+
)
|
141
|
+
end
|
147
142
|
end
|
148
143
|
end
|