diff --git a/app/controllers/admin/categories_controller.rb b/app/controllers/admin/categories_controller.rb index 73e1599e94..9cf04697bd 100644 --- a/app/controllers/admin/categories_controller.rb +++ b/app/controllers/admin/categories_controller.rb @@ -4,13 +4,17 @@ class Admin::CategoriesController < AdminController include TranslatableParams - before_action :check_klass - before_action :set_root, expect: [:destroy, :reorder] before_action :set_category, only: [:edit, :update, :destroy, :reorder] + before_action :set_root, except: [:destroy, :reorder] + before_action :check_klass def index end + def show + redirect_to action: :edit + end + def new @category = Category.new @category.build_all_translations @@ -75,24 +79,25 @@ def reorder_categories(category_ids) def category_params category_params = translatable_params( params.require(:category), - translated_keys: [:locale, :title, :description], + translated_keys: [:locale, :title, :description, :body], general_keys: [:category_tag, :parent_ids] ) category_params[:parent_ids] ||= [@root.id] category_params end - def set_root - @root = current_klass.category_root - end - def set_category @category = Category.find(params[:id]) end + def set_root + @root = current_klass&.category_root + end + helper_method :current_klass def current_klass - params.fetch(:model_type, 'PublicBody').safe_constantize + @klass ||= @category.root.title.safe_constantize if @category&.root + @klass ||= params.fetch(:model_type, 'PublicBody').safe_constantize end def check_klass diff --git a/app/helpers/admin/link_helper.rb b/app/helpers/admin/link_helper.rb index 698decba76..d9241392d8 100644 --- a/app/helpers/admin/link_helper.rb +++ b/app/helpers/admin/link_helper.rb @@ -102,6 +102,12 @@ def track_thing_both_links(track_thing) link_to(icon, icon_link, title: title) + ' ' + "#{track_thing.id}:" end + def category_both_links(category) + # No public links, yet? + link_to(category.title, edit_admin_category_path(category), + title: admin_title) + end + def admin_title 'View full details' end diff --git a/app/models/category.rb b/app/models/category.rb index 9b9ac796f3..6267131809 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -16,6 +16,8 @@ # categories and translatable titles/descriptions. # class Category < ApplicationRecord + include Notable + has_many :parent_relationships, class_name: 'CategoryRelationship', foreign_key: 'child_id', @@ -39,7 +41,10 @@ class Category < ApplicationRecord class_name: 'HasTagString::HasTagStringTag' translates :title, :description + translates :body, touch: true include Translatable + delegate :body, :body=, :body?, to: :translation + after_save { body.save if body.changed? } validates :title, presence: true validate :check_tag_assignments, on: :update @@ -54,6 +59,16 @@ def tree end def list + Category.where(id: list_ids).includes(:translations) + end + + def root + Category.roots.find { _1.list_ids.include?(id) } + end + + protected + + def list_ids sql = <<~SQL.squish WITH RECURSIVE nested_categories AS ( SELECT child_id @@ -70,8 +85,7 @@ def list INNER JOIN nested_categories nc ON c.id = nc.child_id; SQL - ids = Category.find_by_sql([sql, { parent_id: id }]).map(&:id) - Category.where(id: ids).includes(:translations) + Category.find_by_sql([sql, { parent_id: id }]).map(&:id) end private @@ -85,4 +99,8 @@ def check_tag_assignments message: "can't be changed as there are associated objects present" ) end + + class Translation # :nodoc: + has_rich_text :body + end end diff --git a/app/models/concerns/notable.rb b/app/models/concerns/notable.rb index a9f1739cb7..bd881c2f8f 100644 --- a/app/models/concerns/notable.rb +++ b/app/models/concerns/notable.rb @@ -10,7 +10,10 @@ module Notable end def all_notes - concrete_notes.with_translations + tagged_notes.with_translations + notes = concrete_notes.with_translations + return notes.to_a unless Taggable.models.include?(self.class) + + notes + tagged_notes.with_translations end def tagged_notes diff --git a/app/views/admin/categories/_form.html.erb b/app/views/admin/categories/_form.html.erb index 1d1cd4cfde..dff92bdf17 100644 --- a/app/views/admin/categories/_form.html.erb +++ b/app/views/admin/categories/_form.html.erb @@ -40,3 +40,9 @@ <% end %> <% end %> + + +

