holivia 0.12.0 → 0.14.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14dc959e163c982b0cb9ff68d098eb453c99c9802055de1c6086c8b61541894b
4
- data.tar.gz: cb404446122ffd0f4dab4535b358ec50c6bcdda67781c569f9c6db699ca8ed3e
3
+ metadata.gz: fab1251135002a03f719e93cb2f2d1fcb52842e2f5c5fecc3fa8c47c279b8747
4
+ data.tar.gz: 8e2dd66d735bf875c123d42d90c25ab7d853024c5378dc8445d2f8c4eeb233aa
5
5
  SHA512:
6
- metadata.gz: fd225340d2dd039e3a40f1104b0a606db28e3b5d30b3f7bd5a19a3ddc6d4e222a1519db2db64a3429fa8040ddc2131b38b5dafca3ce61701241c939e562475ae
7
- data.tar.gz: c55acec78801a2a38ffa864d95997ae1e0245baa82fa57f53a508592d53a25b77e6c4809cc9d07ff44e9d2eb444a85d22a57d283ade5d32e3ae6d37ae8ec23c8
6
+ metadata.gz: a0c502ac53052598fff122e0b5bafc5028c7cd2dee25ebc6629879f0a77d17516314608012493d41ee8571cb79802d5a276c43e64d03236f2e86d8e7a4c68e77
7
+ data.tar.gz: 5454072e3f4e4d046b1a8de6e60a9a9641db2a5d16eaf85441de7340e065572f4606c83a603bc4f615ef0c86b02f4a03babf28fa267559375c9fa0602fac3c56
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.14.0] - 2026-10-23
4
+
5
+ - Add `holivia enterprise show <id>` for enterprise details: settings, headquarter, CSM, countries, employees count, and the current contract summary for contract viewers and managers
6
+ - Add `holivia enterprise employee-stats <id>` for aggregate employee counts (total, left, current, current dependents and HR managers), excluding demo employees
7
+ - Add read-only `holivia employee index` and `holivia employee show` commands with enterprise, query, left, HR manager, dependent status, demo, and pagination filters; demo employees are excluded unless `--demo` is given
8
+ - Add read-only `holivia contract index` and `holivia contract show` commands with enterprise, status (`active`, `expiring_soon`, `low_remaining`), and pagination filters
9
+ - Employee responses never include Holivia account data (user id, sign-up, or care status); SKILL.md treats employee data as personal data
10
+ - Employee commands require an employee viewer or manager role; contract commands require a contract viewer or manager role
11
+ - Requires the matching Holivia backoffice API deployment
12
+
13
+ ## [0.13.0] - 2026-09-30
14
+
15
+ - Replace terminal password login with browser OAuth authorization using PKCE and existing password/company SSO sign-in.
16
+ - Require CLI upgrade and a new login; remove `--email`/`--password` and legacy `/api/v1/auth/*` endpoints.
17
+ - Use two-hour access tokens, rotating refresh tokens without a fixed expiry, and server revocation for logout.
18
+ - Store per-environment credentials atomically with owner-only permissions and omit credentials from debug logs.
19
+ - Keep browser and CLI sessions independent; existing API permissions continue to apply.
20
+ - Redirect browser authorization callbacks to the localized Holivia completion page while the CLI exchanges tokens separately.
21
+ - Requires the matching Holivia OAuth server deployment and provisioning of the public CLI application.
22
+
3
23
  ## [0.12.0] - 2026-09-16
4
24
 
5
25
  - Add `holivia tag` commands for catalogue CRUD and incremental topic-link management through repeatable `--topic-tag-json` flags or stdin JSON
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Ruby client and command-line interface for the Holivia API.
4
4
 
5
- The `holivia` executable is primarily used to manage Holivia backoffice data from the terminal: environments, authentication, selfcare content, objectives, enterprises, communication library items, HR intervention catalog items, HR home highlights, crises, collective interventions, and appointment diagnostics.
5
+ The `holivia` executable is primarily used to manage Holivia backoffice data from the terminal: environments, authentication, selfcare content, objectives, enterprises, employees, contracts, communication library items, HR intervention catalog items, HR home highlights, crises, collective interventions, and appointment diagnostics.
6
6
 
7
7
  Coding agents can use [`SKILL.md`](SKILL.md) as a downloadable usage guide for operating this CLI safely.
