From b9074f5a224661a1e0ee4a836f06e0f71c3be59e Mon Sep 17 00:00:00 2001 From: Darren Eid Date: Thu, 23 Jul 2026 18:07:38 -0700 Subject: [PATCH 1/5] track topic status changes in a new table - add TopicStatusChange model + migration - record changes from the admin controller (api_update) and post_created - enforce allowed statuses in the controller Co-Authored-By: Claude Opus 4.8 (1M context) --- .../custom_fields_controller.rb | 16 ++++++++++++- .../topic_status_change.rb | 23 +++++++++++++++++++ ...60616011522_create_topic_status_changes.rb | 17 ++++++++++++++ plugin.rb | 11 +++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 app/models/community_custom_fields/topic_status_change.rb create mode 100644 db/migrate/20260616011522_create_topic_status_changes.rb diff --git a/app/controllers/community_custom_fields/custom_fields_controller.rb b/app/controllers/community_custom_fields/custom_fields_controller.rb index 1f8fea7..497468e 100644 --- a/app/controllers/community_custom_fields/custom_fields_controller.rb +++ b/app/controllers/community_custom_fields/custom_fields_controller.rb @@ -8,8 +8,22 @@ class CommunityCustomFields::CustomFieldsController < ::ApplicationController def update topic = Topic.unscoped.find(params[:topic_id]) - topic.custom_fields.merge!(custom_fields_params) + fields = custom_fields_params + + if fields.key?("status") && !CommunityCustomFields::STATUSES.include?(fields["status"]) + return render json: { error: "Invalid status: #{fields["status"].inspect}" }, status: 422 + end + + previous_status = topic.custom_fields["status"] + previous_assignee_id = topic.custom_fields["assignee_id"] + topic.custom_fields.merge!(fields) if topic.save_custom_fields + CommunityCustomFields::TopicStatusChange.record( + topic: topic, + from_status: previous_status, + source: "api_update", + assignee_id: previous_assignee_id + ) topic.touch render json: success_json else diff --git a/app/models/community_custom_fields/topic_status_change.rb b/app/models/community_custom_fields/topic_status_change.rb new file mode 100644 index 0000000..42bf8cd --- /dev/null +++ b/app/models/community_custom_fields/topic_status_change.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module CommunityCustomFields + class TopicStatusChange < ActiveRecord::Base + self.table_name = "community_custom_fields_topic_status_changes" + + belongs_to :topic, class_name: "::Topic" + belongs_to :assignee, class_name: "::User", optional: true + + def self.record(topic:, from_status:, source:, assignee_id:) + to_status = topic.custom_fields["status"] + return if to_status.blank? || to_status == from_status + + create!( + topic_id: topic.id, + from_status: from_status, + to_status: to_status, + source: source, + assignee_id: assignee_id + ) + end + end +end diff --git a/db/migrate/20260616011522_create_topic_status_changes.rb b/db/migrate/20260616011522_create_topic_status_changes.rb new file mode 100644 index 0000000..70b0f5d --- /dev/null +++ b/db/migrate/20260616011522_create_topic_status_changes.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class CreateTopicStatusChanges < ActiveRecord::Migration[7.2] + def change + create_table :community_custom_fields_topic_status_changes do |t| + t.integer :topic_id, null: false + t.integer :assignee_id + t.string :from_status + t.string :to_status, null: false + t.string :source, null: false + t.datetime :created_at, null: false + end + + add_index :community_custom_fields_topic_status_changes, :topic_id + add_index :community_custom_fields_topic_status_changes, :assignee_id + end +end diff --git a/plugin.rb b/plugin.rb index 9c36a63..1dc203c 100644 --- a/plugin.rb +++ b/plugin.rb @@ -28,6 +28,8 @@ module ::CommunityCustomFields waiting_since: :datetime, waiting_id: :integer } + + STATUSES = %w[new open snoozed closed] end require_relative 'lib/community_custom_fields/engine.rb' @@ -65,6 +67,8 @@ module ::CommunityCustomFields topic = post.topic topic.custom_fields[:status] ||= "new" + previous_status = topic.custom_fields[:status] + previous_assignee_id = topic.custom_fields[:assignee_id] if user.admin && post.post_type == 1 topic.custom_fields[:waiting_since] = nil @@ -119,5 +123,12 @@ module ::CommunityCustomFields end topic.save_custom_fields + + CommunityCustomFields::TopicStatusChange.record( + topic: topic, + from_status: previous_status, + source: "post_creation", + assignee_id: previous_assignee_id + ) end end From 10f80940501f5edad740d4d6401caf54da69650e Mon Sep 17 00:00:00 2001 From: Darren Eid Date: Fri, 24 Jul 2026 12:11:16 -0700 Subject: [PATCH 2/5] add trigger (user/post) and duration to status changes - new migration adds user_id, post_id, and duration (bigint, NOT NULL), backfilling duration for existing rows from their created_at history - record the acting user (api_update) or triggering post (post_creation) - compute duration as seconds spent in the status being left, chained off the prior change and falling back to topic.created_at Co-Authored-By: Claude Opus 4.8 (1M context) --- .../custom_fields_controller.rb | 3 +- .../topic_status_change.rb | 13 +++++-- ...er_and_duration_to_topic_status_changes.rb | 36 +++++++++++++++++++ plugin.rb | 3 +- 4 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20260724172111_add_trigger_and_duration_to_topic_status_changes.rb diff --git a/app/controllers/community_custom_fields/custom_fields_controller.rb b/app/controllers/community_custom_fields/custom_fields_controller.rb index 497468e..37bb510 100644 --- a/app/controllers/community_custom_fields/custom_fields_controller.rb +++ b/app/controllers/community_custom_fields/custom_fields_controller.rb @@ -22,7 +22,8 @@ def update topic: topic, from_status: previous_status, source: "api_update", - assignee_id: previous_assignee_id + assignee_id: previous_assignee_id, + user_id: current_user.id ) topic.touch render json: success_json diff --git a/app/models/community_custom_fields/topic_status_change.rb b/app/models/community_custom_fields/topic_status_change.rb index 42bf8cd..c638a29 100644 --- a/app/models/community_custom_fields/topic_status_change.rb +++ b/app/models/community_custom_fields/topic_status_change.rb @@ -6,17 +6,26 @@ class TopicStatusChange < ActiveRecord::Base belongs_to :topic, class_name: "::Topic" belongs_to :assignee, class_name: "::User", optional: true + belongs_to :user, class_name: "::User", optional: true + belongs_to :post, class_name: "::Post", optional: true - def self.record(topic:, from_status:, source:, assignee_id:) + def self.record(topic:, from_status:, source:, assignee_id:, user_id: nil, post_id: nil) to_status = topic.custom_fields["status"] return if to_status.blank? || to_status == from_status + last_change = where(topic_id: topic.id).order(:id).last + started_at = last_change&.created_at || topic.created_at + duration = (Time.current - started_at).to_i + create!( topic_id: topic.id, from_status: from_status, to_status: to_status, source: source, - assignee_id: assignee_id + assignee_id: assignee_id, + user_id: user_id, + post_id: post_id, + duration: duration ) end end diff --git a/db/migrate/20260724172111_add_trigger_and_duration_to_topic_status_changes.rb b/db/migrate/20260724172111_add_trigger_and_duration_to_topic_status_changes.rb new file mode 100644 index 0000000..70a93fd --- /dev/null +++ b/db/migrate/20260724172111_add_trigger_and_duration_to_topic_status_changes.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +class AddTriggerAndDurationToTopicStatusChanges < ActiveRecord::Migration[7.2] + def up + add_column :community_custom_fields_topic_status_changes, :user_id, :integer + add_column :community_custom_fields_topic_status_changes, :post_id, :integer + add_column :community_custom_fields_topic_status_changes, :duration, :bigint + + # Backfill existing rows: seconds spent in the status being left, measured + # from the prior change for the topic (or the topic's creation). + execute <<~SQL + UPDATE community_custom_fields_topic_status_changes sc + SET duration = GREATEST( + TRUNC( + EXTRACT(EPOCH FROM (sc.created_at - COALESCE(prev.prev_created_at, t.created_at, sc.created_at))) + )::bigint, + 0 + ) + FROM ( + SELECT id, topic_id, + LAG(created_at) OVER (PARTITION BY topic_id ORDER BY id) AS prev_created_at + FROM community_custom_fields_topic_status_changes + ) prev + LEFT JOIN topics t ON t.id = prev.topic_id + WHERE sc.id = prev.id; + SQL + + change_column_null :community_custom_fields_topic_status_changes, :duration, false + end + + def down + remove_column :community_custom_fields_topic_status_changes, :duration + remove_column :community_custom_fields_topic_status_changes, :post_id + remove_column :community_custom_fields_topic_status_changes, :user_id + end +end diff --git a/plugin.rb b/plugin.rb index 1dc203c..2d03f4c 100644 --- a/plugin.rb +++ b/plugin.rb @@ -128,7 +128,8 @@ module ::CommunityCustomFields topic: topic, from_status: previous_status, source: "post_creation", - assignee_id: previous_assignee_id + assignee_id: previous_assignee_id, + post_id: post.id ) end end From fdc6b4ea8e9e5be9515ae8c62b4e3fbfca9f8b3f Mon Sep 17 00:00:00 2001 From: Darren Eid Date: Fri, 24 Jul 2026 12:11:16 -0700 Subject: [PATCH 3/5] add CLAUDE.md Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..2640da0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,60 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +A Discourse plugin that adds custom fields to topics so Discourse can be used as a support/ticketing platform. It is currently **backend-only** — the `assets/javascripts` and `test/javascripts` directories are empty placeholders. Almost all logic lives in `plugin.rb`. + +## Architecture + +### `CUSTOM_FIELDS` registry (`plugin.rb`) +The `CommunityCustomFields::CUSTOM_FIELDS` hash (name → type) is the single source of truth. Adding a field there automatically: registers its type on `Topic`, preloads it on `TopicList`, exposes it via the `topic_view` serializer, and makes it permittable in the controller's strong params. Add a field in one place only. + +### The support-ticket state machine (`plugin.rb` event handlers) +The non-obvious core is the `topic_created` and `post_created` handlers, which maintain ticket state on topic custom fields. Understand these before editing: + +- **`status`** moves through `"new"` → `"open"` → `"snoozed"`/`"closed"` and back. `topic_created` seeds `status = "new"`. Valid values are the `CommunityCustomFields::STATUSES` list. +- **`waiting_since` / `waiting_id`** track the customer who is waiting on a reply. Set when a non-admin posts; cleared when an admin posts a regular reply. +- **`post_type`** drives branching: `1` = regular reply, `4` = whisper (staff-only note). Other post types are ignored. The first post (`post_number == 1`) is skipped because `topic_created` already handled it. +- **Admin regular reply** (type 1): clears `waiting_*`. +- **Admin whisper** (type 4): does *not* clear `waiting_*`, but can reopen a `snoozed`/`closed` topic. +- **Customer reply** (non-admin): sets `waiting_*`, reopens `snoozed`, and reopens `closed` — with a **1-month rule**: if the topic was closed more than a month ago (or had no `last_assigned_to_id`), it reopens as `"new"`; otherwise it reopens as `"open"` and is reassigned to the last assignee. +- `user.id <= 0` (system users) and non-`"regular"` archetypes (e.g. PMs) are skipped. + +### Controller (`app/controllers/community_custom_fields/custom_fields_controller.rb`) +Admin-only `PUT` endpoint to set custom fields on a topic. Mounted at `/admin/plugins/community-custom-fields/:topic_id` (see `config/routes.rb`). Uses `Topic.unscoped.find` so it can update topics that are otherwise filtered out (e.g. deleted/closed). It validates any incoming `status` against `CommunityCustomFields::STATUSES` (rejecting unknown values with `422`) and records a status change (see below). + +### Status-change history (`TopicStatusChange`) +Every status transition is logged to the `community_custom_fields_topic_status_changes` table (model: `app/models/community_custom_fields/topic_status_change.rb`). `TopicStatusChange.record` is the single writer — it no-ops unless the topic's current `status` differs from the passed `from_status`. It's called from two places, and `topic_created` is intentionally *not* recorded (no initial `"new"` row): + +- **Controller** (`source: "api_update"`) — passes the acting admin as `user_id`. +- **`post_created`** (`source: "post_creation"`) — passes the triggering `post_id`. + +Row columns: +- **`from_status` / `to_status`** — the transition; `from_status` is null when the topic had no prior status. +- **`assignee_id`** — the assignee *before* the change (attributes the change to whoever owned the ticket during the status being left). +- **`user_id`** (api_update) / **`post_id`** (post_creation) — what triggered the change; only one is set per row. +- **`duration`** — seconds spent in the status being left, measured from the previous recorded change (or `topic.created_at` for the first change). +- **`source`** — `"api_update"` or `"post_creation"`. + +## Commands + +Tests are **Discourse system specs** and cannot run standalone from this repo — they run inside a Discourse host app with this plugin symlinked into `plugins/`. From the Discourse core root: + +```bash +LOAD_PLUGINS=1 bin/rspec plugins/community-custom-fields/spec/system/core_features_spec.rb +``` + +Linting uses Discourse's shared configs (`@discourse/lint-configs`). Install with `pnpm install` (pnpm 9.x, Node ≥ 22 required), then: + +```bash +pnpm eslint . # JS +pnpm ember-template-lint . # Ember templates +pnpm stylelint "**/*.scss" # styles +pnpm prettier --check . # formatting +bundle exec rubocop # Ruby (rubocop-discourse, stree-compatible) +bundle exec stree check . # Ruby formatting (syntax_tree, print-width 100) +``` + +CI (`.github/workflows/discourse-plugin.yml`) runs the shared `discourse/.github` plugin workflow on push to `main` and on PRs. From 7b9411718a2b39251058f1bc19dcbc25b6d9e050 Mon Sep 17 00:00:00 2001 From: Darren Eid Date: Fri, 24 Jul 2026 14:50:18 -0700 Subject: [PATCH 4/5] measure duration from prior status timestamp when no table entry exists For a topic with no existing status-change row, fall back to when the current status was set (its topic_custom_fields row, captured before the change) rather than topic.created_at, so pre-existing topics get an accurate first duration instead of time-since-creation. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 2 +- .../community_custom_fields/custom_fields_controller.rb | 4 +++- app/models/community_custom_fields/topic_status_change.rb | 4 ++-- plugin.rb | 4 +++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2640da0..653663e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -35,7 +35,7 @@ Row columns: - **`from_status` / `to_status`** — the transition; `from_status` is null when the topic had no prior status. - **`assignee_id`** — the assignee *before* the change (attributes the change to whoever owned the ticket during the status being left). - **`user_id`** (api_update) / **`post_id`** (post_creation) — what triggered the change; only one is set per row. -- **`duration`** — seconds spent in the status being left, measured from the previous recorded change (or `topic.created_at` for the first change). +- **`duration`** — seconds spent in the status being left. Measured from the prior recorded change; for a topic with no table entry yet, from when the current status was set (its `topic_custom_fields` row); otherwise from `topic.created_at`. - **`source`** — `"api_update"` or `"post_creation"`. ## Commands diff --git a/app/controllers/community_custom_fields/custom_fields_controller.rb b/app/controllers/community_custom_fields/custom_fields_controller.rb index 37bb510..ded8c02 100644 --- a/app/controllers/community_custom_fields/custom_fields_controller.rb +++ b/app/controllers/community_custom_fields/custom_fields_controller.rb @@ -16,6 +16,7 @@ def update previous_status = topic.custom_fields["status"] previous_assignee_id = topic.custom_fields["assignee_id"] + previous_status_at = TopicCustomField.where(topic_id: topic.id, name: "status").pick(:created_at) topic.custom_fields.merge!(fields) if topic.save_custom_fields CommunityCustomFields::TopicStatusChange.record( @@ -23,7 +24,8 @@ def update from_status: previous_status, source: "api_update", assignee_id: previous_assignee_id, - user_id: current_user.id + user_id: current_user.id, + previous_status_at: previous_status_at ) topic.touch render json: success_json diff --git a/app/models/community_custom_fields/topic_status_change.rb b/app/models/community_custom_fields/topic_status_change.rb index c638a29..f3edf46 100644 --- a/app/models/community_custom_fields/topic_status_change.rb +++ b/app/models/community_custom_fields/topic_status_change.rb @@ -9,12 +9,12 @@ class TopicStatusChange < ActiveRecord::Base belongs_to :user, class_name: "::User", optional: true belongs_to :post, class_name: "::Post", optional: true - def self.record(topic:, from_status:, source:, assignee_id:, user_id: nil, post_id: nil) + def self.record(topic:, from_status:, source:, assignee_id:, user_id: nil, post_id: nil, previous_status_at: nil) to_status = topic.custom_fields["status"] return if to_status.blank? || to_status == from_status last_change = where(topic_id: topic.id).order(:id).last - started_at = last_change&.created_at || topic.created_at + started_at = last_change&.created_at || previous_status_at || topic.created_at duration = (Time.current - started_at).to_i create!( diff --git a/plugin.rb b/plugin.rb index 2d03f4c..551732e 100644 --- a/plugin.rb +++ b/plugin.rb @@ -69,6 +69,7 @@ module ::CommunityCustomFields topic.custom_fields[:status] ||= "new" previous_status = topic.custom_fields[:status] previous_assignee_id = topic.custom_fields[:assignee_id] + previous_status_at = TopicCustomField.where(topic_id: topic.id, name: "status").pick(:created_at) if user.admin && post.post_type == 1 topic.custom_fields[:waiting_since] = nil @@ -129,7 +130,8 @@ module ::CommunityCustomFields from_status: previous_status, source: "post_creation", assignee_id: previous_assignee_id, - post_id: post.id + post_id: post.id, + previous_status_at: previous_status_at ) end end From b0566ba878af5d893a164aea34c8e9fda860cda1 Mon Sep 17 00:00:00 2001 From: Darren Eid Date: Tue, 28 Jul 2026 08:46:36 -0700 Subject: [PATCH 5/5] satisfy CI: syntax_tree formatting and model annotation - format Ruby files per the plugin's .streerc (trailing commas, 100-col wrap); routes/engine/spec were pre-existing violations - add the schema annotation block to TopicStatusChange for the annotations_tests check Co-Authored-By: Claude Opus 4.8 (1M context) --- .../custom_fields_controller.rb | 11 ++++--- .../topic_status_change.rb | 33 +++++++++++++++++-- config/routes.rb | 8 ++--- lib/community_custom_fields/engine.rb | 2 +- plugin.rb | 26 ++++++++------- spec/system/core_features_spec.rb | 2 +- 6 files changed, 57 insertions(+), 25 deletions(-) diff --git a/app/controllers/community_custom_fields/custom_fields_controller.rb b/app/controllers/community_custom_fields/custom_fields_controller.rb index ded8c02..6c01476 100644 --- a/app/controllers/community_custom_fields/custom_fields_controller.rb +++ b/app/controllers/community_custom_fields/custom_fields_controller.rb @@ -16,7 +16,8 @@ def update previous_status = topic.custom_fields["status"] previous_assignee_id = topic.custom_fields["assignee_id"] - previous_status_at = TopicCustomField.where(topic_id: topic.id, name: "status").pick(:created_at) + previous_status_at = + TopicCustomField.where(topic_id: topic.id, name: "status").pick(:created_at) topic.custom_fields.merge!(fields) if topic.save_custom_fields CommunityCustomFields::TopicStatusChange.record( @@ -25,12 +26,14 @@ def update source: "api_update", assignee_id: previous_assignee_id, user_id: current_user.id, - previous_status_at: previous_status_at + previous_status_at: previous_status_at, ) topic.touch render json: success_json else - Rails.logger.error("Failed to save custom fields for topic #{topic.id}: #{topic.errors.full_messages}") + Rails.logger.error( + "Failed to save custom fields for topic #{topic.id}: #{topic.errors.full_messages}", + ) render json: { error: topic.errors.full_messages }, status: 422 end end @@ -40,4 +43,4 @@ def update def custom_fields_params params.require(:custom_field).permit(*CommunityCustomFields::CUSTOM_FIELDS.keys) end -end \ No newline at end of file +end diff --git a/app/models/community_custom_fields/topic_status_change.rb b/app/models/community_custom_fields/topic_status_change.rb index f3edf46..959d5a8 100644 --- a/app/models/community_custom_fields/topic_status_change.rb +++ b/app/models/community_custom_fields/topic_status_change.rb @@ -9,7 +9,15 @@ class TopicStatusChange < ActiveRecord::Base belongs_to :user, class_name: "::User", optional: true belongs_to :post, class_name: "::Post", optional: true - def self.record(topic:, from_status:, source:, assignee_id:, user_id: nil, post_id: nil, previous_status_at: nil) + def self.record( + topic:, + from_status:, + source:, + assignee_id:, + user_id: nil, + post_id: nil, + previous_status_at: nil + ) to_status = topic.custom_fields["status"] return if to_status.blank? || to_status == from_status @@ -25,8 +33,29 @@ def self.record(topic:, from_status:, source:, assignee_id:, user_id: nil, post_ assignee_id: assignee_id, user_id: user_id, post_id: post_id, - duration: duration + duration: duration, ) end end end + +# == Schema Information +# +# Table name: community_custom_fields_topic_status_changes +# +# id :bigint not null, primary key +# duration :bigint not null +# from_status :string +# source :string not null +# to_status :string not null +# created_at :datetime not null +# assignee_id :integer +# post_id :integer +# topic_id :integer not null +# user_id :integer +# +# Indexes +# +# idx_on_assignee_id_bc22060231 (assignee_id) +# index_community_custom_fields_topic_status_changes_on_topic_id (topic_id) +# diff --git a/config/routes.rb b/config/routes.rb index 9f1ba92..5f7a4bc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true -CommunityCustomFields::Engine.routes.draw do - put '/:topic_id' => 'custom_fields#update' -end +CommunityCustomFields::Engine.routes.draw { put "/:topic_id" => "custom_fields#update" } Discourse::Application.routes.draw do - mount ::CommunityCustomFields::Engine, at: '/admin/plugins/community-custom-fields' -end \ No newline at end of file + mount ::CommunityCustomFields::Engine, at: "/admin/plugins/community-custom-fields" +end diff --git a/lib/community_custom_fields/engine.rb b/lib/community_custom_fields/engine.rb index 685ff68..b71c97b 100644 --- a/lib/community_custom_fields/engine.rb +++ b/lib/community_custom_fields/engine.rb @@ -10,4 +10,4 @@ class Engine < ::Rails::Engine Rails.autoloaders.main.eager_load_dir(scheduled_job_dir) if Dir.exist?(scheduled_job_dir) end end -end \ No newline at end of file +end diff --git a/plugin.rb b/plugin.rb index 551732e..1e92381 100644 --- a/plugin.rb +++ b/plugin.rb @@ -13,7 +13,7 @@ module ::CommunityCustomFields CUSTOM_FIELDS = { assignee_id: :integer, first_assigned_to_id: :integer, - first_assigned_at: :datetime, + first_assigned_at: :datetime, last_assigned_to_id: :integer, last_assigned_at: :datetime, account_name: :string, @@ -26,13 +26,13 @@ module ::CommunityCustomFields closed_at: :datetime, snoozed_until: :datetime, waiting_since: :datetime, - waiting_id: :integer + waiting_id: :integer, } STATUSES = %w[new open snoozed closed] end -require_relative 'lib/community_custom_fields/engine.rb' +require_relative "lib/community_custom_fields/engine.rb" after_initialize do CommunityCustomFields::CUSTOM_FIELDS.each do |name, type| @@ -40,7 +40,7 @@ module ::CommunityCustomFields end TopicList.preloaded_custom_fields.merge(CommunityCustomFields::CUSTOM_FIELDS.keys) - + add_to_serializer(:topic_view, :custom_fields) do object.topic.custom_fields.slice(*CommunityCustomFields::CUSTOM_FIELDS.keys) end @@ -64,12 +64,13 @@ module ::CommunityCustomFields next if user.id <= 0 next unless post.post_type == 1 || post.post_type == 4 next if post.post_number == 1 - + topic = post.topic topic.custom_fields[:status] ||= "new" previous_status = topic.custom_fields[:status] previous_assignee_id = topic.custom_fields[:assignee_id] - previous_status_at = TopicCustomField.where(topic_id: topic.id, name: "status").pick(:created_at) + previous_status_at = + TopicCustomField.where(topic_id: topic.id, name: "status").pick(:created_at) if user.admin && post.post_type == 1 topic.custom_fields[:waiting_since] = nil @@ -91,11 +92,11 @@ module ::CommunityCustomFields topic.custom_fields[:assignee_id] = topic.custom_fields[:last_assigned_to_id] topic.custom_fields[:last_assigned_at] = Time.current.iso8601 end - + topic.custom_fields[:outcome] = nil topic.custom_fields[:closed_at] = nil end - else + else if user.id != topic.custom_fields[:waiting_id].to_i topic.custom_fields[:waiting_since] = Time.current.iso8601 topic.custom_fields[:waiting_id] = user.id @@ -110,19 +111,20 @@ module ::CommunityCustomFields # this handles an edge case where `closed_at` was never set topic.custom_fields[:closed_at] ||= Time.current.iso8601 - if topic.custom_fields[:last_assigned_to_id].nil? || Time.iso8601(topic.custom_fields[:closed_at]) < 1.month.ago.iso8601 + if topic.custom_fields[:last_assigned_to_id].nil? || + Time.iso8601(topic.custom_fields[:closed_at]) < 1.month.ago.iso8601 topic.custom_fields[:status] = "new" else topic.custom_fields[:status] = "open" topic.custom_fields[:assignee_id] = topic.custom_fields[:last_assigned_to_id] topic.custom_fields[:last_assigned_at] = Time.current.iso8601 end - + topic.custom_fields[:outcome] = nil topic.custom_fields[:closed_at] = nil end end - + topic.save_custom_fields CommunityCustomFields::TopicStatusChange.record( @@ -131,7 +133,7 @@ module ::CommunityCustomFields source: "post_creation", assignee_id: previous_assignee_id, post_id: post.id, - previous_status_at: previous_status_at + previous_status_at: previous_status_at, ) end end diff --git a/spec/system/core_features_spec.rb b/spec/system/core_features_spec.rb index 72ab0bf..db86db2 100644 --- a/spec/system/core_features_spec.rb +++ b/spec/system/core_features_spec.rb @@ -4,4 +4,4 @@ before { enable_current_plugin } it_behaves_like "having working core features" -end \ No newline at end of file +end