bloomy 0.4.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 453b980c92f83f6acf3d9a1191dcf94484a9a3acbc57811509f534964d0d15d7
4
- data.tar.gz: 2c1e08c2351256c4d16b37729ce8173f144ed3680cbdd2e46f55c2a7e57b23f7
3
+ metadata.gz: 4a147716e1b8f4ccad09501b59a7bc2ad58b38995f1aaeb4ef6f951707c35a10
4
+ data.tar.gz: 6aed3b2ecf2622a802aa3e010308675175e1f5376b375208893e19483476d879
5
5
  SHA512:
6
- metadata.gz: 2ae681b285f824f3ee6c5f5a9806a205d86d2c01fefe84263aa0b1d1d34bd1a3996b17dc98330051125a1b79d0f9e868ed79d7dc015294ba39a5fb71e3032ede
7
- data.tar.gz: 9a7710243dc62d7bb21e6b1fb0f2795c44dbb034b0fab8f787a5b3d93c942be7ff9d25ed9bde6552e10859bfd52565d090d8b0d3f576dda31afe4da440a88707
6
+ metadata.gz: b94e517996379058516393a91851d4ff6c7a3fc3cd2d6612dbe78bf9a183ce1372fac6b2ddadc63d9b296c878ba787e74e4359441b01b2c450cd985f4160ac5b
7
+ data.tar.gz: 86b457f7ae1b198f8acd350e272e23a5a180875bd82da202ea246a93b03750083dde02a7ac29a18f24abd00527dd60081c782dfe73465884ad9926b4288ba969
data/.rubocop.yml CHANGED
@@ -1,30 +1,10 @@
1
- AllCops:
2
- NewCops: enable
3
- SuggestExtensions: false
4
-
5
- Gemspec/RequiredRubyVersion:
6
- Enabled: false
7
-
8
- Metrics/AbcSize:
9
- Enabled: false
10
-
11
- Metrics/BlockLength:
12
- Enabled: false
13
-
14
- Metrics/CyclomaticComplexity:
15
- Enabled: false
16
-
17
- Metrics/MethodLength:
18
- Enabled: false
19
-
20
- Metrics/PerceivedComplexity:
21
- Enabled: false
22
-
23
- Naming/AccessorMethodName:
24
- Enabled: false
25
-
26
- Gemspec/DevelopmentDependencies:
27
- Enabled: false
28
-
29
- Style/StringLiterals:
30
- EnforcedStyle: double_quotes
1
+ require:
2
+ - standard
3
+ - standard-custom
4
+ - standard-performance
5
+ - rubocop-performance
6
+
7
+ inherit_gem:
8
+ standard: config/base.yml
9
+ standard-custom: config/base.yml
10
+ standard-performance: config/base.yml
@@ -0,0 +1,128 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity
10
+ and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ - Demonstrating empathy and kindness toward other people
21
+ - Being respectful of differing opinions, viewpoints, and experiences
22
+ - Giving and gracefully accepting constructive feedback
23
+ - Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ - Focusing on what is best not just for us as individuals, but for the
26
+ overall community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ - The use of sexualized language or imagery, and sexual attention or
31
+ advances of any kind
32
+ - Trolling, insulting or derogatory comments, and personal or political attacks
33
+ - Public or private harassment
34
+ - Publishing others' private information, such as a physical or email
35
+ address, without their explicit permission
36
+ - Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official e-mail address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ .
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series
86
+ of actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or
93
+ permanent ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within
113
+ the community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.0, available at
119
+ https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120
+
121
+ Community Impact Guidelines were inspired by [Mozilla's code of conduct
122
+ enforcement ladder](https://github.com/mozilla/diversity).
123
+
124
+ [homepage]: https://www.contributor-covenant.org
125
+
126
+ For answers to common questions about this code of conduct, see the FAQ at
127
+ https://www.contributor-covenant.org/faq. Translations are available at
128
+ https://www.contributor-covenant.org/translations.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,96 @@
1
+ # Contributing to Bloomy
2
+
3
+ Thank you for your interest in contributing to Bloomy! This document outlines the guidelines for contributing to the project.
4
+
5
+ ## Did you find a bug?
6
+
7
+ - Before creating an issue, please ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/franccesco/bloomy/issues)
8
+ - If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/franccesco/bloomy/issues/new). Be sure to include a title and clear description, as much relevant information as possible. A code sample or a screenshot would be helpful.
9
+ - You can also write issues if you want to discuss a feature request or a general question about the project.
10
+
11
+ ## Do you want to contribute to the Bloomy project?
12
+
13
+ PR's are welcome! Just make sure you have discussed the changes you want to make with the project maintainer before you start working on them. Before getting started, make sure you are not submitting a PR that's purely cosmetic (linting changes, whitespace, etc.)
14
+
15
+ If you want to contribute to the project, please follow these steps:
16
+
17
+ ### Development Setup
18
+
19
+ 1. Fork and clone the repository:
20
+
21
+ ```sh
22
+ git clone https://github.com/your-username/bloomy.git
23
+ ```
24
+
25
+ 2. Install the dependencies:
26
+
27
+ ```sh
28
+ bundle install
29
+ ```
30
+
31
+ 3. Set up pre-commit hooks:
32
+
33
+ ```sh
34
+ pre-commit install
35
+ ```
36
+
37
+ 4. Add your Bloom Growth username and password to an `.env` file. I use [direnv](https://direnv.net/) to manage my environment variables.
38
+
39
+ ```sh
40
+ export USERNAME=your_username
41
+ export PASSWORD=your_password
42
+ ```
43
+
44
+ 5. Run the tests:
45
+
46
+ ```sh
47
+ bundle exec rspec
48
+ ```
49
+
50
+ ### Making Changes
51
+
52
+ Once everything is green, you can start making changes. Make sure to write tests for your changes and run the tests before submitting a PR.
53
+
54
+ As for coding style guidelines make sure you:
55
+
56
+ - Follow the Ruby Style Guide enforced by [StandardRB](https://github.com/standardrb/standard)
57
+ - Use [YARD](https://yardoc.org) documentation for classes and methods
58
+ - Include `@examples` in method documentation
59
+
60
+ ### Pull Request Process
61
+
62
+ 1. Make sure your PR is up-to-date with the `main` branch.
63
+ 2. Make sure your PR passes the CI checks.
64
+ 3. Make sure your PR has a clear title and description.
65
+ 4. Update the version according to [Semantic Versioning](https://semver.org/).
66
+ 5. Optionally, use [Conventional Commits](https://www.conventionalcommits.org/) for your commit messages.
67
+
68
+ Make sure to follow these guidelines to ensure your PR is accepted and merged quickly. Rinse and repeat! 🚀
69
+
70
+ ## Comments on Test Structure
71
+
72
+ When developing new features, make sure to add a test. Tests will usually have the following basic structure:
73
+
74
+ ```ruby
75
+ RSpec.describe "Feature" do
76
+
77
+ # Your setup and teardown code here
78
+ before(:all) do
79
+ @client = Bloomy::Client.new
80
+ @meeting = @client.meeting.create("Meeting Name")
81
+ end
82
+
83
+ after(:all) do
84
+ @client.meeting.delete(@meeting[:meeting_id])
85
+ end
86
+
87
+ # Your tests here
88
+ context "when using the feature" do
89
+ it "performs the expected action" do
90
+ # Test implementation
91
+ end
92
+ end
93
+ end
94
+ ```
95
+
96
+ In the `before(:all)` block, you can set up any necessary objects or variables that will be used in the tests. For example, creating a meeting object that will be used in the tests which will be deleted in the `after(:all)` block.
data/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/bloomy.svg)](https://badge.fury.io/rb/bloomy)[![RSpec Tests](https://github.com/franccesco/bloomy/actions/workflows/main.yml/badge.svg)](https://github.com/franccesco/bloomy/actions/workflows/main.yml) [![Deploy Docs](https://github.com/franccesco/bloomy/actions/workflows/deploy_docs.yml/badge.svg)](https://github.com/franccesco/bloomy/actions/workflows/deploy_docs.yml)
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
+ Bloomy is an **_unofficial_** Ruby library for interacting with the Bloom Growth API. It provides convenient methods for getting user details, todos, rocks, meetings, measurables, and issues.
6
6
 
7
7
  ## Installation
8
8
 
9
9
  Add this line to your application's Gemfile:
10
10
 
11
- ```ruby
11
+ ```sh
12
12
  bundle add bloomy
13
13
  ```
14
14
 
@@ -88,19 +88,19 @@ To interact with todo-related features:
88
88
  todos = client.todo.list
89
89
 
90
90
  # Create a new todo
91
- new_todo = client.todo.create(title: "New Task", meeting_id: 1, due_date: "2024-06-15")
91
+ new_todo = client.todo.create(meeting_id: 1, title: "New Task", due_date: "2024-06-15")
92
92
  ```
93
93
 
94
- ### Rock Management
94
+ ### Goal Management
95
95
 
96
- To interact with rock-related features:
96
+ To interact with goal-related features:
97
97
 
98
98
  ```ruby
99
- # List all rocks for the current user
100
- rocks = client.rock.list
99
+ # List all goals for the current user
100
+ goals = client.goal.list
101
101
 
102
- # Create a new rock
103
- new_rock = client.rock.create(title: "New Rock", meeting_id: 1)
102
+ # Create a new goal
103
+ new_goal = client.goal.create(meeting_id: 1, title: "New Goal")
104
104
  ```
105
105
 
106
106
  ### Scorecard Management
@@ -124,5 +124,5 @@ To interact with issue-related features:
124
124
  issue_details = client.issue.details(issue_id)
125
125
 
126
126
  # Create a new issue
127
- new_issue = client.issue.create("New Issue", meeting_id)
127
+ new_issue = client.issue.create(meeting_id: 1, title: "New Issue")
128
128
  ```
data/lib/bloomy/client.rb CHANGED
@@ -25,6 +25,9 @@ module Bloomy
25
25
  def initialize(api_key = nil)
26
26
  @configuration = Configuration.new unless api_key
27
27
  @api_key = api_key || @configuration.api_key
28
+
29
+ raise ArgumentError, "No API key provided. Set it in configuration or pass it directly." unless @api_key
30
+
28
31
  @base_url = "https://app.bloomgrowth.com/api/v1"
29
32
  @conn = Faraday.new(url: @base_url) do |faraday|
30
33
  faraday.response :json
@@ -29,7 +29,7 @@ class Goal
29
29
  due_date: goal["DueDate"],
30
30
  status: goal["Complete"] ? "Completed" : "Incomplete",
31
31
  meeting_id: goal["Origins"].empty? ? nil : goal["Origins"][0]["Id"],
32
- meeting_name: goal["Origins"].empty? ? nil : goal["Origins"][0]["Name"]
32
+ meeting_title: goal["Origins"].empty? ? nil : goal["Origins"][0]["Name"]
33
33
  }
34
34
  end
35
35
 
@@ -47,12 +47,12 @@ class Goal
47
47
  # #=> { goal_id: 1, title: "New Goal", meeting_id: 1, ... }
48
48
  def create(title:, meeting_id:, user_id: self.user_id)
49
49
  payload = {title: title, accountableUserId: user_id}.to_json
50
- response = @conn.post("/api/v1/L10/#{meeting_id}/rocks", payload).body
50
+ response = @conn.post("L10/#{meeting_id}/rocks", payload).body
51
51
  {
52
52
  goal_id: response["Id"],
53
53
  title: title,
54
54
  meeting_id: meeting_id,
55
- meeting_name: response["Origins"][0]["Name"],
55
+ meeting_title: response["Origins"][0]["Name"],
56
56
  user_id: user_id,
57
57
  user_name: response["Owner"]["Name"],
58
58
  created_at: DateTime.parse(response["CreateTime"])
@@ -67,8 +67,8 @@ class Goal
67
67
  # client.goal.delete(1)
68
68
  # #=> { status: 200 }
69
69
  def delete(goal_id)
70
- response = @conn.delete("/api/v1/rocks/#{goal_id}")
71
- {status: response.status}
70
+ response = @conn.delete("rocks/#{goal_id}")
71
+ response.success?
72
72
  end
73
73
 
74
74
  # Updates a goal
@@ -76,14 +76,46 @@ class Goal
76
76
  # @param goal_id [Integer] the ID of the goal to update
77
77
  # @param title [String] the new title of the goal
78
78
  # @param accountable_user [Integer] the ID of the user responsible for the goal (default: initialized user ID)
79
- # @return [Hash] a hash containing the status of the update operation
79
+ # @param status [String, nil] the status value ('on', 'off', or 'complete')
80
+ # @return [Boolean] true if the update was successful
81
+ # @raise [ArgumentError] if an invalid status value is provided
80
82
  # @example
81
- # client.goal.update(goal_id: 1, title: "Updated Goal")
82
- # #=> { status: 200 }
83
- def update(goal_id:, title:, accountable_user: user_id)
84
- payload = {title: title, accountableUserId: accountable_user}.to_json
85
- response = @conn.put("/api/v1/rocks/#{goal_id}", payload)
86
- {status: response.status}
83
+ # client.goal.update(goal_id: 1, title: "Updated Goal", status: 'on')
84
+ # #=> true
85
+ def update(goal_id:, title:, accountable_user: user_id, status: nil)
86
+ if status
87
+ valid_status = {on: "OnTrack", off: "AtRisk", complete: "Complete"}
88
+ status_key = status.downcase.to_sym
89
+ unless valid_status.key?(status_key)
90
+ raise ArgumentError, "Invalid status value. Must be 'on', 'off', or 'complete'."
91
+ end
92
+ status = valid_status[status_key]
93
+ end
94
+ payload = {title: title, accountableUserId: accountable_user, completion: status}.to_json
95
+ response = @conn.put("rocks/#{goal_id}", payload)
96
+ response.success?
97
+ end
98
+
99
+ # Archives a rock with the specified goal ID.
100
+ #
101
+ # @param goal_id [Integer] The ID of the goal/rock to archive
102
+ # @return [Boolean] Returns true if the archival was successful, false otherwise
103
+ # @example
104
+ # goals.archive(123) #=> true
105
+ def archive(goal_id)
106
+ response = @conn.put("rocks/#{goal_id}/archive")
107
+ response.success?
108
+ end
109
+
110
+ # Restores a previously archived goal identified by the provided goal ID.
111
+ #
112
+ # @param [String, Integer] goal_id The unique identifier of the goal to restore
113
+ # @return [Boolean] true if the restore operation was successful, false otherwise
114
+ # @example Restoring a goal
115
+ # goals.restore("123") #=> true
116
+ def restore(goal_id)
117
+ response = @conn.put("rocks/#{goal_id}/restore")
118
+ response.success?
87
119
  end
88
120
 
89
121
  private
@@ -18,14 +18,14 @@ class Headline
18
18
  # @param owner_id [Integer] the ID of the headline owner
19
19
  # @param notes [String] additional notes for the headline
20
20
  # @return [Hash] the created headline details
21
- def create(meeting_id, title, owner_id: user_id, notes: nil)
21
+ def create(meeting_id:, title:, owner_id: user_id, notes: nil)
22
22
  response = @conn.post("/api/v1/L10/#{meeting_id}/headlines",
23
23
  {title: title, ownerId: owner_id, notes: notes}.to_json)
24
24
  raise "Failed to create headline" unless response.status == 200
25
25
 
26
26
  {
27
27
  id: response.body["Id"],
28
- title: response.body["Title"],
28
+ title: response.body["Name"],
29
29
  owner_id: response.body["OwnerId"],
30
30
  notes_url: response.body["DetailsUrl"]
31
31
  }
@@ -36,7 +36,7 @@ class Headline
36
36
  # @param headline_id [Integer] the ID of the headline to update
37
37
  # @param title [String] the new title of the headline
38
38
  # @return [Hash] the updated headline details
39
- def update(headline_id, title)
39
+ def update(headline_id:, title:)
40
40
  response = @conn.put("/api/v1/headline/#{headline_id}", {title: title}.to_json)
41
41
  raise "Failed to update headline" unless response.status == 200
42
42
  true
@@ -56,7 +56,7 @@ class Headline
56
56
  notes_url: response.body["DetailsUrl"],
57
57
  meeting_details: {
58
58
  id: response.body["OriginId"],
59
- name: response.body["Origin"]
59
+ title: response.body["Origin"]
60
60
  },
61
61
  owner_details: {
62
62
  id: response.body["Owner"]["Id"],
@@ -79,9 +79,7 @@ class Headline
79
79
  # client.headline.list
80
80
  # #=> [{ id: 1, title: "Headline Title", meeting_details: { id: 1, name: "Team Meeting" }, ... }, ...]
81
81
  def list(user_id: nil, meeting_id: nil)
82
- if user_id && meeting_id
83
- raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both."
84
- end
82
+ raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both." if user_id && meeting_id
85
83
 
86
84
  if meeting_id
87
85
  response = @conn.get("/api/v1/l10/#{meeting_id}/headlines")
@@ -98,7 +96,7 @@ class Headline
98
96
  title: headline["Name"],
99
97
  meeting_details: {
100
98
  id: headline["OriginId"],
101
- name: headline["Origin"]
99
+ title: headline["Origin"]
102
100
  },
103
101
  owner_details: {
104
102
  id: headline["Owner"]["Id"],
@@ -116,11 +114,8 @@ class Headline
116
114
  # @param meeting_id [Integer] the ID of the meeting
117
115
  # @param headline_id [Integer] the ID of the headline to delete
118
116
  # @return [Boolean] true if the deletion was successful
119
- def delete(meeting_id, headline_id)
120
- response = @conn.delete("/api/v1/L10/#{meeting_id}/headlines/#{headline_id}")
121
-
122
- # Raise an issue if response.status != 200
123
- raise "Failed to delete headline" unless response.status == 200
124
- true
117
+ def delete(headline_id)
118
+ response = @conn.delete("/api/v1/headline/#{headline_id}")
119
+ response.success?
125
120
  end
126
121
  end
@@ -30,7 +30,7 @@ class Issue
30
30
  completed_at: response["CloseTime"],
31
31
  meeting_details: {
32
32
  id: response["OriginId"],
33
- name: response["Origin"]
33
+ title: response["Origin"]
34
34
  },
35
35
  owner_details: {
36
36
  id: response["Owner"]["Id"],
@@ -73,21 +73,21 @@ class Issue
73
73
  notes_url: issue["DetailsUrl"],
74
74
  created_at: issue["CreateTime"],
75
75
  meeting_id: issue["OriginId"],
76
- meeting_name: issue["Origin"]
76
+ meeting_title: issue["Origin"]
77
77
  }
78
78
  end
79
79
  end
80
80
 
81
- # Marks an issue as complete
81
+ # Marks an issue as solved
82
82
  #
83
83
  # @param issue_id [Integer] the ID of the issue
84
84
  # @return [Boolean] true if the operation was successful, false otherwise
85
85
  # @example
86
- # issue.complete(123)
86
+ # issue.solve(123)
87
87
  # #=> true
88
- def complete(issue_id)
89
- response = @conn.post("issues/#{issue_id}/complete", {complete: true}.to_json).status
90
- response == 200
88
+ def solve(issue_id)
89
+ response = @conn.post("issues/#{issue_id}/complete", {complete: true}.to_json)
90
+ response.success?
91
91
  end
92
92
 
93
93
  # Creates a new issue
@@ -100,7 +100,7 @@ class Meeting
100
100
  response.map do |measurable|
101
101
  {
102
102
  id: measurable["Id"],
103
- name: measurable["Name"].strip,
103
+ title: measurable["Name"].strip,
104
104
  target: measurable["Target"],
105
105
  operator: measurable["Direction"],
106
106
  format: measurable["Modifiers"],
@@ -132,7 +132,7 @@ class Meeting
132
132
  measurables = metrics(meeting_id)
133
133
  {
134
134
  id: meeting[:id],
135
- name: meeting[:name],
135
+ title: meeting[:name],
136
136
  attendees: attendees,
137
137
  issues: issues,
138
138
  todos: todos,
@@ -166,6 +166,7 @@ class Meeting
166
166
  # @example
167
167
  # client.meeting.delete(1)
168
168
  def delete(meeting_id)
169
- @conn.delete("L10/#{meeting_id}")
169
+ response = @conn.delete("L10/#{meeting_id}")
170
+ response.success?
170
171
  end
171
172
  end
@@ -49,10 +49,12 @@ class Scorecard
49
49
  #
50
50
  # # Fetch scorecards for a specific meeting
51
51
  # client.scorecard.list(meeting_id: 99)
52
+ # @note
53
+ # The `week_offset` parameter is useful when fetching scores for previous or future weeks.
54
+ # For example, to fetch scores for the previous week, you can set `week_offset` to -1.
55
+ # To fetch scores for a future week, you can set `week_offset` to a positive value.
52
56
  def list(user_id: nil, meeting_id: nil, show_empty: false, week_offset: nil)
53
- if user_id && meeting_id
54
- raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both."
55
- end
57
+ raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both." if user_id && meeting_id
56
58
 
57
59
  if meeting_id
58
60
  response = @conn.get("scorecard/meeting/#{meeting_id}").body
@@ -70,14 +72,15 @@ class Scorecard
70
72
  target: scorecard["Target"],
71
73
  value: scorecard["Measured"],
72
74
  week: scorecard["Week"],
75
+ week_id: scorecard["ForWeek"],
73
76
  updated_at: scorecard["DateEntered"]
74
77
  }
75
78
  end
76
79
 
77
80
  if week_offset
78
81
  week_data = current_week
79
- week_id = week_data[:week_number] - week_offset
80
- scorecards.select! { |scorecard| scorecard[:week] == week_id }
82
+ week_id = week_data[:week_number] + week_offset
83
+ scorecards.select! { |scorecard| scorecard[:week_id] == week_id }
81
84
  end
82
85
 
83
86
  scorecards.select! { |scorecard| scorecard[:value] || show_empty } unless show_empty
@@ -95,11 +98,11 @@ class Scorecard
95
98
  # #=> true
96
99
  # @note
97
100
  # The `week_offset` parameter is useful when updating scores for previous weeks.
98
- # For example, to update the score for the previous week, you can set `week_offset` to 1.
99
- # To update a future week's score, you can set `week_offset` to a negative value.
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.
100
103
  def score(measurable_id:, score:, week_offset: 0)
101
104
  week_data = current_week
102
- week_id = week_data[:week_number] - week_offset
105
+ week_id = week_data[:week_number] + week_offset
103
106
 
104
107
  response = @conn.put("measurables/#{measurable_id}/week/#{week_id}", {value: score}.to_json)
105
108
  response.success?
@@ -33,9 +33,7 @@ class Todo
33
33
  # client.todo.list(meeting_id: 99)
34
34
  # # => [{ id: 1, title: "New Todo", due_date: "2024-06-15", ... }]
35
35
  def list(user_id: nil, meeting_id: nil)
36
- if user_id && meeting_id
37
- raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both."
38
- end
36
+ raise ArgumentError, "Please provide either `user_id` or `meeting_id`, not both." if user_id && meeting_id
39
37
 
40
38
  if meeting_id
41
39
  response = @conn.get("l10/#{meeting_id}/todos").body
@@ -76,7 +74,7 @@ class Todo
76
74
  {
77
75
  id: response["Id"],
78
76
  title: response["Name"],
79
- meeting_name: response["Origin"],
77
+ meeting_title: response["Origin"],
80
78
  meeting_id: response["OriginId"],
81
79
  due_date: response["DueDate"],
82
80
  notes_url: response["DetailsUrl"]
@@ -92,7 +90,7 @@ class Todo
92
90
  # #=> { status: 200 }
93
91
  def complete(todo_id)
94
92
  response = @conn.post("/api/v1/todo/#{todo_id}/complete?status=true")
95
- {status: response.status}
93
+ response.success?
96
94
  end
97
95
 
98
96
  # Updates an existing todo
@@ -138,6 +136,7 @@ class Todo
138
136
  {
139
137
  id: todo["Id"],
140
138
  meeting_id: todo["OriginId"],
139
+ meeting_title: todo["Origin"],
141
140
  title: todo["Name"],
142
141
  notes_url: todo["DetailsUrl"],
143
142
  due_date: todo["DueDate"],
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Bloomy
4
- VERSION = "0.4.2"
4
+ VERSION = "0.8.0"
5
5
  end
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.2
4
+ version: 0.8.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-08 00:00:00.000000000 Z
11
+ date: 2024-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -49,6 +49,8 @@ files:
49
49
  - ".pre-commit-config.yaml"
50
50
  - ".rspec"
51
51
  - ".rubocop.yml"
52
+ - CODE_OF_CONDUCT.md
53
+ - CONTRIBUTING.md
52
54
  - LICENSE
53
55
  - README.md
54
56
  - Rakefile
@@ -88,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
90
  - !ruby/object:Gem::Version
89
91
  version: '0'
90
92
  requirements: []
91
- rubygems_version: 3.5.17
93
+ rubygems_version: 3.5.23
92
94
  signing_key:
93
95
  specification_version: 4
94
96
  summary: Manage your Bloom Growth account from the command line.