holivia 0.3.0 → 0.5.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: 6e2d692d4098918b86e1fb733a303c51b8bde37583841b2f97f11bf58b2da880
4
- data.tar.gz: 14095f6175eb6fdae474eeb6b31c0b4c856a675da375461d8d5a0748c27ec022
3
+ metadata.gz: 83d3ab262bb3fc4381d4ca420e6186ef577ce8e40db802b0658209e2ea0599b5
4
+ data.tar.gz: 36813fba6ea7c7cdb25d6b5cbfc97905226959e956fa02a146c9d60a54357898
5
5
  SHA512:
6
- metadata.gz: a881a29e44e585bee272a5fe5def48a57b089ca81be00c9ee9d54da355ecd8273c4befbedd98e26d77a978baa0a37b5b12d2a2f1af03afac10519e85e291053f
7
- data.tar.gz: 1478b0f331188b5b5043f01ab4e80643b173f69bb04adeefeba87d37a28ceda194d66fb7c701034298ad2257d6afae38131990b760829c0ba332ab586425ff1a
6
+ metadata.gz: 36d0c89c7d469290018d121ada800c8bf4da4fcc6af6918930c5907c283786b5aded11979050a0f6ef9fb19c127bdebb789e3b014eb09c842c568eb404421f05
7
+ data.tar.gz: 8e9086a2a046deec0170ec502391c8cda726963933d8597159aa98ce498e21d88a0e6aebe059606ae07387cad8655be6f88449ed3035cee1d6a161dfff316044
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.0] - 2026-05-06
4
+
5
+ - Add `--state` flag on `selfcare create` and `selfcare update` for AASM-driven lifecycle transitions
6
+ - Add top-level `holivia objective` commands (`index`, `show`) for the read-only Objective resource
7
+ - Add `holivia selfcare objective` CRUD (`index`, `show`, `create`, `update`, `delete`) for the selfcare↔objective join, with `delete` printing `{deleted: true, id: <id>}` on 204
8
+ - Update compose example and help text to document inline `objectives` array on compose/update payloads
9
+ - Update help text to surface the `states` and `objective_tiers` keys returned by `selfcare schema`
10
+
11
+ ## [0.4.0] - 2026-04-28
12
+
13
+ - Add `--image FILE` flag on `selfcare create` and `selfcare update` for multipart image uploads
14
+ - Update help text with image upload usage and the compose-then-PATCH attach flow
15
+
3
16
  ## [0.3.0] - 2026-03-11
4
17
 
5
18
  - Add multi-environment support with `~/.holivia/config.yml`
@@ -5,6 +5,11 @@
5
5
  "goal": "Comprendre et réduire le stress",
6
6
  "content_type": "video_type",
7
7
  "locale": "fr",