8
8
 
@@ -73,21 +73,23 @@ holivia env debug --false
73
73
 
74
74
  ## Authentication
75
75
 
76
- Log in interactively:
76
+ Log in through your browser using your existing password or company SSO:
77
77
 
78
78
  ```bash
79
79
  holivia login
80
80
  ```
81
81
 
82
- Or pass credentials directly:
83
-
84
- ```bash
85
- holivia login --email user@example.com --password secret
86
- ```
82
+ The CLI opens a browser and prints a URL you can open manually on the same computer. A temporary loopback listener receives the callback. Browserless login is not supported.
87
83
 
88
84
  Credentials are stored per environment in `~/.holivia/credentials.<env>.json`. Access tokens are sent as bearer tokens, and the CLI automatically refreshes credentials after a `401` response when a refresh token is available.
89
85
 
90
- Log out and remove stored credentials for the current environment:
86
+ Access tokens expire after two hours. Refresh tokens have no fixed expiry and rotate when used. Credential files are replaced atomically with owner-only permissions. Pundit permissions still determine which API operations the user may perform.
87
+
88
+ Existing users must upgrade the CLI and run `holivia login` again. The old `/api/v1/auth/login`, `/api/v1/auth/refresh`, and `/api/v1/auth/logout` endpoints and `--email`/`--password` flags have been removed.
89
+
90
+ The database migration drops the legacy `auth_tokens` table. Rolling it back restores the table structure only; deleted or revoked credentials are not restored. Users must log in again.
91
+
92
+ Logout revokes this CLI session and removes credentials for the current environment. Other CLI sessions and browser sessions remain signed in. If the server cannot be reached, credentials are retained so logout can be retried:
91
93
 
92
94
  ```bash
93
95
  holivia logout
@@ -184,6 +186,32 @@ Find an enterprise id:
184
186
  holivia enterprise lookup --query acme
185
187
  ```
186
188
 
189
+ Show details for an enterprise:
190
+
191
+ ```bash
192
+ holivia enterprise show 123
193
+ ```
194
+
195
+ Show employee counts for an enterprise:
196
+
197
+ ```bash
198
+ holivia enterprise employee-stats 123
199
+ ```
200
+
201
+ List and inspect employees of an enterprise:
202
+
203
+ ```bash
204
+ holivia employee index --enterprise-id 123 --query durand --left false
205
+ holivia employee show 42
206
+ ```
207
+
208
+ List and inspect contracts of an enterprise:
209
+
210
+ ```bash
211
+ holivia contract index --enterprise-id 123 --status active
212
+ holivia contract show 7
213
+ ```
214
+
187
215
  List crises for an enterprise:
188
216
 
189
217
  ```bash
data/SKILL.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use this skill when you need to operate the Holivia API through the `holivia` command-line tool.
4
4
 
5
- The CLI manages Holivia backoffice data: environments, authentication, selfcare contents, objectives, selfcare-objective associations, enterprises, HR intervention catalog items, HR home highlights, crises, collective interventions, and appointment video diagnostics.
5
+ The CLI manages Holivia backoffice data: environments, authentication, selfcare contents, objectives, selfcare-objective associations, enterprises, employees, contracts, HR intervention catalog items, HR home highlights, crises, collective interventions, and appointment video diagnostics.
6
6
 
7
7
  ## Preconditions
8
8
 
@@ -16,11 +16,12 @@ Use `holivia` in examples below. If working from a checkout before installation,
16
16
 
17
17
  - Never invent API URLs, credentials, IDs, enum values, or content model fields.
18
18
  - Never print, store, or commit passwords, access tokens, refresh tokens, or files under `~/.holivia/credentials.*.json`.
19
- - Prefer interactive `holivia login` when a human can enter credentials. Use `--password` only when the user explicitly provides it for automation.
19
+ - Use `holivia login` and let the user authenticate in their browser. Terminal email/password flags are no longer supported.
20
20
  - Before creating or updating content, run `holivia selfcare schema` and use its returned enum values and permitted item params as the source of truth.
21
21
  - Before creating or updating intervention catalog items, run `holivia intervention schema` and use its returned enum values and locales as the source of truth.
22
22
  - Before creating or updating HR home highlights, run `holivia highlight schema` and use its returned enum values and locales as the source of truth.
23
23
  - For destructive actions such as `holivia env remove`, `holivia selfcare objective delete`, `holivia crisis delete`, or `holivia collective-intervention delete`, confirm the target environment and ID first unless the user explicitly requested that exact action.
24
+ - Employee data is personal data. Query only the employees a task needs, do not copy employee lists into unrelated output, and never try to infer whether an employee has a Holivia account.
24
25
  - Treat all command output as JSON except informational commands such as `holivia env`, `holivia env list`, `holivia login`, `holivia logout`, `holivia version`, and `holivia --help`.
25
26
 
26
27
  ## Installation
@@ -90,19 +91,19 @@ Debug logging may expose request details. Do not enable it in shared logs unless
90
91
 
91
92
  Credentials are stored per environment at `~/.holivia/credentials.<env>.json`. The CLI sends the access token as a bearer token and refreshes credentials automatically after a `401` response when possible.
92
93
 
93
- Interactive login:
94
+ Browser login using your existing password or company SSO:
94
95
 
95
96
  ```bash
