bloomy 0.1.1 → 0.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +12 -15
- data/lib/bloomy/client.rb +8 -6
- data/lib/bloomy/configuration.rb +1 -1
- data/lib/bloomy/operations/goals.rb +109 -0
- data/lib/bloomy/operations/headlines.rb +107 -0
- data/lib/bloomy/operations/issues.rb +8 -4
- data/lib/bloomy/operations/scorecard.rb +106 -0
- data/lib/bloomy/operations/todos.rb +29 -0
- data/lib/bloomy/version.rb +1 -1
- metadata +6 -5
- data/lib/bloomy/operations/measurables.rb +0 -77
- data/lib/bloomy/operations/rocks.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 787640980ef91fe249c30313f21be2230cc0671de398f714f38e1200fc104a6f
|
4
|
+
data.tar.gz: 6c2bb8a0b8e78371674fe5f18bc66ab44d91629d03484863442f4d3953c59707
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da4639a0e6e6e633f972d31df14818ed64e3b690f565c7308f49ae53a08c061b74d944f4d7088f8ab024ed54b4301d4186a9747802c34b24c2b7f476afdab77a
|
7
|
+
data.tar.gz: 6f4674b867eec7d42f5735c1c7a6725ff173ee2c8f7a1c8b22ef329ed8aa9f384e40632235a578e4d1efe654bccdda75255abbc9ab35313c11375d1815944dcb
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Bloomy
|
2
|
-
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/bloomy)[](https://github.com/franccesco/bloomy/actions/workflows/main.yml) [](https://github.com/franccesco/bloomy/actions/workflows/deploy_docs.yml)
|
3
4
|
|
4
5
|
Bloomy is a Ruby library for interacting with the Bloom Growth API. It provides convenient methods for getting user details, todos, rocks, meetings, measurables, and issues.
|
5
6
|
|
@@ -8,22 +9,18 @@ Bloomy is a Ruby library for interacting with the Bloom Growth API. It provides
|
|
8
9
|
Add this line to your application's Gemfile:
|
9
10
|
|
10
11
|
```ruby
|
11
|
-
|
12
|
-
```
|
13
|
-
|
14
|
-
And then execute:
|
15
|
-
|
16
|
-
```sh
|
17
|
-
bundle install
|
12
|
+
bundle add bloomy
|
18
13
|
```
|
19
14
|
|
20
|
-
Or install it
|
15
|
+
Or install it to your system:
|
21
16
|
|
22
17
|
```sh
|
23
18
|
gem install bloomy
|
24
19
|
```
|
25
20
|
|
26
|
-
##
|
21
|
+
## Get Started
|
22
|
+
|
23
|
+
You can find the [full docs here](https://franccesco.github.io/bloomy/) but here's a quick overview to get you started.
|
27
24
|
|
28
25
|
### Initialize the Configuration
|
29
26
|
|
@@ -106,16 +103,16 @@ rocks = client.rock.list
|
|
106
103
|
new_rock = client.rock.create(title: "New Rock", meeting_id: 1)
|
107
104
|
```
|
108
105
|
|
109
|
-
###
|
106
|
+
### Scorecard Management
|
110
107
|
|
111
108
|
To interact with measurable-related features:
|
112
109
|
|
113
110
|
```ruby
|
114
|
-
# Get
|
115
|
-
|
111
|
+
# Get user scorecard
|
112
|
+
user_scorecard = client.scorecard.list(user_id: 1)
|
116
113
|
|
117
|
-
# Get
|
118
|
-
|
114
|
+
# Get a meeting scorecard
|
115
|
+
meeting_scorecard = client.scorecard.list(meeting_id: 1)
|
119
116
|
```
|
120
117
|
|
121
118
|
### Issue Management
|
data/lib/bloomy/client.rb
CHANGED
@@ -3,16 +3,17 @@
|
|
3
3
|
require "faraday"
|
4
4
|
require_relative "operations/users"
|
5
5
|
require_relative "operations/todos"
|
6
|
-
require_relative "operations/
|
6
|
+
require_relative "operations/goals"
|
7
7
|
require_relative "operations/meetings"
|
8
|
-
require_relative "operations/
|
8
|
+
require_relative "operations/scorecard"
|
9
9
|
require_relative "operations/issues"
|
10
|
+
require_relative "operations/headlines"
|
10
11
|
|
11
12
|
module Bloomy
|
12
13
|
# The Client class is the main entry point for interacting with the Bloomy API.
|
13
|
-
# It provides methods for managing
|
14
|
+
# It provides methods for managing Bloom Growth features.
|
14
15
|
class Client
|
15
|
-
attr_reader :configuration, :user, :todo, :
|
16
|
+
attr_reader :configuration, :user, :todo, :goal, :meeting, :scorecard, :issue, :headline
|
16
17
|
|
17
18
|
# Initializes a new Client instance
|
18
19
|
#
|
@@ -35,10 +36,11 @@ module Bloomy
|
|
35
36
|
@user = User.new(@conn)
|
36
37
|
@user_id = @user.default_user_id
|
37
38
|
@todo = Todo.new(@conn, @user_id)
|
38
|
-
@
|
39
|
+
@goal = Goal.new(@conn, @user_id)
|
39
40
|
@meeting = Meeting.new(@conn, @user_id)
|
40
|
-
@
|
41
|
+
@scorecard = Scorecard.new(@conn, @user_id)
|
41
42
|
@issue = Issue.new(@conn, @user_id)
|
43
|
+
@headline = Headline.new(@conn, @user_id)
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
data/lib/bloomy/configuration.rb
CHANGED
@@ -11,7 +11,7 @@ module Bloomy
|
|
11
11
|
|
12
12
|
# Initializes a new Configuration instance
|
13
13
|
#
|
14
|
-
# @param [String, nil]
|
14
|
+
# @param [String, nil] api_key Pass an optional API key
|
15
15
|
# @example
|
16
16
|
# config = Bloomy::Configuration.new(api_key)
|
17
17
|
def initialize(api_key = nil)
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Class to handle all the operations related to goals
|
4
|
+
class Goal
|
5
|
+
# Initializes a new Goal instance
|
6
|
+
#
|
7
|
+
# @param conn [Object] the connection object to interact with the API
|
8
|
+
# @param user_id [Integer] the ID of the user
|
9
|
+
def initialize(conn, user_id)
|
10
|
+
@conn = conn
|
11
|
+
@user_id = user_id
|
12
|
+
end
|
13
|
+
|
14
|
+
# Lists all goals for a specific user
|
15
|
+
#
|
16
|
+
# @param user_id [Integer] the ID of the user (default is the initialized user ID)
|
17
|
+
# @param archived [Boolean] whether to include archived goals (default: false)
|
18
|
+
# @return [Array<Hash>] an array of hashes containing goal details or a hash with active and archived goals
|
19
|
+
# @example
|
20
|
+
# client.goal.list
|
21
|
+
# #=> [{ id: 1, title: "Complete project", created_at: "2024-06-10", ... }, ...]
|
22
|
+
def list(user_id: @user_id, archived: false)
|
23
|
+
active_goals = @conn.get("rocks/user/#{user_id}?include_origin=true").body.map do |goal|
|
24
|
+
{
|
25
|
+
id: goal["Id"],
|
26
|
+
title: goal["Name"],
|
27
|
+
created_at: goal["CreateTime"],
|
28
|
+
due_date: goal["DueDate"],
|
29
|
+
status: goal["Complete"] ? "Completed" : "Incomplete",
|
30
|
+
meeting_id: goal["Origins"].empty? ? nil : goal["Origins"][0]["Id"],
|
31
|
+
meeting_name: goal["Origins"].empty? ? nil : goal["Origins"][0]["Name"]
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
archived ? {active: active_goals, archived: get_archived_goals(user_id: @user_id)} : active_goals
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates a new goal
|
39
|
+
#
|
40
|
+
# @param title [String] the title of the new goal
|
41
|
+
# @param meeting_id [Integer] the ID of the meeting associated with the goal
|
42
|
+
# @param user_id [Integer] the ID of the user responsible for the goal (default: initialized user ID)
|
43
|
+
# @return [Hash] a hash containing the new goal's details
|
44
|
+
# @example
|
45
|
+
# client.goal.create(title: "New Goal", meeting_id: 1)
|
46
|
+
# #=> { goal_id: 1, title: "New Goal", meeting_id: 1, ... }
|
47
|
+
def create(title:, meeting_id:, user_id: @user_id)
|
48
|
+
payload = {title: title, accountableUserId: user_id}.to_json
|
49
|
+
response = @conn.post("/api/v1/L10/#{meeting_id}/rocks", payload).body
|
50
|
+
{
|
51
|
+
goal_id: response["Id"],
|
52
|
+
title: title,
|
53
|
+
meeting_id: meeting_id,
|
54
|
+
meeting_name: response["Origins"][0]["Name"],
|
55
|
+
user_id: user_id,
|
56
|
+
user_name: response["Owner"]["Name"],
|
57
|
+
created_at: DateTime.parse(response["CreateTime"])
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
# Deletes a goal
|
62
|
+
#
|
63
|
+
# @param goal_id [Integer] the ID of the goal to delete
|
64
|
+
# @return [Hash] a hash containing the status of the delete operation
|
65
|
+
# @example
|
66
|
+
# client.goal.delete(1)
|
67
|
+
# #=> { status: 200 }
|
68
|
+
def delete(goal_id)
|
69
|
+
response = @conn.delete("/api/v1/rocks/#{goal_id}")
|
70
|
+
{status: response.status}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Updates a goal
|
74
|
+
#
|
75
|
+
# @param goal_id [Integer] the ID of the goal to update
|
76
|
+
# @param title [String] the new title of the goal
|
77
|
+
# @param accountable_user [Integer] the ID of the user responsible for the goal (default: initialized user ID)
|
78
|
+
# @return [Hash] a hash containing the status of the update operation
|
79
|
+
# @example
|
80
|
+
# client.goal.update(goal_id: 1, title: "Updated Goal")
|
81
|
+
# #=> { status: 200 }
|
82
|
+
def update(goal_id:, title:, accountable_user: @user_id)
|
83
|
+
payload = {title: title, accountableUserId: accountable_user}.to_json
|
84
|
+
response = @conn.put("/api/v1/rocks/#{goal_id}", payload)
|
85
|
+
{status: response.status}
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Retrieves all archived goals for a specific user (private method)
|
91
|
+
#
|
92
|
+
# @param user_id [Integer] the ID of the user (default is the initialized user ID)
|
93
|
+
# @return [Array<Hash>] an array of hashes containing archived goal details
|
94
|
+
# @example
|
95
|
+
# goal.send(:get_archived_goals)
|
96
|
+
# #=> [{ id: 1, title: "Archived Goal", created_at: "2024-06-10", ... }, ...]
|
97
|
+
def get_archived_goals(user_id: @user_id)
|
98
|
+
response = @conn.get("archivedrocks/user/#{user_id}").body
|
99
|
+
response.map do |goal|
|
100
|
+
{
|
101
|
+
id: goal["Id"],
|
102
|
+
title: goal["Name"],
|
103
|
+
created_at: goal["CreateTime"],
|
104
|
+
due_date: goal["DueDate"],
|
105
|
+
status: goal["Complete"] ? "Complete" : "Incomplete"
|
106
|
+
}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Headline
|
4
|
+
# Initializes a new headline instance
|
5
|
+
#
|
6
|
+
# @param conn [Object] the connection object to interact with the API
|
7
|
+
# @param user_id [Integer] the ID of the user
|
8
|
+
def initialize(conn, user_id)
|
9
|
+
@conn = conn
|
10
|
+
@user_id = user_id
|
11
|
+
end
|
12
|
+
|
13
|
+
# Creates a new headline
|
14
|
+
#
|
15
|
+
# @param meeting_id [Integer] the ID of the meeting
|
16
|
+
# @param title [String] the title of the headline
|
17
|
+
# @param owner_id [Integer] the ID of the owner
|
18
|
+
# @param notes [String] additional notes for the headline
|
19
|
+
# @return [Hash] the created headline details
|
20
|
+
def create(meeting_id, title, owner_id: @user_id, notes: nil)
|
21
|
+
response = @conn.post("/api/v1/L10/#{meeting_id}/headlines",
|
22
|
+
{title: title, ownerId: owner_id, notes: notes}.to_json)
|
23
|
+
raise "Failed to create headline" unless response.status == 200
|
24
|
+
|
25
|
+
{
|
26
|
+
id: response.body["Id"],
|
27
|
+
title: response.body["Title"],
|
28
|
+
owner_id: response.body["OwnerId"],
|
29
|
+
notes: response.body["Notes"]
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Updates a headline
|
34
|
+
#
|
35
|
+
# @param headline_id [Integer] the ID of the headline to update
|
36
|
+
# @param title [String] the new title of the headline
|
37
|
+
# @return [Hash] the updated headline details
|
38
|
+
def update(headline_id, title)
|
39
|
+
response = @conn.put("/api/v1/headline/#{headline_id}", {title: title}.to_json)
|
40
|
+
raise "Failed to update headline" unless response.status == 200
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get headline details
|
45
|
+
#
|
46
|
+
# @param headline_id [Integer] the ID of the headline
|
47
|
+
# @return [Hash] the details of the headline
|
48
|
+
def details(headline_id)
|
49
|
+
response = @conn.get("/api/v1/headline/#{headline_id}?Include_Origin=true")
|
50
|
+
raise "Failed to get headline details" unless response.status == 200
|
51
|
+
|
52
|
+
{
|
53
|
+
id: response.body["Id"],
|
54
|
+
title: response.body["Name"],
|
55
|
+
meeting_details: {
|
56
|
+
id: response.body["OriginId"],
|
57
|
+
name: response.body["Origin"]
|
58
|
+
},
|
59
|
+
owner_details: {
|
60
|
+
id: response.body["Owner"]["Id"],
|
61
|
+
name: response.body["Owner"]["Name"]
|
62
|
+
},
|
63
|
+
archived: response.body["Archived"],
|
64
|
+
created_at: response.body["CreateTime"],
|
65
|
+
closed_at: response.body["CloseTime"]
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get user headlines
|
70
|
+
#
|
71
|
+
# @param user_id [Integer] the ID of the user
|
72
|
+
# @return [Array] the list of headlines for the user
|
73
|
+
def user_headlines(user_id: @user_id)
|
74
|
+
response = @conn.get("/api/v1/headline/users/#{user_id}")
|
75
|
+
raise "Failed to list headlines" unless response.status == 200
|
76
|
+
response.body.map do |headline|
|
77
|
+
{
|
78
|
+
id: headline["Id"],
|
79
|
+
title: headline["Name"],
|
80
|
+
meeting_details: {
|
81
|
+
id: headline["OriginId"],
|
82
|
+
name: headline["Origin"]
|
83
|
+
},
|
84
|
+
owner_details: {
|
85
|
+
id: headline["Owner"]["Id"],
|
86
|
+
name: headline["Owner"]["Name"]
|
87
|
+
},
|
88
|
+
archived: headline["Archived"],
|
89
|
+
created_at: headline["CreateTime"],
|
90
|
+
closed_at: headline["CloseTime"]
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Deletes a headline
|
96
|
+
#
|
97
|
+
# @param meeting_id [Integer] the ID of the meeting
|
98
|
+
# @param headline_id [Integer] the ID of the headline to delete
|
99
|
+
# @return [Boolean] true if the deletion was successful
|
100
|
+
def delete(meeting_id, headline_id)
|
101
|
+
response = @conn.delete("/api/v1/L10/#{meeting_id}/headlines/#{headline_id}")
|
102
|
+
|
103
|
+
# Raise an issue if response.status != 200
|
104
|
+
raise "Failed to delete headline" unless response.status == 200
|
105
|
+
true
|
106
|
+
end
|
107
|
+
end
|
@@ -74,17 +74,21 @@ class Issue
|
|
74
74
|
|
75
75
|
# Creates a new issue
|
76
76
|
#
|
77
|
-
# @param
|
77
|
+
# @param title [String] the title of the new issue
|
78
78
|
# @param meeting_id [Integer] the ID of the meeting associated with the issue
|
79
79
|
# @return [Hash] a hash containing the new issue's ID and title
|
80
80
|
# @example
|
81
81
|
# issue.create("New Issue", 456)
|
82
82
|
# #=> { id: 789, title: "New Issue" }
|
83
|
-
def create(
|
84
|
-
response = @conn.post("issues/create", {title:
|
83
|
+
def create(meeting_id:, title:, user_id: @user_id, notes: nil)
|
84
|
+
response = @conn.post("issues/create", {title: title, meetingid: meeting_id, ownerid: user_id, notes: notes}.to_json)
|
85
85
|
{
|
86
86
|
id: response.body["Id"],
|
87
|
-
|
87
|
+
meeting_id: response.body["OriginId"],
|
88
|
+
meeting_title: response.body["Origin"],
|
89
|
+
title: response.body["Name"],
|
90
|
+
user_id: response.body["Owner"]["Id"],
|
91
|
+
details_url: response.body["DetailsUrl"]
|
88
92
|
}
|
89
93
|
end
|
90
94
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
# Class to handle all the operations related to scorecards
|
6
|
+
# @note
|
7
|
+
# This class is already initialized via the client and usable as `client.scorecard.method`
|
8
|
+
class Scorecard
|
9
|
+
# Initializes a new Scorecard instance
|
10
|
+
#
|
11
|
+
# @param conn [Object] the connection object to interact with the API
|
12
|
+
# @param user_id [Integer] the ID of the user
|
13
|
+
def initialize(conn, user_id)
|
14
|
+
@conn = conn
|
15
|
+
@user_id = user_id
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieves the current week details
|
19
|
+
#
|
20
|
+
# @return [Hash] a hash containing current week details
|
21
|
+
# @example
|
22
|
+
# client.scorecard.current_week
|
23
|
+
# #=> { id: 123, week_number: 24, week_start: "2024-06-10", week_end: "2024-06-16" }
|
24
|
+
def current_week
|
25
|
+
response = @conn.get("weeks/current").body
|
26
|
+
{
|
27
|
+
id: response["Id"],
|
28
|
+
week_number: response["ForWeekNumber"],
|
29
|
+
week_start: response["LocalDate"]["Date"],
|
30
|
+
week_end: response["ForWeek"]
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
# Retrieves the scorecards for a user or a meeting.
|
35
|
+
#
|
36
|
+
# @param user_id [Integer, nil] the ID of the user (defaults to initialized user_id)
|
37
|
+
# @param meeting_id [Integer, nil] the ID of the meeting
|
38
|
+
# @param show_empty [Boolean] whether to include scores with nil values (default: false)
|
39
|
+
# @param week_offset [Integer, nil] offset for the week number to filter scores
|
40
|
+
# @raise [ArgumentError] if both `user_id` and `meeting_id` are provided
|
41
|
+
# @return [Array<Hash>] an array of hashes containing scorecard details
|
42
|
+
# @example
|
43
|
+
# # Fetch scorecards for the current user
|
44
|
+
# client.scorecard.list
|
45
|
+
#
|
46
|
+
# # Fetch scorecards for a specific user
|
47
|
+
# client.scorecard.list(user_id: 42)
|
48
|
+
#
|
49
|
+
# # Fetch scorecards for a specific meeting
|
50
|
+
# client.scorecard.list(meeting_id: 99)
|
51
|
+
def list(user_id: nil, meeting_id: nil, show_empty: false, week_offset: nil)
|
52
|
+
if user_id && meeting_id
|
53
|
+
raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both."
|
54
|
+
end
|
55
|
+
|
56
|
+
if meeting_id
|
57
|
+
response = @conn.get("scorecard/meeting/#{meeting_id}").body
|
58
|
+
else
|
59
|
+
user_id ||= @user_id
|
60
|
+
response = @conn.get("scorecard/user/#{user_id}").body
|
61
|
+
end
|
62
|
+
|
63
|
+
scorecards = response["Scores"].map do |scorecard|
|
64
|
+
{
|
65
|
+
id: scorecard["Id"],
|
66
|
+
measurable_id: scorecard["MeasurableId"],
|
67
|
+
accountable_user_id: scorecard["AccountableUserId"],
|
68
|
+
title: scorecard["MeasurableName"],
|
69
|
+
target: scorecard["Target"],
|
70
|
+
value: scorecard["Measured"],
|
71
|
+
week: scorecard["Week"],
|
72
|
+
updated_at: scorecard["DateEntered"]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
if week_offset
|
77
|
+
week_data = current_week
|
78
|
+
week_id = week_data[:week_number] - week_offset
|
79
|
+
scorecards.select! { |scorecard| scorecard[:week] == week_id }
|
80
|
+
end
|
81
|
+
|
82
|
+
scorecards.select! { |scorecard| scorecard[:value] || show_empty } unless show_empty
|
83
|
+
scorecards
|
84
|
+
end
|
85
|
+
|
86
|
+
# Updates the score for a measurable item for a specific week.
|
87
|
+
#
|
88
|
+
# @param measurable_id [Integer] the ID of the measurable item.
|
89
|
+
# @param score [Numeric] the score to be assigned to the measurable item.
|
90
|
+
# @param week_offset [Integer] the number of weeks to offset from the current week (default is 0).
|
91
|
+
# @return [Boolean] true if the score was successfully updated, false otherwise.
|
92
|
+
# @example
|
93
|
+
# client.scorecard.score(measurable_id: 123, score: 5)
|
94
|
+
# #=> true
|
95
|
+
# @note
|
96
|
+
# The `week_offset` parameter is useful when updating scores for previous weeks.
|
97
|
+
# For example, to update the score for the previous week, you can set `week_offset` to 1.
|
98
|
+
# To update a future week's score, you can set `week_offset` to a negative value.
|
99
|
+
def score(measurable_id:, score:, week_offset: 0)
|
100
|
+
week_data = current_week
|
101
|
+
week_id = week_data[:week_number] - week_offset
|
102
|
+
|
103
|
+
response = @conn.put("measurables/#{measurable_id}/week/#{week_id}", {value: score}.to_json)
|
104
|
+
response.success?
|
105
|
+
end
|
106
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "date"
|
4
|
+
|
3
5
|
# Class to handle all the operations related to todos
|
4
6
|
class Todo
|
5
7
|
# Initializes a new Todo instance
|
@@ -67,4 +69,31 @@ class Todo
|
|
67
69
|
response = @conn.post("/api/v1/todo/#{todo_id}/complete?status=true")
|
68
70
|
{status: response.status}
|
69
71
|
end
|
72
|
+
|
73
|
+
# Updates an existing todo
|
74
|
+
#
|
75
|
+
# @param todo_id [Integer] the ID of the todo to update
|
76
|
+
# @param title [String, nil] the new title of the todo (optional)
|
77
|
+
# @param due_date [String, nil] the new due date of the todo (optional)
|
78
|
+
# @return [Hash] a hash containing the updated todo's details
|
79
|
+
# @example
|
80
|
+
# todo.update(1, title: "Updated Todo", due_date: "2024-11-01T01:41:41.528Z")
|
81
|
+
# #=> { id: 1, title: "Updated Todo", due_date: "2024-11-01T01:41:41.528Z", ... }
|
82
|
+
def update(todo_id:, title: nil, due_date: nil)
|
83
|
+
payload = {}
|
84
|
+
payload[:title] = title if title
|
85
|
+
payload[:dueDate] = due_date if due_date
|
86
|
+
|
87
|
+
raise ArgumentError, "At least one field must be provided" if payload.empty?
|
88
|
+
|
89
|
+
response = @conn.put("/api/v1/todo/#{todo_id}", payload.to_json)
|
90
|
+
raise "Failed to update todo. Status: #{response.status}" unless response.status == 200
|
91
|
+
|
92
|
+
{
|
93
|
+
id: todo_id,
|
94
|
+
title: title,
|
95
|
+
due_date: due_date,
|
96
|
+
updated_at: DateTime.now.to_s
|
97
|
+
}
|
98
|
+
end
|
70
99
|
end
|
data/lib/bloomy/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bloomy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Franccesco Orozco
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -57,10 +57,11 @@ files:
|
|
57
57
|
- lib/bloomy.rb
|
58
58
|
- lib/bloomy/client.rb
|
59
59
|
- lib/bloomy/configuration.rb
|
60
|
+
- lib/bloomy/operations/goals.rb
|
61
|
+
- lib/bloomy/operations/headlines.rb
|
60
62
|
- lib/bloomy/operations/issues.rb
|
61
|
-
- lib/bloomy/operations/measurables.rb
|
62
63
|
- lib/bloomy/operations/meetings.rb
|
63
|
-
- lib/bloomy/operations/
|
64
|
+
- lib/bloomy/operations/scorecard.rb
|
64
65
|
- lib/bloomy/operations/todos.rb
|
65
66
|
- lib/bloomy/operations/users.rb
|
66
67
|
- lib/bloomy/version.rb
|
@@ -86,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
87
|
- !ruby/object:Gem::Version
|
87
88
|
version: '0'
|
88
89
|
requirements: []
|
89
|
-
rubygems_version: 3.5.
|
90
|
+
rubygems_version: 3.5.17
|
90
91
|
signing_key:
|
91
92
|
specification_version: 4
|
92
93
|
summary: Manage your Bloom Growth account from the command line.
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
|
5
|
-
# Class to handle all the operations related to measurables
|
6
|
-
# @note
|
7
|
-
# This class is already initialized via the client and usable as `client.measurable.method`
|
8
|
-
class Measurable
|
9
|
-
# Initializes a new Measurable instance
|
10
|
-
#
|
11
|
-
# @param conn [Object] the connection object to interact with the API
|
12
|
-
# @param user_id [Integer] the ID of the user
|
13
|
-
def initialize(conn, user_id)
|
14
|
-
@conn = conn
|
15
|
-
@user_id = user_id
|
16
|
-
end
|
17
|
-
|
18
|
-
# Retrieves the current week details
|
19
|
-
#
|
20
|
-
# @return [Hash] a hash containing current week details
|
21
|
-
# @example
|
22
|
-
# client.measurable.current_week
|
23
|
-
# #=> { id: 123, week_number: 24, week_start: "2024-06-10", week_end: "2024-06-16" }
|
24
|
-
def current_week
|
25
|
-
response = @conn.get("weeks/current").body
|
26
|
-
{
|
27
|
-
id: response["Id"],
|
28
|
-
week_number: response["ForWeekNumber"],
|
29
|
-
week_start: response["LocalDate"]["Date"],
|
30
|
-
week_end: response["ForWeek"]
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
# Retrieves the scorecard for the user
|
35
|
-
#
|
36
|
-
# @param current_week_only [Boolean] whether to include only the current week's scores (default: true)
|
37
|
-
# @param show_empty [Boolean] whether to include scores with nil values (default: true)
|
38
|
-
# @return [Array<Hash>] an array of hashes containing scorecard details
|
39
|
-
# @example
|
40
|
-
# client.measurable.scorecard
|
41
|
-
# #=> [{ id: 123, title: "Sales", target: 100, value: 80, updated_at: "2024-06-12", week_number: 24 }, ...]
|
42
|
-
def scorecard(current_week_only: true, show_empty: true)
|
43
|
-
response = @conn.get("scorecard/user/mine").body
|
44
|
-
scorecards = response["Scores"].map do |scorecard|
|
45
|
-
{
|
46
|
-
id: scorecard["Id"],
|
47
|
-
title: scorecard["MeasurableName"],
|
48
|
-
target: scorecard["Target"],
|
49
|
-
value: scorecard["Measured"],
|
50
|
-
updated_at: scorecard["DateEntered"],
|
51
|
-
week_number: scorecard["ForWeek"]
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
if current_week_only
|
56
|
-
week_id = current_week[:week_number]
|
57
|
-
scorecards.select do |scorecard|
|
58
|
-
scorecard[:week_number] == week_id && (show_empty || scorecard[:value].nil?)
|
59
|
-
end
|
60
|
-
else
|
61
|
-
scorecards.select { |scorecard| show_empty || scorecard[:value].nil? }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Updates a scorecard with a new measured value
|
66
|
-
#
|
67
|
-
# @param scorecard_id [Integer] the ID of the scorecard to update
|
68
|
-
# @param measured [Numeric] the new measured value
|
69
|
-
# @return [Boolean] true if the operation was successful, false otherwise
|
70
|
-
# @example
|
71
|
-
# client.measurable.update(1, 85)
|
72
|
-
# #=> true
|
73
|
-
def update(scorecard_id, measured)
|
74
|
-
response = @conn.put("scores/#{scorecard_id}", {value: measured}.to_json).status
|
75
|
-
response == 200
|
76
|
-
end
|
77
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Class to handle all the operations related to rocks
|
4
|
-
class Rock
|
5
|
-
# Initializes a new Rock instance
|
6
|
-
#
|
7
|
-
# @param conn [Object] the connection object to interact with the API
|
8
|
-
# @param user_id [Integer] the ID of the user
|
9
|
-
def initialize(conn, user_id)
|
10
|
-
@conn = conn
|
11
|
-
@user_id = user_id
|
12
|
-
end
|
13
|
-
|
14
|
-
# Lists all rocks for a specific user
|
15
|
-
#
|
16
|
-
# @param user_id [Integer] the ID of the user (default is the initialized user ID)
|
17
|
-
# @param archived [Boolean] whether to include archived rocks (default: false)
|
18
|
-
# @return [Array<Hash>] an array of hashes containing rock details or a hash with active and archived rocks
|
19
|
-
# @example
|
20
|
-
# client.rock.list
|
21
|
-
# #=> [{ id: 1, title: "Complete project", created_at: "2024-06-10", ... }, ...]
|
22
|
-
def list(user_id: @user_id, archived: false)
|
23
|
-
active_rocks = @conn.get("rocks/user/#{user_id}?include_origin=true").body.map do |rock|
|
24
|
-
{
|
25
|
-
id: rock["Id"],
|
26
|
-
title: rock["Name"],
|
27
|
-
created_at: rock["CreateTime"],
|
28
|
-
due_date: rock["DueDate"],
|
29
|
-
status: rock["Complete"] ? "Completed" : "Incomplete",
|
30
|
-
meeting_id: rock["Origins"].empty? ? nil : rock["Origins"][0]["Id"],
|
31
|
-
meeting_name: rock["Origins"].empty? ? nil : rock["Origins"][0]["Name"]
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
archived ? {active: active_rocks, archived: get_archived_rocks(user_id: @user_id)} : active_rocks
|
36
|
-
end
|
37
|
-
|
38
|
-
# Creates a new rock
|
39
|
-
#
|
40
|
-
# @param title [String] the title of the new rock
|
41
|
-
# @param meeting_id [Integer] the ID of the meeting associated with the rock
|
42
|
-
# @param user_id [Integer] the ID of the user responsible for the rock (default: initialized user ID)
|
43
|
-
# @return [Hash] a hash containing the new rock's details
|
44
|
-
# @example
|
45
|
-
# client.rock.create(title: "New Rock", meeting_id: 1)
|
46
|
-
# #=> { rock_id: 1, title: "New Rock", meeting_id: 1, ... }
|
47
|
-
def create(title:, meeting_id:, user_id: @user_id)
|
48
|
-
payload = {title: title, accountableUserId: user_id}.to_json
|
49
|
-
response = @conn.post("/api/v1/L10/#{meeting_id}/rocks", payload).body
|
50
|
-
{
|
51
|
-
rock_id: response["Id"],
|
52
|
-
title: title,
|
53
|
-
meeting_id: meeting_id,
|
54
|
-
meeting_name: response["Origins"][0]["Name"],
|
55
|
-
user_id: user_id,
|
56
|
-
user_name: response["Owner"]["Name"],
|
57
|
-
created_at: DateTime.parse(response["CreateTime"])
|
58
|
-
}
|
59
|
-
end
|
60
|
-
|
61
|
-
# Deletes a rock
|
62
|
-
#
|
63
|
-
# @param rock_id [Integer] the ID of the rock to delete
|
64
|
-
# @return [Hash] a hash containing the status of the delete operation
|
65
|
-
# @example
|
66
|
-
# client.rock.delete(1)
|
67
|
-
# #=> { status: 200 }
|
68
|
-
def delete(rock_id)
|
69
|
-
response = @conn.delete("/api/v1/rocks/#{rock_id}")
|
70
|
-
{status: response.status}
|
71
|
-
end
|
72
|
-
|
73
|
-
# Updates a rock
|
74
|
-
#
|
75
|
-
# @param rock_id [Integer] the ID of the rock to update
|
76
|
-
# @param title [String] the new title of the rock
|
77
|
-
# @param accountable_user [Integer] the ID of the user responsible for the rock (default: initialized user ID)
|
78
|
-
# @return [Hash] a hash containing the status of the update operation
|
79
|
-
# @example
|
80
|
-
# client.rock.update(rock_id: 1, title: "Updated Rock")
|
81
|
-
# #=> { status: 200 }
|
82
|
-
def update(rock_id:, title:, accountable_user: @user_id)
|
83
|
-
payload = {title: title, accountableUserId: accountable_user}.to_json
|
84
|
-
response = @conn.put("/api/v1/rocks/#{rock_id}", payload)
|
85
|
-
{status: response.status}
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
# Retrieves all archived rocks for a specific user (private method)
|
91
|
-
#
|
92
|
-
# @param user_id [Integer] the ID of the user (default is the initialized user ID)
|
93
|
-
# @return [Array<Hash>] an array of hashes containing archived rock details
|
94
|
-
# @example
|
95
|
-
# rock.send(:get_archived_rocks)
|
96
|
-
# #=> [{ id: 1, title: "Archived Rock", created_at: "2024-06-10", ... }, ...]
|
97
|
-
def get_archived_rocks(user_id: @user_id)
|
98
|
-
response = @conn.get("archivedrocks/user/#{user_id}").body
|
99
|
-
response.map do |rock|
|
100
|
-
{
|
101
|
-
id: rock["Id"],
|
102
|
-
title: rock["Name"],
|
103
|
-
created_at: rock["CreateTime"],
|
104
|
-
due_date: rock["DueDate"],
|
105
|
-
status: rock["Complete"] ? "Complete" : "Incomplete"
|
106
|
-
}
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|