8
+ "state": "published",
9
+ "objectives": [
10
+ { "objective_id": 18, "tier": "main" },
11
+ { "objective_id": 19, "tier": "secondary" }
12
+ ],
8
13
  "formats": [
9
14
  {
10
15
  "format_type": "video",
@@ -25,9 +25,12 @@ module Holivia
25
25
  holivia selfcare index List all selfcare contents
26
26
  holivia selfcare show <id> Show a selfcare content by id
27
27
  holivia selfcare create [options] Create a selfcare content
28
- holivia selfcare update <id> [options] Update a selfcare content
28
+ (--state draft|ongoing_translation|translation_to_be_reviewed|
29
+ translation_reviewed|published)
30
+ holivia selfcare update <id> [options] Update a selfcare content (same --state values)
29
31
  holivia selfcare compose Create a full content tree atomically (no audio)
30
- holivia selfcare schema Show allowed values for content_types, format_types, item_types
32
+ holivia selfcare schema Show allowed values for content_types, format_types,
33
+ item_types, states, objective_tiers
31
34
 
32
35
  Content Formats:
33
36
  holivia selfcare format create [options] Add a format to a selfcare content
@@ -41,6 +44,22 @@ module Holivia
41
44
  holivia selfcare item create [options] Add an item to a slide
42
45
  holivia selfcare item update <id> [options] Update a slide item
43
46
 
47
+ Objectives:
48
+ holivia objective index [--page N --per-page N --code CODE] List objectives
49
+ holivia objective show <id> Show one objective
50
+ Translated fields are returned in the default locale (fr).
51
+
52
+ Selfcare Content Objectives:
53
+ holivia selfcare objective index [--page N --per-page N --selfcare-content-id ID --objective-id ID]
54
+ List a selfcare content's associated objectives
55
+ holivia selfcare objective show <id> Show one selfcare content objective
56
+ holivia selfcare objective create --selfcare-content-id ID --objective-id ID [--tier main|secondary]
57
+ Associate an objective to a selfcare content (tier defaults to main)
58
+ holivia selfcare objective update <id> --tier main|secondary Change the tier
59
+ holivia selfcare objective delete <id> Dissociate an objective from a selfcare content
60
+ Inline alternative: include "objectives": [{ "objective_id": ID, "tier": "main" }, ...] in the
61
+ JSON payload of compose/update. On update, [] clears the list; omitting the key leaves it untouched.
62
+
44
63
  Data Model:
45
64
  SelfcareContent → ContentFormat (format_type: text, audio, video)
46
65
  → Slide (title, duration) → SlideItem (one of: RichTextItem, VideoItem,
@@ -65,6 +84,10 @@ module Holivia
65
84
  All create/update/compose commands also accept piped JSON via stdin.
66
85
  Audio uploads use --audio <path> on item create/update (sent as multipart/form-data).
67
86
  Accepted audio formats: MP3, MP4, WAV, OGG, FLAC, AAC, M4A, WebM. Max size: 100 MB.
87
+ Image uploads use --image <path> on selfcare create/update (sent as multipart/form-data).
88
+ Accepted image formats: JPEG, PNG, WebP, GIF. Max size: 5 MB.
89
+ Compose is JSON-only — to attach an image to a composed tree, PATCH the returned id:
90
+ holivia selfcare update <id> --image <path>
68
91
 
69
92
  Errors:
70
93
  Validation errors (422) show structured details:
data/lib/holivia/cli.rb CHANGED
@@ -8,16 +8,18 @@ require_relative "commands/format"
8
8
  require_relative "commands/slide"
9
9
  require_relative "commands/env"
10
10
  require_relative "commands/item"
11
+ require_relative "commands/objective"
11
12
 
12
13
  module Holivia
13
14
  class CLI
14
- def self.start(args)
15
+ def self.start(args) # rubocop:disable Metrics/CyclomaticComplexity
15
16
  command = args.shift
16
17
  case command
17
18
  when "login" then Commands::Auth.new.login(args)
18
19
  when "logout" then Commands::Auth.new.logout
19
20
  when "env" then Commands::Env.route(args)
20
21
  when "selfcare" then Commands::Selfcare.route(args)
22
+ when "objective" then Commands::Objective.route(args)
21
23
  when "version", "--version", "-v" then puts "holivia #{Holivia::VERSION}"
22
24
  when "--help", "-h", nil then puts Help::HELP_TEXT
23
25
  else warn "Unknown command: #{command}"
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class Objective < Base
8
+ BASE_PATH = "/api/v1/backoffice/objectives"
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 objective 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 objective index [options]"
24
+ opts.on("--page N", Integer) { |v| params[:page] = v }
25
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
26
+ opts.on("--code CODE") { |v| params[:code] = v }
27
+ end.parse!(args)
28
+
29
+ output(client.get(BASE_PATH, params: params))
30
+ end
31
+
32
+ def show(args = [])
33
+ id = args.shift
34
+ abort "Usage: holivia objective show <id>" unless id
35
+
36
+ output(client.get("#{BASE_PATH}/#{id}"))
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "base"
4
+ require_relative "selfcare_objective"
4
5
 
5
6
  module Holivia
6
7
  module Commands
7
8
  class Selfcare < Base
8
9
  BASE_PATH = "/api/v1/backoffice/selfcare_contents"
9
10
  COMPOSE_EXAMPLE_PATH = Holivia.root.join("examples", "compose.json").to_s
11
+ IMAGE_MIME_TYPES = {
12
+ ".jpg" => "image/jpeg",
13
+ ".jpeg" => "image/jpeg",
14
+ ".png" => "image/png",
15
+ ".webp" => "image/webp",
16
+ ".gif" => "image/gif"
17
+ }.freeze
10
18
 
11
19
  def self.route(args) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/AbcSize
12
20
  subcommand = args.shift
@@ -20,6 +28,7 @@ module Holivia
20
28
  when "format" then Format.route(args)
21
29
  when "slide" then Slide.route(args)
22
30
  when "item" then Item.route(args)
31
+ when "objective" then SelfcareObjective.route(args)
23
32
  else warn "Unknown selfcare command: #{subcommand}"
24
33
  exit 1
25
34
  end
@@ -36,7 +45,7 @@ module Holivia
36
45
  output(client.get("#{BASE_PATH}/#{id}"))
37
46
  end
38
47
 
39
- def create(args = []) # rubocop:disable Metrics/AbcSize
48
+ def create(args = []) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
40
49
  options = {}
41
50
  OptionParser.new do |opts|
42
51
  opts.banner = "Usage: holivia selfcare create [options]"
@@ -45,11 +54,13 @@ module Holivia
45
54
  opts.on("--content-type TYPE") { |v| options[:content_type] = v }
46
55
  opts.on("--duration DURATION", Integer) { |v| options[:duration] = v }
47
56
  opts.on("--description DESC") { |v| options[:description] = v }
57
+ opts.on("--image FILE") { |v| options[:image] = v }
58
+ opts.on("--state STATE") { |v| options[:state] = v }
48
59
  end.parse!(args)
49
60
  options = options.merge(piped_json)
50
61
 
51
62
  abort "No options provided. Use --help for usage." if options.empty?
52
- output(client.post(BASE_PATH, body: options))
63
+ output(client.post(BASE_PATH, body: build_body(options)))
53
64
  end
54
65
 
55
66
  def update(args = []) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
@@ -64,11 +75,13 @@ module Holivia
64
75
  opts.on("--content-type TYPE") { |v| options[:content_type] = v }
65
76
  opts.on("--duration DURATION", Integer) { |v| options[:duration] = v }
66
77
  opts.on("--description DESC") { |v| options[:description] = v }
78
+ opts.on("--image FILE") { |v| options[:image] = v }
79
+ opts.on("--state STATE") { |v| options[:state] = v }
67
80
  end.parse!(args)
68
81
  options = options.merge(piped_json)
69
82
 
70
83
  abort "No options provided. Use --help for usage." if options.empty?
71
- output(client.patch("#{BASE_PATH}/#{id}", body: options))
84
+ output(client.patch("#{BASE_PATH}/#{id}", body: build_body(options)))
72
85
  end
73
86
 
74
87
  def compose(args = []) # rubocop:disable Metrics/MethodLength
@@ -93,6 +106,20 @@ module Holivia
93
106
  def schema(_args = [])
94
107
  output(client.get("#{BASE_PATH}/schema"))
95
108
  end
109
+
110
+ private
111
+
112
+ def build_body(options)
113
+ image_path = options.delete(:image)
114
+ return options unless image_path
115
+
116
+ options.merge(image: Faraday::Multipart::FilePart.new(image_path, detect_mime(image_path)))
117
+ end
118
+
119
+ def detect_mime(path)
120
+ ext = File.extname(path).downcase
121
+ IMAGE_MIME_TYPES.fetch(ext, "application/octet-stream")
122
+ end
96
123
  end
97
124
  end
98
125
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Holivia
6
+ module Commands
7
+ class SelfcareObjective < Base
8
+ BASE_PATH = "/api/v1/backoffice/selfcare_content_objectives"
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
+ when "create" then new.create(args)
16
+ when "update" then new.update(args)
17
+ when "delete" then new.delete(args)
18
+ else warn "Unknown selfcare objective command: #{subcommand}"
19
+ exit 1
20
+ end
21
+ end
22
+
23
+ def index(args = [])
24
+ params = {}
25
+ OptionParser.new do |opts|
26
+ opts.banner = "Usage: holivia selfcare objective index [options]"
27
+ opts.on("--page N", Integer) { |v| params[:page] = v }
28
+ opts.on("--per-page N", Integer) { |v| params[:per_page] = v }
29
+ opts.on("--selfcare-content-id ID", Integer) { |v| params[:selfcare_content_id] = v }
30
+ opts.on("--objective-id ID", Integer) { |v| params[:objective_id] = v }
31
+ end.parse!(args)
32
+
33
+ output(client.get(BASE_PATH, params: params))
34
+ end
35
+
36
+ def show(args = [])
37
+ id = args.shift
38
+ abort "Usage: holivia selfcare objective show <id>" unless id
39
+
40
+ output(client.get("#{BASE_PATH}/#{id}"))
41
+ end
42
+
43
+ def create(args = [])
44
+ options = {}
45
+ OptionParser.new do |opts|
46
+ opts.banner = "Usage: holivia selfcare objective create [options]"
47
+ opts.on("--selfcare-content-id ID", Integer) { |v| options[:selfcare_content_id] = v }
48
+ opts.on("--objective-id ID", Integer) { |v| options[:objective_id] = v }
49
+ opts.on("--tier TIER") { |v| options[:tier] = v }
50
+ end.parse!(args)
51
+ options = options.merge(piped_json)
52
+
53
+ abort "No options provided. Use --help for usage." if options.empty?
54
+ output(client.post(BASE_PATH, body: options))
55
+ end
56
+
57
+ def update(args = [])
58
+ id = args.shift
59
+ abort "Usage: holivia selfcare objective update <id> [options]" unless id
60
+
61
+ options = {}
62
+ OptionParser.new do |opts|
63
+ opts.banner = "Usage: holivia selfcare objective update <id> [options]"
64
+ opts.on("--tier TIER") { |v| options[:tier] = v }
65
+ end.parse!(args)
66
+ options = options.merge(piped_json)
67
+
68
+ abort "No options provided. Use --help for usage." if options.empty?
69
+ output(client.patch("#{BASE_PATH}/#{id}", body: options))
70
+ end
71
+
72
+ def delete(args = [])
73
+ id = args.shift
74
+ abort "Usage: holivia selfcare objective delete <id>" unless id
75
+
76
+ client.delete("#{BASE_PATH}/#{id}")
77
+ output(deleted: true, id: id.to_i)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Holivia
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
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.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Holivia
@@ -66,7 +66,9 @@ files:
66
66
  - lib/holivia/commands/env.rb
67
67
  - lib/holivia/commands/format.rb
68
68
  - lib/holivia/commands/item.rb
69
+ - lib/holivia/commands/objective.rb
69
70
  - lib/holivia/commands/selfcare.rb
71
+ - lib/holivia/commands/selfcare_objective.rb
70
72
  - lib/holivia/commands/slide.rb
71
73
  - lib/holivia/config_error.rb
72
74
  - lib/holivia/configuration.rb