96
97
  holivia login
97
98
  ```
98
99
 
99
- Non-interactive login:
100
+ A browser on the same computer is required. If it does not open automatically, open the printed URL manually. Do not ask for terminal credentials; browserless login is not supported.
100
101
 
101
- ```bash
102
- holivia login --email user@example.com --password secret
103
- ```
102
+ Access tokens expire after two hours. Refresh tokens have no fixed expiry and rotate when used. Credential files are replaced atomically with owner-only permissions. Pundit permissions still determine which API operations the user may perform.
103
+
104
+ Existing users must upgrade the CLI and run `holivia login` again. The old `/api/v1/auth/login`, `/api/v1/auth/refresh`, and `/api/v1/auth/logout` endpoints and `--email`/`--password` flags have been removed.
104
105
 
105
- Logout for the current environment:
106
+ Logout revokes this CLI session and removes credentials for the current environment. Other CLI sessions and browser sessions remain signed in. If the server cannot be reached, credentials are retained so logout can be retried:
106
107
 
107
108
  ```bash
108
109
  holivia logout
@@ -367,6 +368,66 @@ Filter enterprise lookup:
367
368
  holivia enterprise index --headquarter-id 10 --user-id 20 --page 1 --per-page 25
368
369
  ```
369
370
 
371
+ Show details for one enterprise (settings, headquarter, CSM, countries, employees count; the current contract is included only for contract viewers and managers):
372
+
373
+ ```bash
374
+ holivia enterprise show 123
375
+ ```
376
+
377
+ Show aggregate employee counts for one enterprise (excludes demo employees; never includes account sign-up data):
378
+
379
+ ```bash
380
+ holivia enterprise employee-stats 123
381
+ ```
382
+
383
+ ## Employees
384
+
385
+ Requires an employee viewer or manager role. Responses never include Holivia account data (no user id, sign-up, or care status). `employee index` excludes demo employees unless `--demo true` (demo employees only) or `--demo all` (everyone) is given.
386
+
387
+ List employees of an enterprise:
388
+
389
+ ```bash
390
+ holivia employee index --enterprise-id 123 --page 1 --per-page 25
391
+ ```
392
+
393
+ Search and filter employees:
394
+
395
+ ```bash
396
+ holivia employee index --enterprise-id 123 --query durand --left false --hr-manager true
397
+ holivia employee index --enterprise-id 123 --dependent-status dependent
398
+ holivia employee index --enterprise-id 123 --demo true
399
+ ```
400
+
401
+ Show one employee:
402
+
403
+ ```bash
404
+ holivia employee show 42
405
+ ```
406
+
407
+ ## Contracts
408
+
409
+ Requires a contract viewer or manager role.
410
+
411
+ List contracts of an enterprise, most recent first:
412
+
413
+ ```bash
414
+ holivia contract index --enterprise-id 123
415
+ ```
416
+
417
+ Find active contracts, contracts expiring within three months, or contracts with low remaining sessions:
418
+
419
+ ```bash
420
+ holivia contract index --status active
421
+ holivia contract index --status expiring_soon
422
+ holivia contract index --status low_remaining
423
+ ```
424
+
425
+ Show every setting of one contract, including notes:
426
+
427
+ ```bash
428
+ holivia contract show 7
429
+ ```
430
+
370
431
  ## Crises
371
432
 
372
433
  List crises:
data/exe/holivia CHANGED
@@ -9,7 +9,10 @@ rescue Holivia::ApiError => e
9
9
  warn "Error (#{e.status}): #{e.message}"
10
10
  warn JSON.pretty_generate(e.details) if e.details.is_a?(Hash)
11
11
  exit 1
12
- rescue Holivia::ConfigError => e
12
+ rescue Holivia::ConfigError, Holivia::BrowserLogin::Error, OptionParser::ParseError, Faraday::Error => e
13
13
  warn "Error: #{e.message}"
14
14
  exit 1
15
+ rescue Interrupt
16
+ warn "Cancelled."
17
+ exit 130
15
18
  end
data/lib/holivia/auth.rb CHANGED
@@ -2,15 +2,20 @@
2
2
 
3
3
  require "json"
4
4
  require "fileutils"
5
+ require "tempfile"
5
6
 
6
7
  module Holivia
7
8
  class Auth
8
- def initialize(client: Client.new(auth: nil))
9
- @client = client
9
+ def initialize(client: nil, configuration: Holivia.configuration)
10
+ @client = client || Client.new(base_url: configuration.base_url, auth: nil)
11
+ @credentials_path = configuration.credentials_path.dup.freeze
10
12
  end
11
13
 
12
- def login(email:, password:)
13
- response = client.post("/api/v1/auth/login", body: { email: email, password: password })
14
+ def login(code:, code_verifier:, redirect_uri:)
15
+ response = client.post_form("/oauth/token", body: {
16
+ grant_type: "authorization_code", client_id: BrowserLogin::CLIENT_ID,
17
+ code: code, code_verifier: code_verifier, redirect_uri: redirect_uri
18
+ })
14
19
  store_tokens(response)
15
20
  response
16
21
  end
@@ -18,15 +23,25 @@ module Holivia
18
23
  def refresh
19
24
  raise ApiError.new("No refresh token. Run `holivia login`.", status: 401) unless refresh_token
20
25
 
21
- response = client.post("/api/v1/auth/refresh", headers: { "Authorization" => "Bearer #{refresh_token}" })
26
+ response = client.post_form("/oauth/token", body: {
27
+ grant_type: "refresh_token", client_id: BrowserLogin::CLIENT_ID,
28
+ refresh_token: refresh_token
29
+ })
22
30
  store_tokens(response)
23
31
  response
32
+ rescue ApiError => e
33
+ raise unless e.details.is_a?(Hash) && e.details["error"] == "invalid_grant"
34
+
35
+ raise ApiError.new("Session expired or revoked. Run `holivia login`.", status: 401)
24
36
  end
25
37
 
26
38
  def logout
27
- raise ApiError.new("Already logged out.", status: 401) unless access_token
39
+ raise ApiError.new("Already logged out.", status: 401) unless refresh_token
28
40
 
29
- response = client.delete("/api/v1/auth/logout", headers: { "Authorization" => "Bearer #{access_token}" })
41
+ response = client.post_form("/oauth/revoke", body: {
42
+ client_id: BrowserLogin::CLIENT_ID, token: refresh_token,
43
+ token_type_hint: "refresh_token"
44
+ })
30
45
  FileUtils.rm_f(credentials_path)
31
46
  response
32
47
  end
@@ -41,7 +56,7 @@ module Holivia
41
56
 
42
57
  private
43
58
 
44
- attr_reader :client
59
+ attr_reader :client, :credentials_path
45
60
 
46
61
  def credentials
47
62
  return nil unless File.exist?(credentials_path)
@@ -50,17 +65,14 @@ module Holivia
50
65
  end
51
66
 
52
67
  def store_tokens(data)
53
- FileUtils.mkdir_p(File.dirname(credentials_path))
54
-
55
- File.write(credentials_path, JSON.pretty_generate(
56
- "access_token" => data["access_token"],
57
- "refresh_token" => data["refresh_token"]
58
- ))
59
- File.chmod(0o600, credentials_path)
60
- end
61
-
62
- def credentials_path
63
- Holivia.configuration.credentials_path
68
+ directory = File.dirname(credentials_path)
69
+ FileUtils.mkdir_p(directory, mode: 0o700)
70
+ Tempfile.create(["credentials", ".json"], directory) do |file|
71
+ file.write(JSON.pretty_generate(data.slice("access_token", "refresh_token")))
72
+ file.flush
73
+ file.fsync
74
+ File.rename(file.path, credentials_path)
75
+ end
64
76
  end
65
77
  end
66
78
  end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "securerandom"
5
+ require "socket"
6
+ require "timeout"
7
+ require "uri"
8
+
9
+ module Holivia
10
+ class BrowserLogin
11
+ class Error < StandardError; end
12
+
13
+ CLIENT_ID = "holivia-cli"
14
+
15
+ def initialize(base_url: Holivia.configuration.base_url, output: $stderr, timeout: 180, browser_launcher: nil)
16
+ @base_url = base_url.dup.freeze
17
+ @output = output
18
+ @timeout = timeout
19
+ @browser_launcher = browser_launcher || method(:launch_browser)
20
+ end
21
+
22
+ def call
23
+ verifier = SecureRandom.urlsafe_base64(32)
24
+ state = SecureRandom.urlsafe_base64(32)
25
+ server = TCPServer.new("127.0.0.1", 0)
26
+ redirect_uri = "http://127.0.0.1:#{server.addr[1]}/callback"
27
+
28
+ Timeout.timeout(@timeout, Error, "Browser login timed out. Run holivia login to try again.") do
29
+ open_browser(authorization_url(verifier, state, redirect_uri))
30
+ code = receive_code(server, state)
31
+ { code: code, code_verifier: verifier, redirect_uri: redirect_uri }
32
+ end
33
+ ensure
34
+ server&.close
35
+ end
36
+
37
+ private
38
+
39
+ def authorization_url(verifier, state, redirect_uri)
40
+ url = URI.join(@base_url, "/oauth/authorize")
41
+ url.query = URI.encode_www_form(
42
+ client_id: CLIENT_ID, response_type: "code", redirect_uri: redirect_uri,
43
+ code_challenge: [Digest::SHA256.digest(verifier)].pack("m0").tr("+/", "-_").delete("="),
44
+ code_challenge_method: "S256", state: state
45
+ )
46
+ url.to_s
47
+ end
48
+
49
+ def open_browser(url)
50
+ @output.puts "Open this URL in a browser on this computer to log in:\n#{url}"
51
+ @browser_launcher.call(url)
52
+ end
53
+
54
+ def launch_browser(url)
55
+ command = RUBY_PLATFORM.include?("darwin") ? "open" : "xdg-open"
56
+ system(command, url, out: File::NULL, err: File::NULL)
57
+ end
58
+
59
+ def receive_code(server, state)
60
+ loop do
61
+ code = handle_callback(server.accept, state)
62
+ return code if code
63
+ end
64
+ end
65
+
66
+ def handle_callback(socket, state)
67
+ params = callback_params(socket.gets("\r\n\r\n", 8192))
68
+ unless valid_callback?(params, state)
69
+ respond(socket, "400 Bad Request", "Invalid login callback.")
70
+ return nil
71
+ end
72
+
73
+ complete_callback(socket, params)
74
+ rescue SystemCallError, IOError
75
+ nil # A disconnected browser must not prevent a later valid callback.
76
+ ensure
77
+ socket.close
78
+ end
79
+
80
+ def callback_params(request)
81
+ return {} unless request&.end_with?("\r\n\r\n")
82
+
83
+ match = request.lines.first.match(%r{\AGET /callback\?([^\s]+) HTTP/1\.[01]\r\n\z})
84
+ return {} unless match
85
+
86
+ pairs = URI.decode_www_form(match[1])
87
+ return {} unless pairs.map(&:first).uniq.length == pairs.length
88
+
89
+ pairs.to_h
90
+ rescue ArgumentError
91
+ {}
92
+ end
93
+
94
+ def valid_callback?(params, state)
95
+ return false unless params["state"] == state
96
+
97
+ code = params["code"]
98
+ error = params["error"]
99
+ (code && !code.empty? && error.nil?) || (error && !error.empty? && code.nil?)
100
+ end
101
+
102
+ def complete_callback(socket, params)
103
+ if params["error"]
104
+ respond(socket, "200 OK", "Authorization was not granted. Return to the terminal.")
105
+ raise Error, "Authorization was not granted. Run holivia login to try again."
106
+ end
107
+
108
+ redirect_to_completion(socket)
109
+ params.fetch("code")
110
+ end
111
+
112
+ def redirect_to_completion(socket)
113
+ url = URI.join(@base_url, "/oauth/complete")
114
+ socket.write "HTTP/1.1 303 See Other\r\nLocation: #{url}\r\n" \
115
+ "Referrer-Policy: no-referrer\r\nCache-Control: no-store\r\n" \
116
+ "Content-Length: 0\r\nConnection: close\r\n\r\n"
117
+ end
118
+
119
+ def respond(socket, status, message)
120
+ socket.write "HTTP/1.1 #{status}\r\nContent-Type: text/plain; charset=utf-8\r\n" \
121
+ "Content-Length: #{message.bytesize}\r\nCache-Control: no-store\r\n" \
122
+ "Connection: close\r\n\r\n#{message}"
123
+ end
124
+ end
125
+ end
@@ -17,7 +17,7 @@ module Holivia
17
17
  Config stored at ~/.holivia/config.yml. Defaults to staging if no config exists.
18
18
 
19
19
  Authentication:
20
- holivia login [--email EMAIL --password PASSWORD] Log in (flags or interactive prompt)
20
+ holivia login Log in through your browser (password or company SSO)
21
21
  holivia logout Log out and clear stored credentials
22
22
  Tokens are stored at ~/.holivia/credentials.<env>.json and refreshed automatically on 401.
23
23
 
@@ -77,6 +77,24 @@ module Holivia
77
77
  holivia enterprise index [--query TEXT --headquarter-id ID --user-id ID --page N --per-page N]
78
78
  Find enterprises and their enterprise_id values
79
79
  holivia enterprise lookup [options] Alias for enterprise index
80
+ holivia enterprise show <id> Show enterprise details: settings, headquarter, CSM,
81
+ countries, employees count, and the current contract
82
+ for contract viewers
83
+ holivia enterprise employee-stats <id> Show aggregate employee counts (total, left, current,
84
+ current dependents, current HR managers)
85
+
86
+ Employees:
87
+ holivia employee index [--enterprise-id ID --query TEXT --left true|false --hr-manager true|false
88
+ --dependent-status creator|dependent|not_dependent --demo true|false|all
89
+ --page N --per-page N]
90
+ List employees; never includes Holivia account data.
91
+ Demo employees are excluded unless --demo is given
92
+ holivia employee show <id> Show one employee with its enterprise
93
+
94
+ Contracts:
95
+ holivia contract index [--enterprise-id ID --status active|expiring_soon|low_remaining --page N --per-page N]
96
+ List contracts, most recent first
97
+ holivia contract show <id> Show every setting of one contract with its enterprise
80
98
 
81
99
  Communication Items:
82
100
  holivia communication index [--page N --per-page N --query TEXT --locale LOCALE --document-type TYPE]
data/lib/holivia/cli.rb CHANGED
@@ -16,6 +16,8 @@ require_relative "commands/communication_item"
16
16
  require_relative "commands/intervention_item"
17
17
  require_relative "commands/hr_home_highlight"
18
18
  require_relative "commands/enterprise"
19
+ require_relative "commands/employee"
20
+ require_relative "commands/contract"
19
21
  require_relative "commands/crisis"
20
22
  require_relative "commands/collective_intervention"
21
23
  require_relative "commands/support_phone_number"
@@ -37,6 +39,8 @@ module Holivia
37
39
  when "intervention" then Commands::InterventionItem.route(args)
38
40
  when "highlight" then Commands::HrHomeHighlight.route(args)
39
41
  when "enterprise" then Commands::Enterprise.route(args)
42
+ when "employee" then Commands::Employee.route(args)
43
+ when "contract" then Commands::Contract.route(args)
40
44
  when "crisis" then Commands::Crisis.route(args)
41
45
  when "collective-intervention", "collective_intervention", "collective" then Commands::CollectiveIntervention.route(args)
42
46
  when "support-phone-numbers" then Commands::SupportPhoneNumber.route(args)
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "faraday"
4
4
  require "faraday/multipart"
5
+ require "uri"
5
6
 
6
7
  module Holivia
7
8
  class Client
@@ -15,6 +16,16 @@ module Holivia
15
16
  request(:post, path, body:, headers:)
16
17
  end
17
18
 
19
+ def post_form(path, body: {})
20
+ response = connection.post(path) do |req|
21
+ req.headers["Accept"] = "application/json"
22
+ req.headers["Content-Type"] = "application/x-www-form-urlencoded"
23
+ req.body = URI.encode_www_form(body)
24
+ end
25
+
26
+ handle_response(response)
27
+ end
28
+
18
29
  def get(path, params: {}, headers: {})
19
30
  request(:get, path, params:, headers:)
20
31
  end
@@ -59,7 +70,7 @@ module Holivia
59
70
  @connection ||= http.new(url: base_url) do |f|
60
71
  f.request :multipart
61
72
  f.request :json
62
- f.response :logger if Holivia.configuration.debug?
73
+ f.response :logger, nil, headers: false, bodies: false if Holivia.configuration.debug?
63
74
  f.response :json
64
75
  f.adapter Faraday.default_adapter
65
76
  end
@@ -77,6 +88,8 @@ module Holivia
77
88
  return "Request failed" unless body.is_a?(Hash)
78
89
 
79
90
  error = body["error"]
91
+ return [error, body["error_description"]].compact.join(": ") if error.is_a?(String)
92
+
80
93
  error.is_a?(Hash) ? (error["message"] || "Request failed") : (error || "Request failed")
81
94
  end
82
95
 
@@ -1,23 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "io/console"
4
3
  require "optparse"
5
4
 
6
5
  module Holivia
7
6
  module Commands
8
7
  class Auth
9
8
  def login(args = [])
10
- options = {}
11
9
  OptionParser.new do |opts|
12
- opts.banner = "Usage: holivia login [--email EMAIL --password PASSWORD]"
13
- opts.on("--email EMAIL") { |v| options[:email] = v }
14
- opts.on("--password PASSWORD") { |v| options[:password] = v }
10
+ opts.banner = "Usage: holivia login"
15
11
  end.parse!(args)
12
+ raise OptionParser::InvalidArgument, args.join(" ") unless args.empty?
16
13
 
17
- email = options[:email] || prompt("Email: ")
18
- password = options[:password] || prompt_secret("Password: ")
19
-
20
- Holivia::Auth.new.login(email: email, password: password)
14
+ auth = Holivia::Auth.new
15
+ exchange = BrowserLogin.new.call
16
+ auth.login(**exchange)
21
17
  puts "Logged in successfully."
22
18
  end
23
19
 
@@ -25,20 +21,6 @@ module Holivia
25
21
  Holivia::Auth.new.logout
26
22
  puts "Logged out successfully."
27
23
  end
28
-
29
- private
30
-
31
- def prompt(label)
32
- print label
33
- $stdin.gets.chomp
34
- end
35
-
36
- def prompt_secret(label)
37
- print label
38
- result = $stdin.noecho(&:gets).chomp
39
- puts
40
- result
41
- end
42
24
  end
43
25
  end
44
26
  end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class Contract < Base
8
+ BASE_PATH = "/api/v1/backoffice/contracts"
9
+
10
+ def self.route(args)
11
+ subcommand = args.shift
12
+ case subcommand
13
+ when "index" then new.index(args)
14
+ when "show" then new.show(args)
15
+ else warn "Unknown contract command: #{subcommand}"
16
+ exit 1
17
+ end
18
+ end
19
+
20
+ def index(args = [])
21
+ params = {}
22
+ OptionParser.new do |opts|
23
+ opts.banner = "Usage: holivia contract index [options]"
24
+ opts.on("--enterprise-id ID", Integer) { |v| params[:enterprise_id] = v }
25
+ opts.on("--status STATUS") { |v| params[:status] = v }
26
+ opts.on("--page N", Integer) { |v| params[:page] = v }
27
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
28
+ end.parse!(args)
29
+
30
+ output(client.get(BASE_PATH, params: params))
31
+ end
32
+
33
+ def show(args = [])
34
+ id = args.shift
35
+ abort "Usage: holivia contract show <id>" unless id
36
+
37
+ output(client.get("#{BASE_PATH}/#{id}"))
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class Employee < Base
8
+ BASE_PATH = "/api/v1/backoffice/employees"
9
+ BOOLEAN_VALUES = %w[true false].freeze
10
+ DEPENDENT_STATUSES = %w[creator dependent not_dependent].freeze
11
+ DEMO_VALUES = %w[true false all].freeze
12
+
13
+ def self.route(args)
14
+ subcommand = args.shift
15
+ case subcommand
16
+ when "index" then new.index(args)
17
+ when "show" then new.show(args)
18
+ else warn "Unknown employee command: #{subcommand}"
19
+ exit 1
20
+ end
21
+ end
22
+
23
+ def index(args = []) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
24
+ params = {}
25
+ OptionParser.new do |opts|
26
+ opts.banner = "Usage: holivia employee index [options]"
27
+ opts.on("--enterprise-id ID", Integer) { |v| params[:enterprise_id] = v }
28
+ opts.on("--query TEXT") { |v| params[:query] = v }
29
+ opts.on("--left BOOL", BOOLEAN_VALUES) { |v| params[:left] = v }
30
+ opts.on("--hr-manager BOOL", BOOLEAN_VALUES) { |v| params[:hr_manager] = v }
31
+ opts.on("--dependent-status STATUS", DEPENDENT_STATUSES) { |v| params[:dependent_status] = v }
32
+ opts.on("--demo VALUE", DEMO_VALUES) { |v| params[:demo] = v }
33
+ opts.on("--page N", Integer) { |v| params[:page] = v }
34
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
35
+ end.parse!(args)
36
+
37
+ output(client.get(BASE_PATH, params: params))
38
+ end
39
+
40
+ def show(args = [])
41
+ id = args.shift
42
+ abort "Usage: holivia employee show <id>" unless id
43
+
44
+ output(client.get("#{BASE_PATH}/#{id}"))
45
+ end
46
+ end
47
+ end
48
+ end
@@ -11,6 +11,8 @@ module Holivia
11
11
  subcommand = args.shift
12
12
  case subcommand
13
13
  when "index", "lookup", "search" then new.index(args)
14
+ when "show" then new.show(args)
15
+ when "employee-stats" then new.employee_stats(args)
14
16
  else warn "Unknown enterprise command: #{subcommand}"
15
17
  exit 1
16
18
  end
@@ -29,6 +31,20 @@ module Holivia
29
31
 
30
32
  output(client.get(BASE_PATH, params: params))
31
33
  end
34
+
35
+ def show(args = [])
36
+ id = args.shift
37
+ abort "Usage: holivia enterprise show <id>" unless id
38
+
39
+ output(client.get("#{BASE_PATH}/#{id}"))
40
+ end
41
+
42
+ def employee_stats(args = [])
43
+ id = args.shift
44
+ abort "Usage: holivia enterprise employee-stats <id>" unless id
45
+
46
+ output(client.get("#{BASE_PATH}/#{id}/employee_stats"))
47
+ end
32
48
  end
33
49
  end
34
50
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Holivia
4
- VERSION = "0.12.0"
4
+ VERSION = "0.14.0"
5
5
  end
data/lib/holivia.rb CHANGED
@@ -7,6 +7,7 @@ require_relative "holivia/api_error"
7
7
  require_relative "holivia/config_error"
8
8
  require_relative "holivia/client"
9
9
  require_relative "holivia/auth"
10
+ require_relative "holivia/browser_login"
10
11
 
11
12
  module Holivia
12
13
  class << self
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: holivia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Holivia
@@ -57,6 +57,7 @@ files:
57
57
  - lib/holivia.rb
58
58
  - lib/holivia/api_error.rb
59
59
  - lib/holivia/auth.rb
60
+ - lib/holivia/browser_login.rb
60
61
  - lib/holivia/cli.rb
61
62
  - lib/holivia/cli/help.rb
62
63
  - lib/holivia/client.rb
@@ -65,7 +66,9 @@ files:
65
66
  - lib/holivia/commands/base.rb
66
67
  - lib/holivia/commands/collective_intervention.rb
67
68
  - lib/holivia/commands/communication_item.rb
69
+ - lib/holivia/commands/contract.rb
68
70
  - lib/holivia/commands/crisis.rb
71
+ - lib/holivia/commands/employee.rb
69
72
  - lib/holivia/commands/enterprise.rb
70
73
  - lib/holivia/commands/env.rb
71
74
  - lib/holivia/commands/format.rb