diff --git a/app/controllers/admin/custom_field_sections_controller.rb b/app/controllers/admin/custom_field_sections_controller.rb index 3f1e577d..152440f5 100644 --- a/app/controllers/admin/custom_field_sections_controller.rb +++ b/app/controllers/admin/custom_field_sections_controller.rb @@ -51,6 +51,7 @@ def custom_field_section_params custom_fields_attributes: [ :id, :key, + :label, :field_type, :hint, :options, diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb index c220a16e..194089b6 100644 --- a/app/controllers/admin/services_controller.rb +++ b/app/controllers/admin/services_controller.rb @@ -192,6 +192,7 @@ def service_params ], meta_attributes: [ :id, + :label, :key, :value ] diff --git a/app/controllers/api/v1/custom_fields_controller.rb b/app/controllers/api/v1/custom_fields_controller.rb new file mode 100644 index 00000000..11c83a0f --- /dev/null +++ b/app/controllers/api/v1/custom_fields_controller.rb @@ -0,0 +1,39 @@ +class API::V1::CustomFieldsController < ApplicationController + skip_before_action :authenticate_user! + + def index + render json: json_tree(CustomFieldSection.api_public.includes(:custom_fields)).to_json + end + + private + + def json_tree(custom_field_sections) + custom_field_sections.map do |section| + { + id: section.id, + name: section.name, + hint: section.hint, + custom_fields: section.custom_fields.map do |field| + field_hash = { + id: field.id, + label: field.label, + key: field.key, + hint: field.hint, + field_type: field.field_type + } + field_hash[:options] = process_options(field.options) if field.field_type == 'select' + field_hash + end + } + end + end + + def process_options(options_string) + options_string.split(',').map.with_index(1) do |option, index| + { + value: option.strip, + # key: option.strip.parameterize + } + end + end + end \ No newline at end of file diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index 74c4cfc4..bd71b817 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -158,6 +158,7 @@ def service_params meta_attributes: [ :id, :key, + :label, :value ] ) diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index 6ada0bd0..21ce449b 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -1,5 +1,8 @@ class CustomField < ApplicationRecord - validates :key, presence: true, uniqueness: true + before_validation :slugify_key + + validates :key, uniqueness: { allow_blank: true }, format: { with: /\A[a-z0-9\-]+\z/, message: "must be lowercase, numbers, and dashes only", allow_blank: true } + validates :label, presence: true, uniqueness: true validates_presence_of :field_type belongs_to :custom_field_section, counter_cache: :custom_fields_count @@ -12,4 +15,12 @@ def self.types "Date" ] end + + private + + def slugify_key + self.key = key.to_s.parameterize if key.present? + end + + end diff --git a/app/models/custom_field_section.rb b/app/models/custom_field_section.rb index 00b70f15..ec626193 100644 --- a/app/models/custom_field_section.rb +++ b/app/models/custom_field_section.rb @@ -7,4 +7,6 @@ class CustomFieldSection < ApplicationRecord default_scope { order(sort_order: :asc) } scope :visible_to, -> (current_user){ current_user.admin ? all : where(public: true) } + + scope :api_public, -> { where(api_public: true) } end diff --git a/app/models/regular_schedule.rb b/app/models/regular_schedule.rb index 1e654c2d..835e73ef 100644 --- a/app/models/regular_schedule.rb +++ b/app/models/regular_schedule.rb @@ -117,7 +117,7 @@ def description "Every #{month}#{day} from #{dtstart.strftime("%d/%m/%Y")} at #{opens_at.strftime("%I:%M%P")} to #{closes_at.strftime("%I:%M%P")}#{ends}" end else - "#{dtstart.strftime('%A%e %B %Y')} from #{opens_at.strftime("%I:%M%P")} to #{closes_at.strftime("%I:%M%P")}" + "#{dtstart.strftime('%A %e %B %Y')} from #{opens_at.strftime("%I:%M%P")} to #{closes_at.strftime("%I:%M%P")}" end else # opening time diff --git a/app/models/service_meta.rb b/app/models/service_meta.rb index ec884597..96175f36 100644 --- a/app/models/service_meta.rb +++ b/app/models/service_meta.rb @@ -1,5 +1,5 @@ class ServiceMeta < ApplicationRecord belongs_to :service - validates :key, presence: true - validates_uniqueness_of :key, scope: :service_id + validates :label, presence: true + validates_uniqueness_of :label, scope: :service_id end diff --git a/app/serializers/service_meta_serializer.rb b/app/serializers/service_meta_serializer.rb index c6f03512..b70b20a0 100644 --- a/app/serializers/service_meta_serializer.rb +++ b/app/serializers/service_meta_serializer.rb @@ -1,5 +1,6 @@ class ServiceMetaSerializer < ActiveModel::Serializer + attribute :label attribute :key attribute :value end \ No newline at end of file diff --git a/app/views/admin/custom_field_sections/_fields.html.erb b/app/views/admin/custom_field_sections/_fields.html.erb index 38f81cd2..701c2d57 100644 --- a/app/views/admin/custom_field_sections/_fields.html.erb +++ b/app/views/admin/custom_field_sections/_fields.html.erb @@ -39,7 +39,7 @@ diff --git a/app/views/admin/custom_field_sections/_repeatable-fields.html.erb b/app/views/admin/custom_field_sections/_repeatable-fields.html.erb index 0c413a81..efa2d02e 100644 --- a/app/views/admin/custom_field_sections/_repeatable-fields.html.erb +++ b/app/views/admin/custom_field_sections/_repeatable-fields.html.erb @@ -1,7 +1,7 @@
- <%= c.label :key, "Label", class: "field__label" %> - <%= c.text_field :key, class: "field__input" %> + <%= c.label :label, "Label", class: "field__label" %> + <%= c.text_field :label, class: "field__input" %>
@@ -20,6 +20,15 @@ <%= c.text_area :hint, class: "field__input", rows: 1 %>
+<% if @section.api_public %> +
+ <%= c.label :key, "Key", class: "field__label" %> +

This is a unique field used to refer to this field in the API

+ <%= c.text_field :key, class: "field__input", data: { slugify: true } %> +
+<% end %> + + <%= c.hidden_field :_destroy, data: {destroy_field: true} %> \ No newline at end of file diff --git a/app/views/admin/services/editors/_custom-fields.html.erb b/app/views/admin/services/editors/_custom-fields.html.erb index e7a12746..d1367a83 100644 --- a/app/views/admin/services/editors/_custom-fields.html.erb +++ b/app/views/admin/services/editors/_custom-fields.html.erb @@ -8,20 +8,21 @@ <% end %> <% section.custom_fields.each do |field| %> - <% meta = s.object.meta.find_or_initialize_by(key: field.key) %> + <% meta = s.object.meta.find_or_initialize_by(label: field.label, key: field.key) %> <%= s.fields_for :meta, meta do |c| %> + <%= c.hidden_field :label %> <%= c.hidden_field :key %> <% if field.field_type === "checkbox" %>
<%= c.check_box :value, {class: "checkbox__input"}, "Yes", "No" %> - <%= c.label :value, field.key, class: "checkbox__label" %> + <%= c.label :value, field.label, class: "checkbox__label" %>
<% else %>
- <%= c.label :value, field.key, class: "field__label" %> + <%= c.label :value, field.label, class: "field__label" %> <% if field.hint.present? %>

<%= field.hint %>

<% end %> diff --git a/config/routes.rb b/config/routes.rb index c8bbf451..c50a37ef 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -82,6 +82,7 @@ resources :accessibilities, only: [:index] get "me", to: "me#show" resources :services, only: [:index, :show] + resources :custom_fields, only: [:index] end end diff --git a/db/migrate/20241111163850_add_custom_field_label.rb b/db/migrate/20241111163850_add_custom_field_label.rb new file mode 100644 index 00000000..53b64363 --- /dev/null +++ b/db/migrate/20241111163850_add_custom_field_label.rb @@ -0,0 +1,14 @@ +class AddCustomFieldLabel < ActiveRecord::Migration[6.0] + def change + # Add new label column + add_column :custom_fields, :label, :string + + # Copy data from key to label (only on up migration) + reversible do |dir| + dir.up do + CustomField.reset_column_information + CustomField.update_all('label = key') + end + end + end +end diff --git a/db/migrate/20241111181710_add_service_meta_label.rb b/db/migrate/20241111181710_add_service_meta_label.rb new file mode 100644 index 00000000..7eab7033 --- /dev/null +++ b/db/migrate/20241111181710_add_service_meta_label.rb @@ -0,0 +1,14 @@ +class AddServiceMetaLabel < ActiveRecord::Migration[6.0] + def change + # Add new label column + add_column :service_meta, :label, :string + + # Copy data from key to label (only on up migration) + reversible do |dir| + dir.up do + ServiceMeta.reset_column_information + ServiceMeta.update_all('label = key') + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 32ba2452..49336f1a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2024_09_18_091413) do +ActiveRecord::Schema.define(version: 2024_11_11_181710) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -87,6 +87,7 @@ t.string "hint" t.bigint "custom_field_section_id", null: false t.string "options" + t.string "label" t.index ["custom_field_section_id"], name: "index_custom_fields_on_custom_field_section_id" end @@ -318,6 +319,7 @@ t.string "value" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.string "label" t.index ["service_id"], name: "index_service_meta_on_service_id" end diff --git a/lib/tasks/data_import/custom_fields/custom_fields.rake b/lib/tasks/data_import/custom_fields/custom_fields.rake index f41a7eeb..124e01ff 100644 --- a/lib/tasks/data_import/custom_fields/custom_fields.rake +++ b/lib/tasks/data_import/custom_fields/custom_fields.rake @@ -43,7 +43,7 @@ namespace :import do Rails.logger.info("🟠 Field: \"#{row["name"]}\" already exists, skipping.") else custom_field = CustomField.new( - key: row["name"]&.strip, + label: row["name"]&.strip, field_type: row["field_type"].downcase, options: row["field_options"], hint: row["hint"], diff --git a/lib/tasks/data_import/services/import_services.rake b/lib/tasks/data_import/services/import_services.rake index 15a25068..ca50bb1f 100644 --- a/lib/tasks/data_import/services/import_services.rake +++ b/lib/tasks/data_import/services/import_services.rake @@ -68,7 +68,7 @@ namespace :import do def import_service_meta(type, service_id, fields_for_import, row) fields_for_import.map do |t| # Find the existing custom field to add this service meta to - custom_field = CustomField.where(field_type: type).find{|cf| cf.key.downcase.delete("^a-zA-Z0-9 ").gsub(' ', '_') === t} + custom_field = CustomField.where(field_type: type).find{|cf| cf.label.downcase.delete("^a-zA-Z0-9 ").gsub(' ', '_') === t} unless custom_field.present? Rails.logger.info("🟠 Custom field \"#{t}\" of type #{type} does not exist. Please check the field name or create the custom field in order to add this service data. Perhaps you have forgotten to run the custom field import?") @@ -91,7 +91,7 @@ namespace :import do end if value.present? - new_service_meta = ServiceMeta.find_or_initialize_by(service_id: service_id, key: custom_field.key) do |new_sm| + new_service_meta = ServiceMeta.find_or_initialize_by(service_id: service_id, label: custom_field.label) do |new_sm| new_sm.value = value end diff --git a/spec/factories/custom_field.rb b/spec/factories/custom_field.rb index 1ae24899..ac0393a2 100644 --- a/spec/factories/custom_field.rb +++ b/spec/factories/custom_field.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :custom_field do - key { Faker::Lorem.sentence } + label { Faker::Lorem.sentence } field_type { 'text' } custom_field_section diff --git a/spec/factories/service_meta.rb b/spec/factories/service_meta.rb index c5fe941f..2edf68c9 100644 --- a/spec/factories/service_meta.rb +++ b/spec/factories/service_meta.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory :service_meta do - key { Faker::Lorem.sentence } + label { Faker::Lorem.sentence } value { Faker::Number.number } end end \ No newline at end of file diff --git a/spec/models/custom_field_spec.rb b/spec/models/custom_field_spec.rb index 21d844fc..ca040e4f 100644 --- a/spec/models/custom_field_spec.rb +++ b/spec/models/custom_field_spec.rb @@ -3,7 +3,7 @@ RSpec.describe CustomField, type: :model do subject { FactoryBot.build :custom_field } - it { should validate_presence_of :key } - it { should validate_uniqueness_of :key } + it { should validate_presence_of :label } + it { should validate_uniqueness_of :label } it { should validate_presence_of :field_type } end diff --git a/spec/models/regular_schedule_spec.rb b/spec/models/regular_schedule_spec.rb index 828296ce..ba95d84a 100644 --- a/spec/models/regular_schedule_spec.rb +++ b/spec/models/regular_schedule_spec.rb @@ -405,10 +405,10 @@ context 'event times' do - let(:dtstart) { DateTime.new(2023, 10, 4) } # Wednesday + let(:dtstart) { Date.new(2023, 10, 4) } # Wednesday context 'single event time' do it 'should return description of the single event time' do - expect(regular_schedule.description).to eq("#{dtstart.strftime('%A%e %B %Y')} from #{opens_at.strftime("%I:%M%P")} to #{closes_at.strftime("%I:%M%P")}") + expect(regular_schedule.description).to eq("#{dtstart.strftime('%A %e %B %Y')} from #{opens_at.strftime("%I:%M%P")} to #{closes_at.strftime("%I:%M%P")}") end end diff --git a/spec/models/service_meta_spec.rb b/spec/models/service_meta_spec.rb index 7ecab145..04fed37a 100644 --- a/spec/models/service_meta_spec.rb +++ b/spec/models/service_meta_spec.rb @@ -3,6 +3,6 @@ RSpec.describe ServiceMeta, type: :model do subject { FactoryBot.create :service_meta, service: FactoryBot.create(:service) } - it { should validate_presence_of(:key) } - it { should validate_uniqueness_of(:key).scoped_to(:service_id) } + it { should validate_presence_of(:label) } + it { should validate_uniqueness_of(:label).scoped_to(:service_id) } end diff --git a/spec/tasks/data_import/services_spec.rb b/spec/tasks/data_import/services_spec.rb index eb888116..08dc6111 100644 --- a/spec/tasks/data_import/services_spec.rb +++ b/spec/tasks/data_import/services_spec.rb @@ -58,11 +58,11 @@ context 'with custom fields in the DB' do before do - FactoryBot.create :custom_field, key: 'text field' - FactoryBot.create :custom_field, :number, key: 'number field' - FactoryBot.create :custom_field, :checkbox, key: 'checkbox field' - FactoryBot.create :custom_field, :date, key: 'date field' - FactoryBot.create :custom_field, :select, key: 'select field' + FactoryBot.create :custom_field, label: 'text field' + FactoryBot.create :custom_field, :number, label: 'number field' + FactoryBot.create :custom_field, :checkbox, label: 'checkbox field' + FactoryBot.create :custom_field, :date, label: 'date field' + FactoryBot.create :custom_field, :select, label: 'select field' end it 'creates the service meta' do