From 7c17a7cb96bf990c1e3789e5ad6934a0f2b1a77b Mon Sep 17 00:00:00 2001 From: Rodribm10 Date: Wed, 15 Apr 2026 10:17:59 -0300 Subject: [PATCH] feat(lifecycle): REST endpoint for lifecycle rules CRUD Co-Authored-By: Claude Sonnet 4.6 --- .../captain/lifecycle_rules_controller.rb | 40 ++++++++- .../lifecycle_rules/create.json.jbuilder | 1 + .../lifecycle_rules/index.json.jbuilder | 9 ++ .../lifecycle_rules/show.json.jbuilder | 1 + .../lifecycle_rules/update.json.jbuilder | 1 + .../captain/_lifecycle_rule.json.jbuilder | 15 ++++ .../lifecycle_rules_controller_spec.rb | 82 +++++++++++++++++++ 7 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/create.json.jbuilder create mode 100644 enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/index.json.jbuilder create mode 100644 enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/show.json.jbuilder create mode 100644 enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/update.json.jbuilder create mode 100644 enterprise/app/views/api/v1/models/captain/_lifecycle_rule.json.jbuilder create mode 100644 spec/enterprise/controllers/api/v1/accounts/captain/lifecycle_rules_controller_spec.rb diff --git a/enterprise/app/controllers/api/v1/accounts/captain/lifecycle_rules_controller.rb b/enterprise/app/controllers/api/v1/accounts/captain/lifecycle_rules_controller.rb index 0410bb8c3..c8419978e 100644 --- a/enterprise/app/controllers/api/v1/accounts/captain/lifecycle_rules_controller.rb +++ b/enterprise/app/controllers/api/v1/accounts/captain/lifecycle_rules_controller.rb @@ -1,5 +1,43 @@ class Api::V1::Accounts::Captain::LifecycleRulesController < Api::V1::Accounts::BaseController + before_action :current_account + before_action -> { check_authorization(Captain::Lifecycle::Rule) } + before_action :set_rule, only: [:show, :update, :destroy] + def index - head :ok + @rules = Current.account.captain_lifecycle_rules.order(priority: :asc, id: :desc) + end + + def show; end + + def create + @rule = Current.account.captain_lifecycle_rules.create!( + rule_params.merge(created_by_user: Current.user) + ) + render 'api/v1/accounts/captain/lifecycle_rules/show' + end + + def update + @rule.update!(rule_params) + render 'api/v1/accounts/captain/lifecycle_rules/show' + end + + def destroy + @rule.destroy! + head :no_content + end + + private + + def set_rule + @rule = Current.account.captain_lifecycle_rules.find(params[:id]) + end + + def rule_params + params.require(:rule).permit( + :name, :description, :enabled, :event, :offset_minutes, + :message_type, :message_body, :priority, + filters: {}, + message_payload: {} + ) end end diff --git a/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/create.json.jbuilder b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/create.json.jbuilder new file mode 100644 index 000000000..e431dc55a --- /dev/null +++ b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/captain/lifecycle_rule', resource: @rule diff --git a/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/index.json.jbuilder b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/index.json.jbuilder new file mode 100644 index 000000000..22cdb2bda --- /dev/null +++ b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/index.json.jbuilder @@ -0,0 +1,9 @@ +json.payload do + json.array! @rules do |rule| + json.partial! 'api/v1/models/captain/lifecycle_rule', resource: rule + end +end + +json.meta do + json.total_count @rules.count +end diff --git a/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/show.json.jbuilder b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/show.json.jbuilder new file mode 100644 index 000000000..e431dc55a --- /dev/null +++ b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/captain/lifecycle_rule', resource: @rule diff --git a/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/update.json.jbuilder b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/update.json.jbuilder new file mode 100644 index 000000000..e431dc55a --- /dev/null +++ b/enterprise/app/views/api/v1/accounts/captain/lifecycle_rules/update.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'api/v1/models/captain/lifecycle_rule', resource: @rule diff --git a/enterprise/app/views/api/v1/models/captain/_lifecycle_rule.json.jbuilder b/enterprise/app/views/api/v1/models/captain/_lifecycle_rule.json.jbuilder new file mode 100644 index 000000000..cc7477036 --- /dev/null +++ b/enterprise/app/views/api/v1/models/captain/_lifecycle_rule.json.jbuilder @@ -0,0 +1,15 @@ +json.id resource.id +json.account_id resource.account_id +json.name resource.name +json.description resource.description +json.enabled resource.enabled +json.event resource.event +json.offset_minutes resource.offset_minutes +json.filters resource.filters || {} +json.message_type resource.message_type +json.message_body resource.message_body +json.message_payload resource.message_payload +json.priority resource.priority +json.created_by_user_id resource.created_by_user_id +json.created_at resource.created_at&.iso8601 +json.updated_at resource.updated_at&.iso8601 diff --git a/spec/enterprise/controllers/api/v1/accounts/captain/lifecycle_rules_controller_spec.rb b/spec/enterprise/controllers/api/v1/accounts/captain/lifecycle_rules_controller_spec.rb new file mode 100644 index 000000000..651a3e3e7 --- /dev/null +++ b/spec/enterprise/controllers/api/v1/accounts/captain/lifecycle_rules_controller_spec.rb @@ -0,0 +1,82 @@ +require 'rails_helper' + +RSpec.describe 'Api::V1::Accounts::Captain::LifecycleRules', type: :request do + let(:account) { create(:account) } + let(:admin) { create(:user, account: account, role: :administrator) } + let(:agent) { create(:user, account: account, role: :agent) } + let(:other_account) { create(:account) } + + def json_response + JSON.parse(response.body, symbolize_names: true) + end + + describe 'GET /api/v1/accounts/:account_id/captain/lifecycle_rules' do + it 'returns 401 when unauthenticated' do + get "/api/v1/accounts/#{account.id}/captain/lifecycle_rules" + expect(response).to have_http_status(:unauthorized) + end + + it 'returns the account rules (and not others)' do + create_list(:captain_lifecycle_rule, 2, account: account) + create(:captain_lifecycle_rule, account: other_account) + + get "/api/v1/accounts/#{account.id}/captain/lifecycle_rules", + headers: admin.create_new_auth_token, as: :json + + expect(response).to have_http_status(:success) + expect(json_response[:payload].length).to eq(2) + end + end + + describe 'POST /api/v1/accounts/:account_id/captain/lifecycle_rules' do + let(:valid_params) do + { + rule: { + name: 'Lembrete pré check-in', + event: 'checkin.scheduled_at', + offset_minutes: -10, + message_type: 'text', + message_body: 'Oi {{ customer.first_name }}', + filters: { unit_ids: [1] }, + enabled: true + } + } + end + + it 'blocks agents' do + post "/api/v1/accounts/#{account.id}/captain/lifecycle_rules", + params: valid_params, headers: agent.create_new_auth_token, as: :json + expect(response).to have_http_status(:unauthorized) + end + + it 'creates for admin' do + post "/api/v1/accounts/#{account.id}/captain/lifecycle_rules", + params: valid_params, headers: admin.create_new_auth_token, as: :json + expect(response).to have_http_status(:success) + expect(json_response[:name]).to eq('Lembrete pré check-in') + expect(Captain::Lifecycle::Rule.where(account: account).count).to eq(1) + end + end + + describe 'PATCH /api/v1/accounts/:account_id/captain/lifecycle_rules/:id' do + let(:rule) { create(:captain_lifecycle_rule, account: account, name: 'old') } + + it 'updates for admin' do + patch "/api/v1/accounts/#{account.id}/captain/lifecycle_rules/#{rule.id}", + params: { rule: { name: 'new' } }, + headers: admin.create_new_auth_token, as: :json + expect(response).to have_http_status(:success) + expect(rule.reload.name).to eq('new') + end + end + + describe 'DELETE /api/v1/accounts/:account_id/captain/lifecycle_rules/:id' do + it 'destroys for admin' do + rule = create(:captain_lifecycle_rule, account: account) + delete "/api/v1/accounts/#{account.id}/captain/lifecycle_rules/#{rule.id}", + headers: admin.create_new_auth_token, as: :json + expect(response).to have_http_status(:success) + expect(Captain::Lifecycle::Rule.where(id: rule.id)).to be_empty + end + end +end