Notes

+ +<%= render partial: 'admin/notes/show', + locals: { notes: @category.all_notes, notable: @category } %> diff --git a/app/views/admin/categories/_locale_fields.html.erb b/app/views/admin/categories/_locale_fields.html.erb index 77134a75a6..bc4e5e7221 100644 --- a/app/views/admin/categories/_locale_fields.html.erb +++ b/app/views/admin/categories/_locale_fields.html.erb @@ -11,3 +11,10 @@ <%= t.text_field :description, class: "span4" %> + +
+ <%= t.label :body, class: 'control-label' %> +
+ <%= t.rich_text_area :body %> +
+
diff --git a/doc/CHANGES.md b/doc/CHANGES.md index 99cea028db..e1aa74cc4a 100644 --- a/doc/CHANGES.md +++ b/doc/CHANGES.md @@ -2,6 +2,7 @@ ## Highlighted Features +* Allow categories to have notes associated with them (Graeme Porteous) * Add styling option and rich text editor to the notes admin (Graeme Porteous) * Strengthen 2FA warning. Users *must* remember to keep this code safe (Gareth Rees) diff --git a/spec/controllers/admin/categories_controller_spec.rb b/spec/controllers/admin/categories_controller_spec.rb index 78b9a1f9b4..67a0d5572f 100644 --- a/spec/controllers/admin/categories_controller_spec.rb +++ b/spec/controllers/admin/categories_controller_spec.rb @@ -27,6 +27,14 @@ end end + describe 'GET show' do + it 'redirects to the edit action' do + category = FactoryBot.create(:category) + get :show, params: { id: category.id } + expect(response).to redirect_to(edit_admin_category_path(category)) + end + end + describe 'GET new' do it 'assigns root for correct model' do get :new, params: { model_type: 'PublicBody' } @@ -255,7 +263,7 @@ } end - it 'assigns root for correct model' do + it 'overrides model type param in favor of the categories root' do patch :update, params: { model_type: 'PublicBody', id: category.id, @@ -268,7 +276,7 @@ id: category.id, category: params } - expect(assigns(:root)).to eq(InfoRequest.category_root) + expect(assigns(:root)).to eq(PublicBody.category_root) end it 'finds the category to update' do diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index 4f0b12a7e5..2b1a69aec1 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -12,8 +12,11 @@ # require 'spec_helper' +require 'models/concerns/notable' RSpec.describe Category, type: :model do + it_behaves_like 'concerns/notable', :category + set_fixture_class has_tag_string_tags: HasTagString::HasTagStringTag let(:category) { FactoryBot.build(:category) } @@ -214,4 +217,36 @@ expect { list.each(&:title) }.to_not change { @query_count } end end + + describe '#root' do + subject { branch.root } + + let(:root) do + FactoryBot.create(:category, title: 'PublicBody') + end + + let(:trunk) do + FactoryBot.create(:category, title: 'Trunk', parents: [root]) + end + + let(:branch) do + FactoryBot.create(:category, title: 'Branch', parents: [trunk]) + end + + it 'returns uppermost root category' do + expect(branch.root).to eq(root) + end + end + + describe 'translations' do + def plain_body + category.body_translations.transform_values(&:to_plain_text) + end + + it 'adds translated body' do + expect(plain_body).to_not include(es: 'content') + AlaveteliLocalization.with_locale(:es) { category.body = 'content' } + expect(plain_body).to include(es: 'content') + end + end end