diff --git a/app/controllers/admin/boxes_controller.rb b/app/controllers/admin/boxes_controller.rb
index f4e127a72..673bd532e 100644
--- a/app/controllers/admin/boxes_controller.rb
+++ b/app/controllers/admin/boxes_controller.rb
@@ -3,7 +3,7 @@ class Admin::BoxesController < ApplicationController
def index
authorize Box
- @boxes = policy_scope([:admin, Box])
+ @boxes = policy_scope([:admin, Box]).order(:name)
end
def show
diff --git a/app/controllers/admin/group_memberships_controller.rb b/app/controllers/admin/group_memberships_controller.rb
index 418c3e230..9f02bfca6 100644
--- a/app/controllers/admin/group_memberships_controller.rb
+++ b/app/controllers/admin/group_memberships_controller.rb
@@ -1,10 +1,9 @@
class Admin::GroupMembershipsController < ApplicationController
before_action :set_group_membership, only: %i[destroy]
- # TODO - rediscuss the whole concept of SITE_ADMIN vs TENANT admin responsibilities and functionality
def create
- # TODO: Takto mi teoreticky moze vzniknut neopravneny membership, lebo nekontrolujem tenanta. Ako spravit tak, aby som nezacal pisat exlpicitne rucne kontroly?
- @group_membership = GroupMembership.new(group_membership_params)
+ @group = Current.tenant.groups.find(group_membership_params[:group_id])
+ @group_membership = @group.group_memberships.build(group_membership_params)
authorize([:admin, @group_membership])
if @group_membership.save
@@ -17,15 +16,19 @@ def create
def destroy
authorize([:admin, @group_membership])
- @group_membership.destroy
- redirect_to edit_members_admin_tenant_group_path(Current.tenant, @group_membership.group),
- notice: 'Group was membership was successfully deleted'
+ if @group_membership.destroy
+ redirect_to edit_members_admin_tenant_group_path(Current.tenant, @group_membership.group),
+ notice: 'Group was membership was successfully deleted'
+ else
+ flash[:alert] = @group_membership.errors.full_messages[0]
+ redirect_to edit_members_admin_tenant_group_path(Current.tenant, @group_membership.group)
+ end
end
private
def set_group_membership
- @group_membership = policy_scope([:admin,GroupMembership]).find(params[:id])
+ @group_membership = policy_scope([:admin, GroupMembership]).find(params[:id])
end
def group_membership_params
diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb
index 0c7706902..b6d81b732 100644
--- a/app/controllers/admin/tags_controller.rb
+++ b/app/controllers/admin/tags_controller.rb
@@ -1,12 +1,13 @@
class Admin::TagsController < ApplicationController
- before_action :set_tag, only: %i[show edit update destroy visibility_toggle]
+ before_action :set_tag, only: %i[show edit update destroy]
+
+ include TagCreation
def index
authorize [:admin, Tag]
- tags = policy_scope([:admin, Tag]).order(:name)
+ tags = policy_scope([:admin, Tag]).includes(:tenant).order(:name)
- @external_tags = tags.where(external: true)
- @internal_tags = tags.where(external: false)
+ @simple_tags = tags.simple
end
def show
@@ -15,52 +16,51 @@ def show
end
def new
- @tag = Current.tenant.tags.new
- authorize([:admin, @tag])
+ @tag = SimpleTag.new
+ authorize(@tag, policy_class: Admin::TagPolicy)
end
def edit
- authorize([:admin, @tag])
+ authorize(@tag, policy_class: Admin::TagPolicy)
end
def create
- @tag = Current.tenant.tags.new(tag_params)
- @tag.user_id = Current.user.id
- authorize([:admin, @tag])
+ @tag = SimpleTag.new(simple_tag_params.merge(simple_tag_creation_params))
+ authorize(@tag, policy_class: Admin::TagPolicy)
if @tag.save
- redirect_to admin_tenant_tags_path(Current.tenant), notice: 'Tag was successfully created'
+ redirect_to admin_tenant_tags_path(Current.tenant), notice: "Štítok bol úspešne vytvorený"
else
render :new, status: :unprocessable_entity
end
end
def update
- authorize([:admin, @tag])
- if @tag.update(tag_params)
- redirect_to admin_tenant_tags_path(Current.tenant), notice: 'Tag was successfully updated'
+ authorize(@tag, policy_class: Admin::TagPolicy)
+
+ if @tag.update(simple_tag_params)
+ redirect_to admin_tenant_tags_path(Current.tenant), notice: "Štítok bol úspešne upravený"
else
render :edit, status: :unprocessable_entity
end
end
def destroy
- authorize([:admin, @tag])
- @tag.destroy
- redirect_to admin_tenant_tags_path(Current.tenant), notice: 'Tag was successfully created'
+ authorize(@tag, policy_class: Admin::TagPolicy)
+ if @tag.destroy
+ redirect_to admin_tenant_tags_path(Current.tenant), notice: "Štítok bol úspešne odstránený"
+ else
+ redirect_to admin_tenant_tags_path(Current.tenant), alert: @tag.errors.full_messages[0]
+ end
end
private
def set_tag
- @tag = Tag.find(params[:id])
- end
-
- def tag_params
- params.require(:tag).permit(:name, :visible, :user_id, :tenant_id)
+ @tag = SimpleTag.find(params[:id])
end
- def tag_params_visibility
- params.permit(:visible)
+ def simple_tag_params
+ params.require(:simple_tag).permit(:name, :visible, :color, :icon)
end
end
diff --git a/app/controllers/admin/tenants_controller.rb b/app/controllers/admin/tenants_controller.rb
deleted file mode 100644
index 8cc883821..000000000
--- a/app/controllers/admin/tenants_controller.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-class Admin::TenantsController < ApplicationController
- before_action :set_tenant, only: %i[show edit update destroy]
-
- def index
- authorize([:admin, Tenant])
- @tenants = policy_scope([:admin, Tenant])
- end
-
- def show
- @tenant = policy_scope([:admin, Tenant]).find(params[:id])
- authorize([:admin, @tenant])
- session[:tenant_id] = @tenant.id
- Current.tenant = @tenant
- end
-
- def new
- @tenant = Tenant.new
- authorize([:admin, @tenant])
- end
-
- def edit
- authorize([:admin, @tenant])
- end
-
- def create
- @tenant = Tenant.new(tenant_params)
- authorize([:admin, @tenant])
- if @tenant.save
- redirect_to admin_tenants_url, notice: 'Tenant was successfully created'
- else
- render :new, status: :unprocessable_entity
- end
- end
-
- # PATCH/PUT /tenants/1 or /tenants/1.json
- def update
- authorize([:admin, @tenant])
- if @tenant.update(tenant_params)
- redirect_to admin_tenants_url, notice: 'Tenant was successfully updated'
- else
- render :edit, status: :unprocessable_entity
- end
- end
-
- # DELETE /tenants/1 or /tenants/1.json
- def destroy
- authorize([:admin, @tenant])
- @tenant.destroy
- session[:tenant_id] = nil if Current.tenant == @tenant
- redirect_to admin_tenants_url, notice: 'Tenant was successfully destroyed'
- end
-
- private
-
- # Use callbacks to share common setup or constraints between actions.
- def set_tenant
- @tenant = Tenant.find(params[:id])
- end
-
- # Only allow a list of trusted parameters through.
- def tenant_params
- params.require(:tenant).permit(:name)
- end
-end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index feba69499..367866d8f 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -3,7 +3,7 @@ class Admin::UsersController < ApplicationController
def index
authorize([:admin, User])
- @users = policy_scope([:admin, User]).where(tenant_id: Current.tenant.id)
+ @users = policy_scope([:admin, User]).where(tenant_id: Current.tenant.id).order(:name)
end
def new
@@ -37,8 +37,12 @@ def update
def destroy
authorize([:admin, @user])
- @user.destroy
- redirect_to admin_tenant_users_url(Current.tenant), notice: 'User was successfully destroyed'
+ if @user.destroy
+ redirect_to admin_tenant_users_url(Current.tenant), notice: 'User was successfully destroyed'
+ else
+ flash[:alert] = @user.errors.full_messages[0]
+ redirect_to admin_tenant_users_url(Current.tenant)
+ end
end
private
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index cbeab931e..90ae21fb2 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base
include Authentication
include Pundit::Authorization
after_action :verify_authorized
- after_action :verify_policy_scoped, only: :index
+ after_action :verify_policy_scoped, only: :index if respond_to?(:index)
before_action :set_menu_context
def pundit_user
diff --git a/app/controllers/concerns/tag_creation.rb b/app/controllers/concerns/tag_creation.rb
index 85e963194..8cd2f16b7 100644
--- a/app/controllers/concerns/tag_creation.rb
+++ b/app/controllers/concerns/tag_creation.rb
@@ -1,5 +1,5 @@
module TagCreation
- def tag_creation_params
+ def simple_tag_creation_params
{
owner: Current.user,
tenant: Current.tenant,
diff --git a/app/controllers/health_check_controller.rb b/app/controllers/health_check_controller.rb
new file mode 100644
index 000000000..1202a5929
--- /dev/null
+++ b/app/controllers/health_check_controller.rb
@@ -0,0 +1,34 @@
+class HealthCheckController < ApplicationController
+ skip_before_action :authenticate
+ skip_after_action :verify_authorized
+ skip_before_action :set_menu_context
+
+ def show
+ if ActiveRecord::Base.connection.active?
+ render status: :ok, json: { ok: true }
+ else
+ render status: :service_unavailable, json: { ok: false }
+ end
+ rescue Exception
+ render status: :service_unavailable, json: { ok: false }
+ end
+
+ def failing_jobs
+ failed_jobs = GoodJob::Job.where.not(error: nil)
+ if failed_jobs.any?
+ render status: :service_unavailable,
+ json: { ok: false }
+ else
+ render status: :ok, json: { ok: true }
+ end
+ end
+
+ def stuck_jobs
+ stuck_jobs = GoodJob::Job.where(finished_at: nil).where("COALESCE(scheduled_at, created_at) < ?", 30.minutes.ago)
+ if stuck_jobs.any?
+ render status: :service_unavailable, json: { ok: false }
+ else
+ render status: :ok, json: { ok: true }
+ end
+ end
+end
diff --git a/app/controllers/message_drafts_controller.rb b/app/controllers/message_drafts_controller.rb
index f88565467..602734f5a 100644
--- a/app/controllers/message_drafts_controller.rb
+++ b/app/controllers/message_drafts_controller.rb
@@ -30,7 +30,6 @@ def update
authorize @message
permitted_params = message_params
-
@message.update_content(title: permitted_params["message_title"], body: permitted_params["message_text"])
end
@@ -40,7 +39,6 @@ def submit
if @message.submittable?
Govbox::SubmitMessageDraftJob.perform_later(@message)
@message.being_submitted!
-
redirect_to message_thread_path(@message.thread), notice: "Správa bola zaradená na odoslanie"
else
# TODO: prisposobit chybovu hlasku aj importovanym draftom
@@ -58,7 +56,7 @@ def submit_all
message_draft.being_submitted!
end
- boxes_to_sync = Current.tenant.boxes.joins(message_threads: :messages).where(messages: { id: @messages.map(&:id) } ).uniq
+ boxes_to_sync = Current.tenant.boxes.joins(message_threads: :messages).where(messages: { id: @messages.map(&:id) }).uniq
jobs_batch.enqueue(on_finish: Govbox::ScheduleDelayedSyncBoxJob, boxes: boxes_to_sync)
end
@@ -72,6 +70,19 @@ def destroy
redirect_to redirect_path, notice: "Draft bol zahodený"
end
+ def unlock
+ authorize @message
+ if @message.remove_form_signature
+ redirect_to message_thread_path(@message.thread), notice: "Podpisy boli úspešne odstránené, správu je možné upravovať"
+ else
+ redirect_to message_thread_path(@message.thread), alert: "Nastala neočakávaná chyba, nepodarilo sa odstrániť podpisy"
+ end
+ end
+
+ def confirm_unlock
+ authorize @message
+ end
+
private
def load_message_drafts
diff --git a/app/controllers/message_threads/bulk/tags_controller.rb b/app/controllers/message_threads/bulk/tags_controller.rb
index 2912e65e4..7e8ce07ea 100644
--- a/app/controllers/message_threads/bulk/tags_controller.rb
+++ b/app/controllers/message_threads/bulk/tags_controller.rb
@@ -27,8 +27,8 @@ def prepare
end
def create_tag
- new_tag = Tag.new(tag_creation_params.merge(name: params[:new_tag].strip))
- authorize(new_tag, "create?")
+ new_tag = SimpleTag.new(simple_tag_creation_params.merge(name: params[:new_tag].strip))
+ authorize(new_tag, "create?", policy_class: TagPolicy)
@tags_changes = TagsChanges.new(
tag_scope: tag_scope,
@@ -61,7 +61,7 @@ def update
private
def tag_scope
- Current.tenant.tags.visible.order(:name)
+ Current.tenant.simple_tags.visible.order(:name)
end
def message_thread_policy_scope
diff --git a/app/controllers/message_threads/tags_controller.rb b/app/controllers/message_threads/tags_controller.rb
index 53bbb6688..e48e68c20 100644
--- a/app/controllers/message_threads/tags_controller.rb
+++ b/app/controllers/message_threads/tags_controller.rb
@@ -27,8 +27,8 @@ def prepare
end
def create_tag
- new_tag = Tag.new(tag_creation_params.merge(name: params[:new_tag].strip))
- authorize(new_tag, "create?")
+ new_tag = SimpleTag.new(simple_tag_creation_params.merge(name: params[:new_tag].strip))
+ authorize(new_tag, "create?", policy_class: TagPolicy)
@tags_changes = TagsChanges.new(
tag_scope: tag_scope,
@@ -64,7 +64,7 @@ def set_message_thread
end
def tag_scope
- Current.tenant.tags.visible.order(:name)
+ Current.tenant.simple_tags.visible.order(:name)
end
def message_thread_policy_scope
diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb
index f91170ccb..ce6695b20 100644
--- a/app/controllers/message_threads_controller.rb
+++ b/app/controllers/message_threads_controller.rb
@@ -1,5 +1,5 @@
class MessageThreadsController < ApplicationController
- before_action :set_message_thread, only: %i[show rename update search_available_tags history]
+ before_action :set_message_thread, only: %i[show rename update history]
before_action :set_thread_tags, only: %i[show history]
before_action :set_thread_messages, only: %i[show history]
before_action :load_threads, only: %i[index scroll]
@@ -16,11 +16,11 @@ def rename
end
def update
+ # currently only title update (rename) expected
authorize @message_thread
path = message_thread_path(@message_thread)
-
- return unless @message_thread.update(message_thread_params)
+ return unless @message_thread.rename(message_thread_params)
redirect_back fallback_location: path, notice: 'Názov vlákna bol upravený'
end
diff --git a/app/components/service_worker_controller.rb b/app/controllers/service_worker_controller.rb
similarity index 87%
rename from app/components/service_worker_controller.rb
rename to app/controllers/service_worker_controller.rb
index dbbc64d6c..f5fca23b9 100644
--- a/app/components/service_worker_controller.rb
+++ b/app/controllers/service_worker_controller.rb
@@ -3,7 +3,6 @@ class ServiceWorkerController < ApplicationController
# TODO make this a one call
skip_before_action :authenticate
skip_after_action :verify_authorized
- skip_after_action :verify_policy_scoped
skip_before_action :set_menu_context
def service_worker
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index bf17d36f1..e8135bea3 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -1,7 +1,6 @@
class SessionsController < ApplicationController
skip_before_action :authenticate
skip_after_action :verify_authorized
- skip_after_action :verify_policy_scoped
skip_before_action :set_menu_context
layout 'login'
@@ -10,9 +9,11 @@ def login
def create
create_session
+ EventBus.publish(:user_logged_in, Current.user)
end
def destroy
+ EventBus.publish(:user_logged_out, User.find_by(id: session[:user_id]))
clean_session
redirect_to root_path
diff --git a/app/helpers/colorized_helper.rb b/app/helpers/colorized_helper.rb
new file mode 100644
index 000000000..0f9b49105
--- /dev/null
+++ b/app/helpers/colorized_helper.rb
@@ -0,0 +1,29 @@
+module ColorizedHelper
+ def color_select_options
+ [""] + Colorized.colors.map { |color| [color, { class: "bg-#{color}-100 text-#{color}-600" }] }
+ end
+end
+
+# NOTE: Tailwind processor catches these
+# class="bg-slate-50 border-slate-400 text-slate-600 ring-slate-500/10"
+# class="bg-gray-50 border-gray-400 text-gray-600 ring-gray-500/10"
+# class="bg-zinc-50 border-zinc-400 text-zinc-600 ring-zinc-500/10"
+# class="bg-neutral-50 border-neutral-400 text-neutral-600 ring-neutral-500/10"
+# class="bg-stone-50 border-stone-400 text-stone-600 ring-stone-500/10"
+# class="bg-red-50 border-red-400 text-red-600 ring-red-500/10"
+# class="bg-orange-50 border-orange-400 text-orange-600 ring-orange-500/10"
+# class="bg-amber-50 border-amber-400 text-amber-600 ring-amber-500/10"
+# class="bg-yellow-50 border-yellow-400 text-yellow-600 ring-yellow-500/10"
+# class="bg-lime-50 border-lime-400 text-lime-600 ring-lime-500/10"
+# class="bg-green-50 border-green-400 text-green-600 ring-green-500/10"
+# class="bg-emerald-50 border-emerald-400 text-emerald-600 ring-emerald-500/10"
+# class="bg-teal-50 border-teal-400 text-teal-600 ring-teal-500/10"
+# class="bg-cyan-50 border-cyan-400 text-cyan-600 ring-cyan-500/10"
+# class="bg-sky-50 border-sky-400 text-sky-600 ring-sky-500/10"
+# class="bg-blue-50 border-blue-400 text-blue-600 ring-blue-500/10"
+# class="bg-indigo-50 border-indigo-400 text-indigo-600 ring-indigo-500/10"
+# class="bg-violet-50 border-violet-400 text-violet-600 ring-violet-500/10"
+# class="bg-purple-50 border-purple-400 text-purple-600 ring-purple-500/10"
+# class="bg-fuchsia-50 border-fuchsia-400 text-fuchsia-600 ring-fuchsia-500/10"
+# class="bg-pink-50 border-pink-400 text-pink-600 ring-pink-500/10"
+# class="bg-rose-50 border-rose-400 text-rose-600 ring-rose-500/10"
diff --git a/app/helpers/iconized_helper.rb b/app/helpers/iconized_helper.rb
new file mode 100644
index 000000000..529202e7f
--- /dev/null
+++ b/app/helpers/iconized_helper.rb
@@ -0,0 +1,5 @@
+module IconizedHelper
+ def icon_select_options
+ [""] + Iconized.icons
+ end
+end
diff --git a/app/helpers/tenants_helper.rb b/app/helpers/tenants_helper.rb
deleted file mode 100644
index b7bb45d08..000000000
--- a/app/helpers/tenants_helper.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-module TenantsHelper
-end
diff --git a/app/javascript/controllers/all_checkboxes_controller.js b/app/javascript/controllers/all_checkboxes_controller.js
index b3e9a615e..f2e7c82fb 100644
--- a/app/javascript/controllers/all_checkboxes_controller.js
+++ b/app/javascript/controllers/all_checkboxes_controller.js
@@ -27,7 +27,7 @@ export default class extends Controller {
else if (!input.checked && target_state == "true") target_state = "indeterminate";
});
- if (target_state == "false") this.checkboxTarget.checked = false;
+ if (!target_state || target_state == "false") this.checkboxTarget.checked = false;
else if (target_state == "true") this.checkboxTarget.checked = true;
else this.checkboxTarget.indeterminate = true;
}
diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js
index fe27a219b..1aa77e206 100644
--- a/app/javascript/controllers/application.js
+++ b/app/javascript/controllers/application.js
@@ -16,5 +16,23 @@ application.register('tabs', Tabs)
application.register('popover', Popover)
application.register('toggle', Toggle)
application.register('slideover', Slideover)
+document.addEventListener('turbo:before-cache', function(event) {
+ const setOpenAsFalse = (attribute) => {
+ const element = event.target.querySelector(`[${attribute}="true"]`)
+ element?.setAttribute(attribute, "false")
+ }
+
+ const addHiddenClass = () => {
+ event.target.querySelectorAll("[data-turbo-temporary-hide]").forEach((elm) => {
+ if (!elm.classList.contains('hidden')) {
+ elm.classList.add('hidden')
+ }
+ })
+ }
+
+ addHiddenClass()
+ setOpenAsFalse('data-slideover-open-value')
+ setOpenAsFalse('data-dropdown-open-value')
+})
export { application }
\ No newline at end of file
diff --git a/app/javascript/controllers/message_drafts_controller.js b/app/javascript/controllers/message_drafts_controller.js
index 922f022e7..8d8df8741 100644
--- a/app/javascript/controllers/message_drafts_controller.js
+++ b/app/javascript/controllers/message_drafts_controller.js
@@ -31,7 +31,7 @@ export default class extends Controller {
const messageDraftsTexts = document.querySelectorAll('textarea[id^="text_message_draft_"]');
const length = messageDraftsTexts.length;
if (messageDraftsTexts.length > 1) {
- messageDraftsTexts[length - 2].setAttribute('autofocus', false);
+ messageDraftsTexts[length - 2].setAttribute("autofocus", false);
}
messageDraftsTexts[length - 1].focus();
diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb
index 490457ad6..765aa65ea 100644
--- a/app/jobs/application_job.rb
+++ b/app/jobs/application_job.rb
@@ -1,3 +1,5 @@
class ApplicationJob < ActiveJob::Base
include Rollbar::ActiveJob
+
+ retry_on StandardError, wait: :polynomially_longer, attempts: Float::INFINITY
end
diff --git a/app/jobs/govbox/process_message_job.rb b/app/jobs/govbox/process_message_job.rb
index e47165faa..69e6af5d3 100644
--- a/app/jobs/govbox/process_message_job.rb
+++ b/app/jobs/govbox/process_message_job.rb
@@ -4,7 +4,7 @@ module Govbox
class ProcessMessageJob < ApplicationJob
queue_as :default
- retry_on ::ApplicationRecord::FailedToAcquireLockError, wait: :exponentially_longer, attempts: Float::INFINITY
+ retry_on ::ApplicationRecord::FailedToAcquireLockError, wait: :polynomially_longer, attempts: Float::INFINITY
def perform(govbox_message)
ActiveRecord::Base.transaction do
diff --git a/app/jobs/govbox/process_unauthorized_delivery_notification_job.rb b/app/jobs/govbox/process_unauthorized_delivery_notification_job.rb
index a43782b64..cc9c80b68 100644
--- a/app/jobs/govbox/process_unauthorized_delivery_notification_job.rb
+++ b/app/jobs/govbox/process_unauthorized_delivery_notification_job.rb
@@ -15,10 +15,7 @@ def perform(govbox_message)
message.update(collapsed: true)
- delivery_notification_tag = Tag.find_by!(
- system_name: Govbox::Message::DELIVERY_NOTIFICATION_TAG,
- tenant: message.thread.box.tenant,
- )
+ delivery_notification_tag = Upvs::DeliveryNotificationTag.find_or_create_for_tenant!(message.thread.box.tenant)
message.tags.delete(delivery_notification_tag) if message.tags.include?(delivery_notification_tag)
unless message.thread.messages.any?(&:can_be_authorized?)
diff --git a/app/jobs/govbox/submit_message_draft_job.rb b/app/jobs/govbox/submit_message_draft_job.rb
index 04e7fe397..bb3defaa3 100644
--- a/app/jobs/govbox/submit_message_draft_job.rb
+++ b/app/jobs/govbox/submit_message_draft_job.rb
@@ -25,9 +25,7 @@ def perform(message_draft, schedule_sync: true, upvs_client: UpvsEnvironment.upv
success, response_status, response_body = sktalk_api.receive_and_save_to_outbox(message_draft_data)
if success
- message_draft.metadata["status"] = "submitted"
- message_draft.save!
-
+ message_draft.submitted!
Govbox::SyncBoxJob.set(wait: 3.minutes).perform_later(message_draft.thread.box) if schedule_sync
else
handle_submit_fail(message_draft, response_status, response_body.dig("message"))
diff --git a/app/lib/event_bus.rb b/app/lib/event_bus.rb
index 23cc117a2..6bbf04cf5 100644
--- a/app/lib/event_bus.rb
+++ b/app/lib/event_bus.rb
@@ -57,5 +57,38 @@ def self.reset!
EventBus.subscribe :box_destroyed, ->(box_id) { Govbox::DestroyBoxDataJob.perform_later(box_id) }
EventBus.subscribe :message_thread_note_created, ->(note) { AuditLog::MessageThreadNoteCreated.create_audit_record(note) }
-EventBus.subscribe :message_thread_note_changed, ->(note) { AuditLog::MessageThreadNoteChanged.create_audit_record(note) }
-EventBus.subscribe :message_thread_tag_changed, ->(thread_tag) { AuditLog::MessageThreadTagChanged.create_audit_record(thread_tag) }
+EventBus.subscribe :message_thread_note_updated, ->(note) { AuditLog::MessageThreadNoteUpdated.create_audit_record(note) }
+EventBus.subscribe :message_threads_tag_created, ->(thread_tag) { AuditLog::MessageThreadTagCreated.create_audit_record(thread_tag) }
+EventBus.subscribe :message_threads_tag_updated, ->(thread_tag) { AuditLog::MessageThreadTagUpdated.create_audit_record(thread_tag) }
+EventBus.subscribe :message_threads_tag_destroyed, ->(thread_tag) { AuditLog::MessageThreadTagDestroyed.create_audit_record(thread_tag) }
+EventBus.subscribe :message_delivery_authorized, ->(message) { AuditLog::MessageDeliveryAuthorized.create_audit_record(message) }
+EventBus.subscribe :message_draft_being_submitted, ->(message) { AuditLog::MessageDraftBeingSubmitted.create_audit_record(message) }
+EventBus.subscribe :message_draft_submitted, ->(message) { AuditLog::MessageDraftSubmitted.create_audit_record(message) }
+EventBus.subscribe :message_draft_destroyed, ->(message) { AuditLog::MessageDraftDestroyed.create_audit_record(message) }
+EventBus.subscribe :message_thread_renamed, ->(message_thread) { AuditLog::MessageThreadRenamed.create_audit_record(message_thread) }
+EventBus.subscribe :message_threads_merged, ->(message_threads_collection) { AuditLog::MessageThreadsMerged.create_audit_record(message_threads_collection) }
+EventBus.subscribe :message_object_updated, ->(message_object) { AuditLog::MessageObjectUpdated.create_audit_record(message_object) }
+
+EventBus.subscribe :user_logged_in, ->(user) { AuditLog::UserLoggedIn.create_audit_record(user) }
+EventBus.subscribe :user_logged_out, ->(user) { AuditLog::UserLoggedOut.create_audit_record(user) }
+EventBus.subscribe :user_created, ->(user) { AuditLog::UserCreated.create_audit_record(user) }
+EventBus.subscribe :user_updated, ->(user) { AuditLog::UserUpdated.create_audit_record(user) }
+EventBus.subscribe :user_destroyed, ->(user) { AuditLog::UserDestroyed.create_audit_record(user) }
+EventBus.subscribe :group_created, ->(group) { AuditLog::GroupCreated.create_audit_record(group) }
+EventBus.subscribe :group_updated, ->(group) { AuditLog::GroupUpdated.create_audit_record(group) }
+EventBus.subscribe :group_destroyed, ->(group) { AuditLog::GroupDestroyed.create_audit_record(group) }
+EventBus.subscribe :group_membership_created, ->(group_membership) { AuditLog::GroupMembershipCreated.create_audit_record(group_membership) }
+EventBus.subscribe :group_membership_updated, ->(group_membership) { AuditLog::GroupMembershipUpdated.create_audit_record(group_membership) }
+EventBus.subscribe :group_membership_destroyed, ->(group_membership) { AuditLog::GroupMembershipDestroyed.create_audit_record(group_membership) }
+EventBus.subscribe :tag_created, ->(tag) { AuditLog::TagCreated.create_audit_record(tag) }
+EventBus.subscribe :tag_updated, ->(tag) { AuditLog::TagUpdated.create_audit_record(tag) }
+EventBus.subscribe :tag_destroyed, ->(tag) { AuditLog::TagDestroyed.create_audit_record(tag) }
+EventBus.subscribe :tag_group_created, ->(tag_group) { AuditLog::TagGroupCreated.create_audit_record(tag_group) }
+EventBus.subscribe :tag_group_updated, ->(tag_group) { AuditLog::TagGroupUpdated.create_audit_record(tag_group) }
+EventBus.subscribe :tag_group_destroyed, ->(tag_group) { AuditLog::TagGroupDestroyed.create_audit_record(tag_group) }
+EventBus.subscribe :automation_rule_created, ->(automation_rule) { AuditLog::AutomationRuleCreated.create_audit_record(automation_rule) }
+EventBus.subscribe :automation_rule_updated, ->(automation_rule) { AuditLog::AutomationRuleUpdated.create_audit_record(automation_rule) }
+EventBus.subscribe :automation_rule_destroyed, ->(automation_rule) { AuditLog::AutomationRuleDestroyed.create_audit_record(automation_rule) }
+EventBus.subscribe :filter_created, ->(filter) { AuditLog::FilterCreated.create_audit_record(filter) }
+EventBus.subscribe :filter_updated, ->(filter) { AuditLog::FilterUpdated.create_audit_record(filter) }
+EventBus.subscribe :filter_destroyed, ->(filter) { AuditLog::FilterDestroyed.create_audit_record(filter) }
diff --git a/app/lib/sidebar_menu.rb b/app/lib/sidebar_menu.rb
index f05572c71..4409f1346 100644
--- a/app/lib/sidebar_menu.rb
+++ b/app/lib/sidebar_menu.rb
@@ -11,8 +11,7 @@ def initialize(controller, action, parameters = nil)
private
def initial_structure(controller, _action)
- return admin_main_menu if (controller.in? %w[groups users tags tag_groups automation_rules boxes tenants
- filters]) && (Current.user.admin? || Current.user.site_admin?)
+ return admin_menu + site_admin_menu if controller.in? %w[groups users tags tag_groups automation_rules boxes filters]
default_main_menu
end
@@ -26,22 +25,30 @@ def default_main_menu
]
end
- def admin_main_menu
+ def admin_menu
+ return [] unless Current.user.admin?
+
[
Layout::BackToBoxComponent.new,
TW::SidebarMenuDividerComponent.new(name: 'Nastavenia'),
TW::SidebarMenuItemComponent.new(name: 'Filtre', url: filters_path, icon: Icons::BookmarkComponent.new),
TW::SidebarMenuItemComponent.new(name: 'Pravidlá', url: settings_automation_rules_path, icon: Icons::FunnelComponent.new),
TW::SidebarMenuDividerComponent.new(name: 'Administrácia'),
- Current.user.site_admin? ? TW::SidebarMenuItemComponent.new(name: 'Tenanti', url: admin_tenants_path, icon: Icons::RectangleGroupComponent.new) : nil,
TW::SidebarMenuItemComponent.new(name: 'Používatelia', url: admin_tenant_users_path(Current.tenant), icon: Icons::UsersComponent.new),
TW::SidebarMenuItemComponent.new(name: 'Prístup', url: admin_tenant_tag_groups_path(Current.tenant), icon: Icons::LockClosedComponent.new),
TW::SidebarMenuItemComponent.new(name: 'Schránky', url: admin_tenant_boxes_path(Current.tenant), icon: Icons::RectangleStackComponent.new),
TW::SidebarMenuItemComponent.new(name: 'Skupiny', url: admin_tenant_groups_path(Current.tenant), icon: Icons::UserGroupsComponent.new),
- TW::SidebarMenuItemComponent.new(name: 'Štítky', url: admin_tenant_tags_path(Current.tenant), icon: Icons::TagComponent.new),
+ TW::SidebarMenuItemComponent.new(name: 'Štítky', url: admin_tenant_tags_path(Current.tenant), icon: Icons::TagComponent.new)
+ ]
+ end
+
+ def site_admin_menu
+ return [] unless Current.user.site_admin?
+
+ [
Layout::SidebarDividerComponent.new,
TW::SidebarMenuDividerComponent.new(name: 'Admin'),
- TW::SidebarMenuItemComponent.new(name: 'Good Job Dashboard', url: good_job_path, icon: Icons::CogSixToothComponent.new),
- ].compact
+ TW::SidebarMenuItemComponent.new(name: 'Good Job Dashboard', url: good_job_path, icon: Icons::CogSixToothComponent.new)
+ ]
end
end
diff --git a/app/models/audit_log.rb b/app/models/audit_log.rb
index 1289ca0b2..1a9c6d891 100644
--- a/app/models/audit_log.rb
+++ b/app/models/audit_log.rb
@@ -22,7 +22,7 @@
class AuditLog < ApplicationRecord
belongs_to :tenant
belongs_to :actor, class_name: "User"
- belongs_to :message_thread
+ belongs_to :message_thread, optional: true
class MessageThreadNoteCreated < AuditLog
def self.create_audit_record(note)
@@ -34,7 +34,7 @@ def self.create_audit_record(note)
end
end
- class MessageThreadNoteChanged < AuditLog
+ class MessageThreadNoteUpdated < AuditLog
def self.create_audit_record(note)
create_record(
object: note,
@@ -45,8 +45,17 @@ def self.create_audit_record(note)
end
end
- # TODO: Pre tagy sa asi budeme musiet subscribnut na nove eventy, kedze tu nevieme, ci to je destroy/create (dokonca teoreticky update)
- class MessageThreadTagChanged < AuditLog
+ class MessageThreadTagCreated < AuditLog
+ def self.create_audit_record(thread_tag)
+ create_record(
+ object: thread_tag,
+ new_value: thread_tag.tag.name,
+ message_thread: thread_tag.message_thread
+ )
+ end
+ end
+
+ class MessageThreadTagUpdated < AuditLog
def self.create_audit_record(thread_tag)
create_record(
object: thread_tag,
@@ -57,6 +66,210 @@ def self.create_audit_record(thread_tag)
end
end
+ class MessageThreadTagDestroyed < AuditLog
+ def self.create_audit_record(thread_tag)
+ create_record(
+ object: thread_tag,
+ previous_value: thread_tag.tag.name,
+ message_thread: thread_tag.message_thread
+ )
+ end
+ end
+
+ class UserLoggedIn < AuditLog
+ def self.create_audit_record(user)
+ create_record(object: user, tenant: user.tenant)
+ end
+ end
+
+ class UserLoggedOut < AuditLog
+ def self.create_audit_record(user)
+ create_record(
+ object: user,
+ tenant: user.tenant,
+ actor: user,
+ actor_name: user.name
+ )
+ end
+ end
+
+ class FilterCreated < AuditLog
+ def self.create_audit_record(filter)
+ create_record(object: filter, new_value: filter.name)
+ end
+ end
+
+ class FilterUpdated < AuditLog
+ def self.create_audit_record(filter)
+ create_record(object: filter, new_value: filter.name, previous_value: filter.name_previously_was)
+ end
+ end
+
+ class FilterDestroyed < AuditLog
+ def self.create_audit_record(filter)
+ create_record(object: filter, previous_value: filter.name)
+ end
+ end
+
+ class TagCreated < AuditLog
+ def self.create_audit_record(tag)
+ create_record(object: tag, new_value: tag.name)
+ end
+ end
+
+ class TagUpdated < AuditLog
+ def self.create_audit_record(tag)
+ create_record(object: tag, new_value: tag.name, previous_value: tag.name_previously_was)
+ end
+ end
+
+ class TagDestroyed < AuditLog
+ def self.create_audit_record(tag)
+ create_record(object: tag, previous_value: tag.name)
+ end
+ end
+
+ class TagGroupCreated < AuditLog
+ def self.create_audit_record(tag_group)
+ create_record(object: tag_group)
+ end
+ end
+
+ class TagGroupUpdated < AuditLog
+ def self.create_audit_record(tag_group)
+ create_record(object: tag_group)
+ end
+ end
+
+ class TagGroupDestroyed < AuditLog
+ def self.create_audit_record(tag_group)
+ create_record(object: tag_group)
+ end
+ end
+
+ class GroupCreated < AuditLog
+ def self.create_audit_record(group)
+ create_record(object: group, new_value: group.name)
+ end
+ end
+
+ class GroupUpdated < AuditLog
+ def self.create_audit_record(group)
+ create_record(object: group, new_value: group.name, previous_value: group.name_previously_was)
+ end
+ end
+
+ class GroupDestroyed < AuditLog
+ def self.create_audit_record(group)
+ create_record(object: group, previous_value: group.name)
+ end
+ end
+
+ class GroupMembershipCreated < AuditLog
+ def self.create_audit_record(group_membership)
+ create_record(object: group_membership)
+ end
+ end
+
+ class GroupMembershipUpdated < AuditLog
+ def self.create_audit_record(group_membership)
+ create_record(object: group_membership)
+ end
+ end
+
+ class GroupMembershipDestroyed < AuditLog
+ def self.create_audit_record(group_membership)
+ create_record(object: group_membership)
+ end
+ end
+
+ class UserCreated < AuditLog
+ def self.create_audit_record(user)
+ create_record(object: user, new_value: user.name)
+ end
+ end
+
+ class UserUpdated < AuditLog
+ def self.create_audit_record(user)
+ create_record(object: user, new_value: user.name, previous_value: user.name_previously_was)
+ end
+ end
+
+ class UserDestroyed < AuditLog
+ def self.create_audit_record(user)
+ create_record(object: user, previous_value: user.name)
+ end
+ end
+
+ class AutomationRuleCreated < AuditLog
+ def self.create_audit_record(automation_rule)
+ create_record(object: automation_rule, new_value: automation_rule.name)
+ end
+ end
+
+ class AutomationRuleUpdated < AuditLog
+ def self.create_audit_record(automation_rule)
+ create_record(object: automation_rule, new_value: automation_rule.name, previous_value: automation_rule.name_previously_was)
+ end
+ end
+
+ class AutomationRuleDestroyed < AuditLog
+ def self.create_audit_record(automation_rule)
+ create_record(object: automation_rule, previous_value: automation_rule.name)
+ end
+ end
+
+ # TODO: move to non-core domain
+ class MessageDeliveryAuthorized < AuditLog
+ def self.create_audit_record(message)
+ create_record(object: message, message_thread: message.thread)
+ end
+ end
+
+ class MessageDraftBeingSubmitted < AuditLog
+ def self.create_audit_record(message)
+ create_record(object: message, message_thread: message.thread)
+ end
+ end
+
+ class MessageDraftSubmitted < AuditLog
+ def self.create_audit_record(message)
+ create_record(object: message, message_thread: message.thread)
+ end
+ end
+
+ class MessageDraftDestroyed < AuditLog
+ def self.create_audit_record(message)
+ create_record(object: message, message_thread: message.thread)
+ end
+ end
+
+ class MessageThreadRenamed < AuditLog
+ def self.create_audit_record(message_thread)
+ create_record(
+ object: message_thread,
+ message_thread: message_thread,
+ previous_value: message_thread.title_previously_was,
+ new_value: message_thread.title
+ )
+ end
+ end
+
+ class MessageThreadsMerged < AuditLog
+ def self.create_audit_record(message_threads_collection)
+ create_record(
+ message_thread: message_threads_collection.first,
+ object: message_threads_collection
+ )
+ end
+ end
+
+ class MessageObjectUpdated < AuditLog
+ def self.create_audit_record(message_object)
+ create_record(object: message_object, message_thread: message_object.message.message_thread)
+ end
+ end
+
def self.create_record(object:, **args)
create(
tenant: Current.tenant,
@@ -64,13 +277,21 @@ def self.create_record(object:, **args)
# TODO: SYSTEM alebo nil alebo nieco ine?
actor_name: Current.user&.name || 'SYSTEM',
happened_at: Time.current,
- changeset: object.previous_changes,
+ changeset: changeset(object),
thread_id_archived: args[:message_thread]&.id,
thread_title: args[:message_thread]&.title,
**args
)
end
+ def self.changeset(object)
+ if object.respond_to?(:previous_changes) && object.previous_changes.any?
+ object.previous_changes
+ else
+ object.to_json
+ end
+ end
+
def self.to_csv
CSV.generate do |csv|
csv << column_names
diff --git a/app/models/automation/rule.rb b/app/models/automation/rule.rb
index de1494bac..754f14718 100644
--- a/app/models/automation/rule.rb
+++ b/app/models/automation/rule.rb
@@ -12,6 +12,8 @@
#
module Automation
class Rule < ApplicationRecord
+ include AuditableEvents
+
belongs_to :tenant
belongs_to :user
has_many :conditions,
diff --git a/app/models/box.rb b/app/models/box.rb
index 2b41b62e7..1a95cbe2b 100644
--- a/app/models/box.rb
+++ b/app/models/box.rb
@@ -15,6 +15,8 @@
# tenant_id :bigint not null
#
class Box < ApplicationRecord
+ include Colorized
+
belongs_to :tenant
belongs_to :api_connection
@@ -30,32 +32,6 @@ class Box < ApplicationRecord
before_create { self.color = Box.colors.keys[name.hash % Box.colors.size] if color.blank? }
- enum :color,
- {
- slate: 'slate',
- gray: 'gray',
- zinc: 'zinc',
- neutral: 'neutral',
- stone: 'stone',
- red: 'red',
- orange: 'orange',
- amber: 'amber',
- yellow: 'yellow',
- lime: 'lime',
- green: 'green',
- emerald: 'emerald',
- teal: 'teal',
- cyan: 'cyan',
- sky: 'sky',
- blue: 'blue',
- indigo: 'indigo',
- violet: 'violet',
- purple: 'purple',
- fuchsia: 'fuchsia',
- pink: 'pink',
- rose: 'rose'
- }
-
validate :validate_box_with_api_connection
private
diff --git a/app/models/concerns/auditable_events.rb b/app/models/concerns/auditable_events.rb
new file mode 100644
index 000000000..98334c844
--- /dev/null
+++ b/app/models/concerns/auditable_events.rb
@@ -0,0 +1,25 @@
+module AuditableEvents
+ extend ActiveSupport::Concern
+
+ included do
+ after_destroy :audit_destroy
+ after_create :audit_create
+ after_update :audit_update
+ end
+
+ def audit_destroy
+ EventBus.publish(event_name(:destroyed), self)
+ end
+
+ def audit_create
+ EventBus.publish(event_name(:created), self)
+ end
+
+ def audit_update
+ EventBus.publish(event_name(:updated), self)
+ end
+
+ def event_name(action)
+ "#{self.class.name.underscore.gsub("/", "_")}_#{action}".to_sym
+ end
+end
diff --git a/app/models/concerns/colorized.rb b/app/models/concerns/colorized.rb
new file mode 100644
index 000000000..2f0baf238
--- /dev/null
+++ b/app/models/concerns/colorized.rb
@@ -0,0 +1,59 @@
+module Colorized
+ extend ActiveSupport::Concern
+
+ included do
+ enum :color,
+ {
+ slate: 'slate',
+ gray: 'gray',
+ zinc: 'zinc',
+ neutral: 'neutral',
+ stone: 'stone',
+ red: 'red',
+ orange: 'orange',
+ amber: 'amber',
+ yellow: 'yellow',
+ lime: 'lime',
+ green: 'green',
+ emerald: 'emerald',
+ teal: 'teal',
+ cyan: 'cyan',
+ sky: 'sky',
+ blue: 'blue',
+ indigo: 'indigo',
+ violet: 'violet',
+ purple: 'purple',
+ fuchsia: 'fuchsia',
+ pink: 'pink',
+ rose: 'rose'
+ }
+ end
+
+ def self.colors
+ [
+ :slate,
+ :gray,
+ :zinc,
+ :neutral,
+ :stone,
+ :red,
+ :orange,
+ :amber,
+ :yellow,
+ :lime,
+ :green,
+ :emerald,
+ :teal,
+ :cyan,
+ :sky,
+ :blue,
+ :indigo,
+ :violet,
+ :purple,
+ :fuchsia,
+ :pink,
+ :rose
+ ]
+ end
+end
+
diff --git a/app/models/concerns/iconized.rb b/app/models/concerns/iconized.rb
new file mode 100644
index 000000000..3a3503a42
--- /dev/null
+++ b/app/models/concerns/iconized.rb
@@ -0,0 +1,12 @@
+module Iconized
+ extend ActiveSupport::Concern
+
+ def self.icons
+ Common::IconComponent::ICONS.keys
+ end
+
+ included do
+ validates_inclusion_of :icon, in: Iconized.icons, allow_blank: true
+ end
+end
+
diff --git a/app/models/draft_tag.rb b/app/models/draft_tag.rb
new file mode 100644
index 000000000..d4f47b6b7
--- /dev/null
+++ b/app/models/draft_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class DraftTag < Tag
+ def destroyable?
+ false
+ end
+end
diff --git a/app/models/everything_tag.rb b/app/models/everything_tag.rb
new file mode 100644
index 000000000..59e998f35
--- /dev/null
+++ b/app/models/everything_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class EverythingTag < Tag
+ def destroyable?
+ false
+ end
+end
diff --git a/app/models/filter.rb b/app/models/filter.rb
index ce8e437b8..e64e2e8ef 100644
--- a/app/models/filter.rb
+++ b/app/models/filter.rb
@@ -12,6 +12,8 @@
# tenant_id :bigint not null
#
class Filter < ApplicationRecord
+ include AuditableEvents
+
belongs_to :author, class_name: 'User'
belongs_to :tenant
diff --git a/app/models/govbox/authorize_delivery_notification_action.rb b/app/models/govbox/authorize_delivery_notification_action.rb
index e0609f40c..7f8f541ee 100644
--- a/app/models/govbox/authorize_delivery_notification_action.rb
+++ b/app/models/govbox/authorize_delivery_notification_action.rb
@@ -8,6 +8,8 @@ def self.run(message)
Govbox::Message.remove_delivery_notification_tag(message)
Govbox::AuthorizeDeliveryNotificationJob.perform_later(message)
+
+ EventBus.publish(:message_delivery_authorized, message)
end
can_be_authorized
diff --git a/app/models/govbox/message.rb b/app/models/govbox/message.rb
index aa29da3c6..3c7373308 100644
--- a/app/models/govbox/message.rb
+++ b/app/models/govbox/message.rb
@@ -120,10 +120,9 @@ def self.create_message_objects(message, raw_message)
end
def self.add_upvs_related_tags(message, govbox_message)
- upvs_tag = Tag.find_or_create_by!(
- system_name: "slovensko.sk:#{govbox_message.folder.full_name}",
- tenant: govbox_message.box.tenant,
- external: true,
+ upvs_tag = SimpleTag.find_or_create_by!(
+ external_name: "slovensko.sk:#{govbox_message.folder.full_name}",
+ tenant: govbox_message.box.tenant
) do |tag|
tag.name = "slovensko.sk:#{govbox_message.folder.full_name}"
tag.visible = !govbox_message.folder.system?
@@ -134,18 +133,14 @@ def self.add_upvs_related_tags(message, govbox_message)
end
def self.add_delivery_notification_tag(message)
- delivery_notification_tag = Tag.find_by!(
- system_name: DELIVERY_NOTIFICATION_TAG,
- tenant: message.thread.box.tenant,
- )
- message.add_cascading_tag(delivery_notification_tag)
+ message.add_cascading_tag(delivery_notification_tag(message))
end
def self.remove_delivery_notification_tag(message)
- delivery_notification_tag = Tag.find_by!(
- system_name: DELIVERY_NOTIFICATION_TAG,
- tenant: message.thread.box.tenant,
- )
- message.remove_cascading_tag(delivery_notification_tag)
+ message.remove_cascading_tag(delivery_notification_tag(message))
+ end
+
+ def self.delivery_notification_tag(message)
+ Upvs::DeliveryNotificationTag.find_or_create_for_tenant!(message.thread.box.tenant)
end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 0ce00e218..ad556501f 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -11,6 +11,8 @@
# tenant_id :bigint not null
#
class Group < ApplicationRecord
+ include AuditableEvents
+
belongs_to :tenant
has_many :group_memberships, dependent: :destroy
has_many :users, through: :group_memberships
diff --git a/app/models/group_membership.rb b/app/models/group_membership.rb
index 858b5b9c4..3f3f3b12d 100644
--- a/app/models/group_membership.rb
+++ b/app/models/group_membership.rb
@@ -9,6 +9,45 @@
# user_id :bigint not null
#
class GroupMembership < ApplicationRecord
+ include AuditableEvents
+
belongs_to :group
belongs_to :user
+
+ after_create :create_signing_tags!, if: ->(membership) { membership.group.is_a?(SignerGroup) }
+ after_destroy :destroy_all_signature_requests!, if: ->(membership) { membership.group.is_a?(SignerGroup) }
+
+ def create_signing_tags!
+ user_group = user.user_group
+ tenant = group.tenant
+
+ find_or_create_signing_tag(
+ tags_scope: tenant.signature_requested_from_tags,
+ user_group: user_group,
+ tag_name: "Na podpis: #{user.name}"
+ )
+
+ find_or_create_signing_tag(
+ tags_scope: tenant.signed_by_tags,
+ user_group: user_group,
+ tag_name: "Podpísané: #{user.name}"
+ )
+ end
+
+ def destroy_all_signature_requests!
+ tag = group.tenant.signature_requested_from_tags.find_tag_containing_group(user.user_group)
+ tag.destroy if tag
+ end
+
+
+ def find_or_create_signing_tag(tags_scope:, user_group:, tag_name:)
+ tag = tags_scope.find_tag_containing_group(user_group) || tags_scope.find_or_initialize_by(
+ name: tag_name
+ )
+
+ tag.name = tag_name
+ tag.visible = true
+ tag.groups = [user_group]
+ tag.save!
+ end
end
diff --git a/app/models/message_draft.rb b/app/models/message_draft.rb
index 2c8730e7a..0328c01f6 100644
--- a/app/models/message_draft.rb
+++ b/app/models/message_draft.rb
@@ -22,19 +22,19 @@
# message_thread_id :bigint not null
#
class MessageDraft < Message
- belongs_to :import, class_name: 'MessageDraftsImport', foreign_key: :import_id, optional: true
+ belongs_to :import, class_name: 'MessageDraftsImport', optional: true
after_create do
- drafts_tag = self.thread.box.tenant.tags.find_by(system_name: Tag::DRAFT_SYSTEM_NAME)
- self.add_cascading_tag(drafts_tag)
+ add_cascading_tag(thread.box.tenant.draft_tag!)
end
after_destroy do
- # TODO has to use `reload` because of `inverse_of` messages are in memory and deleting already deleted record fails
- if self.thread.messages.reload.none?
- self.thread.destroy!
- elsif self.thread.message_drafts.reload.none?
- drafts_tag = self.thread.tags.find_by(system_name: Tag::DRAFT_SYSTEM_NAME)
+ EventBus.publish(:message_draft_destroyed, self)
+ # TODO: has to use `reload` because of `inverse_of` messages are in memory and deleting already deleted record fails
+ if thread.messages.reload.none?
+ thread.destroy!
+ elsif thread.message_drafts.reload.none?
+ drafts_tag = thread.tags.find_by(type: DraftTag.to_s)
thread.tags.delete(drafts_tag)
end
end
@@ -43,14 +43,14 @@ class MessageDraft < Message
GENERAL_AGENDA_POSP_VERSION = "1.9"
GENERAL_AGENDA_MESSAGE_TYPE = "App.GeneralAgenda"
- with_options on: :validate_data do |message_draft|
- message_draft.validates :uuid, format: { with: Utils::UUID_PATTERN }, allow_blank: false
- message_draft.validate :validate_metadata
- message_draft.validate :validate_form
- message_draft.validate :validate_objects
+ with_options on: :validate_data do
+ validates :uuid, format: { with: Utils::UUID_PATTERN }, allow_blank: false
+ validate :validate_metadata
+ validate :validate_form
+ validate :validate_objects
end
- def self.create_message_reply(original_message: , author:)
+ def self.create_message_reply(original_message:, author:)
message_draft = original_message.thread.message_drafts.create!(
uuid: SecureRandom.uuid,
sender_name: original_message.recipient_name,
@@ -70,14 +70,7 @@ def self.create_message_reply(original_message: , author:)
"status": "created"
}
)
-
- # TODO clean the domain (no UPVS stuff)
- message_draft.objects.create!(
- name: "form.xml",
- mimetype: "application/x-eform-xml",
- object_type: "FORM",
- is_signed: false
- )
+ message_draft.create_form_object
message_draft
end
@@ -86,22 +79,10 @@ def update_content(title:, body:)
self.title = title
metadata["message_body"] = body
save!
-
return unless title.present? && body.present?
- # TODO clean the domain (no UPVS stuff)
- if form.message_object_datum
- form.message_object_datum.update(
- blob: Upvs::FormBuilder.build_general_agenda_xml(subject: title, body: body)
- )
- else
- form.message_object_datum = MessageObjectDatum.create(
- message_object: form,
- blob: Upvs::FormBuilder.build_general_agenda_xml(subject: title, body: body)
- )
- end
-
- self.reload
+ update_form_object
+ reload
end
def draft?
@@ -116,6 +97,12 @@ def editable?
metadata["posp_id"] == GENERAL_AGENDA_POSP_ID && !form&.is_signed? && not_yet_submitted?
end
+ def reason_for_readonly
+ return :read_only_agenda unless metadata["posp_id"] == GENERAL_AGENDA_POSP_ID
+ return :form_submitted if submitted? || being_submitted?
+ return :form_signed if form.is_signed?
+ end
+
def custom_visualization?
metadata["posp_id"] == GENERAL_AGENDA_POSP_ID
end
@@ -139,8 +126,15 @@ def submitted?
def being_submitted!
metadata["status"] = "being_submitted"
save!
+ EventBus.publish(:message_draft_being_submitted, self)
+ end
+
+ def submitted!
+ metadata["status"] = "submitted"
+ save!
+ EventBus.publish(:message_draft_submitted, self)
end
-
+
def invalid?
metadata["status"] == "invalid"
end
@@ -149,6 +143,26 @@ def original_message
Message.find(metadata["original_message_id"]) if metadata["original_message_id"]
end
+ def remove_form_signature
+ return false unless form
+ return false unless form.is_signed?
+
+ form.destroy
+ create_form_object
+ reload
+ update_form_object
+ end
+
+ def create_form_object
+ # TODO: clean the domain (no UPVS stuff)
+ objects.create!(
+ name: "form.xml",
+ mimetype: "application/x-eform-xml",
+ object_type: "FORM",
+ is_signed: false
+ )
+ end
+
private
def validate_metadata
@@ -176,4 +190,18 @@ def validate_objects
errors.merge!(object.errors)
end
end
+
+ def update_form_object
+ # TODO: clean the domain (no UPVS stuff)
+ if form.message_object_datum
+ form.message_object_datum.update(
+ blob: Upvs::FormBuilder.build_general_agenda_xml(subject: title, body: metadata["message_body"])
+ )
+ else
+ form.message_object_datum = MessageObjectDatum.create(
+ message_object: form,
+ blob: Upvs::FormBuilder.build_general_agenda_xml(subject: title, body: metadata["message_body"])
+ )
+ end
+ end
end
diff --git a/app/models/message_object.rb b/app/models/message_object.rb
index 1ca1fd0ec..dcfb4e877 100644
--- a/app/models/message_object.rb
+++ b/app/models/message_object.rb
@@ -16,7 +16,7 @@
class MessageObject < ApplicationRecord
belongs_to :message, inverse_of: :objects
has_one :message_object_datum, dependent: :destroy
- has_many :nested_message_objects, inverse_of: :message_object
+ has_many :nested_message_objects, inverse_of: :message_object, dependent: :destroy
scope :unsigned, -> { where(is_signed: false) }
scope :to_be_signed, -> { where(to_be_signed: true) }
@@ -25,6 +25,8 @@ class MessageObject < ApplicationRecord
validates :name, presence: true, on: :validate_data
validate :allowed_mime_type?, on: :validate_data
+ after_update ->(message_object) { EventBus.publish(:message_object_changed, message_object) }
+
def self.create_message_objects(message, objects)
objects.each do |raw_object|
message_object_content = raw_object.read.force_encoding("UTF-8")
@@ -53,7 +55,7 @@ def form?
end
def signable?
- # TODO vymazat druhu podmienku po povoleni viacnasobneho podpisovania
+ # TODO: vymazat druhu podmienku po povoleni viacnasobneho podpisovania
message.draft? && !is_signed
end
@@ -62,21 +64,13 @@ def asice?
end
def destroyable?
- # TODO avoid loading message association if we have
- message.draft? && message.not_yet_submitted? && !form?
- end
-
- def asice?
- mimetype == 'application/vnd.etsi.asic-e+zip'
- end
-
- def destroyable?
+ # TODO: avoid loading message association if we have
message.draft? && message.not_yet_submitted? && !form?
end
private
def allowed_mime_type?
- errors.add(:mime_type, "of #{name} object is disallowed, allowed_mime_types: #{Utils::EXTENSIONS_ALLOW_LIST.join(', ')}") unless mimetype
+ errors.add(:mime_type, "of #{name} object is disallowed, allowed_mime_types: #{Utils::EXTENSIONS_ALLOW_LIST.join(", ")}") unless mimetype
end
end
diff --git a/app/models/message_thread.rb b/app/models/message_thread.rb
index fc99099a0..e51f8eee7 100644
--- a/app/models/message_thread.rb
+++ b/app/models/message_thread.rb
@@ -30,6 +30,7 @@ def find_or_create_by_uuid!(uuid:)
attr_accessor :search_highlight
+ after_create_commit ->(thread) { thread.tags << thread.tenant.everything_tag }
after_create_commit ->(thread) { EventBus.publish(:message_thread_created, thread) }
after_update_commit ->(thread) { EventBus.publish(:message_thread_changed, thread) }
@@ -47,6 +48,11 @@ def automation_rules_for_event(event)
tenant.automation_rules.where(trigger_event: event)
end
+ def rename(params)
+ update(params)
+ EventBus.publish(:message_thread_renamed, self)
+ end
+
def mark_all_messages_read
messages.where(read: false).each do |message|
message.read = true
@@ -55,6 +61,7 @@ def mark_all_messages_read
end
def self.merge_threads
+ EventBus.publish(:message_threads_merged, all)
transaction do
target_thread = first
all.each do |thread|
diff --git a/app/models/message_thread_note.rb b/app/models/message_thread_note.rb
index a4988e44b..81d291c5f 100644
--- a/app/models/message_thread_note.rb
+++ b/app/models/message_thread_note.rb
@@ -9,8 +9,7 @@
# message_thread_id :bigint not null
#
class MessageThreadNote < ApplicationRecord
- belongs_to :message_thread
+ include AuditableEvents
- after_create_commit ->(note) { EventBus.publish(:message_thread_note_created, note) }
- after_update_commit ->(note) { EventBus.publish(:message_thread_note_changed, note) }
+ belongs_to :message_thread
end
diff --git a/app/models/message_threads_tag.rb b/app/models/message_threads_tag.rb
index dceac557b..bf74f58bb 100644
--- a/app/models/message_threads_tag.rb
+++ b/app/models/message_threads_tag.rb
@@ -9,6 +9,8 @@
# tag_id :bigint not null
#
class MessageThreadsTag < ApplicationRecord
+ include AuditableEvents
+
belongs_to :message_thread
belongs_to :tag
@@ -19,13 +21,13 @@ class MessageThreadsTag < ApplicationRecord
validates_uniqueness_of :tag_id, scope: :message_thread_id
validate :thread_and_tag_tenants_matches
- scope :only_visible_tags, ->{ includes(:tag).joins(:tag).where("tags.visible = ?", true).order("tags.name") }
+ scope :only_visible_tags, -> { includes(:tag).joins(:tag).where("tags.visible = ?", true).order("tags.name") }
after_commit ->(message_threads_tag) { EventBus.publish(:message_thread_tag_changed, message_threads_tag) }
def thread_and_tag_tenants_matches
- unless message_thread.box.tenant == tag.tenant && tag.tenant
- errors.add :name, 'Unpermitted combination of tag and message thread'
- end
+ return if message_thread.box.tenant == tag.tenant && tag.tenant
+
+ errors.add :name, 'Unpermitted combination of tag and message thread'
end
end
diff --git a/app/models/signature_requested_from_tag.rb b/app/models/signature_requested_from_tag.rb
new file mode 100644
index 000000000..c9e44b302
--- /dev/null
+++ b/app/models/signature_requested_from_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class SignatureRequestedFromTag < Tag
+ def destroyable?
+ false
+ end
+end
diff --git a/app/models/signature_requested_tag.rb b/app/models/signature_requested_tag.rb
new file mode 100644
index 000000000..2dab3f5bc
--- /dev/null
+++ b/app/models/signature_requested_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class SignatureRequestedTag < Tag
+ def destroyable?
+ false
+ end
+end
diff --git a/app/models/signed_by_tag.rb b/app/models/signed_by_tag.rb
new file mode 100644
index 000000000..5811aad51
--- /dev/null
+++ b/app/models/signed_by_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class SignedByTag < Tag
+ def destroyable?
+ false
+ end
+end
diff --git a/app/models/signed_tag.rb b/app/models/signed_tag.rb
new file mode 100644
index 000000000..84c588e1f
--- /dev/null
+++ b/app/models/signed_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class SignedTag < Tag
+ def destroyable?
+ false
+ end
+end
diff --git a/app/models/simple_tag.rb b/app/models/simple_tag.rb
new file mode 100644
index 000000000..793824314
--- /dev/null
+++ b/app/models/simple_tag.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class SimpleTag < Tag
+ def destroyable?
+ true
+ end
+end
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 165d294ad..528ff5cbd 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -2,39 +2,54 @@
#
# Table name: tags
#
-# id :bigint not null, primary key
-# external :boolean default(FALSE)
-# name :string not null
-# system_name :string
-# visible :boolean default(TRUE), not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# tenant_id :bigint not null
-# user_id :bigint
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
#
class Tag < ApplicationRecord
+ include AuditableEvents
+ include Colorized, Iconized
+
belongs_to :tenant
- belongs_to :owner, class_name: 'User', optional: true, foreign_key: :user_id
+ belongs_to :owner, class_name: 'User', optional: true
has_many :tag_groups, dependent: :destroy
has_many :groups, through: :tag_groups
- has_many :messages_tags
+ has_many :messages_tags, dependent: :destroy
has_many :messages, through: :messages_tags
- has_many :message_threads_tags
+ has_many :message_threads_tags, dependent: :destroy
has_many :message_threads, through: :message_threads_tags
- has_many :automation_actions, as: :action_object
+ has_many :automation_actions, class_name: "Automation::Action", as: :action_object, dependent: :restrict_with_error
validates :name, presence: true
validates :name, uniqueness: { scope: :tenant_id, case_sensitive: false }
+ scope :simple, -> { where(type: SimpleTag.to_s) }
scope :visible, -> { where(visible: true) }
- after_create_commit ->(tag) { tag.mark_readable_by_groups([tag.tenant.admin_group]) }
after_update_commit ->(tag) { EventBus.publish(:tag_renamed, tag) if previous_changes.key?("name") }
- after_destroy ->(tag) { EventBus.publish(:tag_destroyed, tag) }
-
- DRAFT_SYSTEM_NAME = 'draft'
def mark_readable_by_groups(groups)
self.groups += groups
end
+
+ def gives_access?
+ tag_groups_count.positive?
+ end
+
+ def destroyable?
+ raise NotImplementedError
+ end
+
+ def self.find_tag_containing_group(group)
+ includes(:groups).to_a.find { |tag| tag.groups.include?(group) }
+ end
end
diff --git a/app/models/tag_group.rb b/app/models/tag_group.rb
index 942e7d623..92e3a448f 100644
--- a/app/models/tag_group.rb
+++ b/app/models/tag_group.rb
@@ -9,8 +9,10 @@
# tag_id :bigint not null
#
class TagGroup < ApplicationRecord
+ include AuditableEvents
+
belongs_to :group
- belongs_to :tag
+ belongs_to :tag, counter_cache: true
# used for joins only
has_many :group_memberships, primary_key: :group_id, foreign_key: :group_id
diff --git a/app/models/tenant.rb b/app/models/tenant.rb
index fb3f9d99d..632a62d4d 100644
--- a/app/models/tenant.rb
+++ b/app/models/tenant.rb
@@ -2,35 +2,82 @@
#
# Table name: tenants
#
-# id :bigint not null, primary key
-# name :string not null
-# created_at :datetime not null
-# updated_at :datetime not null
+# id :bigint not null, primary key
+# feature_flags :string default([]), is an Array
+# name :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
#
class Tenant < ApplicationRecord
has_many :users, dependent: :destroy
- has_many :groups, dependent: :destroy
has_one :all_group
has_one :signer_group
has_one :admin_group
+ has_many :groups, dependent: :destroy
has_many :custom_groups
+ has_one :draft_tag
+ has_one :everything_tag
+ has_one :signature_requested_tag
+ has_one :signed_tag
+ has_many :tags, dependent: :destroy
+ has_many :signature_requested_from_tags
+ has_many :signed_by_tags
+ has_many :simple_tags
+
has_many :boxes, dependent: :destroy
has_many :automation_rules, class_name: "Automation::Rule", dependent: :destroy
- has_many :tags, dependent: :destroy
has_many :filters
+
after_create :create_default_objects
validates_presence_of :name
+ AVAILABLE_FEATURE_FLAGS = [:audit_log]
+
+ def draft_tag!
+ draft_tag || raise(ActiveRecord::RecordNotFound.new("`DraftTag` not found in tenant: #{self.id}"))
+ end
+
+ def feature_enabled?(feature)
+ raise "Unknown feature #{feature}" unless feature.in? AVAILABLE_FEATURE_FLAGS
+
+ feature.to_s.in? feature_flags
+ end
+
+ def enable_feature(feature)
+ raise "Unknown feature #{feature}" unless feature.in? AVAILABLE_FEATURE_FLAGS
+ raise "Feature already enabled" if feature.to_s.in? feature_flags
+
+ feature_flags << feature
+ save!
+ end
+
+ def disable_feature(feature)
+ raise "Unknown feature #{feature}" unless feature.in? AVAILABLE_FEATURE_FLAGS
+ raise "Feature not enabled" unless feature.to_s.in? feature_flags
+
+ feature_flags.delete_if { |f| f == feature.to_s }
+ save!
+ end
+
+ def make_admins_see_everything!
+ everything_tag.groups << admin_group
+ end
+
private
def create_default_objects
create_all_group!(name: "all")
create_admin_group!(name: "admins")
create_signer_group!(name: "signers")
- tags.create!(name: 'Drafty', system_name: Tag::DRAFT_SYSTEM_NAME, external: false, visible: true)
- tags.create!(name: 'Na prevzatie', system_name: 'delivery_notification', external: false, visible: true)
+
+ create_draft_tag!(name: "Rozpracované", visible: true)
+ create_everything_tag!(name: "Všetky správy", visible: false)
+ create_signature_requested_tag!(name: "Na podpis", visible: true)
+ create_signed_tag!(name: "Podpísané", visible: true)
+
+ make_admins_see_everything!
end
end
diff --git a/app/models/upvs/delivery_notification_tag.rb b/app/models/upvs/delivery_notification_tag.rb
new file mode 100644
index 000000000..efef2da63
--- /dev/null
+++ b/app/models/upvs/delivery_notification_tag.rb
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: tags
+#
+# id :bigint not null, primary key
+# color :enum
+# external_name :string
+# icon :string
+# name :string not null
+# tag_groups_count :integer default(0), not null
+# type :string not null
+# visible :boolean default(TRUE), not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# owner_id :bigint
+# tenant_id :bigint not null
+#
+class Upvs::DeliveryNotificationTag < ::Tag
+ def self.find_or_create_for_tenant!(tenant)
+ find_or_create_by!(
+ type: self.to_s,
+ tenant: tenant
+ ) do |tag|
+ tag.name = "Na prevzatie"
+ tag.visible = true
+ end
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 7bf81e460..b39cbe4c4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -10,11 +10,13 @@
# tenant_id :bigint
#
class User < ApplicationRecord
+ include AuditableEvents
+
belongs_to :tenant
has_many :group_memberships, dependent: :destroy
has_many :groups, through: :group_memberships
- has_many :own_tags, class_name: 'Tag', foreign_key: 'user_id', inverse_of: :owner, dependent: :nullify
+ has_many :own_tags, class_name: 'Tag', inverse_of: :owner, foreign_key: :owner_id, dependent: :nullify
has_many :message_drafts, foreign_key: :author_id
has_many :automation_rules, class_name: 'Automation::Rule'
has_many :filters, foreign_key: :author_id
@@ -37,6 +39,14 @@ def user_group
groups.where(type: "UserGroup").first
end
+ def signed_by_tag
+ tenant.signed_by_tags.find_tag_containing_group(user_group)
+ end
+
+ def signature_requested_from_tag
+ tenant.signature_requested_from_tags.find_tag_containing_group(user_group)
+ end
+
private
def delete_user_group
diff --git a/app/policies/admin/audit_log_policy.rb b/app/policies/admin/audit_log_policy.rb
index 5847a07ba..17d370a5f 100644
--- a/app/policies/admin/audit_log_policy.rb
+++ b/app/policies/admin/audit_log_policy.rb
@@ -10,12 +10,15 @@ def initialize(user, audit_log)
class Scope < Scope
def resolve
- @user.site_admin? ? scope.all : scope.where(tenant: @user.tenant)
+ scope.where(tenant: @user.tenant)
end
end
def index?
- @user.site_admin? || @user.admin?
+ return false unless Current.tenant.feature_enabled?(:audit_log)
+ return false unless @user.admin?
+
+ true
end
def scroll?
diff --git a/app/policies/admin/box_policy.rb b/app/policies/admin/box_policy.rb
index 88184ecfb..1d46c398a 100644
--- a/app/policies/admin/box_policy.rb
+++ b/app/policies/admin/box_policy.rb
@@ -10,20 +10,20 @@ def initialize(user, box)
class Scope < Scope
def resolve
- @user.site_admin? ? scope.all : scope.where(tenant: @user.tenant)
+ scope.where(tenant: @user.tenant)
end
end
def index
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def show?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def create?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def new?
@@ -31,7 +31,7 @@ def new?
end
def update?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def edit?
@@ -39,6 +39,6 @@ def edit?
end
def destroy?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
end
diff --git a/app/policies/admin/group_membership_policy.rb b/app/policies/admin/group_membership_policy.rb
index b880b1c71..47058d013 100644
--- a/app/policies/admin/group_membership_policy.rb
+++ b/app/policies/admin/group_membership_policy.rb
@@ -10,44 +10,22 @@ def initialize(user, group_membership)
class Scope < Scope
def resolve
- if @user.site_admin?
- scope.all
- else
- scope.includes(:user, :group).where(user: {tenant_id: Current.tenant.id}, group: {tenant_id: Current.tenant.id})
- end
+ scope.includes(:user, :group).where(user: { tenant: Current.tenant }, group: { tenant: Current.tenant })
end
end
- def index
- @user.site_admin? || @user.admin?
- end
-
- def show?
- @user.site_admin? || @user.admin?
- end
-
def create?
- return false if !@user.site_admin? && !@user.admin?
+ return false unless @user.admin?
return false unless @group_membership.group.tenant == Current.tenant
return false unless @group_membership.user.tenant == Current.tenant
true
end
- def new?
- create?
- end
-
- def update?
- @user.site_admin? || @user.admin?
- end
-
- def edit?
- update?
- end
-
def destroy?
- @user.site_admin? || @user.admin?
+ return false unless @user.admin?
+ return true unless @group_membership.user == @user && @group_membership.group.type == 'AdminGroup'
+
+ false
end
end
-
diff --git a/app/policies/admin/group_policy.rb b/app/policies/admin/group_policy.rb
index 9800bba87..c988eb20f 100644
--- a/app/policies/admin/group_policy.rb
+++ b/app/policies/admin/group_policy.rb
@@ -10,24 +10,20 @@ def initialize(user, group)
class Scope < Scope
def resolve
- if @user.site_admin?
- scope.all
- else
- scope.where(tenant_id: @user.tenant_id)
- end
+ scope.where(tenant: @user.tenant)
end
end
def index?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def show?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def create?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def new?
@@ -37,7 +33,7 @@ def new?
def update?
return false unless @group.editable?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def edit?
@@ -49,25 +45,24 @@ def edit_members?
end
def show_members?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def edit_permissions?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def destroy?
return false if @group.system?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def search_non_members?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def search_non_tags?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
-
end
diff --git a/app/policies/admin/tag_group_policy.rb b/app/policies/admin/tag_group_policy.rb
index b17405123..443bb169f 100644
--- a/app/policies/admin/tag_group_policy.rb
+++ b/app/policies/admin/tag_group_policy.rb
@@ -10,24 +10,20 @@ def initialize(user, tag_group)
class Scope < Scope
def resolve
- if @user.site_admin?
- scope.all
- else
- scope.includes(:group, :tag).where(group: { tenant_id: Current.tenant.id }, tag: { tenant_id: Current.tenant.id })
- end
+ scope.includes(:group, :tag).where(group: { tenant: Current.tenant }, tag: { tenant: Current.tenant })
end
end
def index?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def show?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def create?
- return false if !@user.site_admin? && !@user.admin?
+ return false unless @user.admin?
return false unless @tag_group.tag.tenant == Current.tenant
return false unless @tag_group.group.tenant == Current.tenant
@@ -39,7 +35,7 @@ def new?
end
def update?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def edit?
@@ -47,6 +43,6 @@ def edit?
end
def destroy?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
end
diff --git a/app/policies/admin/tag_policy.rb b/app/policies/admin/tag_policy.rb
index fa70bced6..e920efc1e 100644
--- a/app/policies/admin/tag_policy.rb
+++ b/app/policies/admin/tag_policy.rb
@@ -10,20 +10,20 @@ def initialize(user, tag)
class Scope < Scope
def resolve
- @user.site_admin? ? scope.all : scope.where(tenant: @user.tenant)
+ scope.where(tenant: @user.tenant)
end
end
def index?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def show?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def create?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def new?
@@ -31,7 +31,7 @@ def new?
end
def update?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def edit?
@@ -39,6 +39,6 @@ def edit?
end
def destroy?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
end
diff --git a/app/policies/admin/tenant_policy.rb b/app/policies/admin/tenant_policy.rb
deleted file mode 100644
index e7a3de238..000000000
--- a/app/policies/admin/tenant_policy.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# frozen_string_literal: true
-
-class Admin::TenantPolicy < ApplicationPolicy
- attr_reader :user, :tenant
-
- def initialize(user, tenant)
- @user = user
- @tenant = tenant
- end
-
- class Scope < Scope
- def resolve
- if @user.site_admin?
- scope.all
- else
- scope.where(id: @user.tenant_id)
- end
- end
- end
-
- def index?
- @user.site_admin? || @user.admin?
- end
-
- def show?
- @user.site_admin? || @user.admin?
- end
-
- def create?
- @user.site_admin?
- end
-
- def new?
- create?
- end
-
- def update?
- @user.site_admin?
- end
-
- def edit?
- update?
- end
-
- def destroy?
- @user.site_admin?
- end
-end
diff --git a/app/policies/admin/user_policy.rb b/app/policies/admin/user_policy.rb
index 645c9467a..e3cb3cd42 100644
--- a/app/policies/admin/user_policy.rb
+++ b/app/policies/admin/user_policy.rb
@@ -1,32 +1,40 @@
# frozen_string_literal: true
class Admin::UserPolicy < ApplicationPolicy
- attr_reader :user
+ def initialize(actor, user_to_authorize)
+ @actor = actor
+ @user_to_authorize = user_to_authorize
+ end
- def initialize(user_logged_in, user_to_authorize)
- @user = user_logged_in
+ def user
+ @actor
end
class Scope < Scope
+ def initialize(actor, scope)
+ @actor = actor
+ @scope = scope
+ end
+
+ def user
+ @actor
+ end
+
def resolve
- if @user.site_admin?
- scope.all
- else
- scope.where(tenant_id: @user.tenant_id)
- end
+ scope.where(tenant: @actor.tenant)
end
end
def index?
- @user.site_admin? || @user.admin?
+ @actor.admin?
end
def show?
- @user.site_admin? || @user.admin?
+ @actor.admin?
end
def create?
- @user.site_admin? || @user.admin?
+ @actor.admin?
end
def new?
@@ -34,7 +42,7 @@ def new?
end
def update?
- @user.site_admin? || @user.admin?
+ @actor.admin?
end
def edit?
@@ -42,7 +50,9 @@ def edit?
end
def destroy?
- @user.site_admin? || @user.admin?
- end
+ return false unless @actor.admin?
+ return false if @user_to_authorize == @actor
+ true
+ end
end
diff --git a/app/policies/box_policy.rb b/app/policies/box_policy.rb
index 8468f5991..b973d9a31 100644
--- a/app/policies/box_policy.rb
+++ b/app/policies/box_policy.rb
@@ -10,20 +10,20 @@ def initialize(user, box)
class Scope < Scope
def resolve
- @user.site_admin? ? scope.all : scope.where(tenant: @user.tenant)
+ scope.where(tenant: @user.tenant)
end
end
def index?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def show?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def sync?
- @user.site_admin? || @user.admin?
+ @user.admin?
end
def select?
@@ -41,5 +41,4 @@ def search?
def get_selector?
true
end
-
end
diff --git a/app/policies/filter_policy.rb b/app/policies/filter_policy.rb
index 66064bb92..2fe871ffd 100644
--- a/app/policies/filter_policy.rb
+++ b/app/policies/filter_policy.rb
@@ -12,7 +12,7 @@ class ScopeEditable < Scope
def resolve
scoped = scope.where(tenant_id: Current.tenant)
- return scoped if @user.admin? || @user.site_admin?
+ return scoped if @user.admin?
scoped.where(author_id: @user.id)
end
@@ -37,19 +37,19 @@ def create?
end
def edit?
- true if @user.admin? || @user.site_admin?
+ true if @user.admin?
is_author_current_user?
end
def update?
- true if @user.admin? || @user.site_admin?
+ true if @user.admin?
is_author_current_user?
end
def destroy?
- true if @user.admin? || @user.site_admin?
+ true if @user.admin?
is_author_current_user?
end
diff --git a/app/policies/message_draft_policy.rb b/app/policies/message_draft_policy.rb
index ceaedfd3f..4ce896f79 100644
--- a/app/policies/message_draft_policy.rb
+++ b/app/policies/message_draft_policy.rb
@@ -10,8 +10,6 @@ def initialize(user, message)
class Scope < Scope
def resolve
- return scope.all if @user.site_admin?
-
# TODO: this does not work for imported drafts (no tags present)
scope.where(author_id: @user.id).where(
MessageThreadsTag
@@ -29,7 +27,7 @@ def index?
end
def create?
- true # TODO can everyone create new messages?
+ true # TODO: can everyone create new messages?
end
def show?
@@ -51,4 +49,12 @@ def submit_all?
def destroy?
create?
end
+
+ def confirm_unlock?
+ unlock?
+ end
+
+ def unlock?
+ create?
+ end
end
diff --git a/app/policies/message_object_policy.rb b/app/policies/message_object_policy.rb
index 1e92eb535..764e73333 100644
--- a/app/policies/message_object_policy.rb
+++ b/app/policies/message_object_policy.rb
@@ -10,8 +10,6 @@ def initialize(user, message_object)
class Scope < Scope
def resolve
- return scope.all if @user.site_admin?
-
scope.where(
Message
.select(1)
diff --git a/app/policies/message_policy.rb b/app/policies/message_policy.rb
index e1c51452a..8d3785b7b 100644
--- a/app/policies/message_policy.rb
+++ b/app/policies/message_policy.rb
@@ -10,8 +10,6 @@ def initialize(user, message)
class Scope < Scope
def resolve
- return scope.all if @user.site_admin?
-
scope.where(
MessageThreadsTag
.select(1)
diff --git a/app/policies/message_thread_policy.rb b/app/policies/message_thread_policy.rb
index 1f415dc21..1c9075a1c 100644
--- a/app/policies/message_thread_policy.rb
+++ b/app/policies/message_thread_policy.rb
@@ -10,8 +10,6 @@ def initialize(user, message_thread)
class Scope < Scope
def resolve
- return scope.all if @user.site_admin?
-
scope.where(
MessageThreadsTag
.select(1)
diff --git a/app/policies/message_threads_tag_policy.rb b/app/policies/message_threads_tag_policy.rb
index f4ab84fe9..ad75ed282 100644
--- a/app/policies/message_threads_tag_policy.rb
+++ b/app/policies/message_threads_tag_policy.rb
@@ -10,8 +10,6 @@ def initialize(user, message_threads_tag)
class Scope < Scope
def resolve
- return scope.all if @user.site_admin?
-
scope_tags_to_accessible_by_user(scope)
end
@@ -58,4 +56,3 @@ def prepare?
true
end
end
-
diff --git a/app/policies/messages_tag_policy.rb b/app/policies/messages_tag_policy.rb
index 0f4436d11..a32d96e72 100644
--- a/app/policies/messages_tag_policy.rb
+++ b/app/policies/messages_tag_policy.rb
@@ -10,11 +10,7 @@ def initialize(user, messages_tag)
class Scope < Scope
def resolve
- if @user.site_admin?
- scope.all
- else
- scope.joins(:message, :tag).where(message: Pundit.policy_scope(user, Message), tag: Pundit.policy_scope(user, Tag))
- end
+ scope.joins(:message, :tag).where(message: Pundit.policy_scope(user, Message), tag: Pundit.policy_scope(user, Tag))
end
end
diff --git a/app/policies/nested_message_object_policy.rb b/app/policies/nested_message_object_policy.rb
index 0e7d64932..592ed099b 100644
--- a/app/policies/nested_message_object_policy.rb
+++ b/app/policies/nested_message_object_policy.rb
@@ -10,8 +10,6 @@ def initialize(user, nested_message_object)
class Scope < Scope
def resolve
- return scope.all if @user.site_admin?
-
scope.joins(:message_object).where(
Message
.select(1)
diff --git a/app/policies/tag_policy.rb b/app/policies/tag_policy.rb
index 39b31e1be..fc145abd2 100644
--- a/app/policies/tag_policy.rb
+++ b/app/policies/tag_policy.rb
@@ -10,7 +10,6 @@ def initialize(user, tag)
class Scope < Scope
def resolve
- return scope.where(tenant: Current.tenant) if @user.site_admin?
return scope.where(tenant: @user.tenant) if @user.admin?
scope.where(
@@ -37,4 +36,8 @@ def create?
def new?
true
end
+
+ def destroy?
+ @tag.destroyable? && (@tag.owner == @user || @user.admin?)
+ end
end
diff --git a/app/views/admin/tags/edit.html.erb b/app/views/admin/tags/edit.html.erb
index 18d320002..a3793dbd3 100644
--- a/app/views/admin/tags/edit.html.erb
+++ b/app/views/admin/tags/edit.html.erb
@@ -1 +1 @@
-<%= render Admin::Tags::TagFormComponent.new(tag: @tag, action: :edit) %>
+<%= render Admin::Tags::TagFormComponent.new(tag: @tag) %>
diff --git a/app/views/admin/tags/index.html.erb b/app/views/admin/tags/index.html.erb
index a3da1ebae..1deec69a7 100644
--- a/app/views/admin/tags/index.html.erb
+++ b/app/views/admin/tags/index.html.erb
@@ -1,3 +1 @@
-<%= render Admin::Tags::TagsListComponent.new(
- external_tags: @external_tags,
- internal_tags: @internal_tags) %>
+<%= render Admin::Tags::TagsListComponent.new(simple_tags: @simple_tags) %>
diff --git a/app/views/admin/tags/new.html.erb b/app/views/admin/tags/new.html.erb
index eda4f5ee3..a3793dbd3 100644
--- a/app/views/admin/tags/new.html.erb
+++ b/app/views/admin/tags/new.html.erb
@@ -1 +1 @@
-<%= render Admin::Tags::TagFormComponent.new(tag: @tag, action: :new) %>
+<%= render Admin::Tags::TagFormComponent.new(tag: @tag) %>
diff --git a/app/views/admin/tags/visibility_toggle.html.erb b/app/views/admin/tags/visibility_toggle.html.erb
deleted file mode 100644
index bce935c2b..000000000
--- a/app/views/admin/tags/visibility_toggle.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-<%= render Admin::Tags::VisibilityToggleComponent.new(@tag) %>
diff --git a/app/views/admin/tenants/_form.html.erb b/app/views/admin/tenants/_form.html.erb
deleted file mode 100644
index 54c570ac4..000000000
--- a/app/views/admin/tenants/_form.html.erb
+++ /dev/null
@@ -1,19 +0,0 @@
-<%= form_with(model: [:admin, tenant], class: "contents") do |form| %>
- <% if tenant.errors.any? %>
-
-
<%= pluralize(tenant.errors.count, "error") %> prohibited this tenant from being saved:
-
- <% tenant.errors.each do |error| %>
- <%= error.full_message %>
- <% end %>
-
-
- <% end %>
-
- <%= form.label :name %>
- <%= form.text_field :name, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
-
-
- <%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %>
-
-<% end %>
diff --git a/app/views/admin/tenants/_tenant.html.erb b/app/views/admin/tenants/_tenant.html.erb
deleted file mode 100644
index 60255310d..000000000
--- a/app/views/admin/tenants/_tenant.html.erb
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
- Name:
- <%= tenant.name %>
-
- <% if action_name != "show" %>
- <%= link_to "Show this tenant", [:admin, tenant], class: "rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %>
- <%= link_to 'Edit this tenant', edit_admin_tenant_path(tenant), class: "rounded-lg py-3 ml-2 px-5 bg-gray-100 inline-block font-medium" %>
-
- <% end %>
-
diff --git a/app/views/admin/tenants/edit.html.erb b/app/views/admin/tenants/edit.html.erb
deleted file mode 100644
index 2d31254c0..000000000
--- a/app/views/admin/tenants/edit.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-<%= render Admin::Tenants::TenantFormComponent.new(tenant: @tenant, action: :edit) %>
diff --git a/app/views/admin/tenants/index.html.erb b/app/views/admin/tenants/index.html.erb
deleted file mode 100644
index 432a180e3..000000000
--- a/app/views/admin/tenants/index.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-<%= render Admin::Tenants::TenantsListComponent.new(@tenants) %>
diff --git a/app/views/admin/tenants/new.html.erb b/app/views/admin/tenants/new.html.erb
deleted file mode 100644
index e4989ae8f..000000000
--- a/app/views/admin/tenants/new.html.erb
+++ /dev/null
@@ -1 +0,0 @@
-<%= render Admin::Tenants::TenantFormComponent.new(tenant: @tenant, action: :new) %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 53d412e81..9894172df 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -3,7 +3,6 @@
GovboxPro
-
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
diff --git a/app/views/message_drafts/confirm_unlock.html.erb b/app/views/message_drafts/confirm_unlock.html.erb
new file mode 100644
index 000000000..95f58cc7d
--- /dev/null
+++ b/app/views/message_drafts/confirm_unlock.html.erb
@@ -0,0 +1,3 @@
+<%= tag.turbo_frame id: "modal" do %>
+ <%= render MessageDraftConfirmUnlockComponent.new(@message) %>
+<% end %>
diff --git a/bin/rails b/bin/rails
index 21d3e02d8..efc037749 100755
--- a/bin/rails
+++ b/bin/rails
@@ -1,5 +1,4 @@
#!/usr/bin/env ruby
-load File.expand_path("spring", __dir__)
-APP_PATH = File.expand_path('../config/application', __dir__)
+APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"
diff --git a/bin/rake b/bin/rake
index 7327f471e..4fbf10b96 100755
--- a/bin/rake
+++ b/bin/rake
@@ -1,5 +1,4 @@
#!/usr/bin/env ruby
-load File.expand_path("spring", __dir__)
require_relative "../config/boot"
require "rake"
Rake.application.run
diff --git a/bin/setup b/bin/setup
index 57923026c..3cd5a9d78 100755
--- a/bin/setup
+++ b/bin/setup
@@ -2,10 +2,10 @@
require "fileutils"
# path to your application root.
-APP_ROOT = File.expand_path('..', __dir__)
+APP_ROOT = File.expand_path("..", __dir__)
def system!(*args)
- system(*args) || abort("\n== Command #{args} failed ==")
+ system(*args, exception: true)
end
FileUtils.chdir APP_ROOT do
@@ -13,21 +13,21 @@ FileUtils.chdir APP_ROOT do
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
# Add necessary setup steps to this file.
- puts '== Installing dependencies =='
- system! 'gem install bundler --conservative'
- system('bundle check') || system!('bundle install')
+ puts "== Installing dependencies =="
+ system! "gem install bundler --conservative"
+ system("bundle check") || system!("bundle install")
# puts "\n== Copying sample files =="
- # unless File.exist?('config/database.yml')
- # FileUtils.cp 'config/database.yml.sample', 'config/database.yml'
+ # unless File.exist?("config/database.yml")
+ # FileUtils.cp "config/database.yml.sample", "config/database.yml"
# end
puts "\n== Preparing database =="
- system! 'bin/rails db:prepare'
+ system! "bin/rails db:prepare"
puts "\n== Removing old logs and tempfiles =="
- system! 'bin/rails log:clear tmp:clear'
+ system! "bin/rails log:clear tmp:clear"
puts "\n== Restarting application server =="
- system! 'bin/rails restart'
+ system! "bin/rails restart"
end
diff --git a/config/application.rb b/config/application.rb
index 1ca2b8559..3f94de956 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -13,7 +13,7 @@
module GovboxPro
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
- config.load_defaults 6.1
+ config.load_defaults 7.1
config.middleware.use Rack::Attack
diff --git a/config/boot.rb b/config/boot.rb
index 3cda23b4d..988a5ddc4 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -1,4 +1,4 @@
-ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
require "bundler/setup" # Set up gems listed in the Gemfile.
require "bootsnap/setup" # Speed up boot time by caching expensive operations.
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 7a9f6c3a8..2e7fb486b 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -6,7 +6,7 @@
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
- config.cache_classes = false
+ config.enable_reloading = true
# Do not eager load code on boot.
config.eager_load = false
@@ -14,15 +14,18 @@
# Show full error reports.
config.consider_all_requests_local = true
+ # Enable server timing
+ config.server_timing = true
+
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
- if Rails.root.join('tmp', 'caching-dev.txt').exist?
+ if Rails.root.join("tmp/caching-dev.txt").exist?
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
config.cache_store = :memory_store
config.public_file_server.headers = {
- 'Cache-Control' => "public, max-age=#{2.days.to_i}"
+ "Cache-Control" => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
@@ -53,10 +56,8 @@
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
- # Debug mode disables concatenation and preprocessing of assets.
- # This option may cause significant delays in view rendering with a large
- # number of complex assets.
- config.assets.debug = true
+ # Highlight code that enqueued background job in logs.
+ config.active_job.verbose_enqueue_logs = true
# Suppress logger output for asset requests.
config.assets.quiet = true
@@ -67,10 +68,9 @@
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
- # Use an evented file watcher to asynchronously detect changes in source code,
- # routes, locales, etc. This feature depends on the listen gem.
- config.file_watcher = ActiveSupport::EventedFileUpdateChecker
-
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
+
+ # Raise error when a before_action's only/except options reference missing actions
+ config.action_controller.raise_on_missing_callback_actions = true
end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index dcf360d58..6f54ba5d6 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -4,7 +4,7 @@
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
- config.cache_classes = true
+ config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
@@ -13,53 +13,62 @@
config.eager_load = true
# Full error reports are disabled and caching is turned on.
- config.consider_all_requests_local = false
+ config.consider_all_requests_local = false
config.action_controller.perform_caching = true
- # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
- # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
+ # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
+ # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
- # Disable serving static files from the `/public` folder by default since
- # Apache or NGINX already handles this.
- config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
+ # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
+ # config.public_file_server.enabled = false
# Compress CSS using a preprocessor.
- config.assets.css_compressor = nil
+ # config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
- # config.asset_host = 'http://assets.example.com'
+ # config.asset_host = "http://assets.example.com"
# Specifies the header that your server uses for sending files.
- # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
- # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
+ # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
+ # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options).
config.active_storage.service = :local
# Mount Action Cable outside main process or domain.
# config.action_cable.mount_path = nil
- # config.action_cable.url = 'wss://example.com/cable'
- # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
+ # config.action_cable.url = "wss://example.com/cable"
+ # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ]
+
+ # Assume all access to the app is happening through a SSL-terminating reverse proxy.
+ # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
+ # config.assume_ssl = true
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
- # Include generic and useful information about system operation, but avoid logging too much
- # information to avoid inadvertent exposure of personally identifiable information (PII).
- config.log_level = ENV['LOG_LEVEL'] || :info
+ # Log to STDOUT by default
+ config.logger = ActiveSupport::Logger.new(STDOUT)
+ .tap { |logger| logger.formatter = ::Logger::Formatter.new }
+ .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
+ # Info include generic and useful information about system operation, but avoids logging too much
+ # information to avoid inadvertent exposure of personally identifiable information (PII). If you
+ # want to log everything, set the level to "debug".
+ config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
+
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment).
- # config.active_job.queue_adapter = :resque
+ # config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "govbox_pro_production"
config.action_mailer.perform_caching = false
@@ -72,49 +81,17 @@
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
- # Send deprecation notices to registered listeners.
- config.active_support.deprecation = :notify
-
- # Log disallowed deprecations.
- config.active_support.disallowed_deprecation = :log
-
- # Tell Active Support which deprecation messages to disallow.
- config.active_support.disallowed_deprecation_warnings = []
-
- # Use default logging formatter so that PID and timestamp are not suppressed.
- config.log_formatter = ::Logger::Formatter.new
-
- # Use a different logger for distributed setups.
- # require "syslog/logger"
- # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
-
- if ENV["RAILS_LOG_TO_STDOUT"].present?
- logger = ActiveSupport::Logger.new(STDOUT)
- logger.formatter = config.log_formatter
- config.logger = ActiveSupport::TaggedLogging.new(logger)
- end
+ # Don't log any deprecations.
+ config.active_support.report_deprecations = false
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
- # Inserts middleware to perform automatic connection switching.
- # The `database_selector` hash is used to pass options to the DatabaseSelector
- # middleware. The `delay` is used to determine how long to wait after a write
- # to send a subsequent read to the primary.
- #
- # The `database_resolver` class is used by the middleware to determine which
- # database is appropriate to use based on the time delay.
- #
- # The `database_resolver_context` class is used by the middleware to set
- # timestamps for the last write to the primary. The resolver uses the context
- # class timestamps to determine how long to wait before reading from the
- # replica.
- #
- # By default Rails will store a last write timestamp in the session. The
- # DatabaseSelector middleware is designed as such you can define your own
- # strategy for connection switching and pass that into the middleware through
- # these configuration options.
- # config.active_record.database_selector = { delay: 2.seconds }
- # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
- # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
+ # Enable DNS rebinding protection and other `Host` header attacks.
+ # config.hosts = [
+ # "example.com", # Allow requests from example.com
+ # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
+ # ]
+ # Skip DNS rebinding protection for the default health check endpoint.
+ # config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 93ed4f1b7..adbb4a6f4 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -8,27 +8,28 @@
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
- config.cache_classes = false
- config.action_view.cache_template_loading = true
+ # While tests run files are not watched, reloading is not necessary.
+ config.enable_reloading = false
- # Do not eager load code on boot. This avoids loading your whole application
- # just for the purpose of running a single test. If you are using a tool that
- # preloads Rails for running tests, you may have to set it to true.
- config.eager_load = false
+ # Eager loading loads your entire application. When running a single test locally,
+ # this is usually not necessary, and can slow down your test suite. However, it's
+ # recommended that you enable it in continuous integration systems to ensure eager
+ # loading is working properly before deploying your code.
+ config.eager_load = ENV["CI"].present?
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
- 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
+ "Cache-Control" => "public, max-age=#{1.hour.to_i}"
}
# Show full error reports and disable caching.
- config.consider_all_requests_local = true
+ config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.cache_store = :null_store
- # Raise exceptions instead of rendering exception templates.
- config.action_dispatch.show_exceptions = false
+ # Render exception templates for rescuable exceptions and raise for other exceptions.
+ config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
@@ -57,4 +58,7 @@
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
+
+ # Raise error when a before_action's only/except options reference missing actions
+ config.action_controller.raise_on_missing_callback_actions = true
end
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb
index 4b828e80c..19f51aaad 100644
--- a/config/initializers/assets.rb
+++ b/config/initializers/assets.rb
@@ -1,7 +1,7 @@
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
-Rails.application.config.assets.version = '1.0'
+Rails.application.config.assets.version = "1.0"
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index 35d0f26fc..b3076b38f 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -1,30 +1,25 @@
# Be sure to restart your server when you modify this file.
-# Define an application-wide content security policy
-# For further information see the following documentation
-# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
+# Define an application-wide content security policy.
+# See the Securing Rails Applications Guide for more information:
+# https://guides.rubyonrails.org/security.html#content-security-policy-header
-# Rails.application.config.content_security_policy do |policy|
-# policy.default_src :self, :https
-# policy.font_src :self, :https, :data
-# policy.img_src :self, :https, :data
-# policy.object_src :none
-# policy.script_src :self, :https
-# policy.style_src :self, :https
-# # If you are using webpack-dev-server then specify webpack-dev-server host
-# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
-
-# # Specify URI for violation reports
-# # policy.report_uri "/csp-violation-report-endpoint"
+# Rails.application.configure do
+# config.content_security_policy do |policy|
+# policy.default_src :self, :https
+# policy.font_src :self, :https, :data
+# policy.img_src :self, :https, :data
+# policy.object_src :none
+# policy.script_src :self, :https
+# policy.style_src :self, :https
+# # Specify URI for violation reports
+# # policy.report_uri "/csp-violation-report-endpoint"
+# end
+#
+# # Generate session nonces for permitted importmap, inline scripts, and inline styles.
+# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
+# config.content_security_policy_nonce_directives = %w(script-src style-src)
+#
+# # Report violations without enforcing the policy.
+# # config.content_security_policy_report_only = true
# end
-
-# If you are using UJS then enable automatic nonce generation
-# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
-
-# Set the nonce only to specific directives
-# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
-
-# Report CSP violations to a specified URI
-# For further information see the following documentation:
-# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
-# Rails.application.config.content_security_policy_report_only = true
diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb
index 4b34a0366..c2d89e28a 100644
--- a/config/initializers/filter_parameter_logging.rb
+++ b/config/initializers/filter_parameter_logging.rb
@@ -1,6 +1,8 @@
# Be sure to restart your server when you modify this file.
-# Configure sensitive parameters which will be filtered from the log file.
+# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
+# Use this to limit dissemination of sensitive information.
+# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
]
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index ac033bf9d..3860f659e 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -4,13 +4,13 @@
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-# inflect.plural /^(ox)$/i, '\1en'
-# inflect.singular /^(ox)en/i, '\1'
-# inflect.irregular 'person', 'people'
+# inflect.plural /^(ox)$/i, "\\1en"
+# inflect.singular /^(ox)en/i, "\\1"
+# inflect.irregular "person", "people"
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-# inflect.acronym 'RESTful'
+# inflect.acronym "RESTful"
# end
diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb
index 00f64d71b..7db3b9577 100644
--- a/config/initializers/permissions_policy.rb
+++ b/config/initializers/permissions_policy.rb
@@ -1,11 +1,13 @@
+# Be sure to restart your server when you modify this file.
+
# Define an application-wide HTTP permissions policy. For further
-# information see https://developers.google.com/web/updates/2018/06/feature-policy
-#
-# Rails.application.config.permissions_policy do |f|
-# f.camera :none
-# f.gyroscope :none
-# f.microphone :none
-# f.usb :none
-# f.fullscreen :self
-# f.payment :self, "https://secure.example.com"
+# information see: https://developers.google.com/web/updates/2018/06/feature-policy
+
+# Rails.application.config.permissions_policy do |policy|
+# policy.camera :none
+# policy.gyroscope :none
+# policy.microphone :none
+# policy.usb :none
+# policy.fullscreen :self
+# policy.payment :self, "https://secure.example.com"
# end
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 3b25971c4..55f2cfe08 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -6,6 +6,12 @@ sk:
errors:
messages:
record_invalid: "Validácia neúspešná: %{errors}"
+ models:
+ tag:
+ attributes:
+ base:
+ restrict_dependent_destroy:
+ has_many: "Štítok je použitý v automatizačných pravidlách, nie je ho možné vymazať. Upravte najskôr pravidlá"
date:
abbr_day_names:
- Ne
@@ -248,3 +254,7 @@ sk:
tag_editing_in_message_threads:
one: "Úprava štítkov v jednom vlákne"
other: "Úprava štítkov v %{count} vláknach"
+ message_draft:
+ form_signed: "Správa už bola podpísaná. Podpísanú správu nie je možné ďalej upravovať. V prípade potreby zmien kliknite na tlačidlo Odstrániť podpisy. Všetky podpisy budú odstránené, správu bude ďalej možné upravovať. Následne ju bude potrebné znova podpísať."
+ form_submitted: "Správa už bola odoslaná. Odoslanú správu nie je možné ďalej upravovať. V prípade potreby pripravte novú správu a odošlite ju."
+ read_only_agenda: "Správu nie je možné ďalej upravovať. V prípade potreby pripravte novú správu a odošlite ju."
diff --git a/config/routes.rb b/config/routes.rb
index a2e367520..65e013405 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -105,7 +105,9 @@
resources :message_drafts do
member do
- post 'submit'
+ post :confirm_unlock
+ post :unlock
+ post :submit
end
post 'submit_all', on: :collection
@@ -131,6 +133,10 @@
get "/service-worker.js" => "service_worker#service_worker"
get "/manifest.json" => "service_worker#manifest"
+ get "/health", to: "health_check#show"
+ get "/health/jobs/failing", to: "health_check#failing_jobs"
+ get "/health/jobs/stuck", to: "health_check#stuck_jobs"
+
root 'message_threads#index'
class GoodJobAdmin
diff --git a/db/migrate/20231127112038_update_audit_logs_from_changed_to_updated.rb b/db/migrate/20231127112038_update_audit_logs_from_changed_to_updated.rb
new file mode 100644
index 000000000..2f04e336e
--- /dev/null
+++ b/db/migrate/20231127112038_update_audit_logs_from_changed_to_updated.rb
@@ -0,0 +1,6 @@
+class UpdateAuditLogsFromChangedToUpdated < ActiveRecord::Migration[7.0]
+ def change
+ AuditLog.connection.execute("update audit_logs set type = 'AuditLog::MessageThreadTagUpdated' where type = 'AuditLog::MessageThreadTagChanged'")
+ AuditLog.connection.execute("update audit_logs set type = 'AuditLog::MessageThreadNoteUpdated' where type = 'AuditLog::MessageThreadNoteChanged'")
+ end
+end
diff --git a/db/migrate/20231129090725_rename_tag_user_id_to_owner_id.rb b/db/migrate/20231129090725_rename_tag_user_id_to_owner_id.rb
new file mode 100644
index 000000000..f745aa0dd
--- /dev/null
+++ b/db/migrate/20231129090725_rename_tag_user_id_to_owner_id.rb
@@ -0,0 +1,5 @@
+class RenameTagUserIdToOwnerId < ActiveRecord::Migration[7.0]
+ def change
+ rename_column :tags, :user_id, :owner_id
+ end
+end
diff --git a/db/migrate/20231129094053_convert_tags_to_sti.rb b/db/migrate/20231129094053_convert_tags_to_sti.rb
new file mode 100644
index 000000000..ad0019e41
--- /dev/null
+++ b/db/migrate/20231129094053_convert_tags_to_sti.rb
@@ -0,0 +1,51 @@
+class ConvertTagsToSti < ActiveRecord::Migration[7.0]
+ def up
+ add_column :tags, :type, :string, null: true
+
+ Tag.find_each do |tag|
+ changes = if tag.system_name == "draft"
+ {
+ type: "DraftTag",
+ name: "Rozpracované",
+ system_name: nil
+ }
+ elsif tag.system_name == "delivery_notification"
+ {
+ type: "Upvs::DeliveryNotificationTag",
+ name: "Na prevzatie",
+ system_name: nil
+ }
+ else
+ {
+ type: "SimpleTag"
+ }
+ end
+
+ tag.update_columns(changes)
+ end
+
+ change_column_null :tags, :type, false
+ end
+
+ def down
+ Tag.find_each do |tag|
+ changes = if tag.type == "DraftTag"
+ {
+ system_name: "draft"
+ }
+ elsif tag.type == "Upvs::DeliveryNotificationTag"
+ {
+ system_name: "delivery_notification"
+ }
+ elsif tag.system_name.present?
+ {
+ external: true
+ }
+ end
+
+ tag.update_columns(changes)
+ end
+
+ remove_column :tags, :type
+ end
+end
diff --git a/db/migrate/20231129143117_add_features_to_tenant.rb b/db/migrate/20231129143117_add_features_to_tenant.rb
new file mode 100644
index 000000000..2dccf8ad4
--- /dev/null
+++ b/db/migrate/20231129143117_add_features_to_tenant.rb
@@ -0,0 +1,5 @@
+class AddFeaturesToTenant < ActiveRecord::Migration[7.0]
+ def change
+ add_column :tenants, :feature_flags, :string, array: true, default: []
+ end
+end
diff --git a/db/migrate/20231201113708_clean_external_columns_in_tags.rb b/db/migrate/20231201113708_clean_external_columns_in_tags.rb
new file mode 100644
index 000000000..05b5bc9fa
--- /dev/null
+++ b/db/migrate/20231201113708_clean_external_columns_in_tags.rb
@@ -0,0 +1,6 @@
+class CleanExternalColumnsInTags < ActiveRecord::Migration[7.0]
+ def change
+ rename_column :tags, :system_name, :external_name
+ remove_column :tags, :external, :boolean, default: false
+ end
+end
diff --git a/db/migrate/20231204132823_generate_tenant_signing_tags.rb b/db/migrate/20231204132823_generate_tenant_signing_tags.rb
new file mode 100644
index 000000000..ba301bd08
--- /dev/null
+++ b/db/migrate/20231204132823_generate_tenant_signing_tags.rb
@@ -0,0 +1,13 @@
+class GenerateTenantSigningTags < ActiveRecord::Migration[7.0]
+ def up
+ Tenant.find_each do |tenant|
+ tenant.create_signature_requested_tag!(name: "Na podpis", visible: true)
+ tenant.create_signed_tag!(name: "Podpísané", visible: true)
+ end
+ end
+
+ def down
+ SignatureRequestedTag.destroy_all
+ SignedTag.destroy_all
+ end
+end
diff --git a/db/migrate/20231204133308_generate_signers_tags.rb b/db/migrate/20231204133308_generate_signers_tags.rb
new file mode 100644
index 000000000..5063420d3
--- /dev/null
+++ b/db/migrate/20231204133308_generate_signers_tags.rb
@@ -0,0 +1,12 @@
+class GenerateSignersTags < ActiveRecord::Migration[7.0]
+ def up
+ SignerGroup.includes(group_memberships: [:group, :user]).find_each do |group|
+ group.group_memberships.each(&:create_signing_tags!)
+ end
+ end
+
+ def down
+ SignatureRequestedFromTag.destroy_all
+ SignedByTag.destroy_all
+ end
+end
diff --git a/db/migrate/20231204143711_add_unique_indexes_for_signings.rb b/db/migrate/20231204143711_add_unique_indexes_for_signings.rb
new file mode 100644
index 000000000..8e5edc72a
--- /dev/null
+++ b/db/migrate/20231204143711_add_unique_indexes_for_signings.rb
@@ -0,0 +1,15 @@
+class AddUniqueIndexesForSignings < ActiveRecord::Migration[7.0]
+ def up
+ remove_index :group_memberships, :group_id
+ add_index :group_memberships, [:group_id, :user_id], unique: true
+
+ execute "CREATE UNIQUE INDEX signings_tags ON tags (tenant_id, type) WHERE (type IN ('SignatureRequestedTag', 'SignedTag'));"
+ end
+
+ def down
+ execute "DROP INDEX signings_tags;"
+
+ remove_index :group_memberships, [:group_id, :user_id], unique: true
+ add_index :group_memberships, :group_id
+ end
+end
diff --git a/db/migrate/20231205190743_add_icon_to_tags.rb b/db/migrate/20231205190743_add_icon_to_tags.rb
new file mode 100644
index 000000000..588309564
--- /dev/null
+++ b/db/migrate/20231205190743_add_icon_to_tags.rb
@@ -0,0 +1,5 @@
+class AddIconToTags < ActiveRecord::Migration[7.0]
+ def change
+ add_column :tags, :icon, :string
+ end
+end
diff --git a/db/migrate/20231205190907_add_group_memberships_counter_to_tags.rb b/db/migrate/20231205190907_add_group_memberships_counter_to_tags.rb
new file mode 100644
index 000000000..0aa58d1aa
--- /dev/null
+++ b/db/migrate/20231205190907_add_group_memberships_counter_to_tags.rb
@@ -0,0 +1,8 @@
+class AddGroupMembershipsCounterToTags < ActiveRecord::Migration[7.0]
+ def change
+ add_column :tags, :tag_groups_count, :integer, null: false, default: 0
+ Tag.find_each do |tag|
+ Tag.reset_counters(tag.id, :tag_groups)
+ end
+ end
+end
diff --git a/db/migrate/20231205192436_add_color_to_tags.rb b/db/migrate/20231205192436_add_color_to_tags.rb
new file mode 100644
index 000000000..4c417fbc5
--- /dev/null
+++ b/db/migrate/20231205192436_add_color_to_tags.rb
@@ -0,0 +1,7 @@
+class AddColorToTags < ActiveRecord::Migration[7.0]
+ def change
+ change_table :tags do |t|
+ t.enum :color, enum_type: 'color'
+ end
+ end
+end
diff --git a/db/migrate/20231206090833_migrate_to_everything_tag.rb b/db/migrate/20231206090833_migrate_to_everything_tag.rb
new file mode 100644
index 000000000..7a61cf292
--- /dev/null
+++ b/db/migrate/20231206090833_migrate_to_everything_tag.rb
@@ -0,0 +1,19 @@
+class MigrateToEverythingTag < ActiveRecord::Migration[7.0]
+ def up
+ Tenant.find_each do |tenant|
+ tenant.admin_group.tag_groups.destroy_all
+
+ tenant.create_everything_tag!(name: "Všetky správy", visible: false) unless tenant.everything_tag
+ tenant.make_admins_see_everything!
+ tenant.boxes.find_each do |box|
+ box.message_threads.find_each do |thread|
+ thread.tags << tenant.everything_tag
+ end
+ end
+ end
+ end
+
+ def down
+ # noop
+ end
+end
diff --git a/db/migrate/20231206133647_create_good_jobs_error_event.rb b/db/migrate/20231206133647_create_good_jobs_error_event.rb
new file mode 100644
index 000000000..e301ad751
--- /dev/null
+++ b/db/migrate/20231206133647_create_good_jobs_error_event.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CreateGoodJobsErrorEvent < ActiveRecord::Migration[7.1]
+ def change
+ reversible do |dir|
+ dir.up do
+ # Ensure this incremental update migration is idempotent
+ # with monolithic install migration.
+ return if connection.column_exists?(:good_jobs, :error_event)
+ end
+ end
+
+ add_column :good_jobs, :error_event, :integer, limit: 2
+ add_column :good_job_executions, :error_event, :integer, limit: 2
+ end
+end
diff --git a/db/migrate/20231206141003_add_service_name_to_active_storage_blobs.active_storage.rb b/db/migrate/20231206141003_add_service_name_to_active_storage_blobs.active_storage.rb
new file mode 100644
index 000000000..a15c6ce8e
--- /dev/null
+++ b/db/migrate/20231206141003_add_service_name_to_active_storage_blobs.active_storage.rb
@@ -0,0 +1,22 @@
+# This migration comes from active_storage (originally 20190112182829)
+class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0]
+ def up
+ return unless table_exists?(:active_storage_blobs)
+
+ unless column_exists?(:active_storage_blobs, :service_name)
+ add_column :active_storage_blobs, :service_name, :string
+
+ if configured_service = ActiveStorage::Blob.service.name
+ ActiveStorage::Blob.unscoped.update_all(service_name: configured_service)
+ end
+
+ change_column :active_storage_blobs, :service_name, :string, null: false
+ end
+ end
+
+ def down
+ return unless table_exists?(:active_storage_blobs)
+
+ remove_column :active_storage_blobs, :service_name
+ end
+end
diff --git a/db/migrate/20231206141004_create_active_storage_variant_records.active_storage.rb b/db/migrate/20231206141004_create_active_storage_variant_records.active_storage.rb
new file mode 100644
index 000000000..94ac83af0
--- /dev/null
+++ b/db/migrate/20231206141004_create_active_storage_variant_records.active_storage.rb
@@ -0,0 +1,27 @@
+# This migration comes from active_storage (originally 20191206030411)
+class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0]
+ def change
+ return unless table_exists?(:active_storage_blobs)
+
+ # Use Active Record's configured type for primary key
+ create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t|
+ t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type
+ t.string :variation_digest, null: false
+
+ t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
+ t.foreign_key :active_storage_blobs, column: :blob_id
+ end
+ end
+
+ private
+ def primary_key_type
+ config = Rails.configuration.generators
+ config.options[config.orm][:primary_key_type] || :primary_key
+ end
+
+ def blobs_primary_key_type
+ pkey_name = connection.primary_key(:active_storage_blobs)
+ pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name }
+ pkey_column.bigint? ? :bigint : pkey_column.type
+ end
+end
diff --git a/db/migrate/20231206141005_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb b/db/migrate/20231206141005_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
new file mode 100644
index 000000000..93c8b85ad
--- /dev/null
+++ b/db/migrate/20231206141005_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb
@@ -0,0 +1,8 @@
+# This migration comes from active_storage (originally 20211119233751)
+class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0]
+ def change
+ return unless table_exists?(:active_storage_blobs)
+
+ change_column_null(:active_storage_blobs, :checksum, true)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 87bdaf763..392e335c3 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[7.0].define(version: 2023_11_27_223506) do
+ActiveRecord::Schema[7.1].define(version: 2023_12_06_141005) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
@@ -177,6 +177,7 @@
t.datetime "scheduled_at"
t.datetime "finished_at"
t.text "error"
+ t.integer "error_event", limit: 2
t.index ["active_job_id", "created_at"], name: "index_good_job_executions_on_active_job_id_and_created_at"
end
@@ -214,6 +215,7 @@
t.boolean "is_discrete"
t.integer "executions_count"
t.text "job_class"
+ t.integer "error_event", limit: 2
t.index ["active_job_id", "created_at"], name: "index_good_jobs_on_active_job_id_and_created_at"
t.index ["active_job_id"], name: "index_good_jobs_on_active_job_id"
t.index ["batch_callback_id"], name: "index_good_jobs_on_batch_callback_id", where: "(batch_callback_id IS NOT NULL)"
@@ -261,7 +263,7 @@
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.index ["group_id"], name: "index_group_memberships_on_group_id"
+ t.index ["group_id", "user_id"], name: "index_group_memberships_on_group_id_and_user_id", unique: true
t.index ["user_id"], name: "index_group_memberships_on_user_id"
end
@@ -429,18 +431,23 @@
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "visible", default: true, null: false
- t.bigint "user_id"
- t.boolean "external", default: false
- t.string "system_name"
+ t.bigint "owner_id"
+ t.string "external_name"
+ t.string "type", null: false
+ t.string "icon"
+ t.integer "tag_groups_count", default: 0, null: false
+ t.enum "color", enum_type: "color"
t.index "tenant_id, lower((name)::text)", name: "index_tags_on_tenant_id_and_lowercase_name", unique: true
+ t.index ["owner_id"], name: "index_tags_on_owner_id"
+ t.index ["tenant_id", "type"], name: "signings_tags", unique: true, where: "((type)::text = ANY ((ARRAY['SignatureRequestedTag'::character varying, 'SignedTag'::character varying])::text[]))"
t.index ["tenant_id"], name: "index_tags_on_tenant_id"
- t.index ["user_id"], name: "index_tags_on_user_id"
end
create_table "tenants", force: :cascade do |t|
t.string "name", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.string "feature_flags", default: [], array: true
end
create_table "upvs_form_template_related_documents", force: :cascade do |t|
@@ -511,7 +518,7 @@
add_foreign_key "tag_groups", "groups"
add_foreign_key "tag_groups", "tags"
add_foreign_key "tags", "tenants"
- add_foreign_key "tags", "users"
+ add_foreign_key "tags", "users", column: "owner_id"
add_foreign_key "upvs_form_template_related_documents", "upvs_form_templates"
add_foreign_key "users", "tenants"
end
diff --git a/db/seeds.rb b/db/seeds.rb
index 37af36359..f453850d1 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -11,7 +11,7 @@
api_connection = Govbox::ApiConnection.find_or_create_by!(sub: "SPL_Irvin_83300252_KK_24022023", api_token_private_key: File.read(Rails.root + "security/govbox_api_fix.pem"))
tenant.boxes.find_or_create_by!(name: "Dev box", uri: "ico://sk/83300252", short_name: 'DEV', api_connection: api_connection)
-tenant.tags.find_or_create_by!(name: 'NASES', system_name: 'NASES', user_id: tenant.users.first.id)
+tenant.tags.find_or_create_by!(type: 'SimpleTag', name: 'NASES', owner_id: tenant.users.first.id)
if tenant.users.first
rule = tenant.automation_rules.create!(name: 'NASES Tag Sender Rule', user: tenant.users.first, trigger_event: :message_created)
diff --git a/package.json b/package.json
index 10819f70c..e8894a76f 100644
--- a/package.json
+++ b/package.json
@@ -6,9 +6,9 @@
"license": "MIT",
"dependencies": {
"@hotwired/stimulus": "^3.2.1",
- "@hotwired/turbo-rails": "^7.3.0",
- "@rails/request.js": "^0.0.8",
- "esbuild": "^0.17.19",
+ "@hotwired/turbo-rails": "^7.0.0",
+ "@rails/request.js": "^0.0.9",
+ "esbuild": "^0.19.8",
"tailwindcss-stimulus-components": "^4.0.4"
},
"scripts": {
diff --git a/test/fixtures/boxes.yml b/test/fixtures/boxes.yml
index efb9325fa..89d61afc3 100644
--- a/test/fixtures/boxes.yml
+++ b/test/fixtures/boxes.yml
@@ -19,7 +19,7 @@ solver_main:
uri: MyString2
tenant: solver
short_name: MY1
- api_connection: three
+ api_connection: govbox_api_api_connection1
google_box_with_govbox_api_connection:
name: Box with GovBox API connection
diff --git a/test/fixtures/filters.yml b/test/fixtures/filters.yml
index 4f210ce6d..df801de55 100644
--- a/test/fixtures/filters.yml
+++ b/test/fixtures/filters.yml
@@ -2,14 +2,14 @@
one:
tenant: ssd
- author: one
+ author: basic
name: With General text
query: general
position: 1
two:
tenant: ssd
- author: two
+ author: admin
name: With Legal text
query: Legal
position: 2
diff --git a/test/fixtures/govbox/folders.yml b/test/fixtures/govbox/folders.yml
index 1eb59d8e8..5287801ec 100644
--- a/test/fixtures/govbox/folders.yml
+++ b/test/fixtures/govbox/folders.yml
@@ -8,7 +8,7 @@ ssd_one:
ssd_two:
edesk_folder_id: 7890123
- parent_folder: one
+ parent_folder: ssd_one
box: ssd_main
name: MyName
system: false
diff --git a/test/fixtures/group_memberships.yml b/test/fixtures/group_memberships.yml
index 156382ccf..535aa84f9 100644
--- a/test/fixtures/group_memberships.yml
+++ b/test/fixtures/group_memberships.yml
@@ -1,9 +1,9 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
-one:
+ssd_basic_basic_user:
user: basic
- group: basic_user
+ group: ssd_basic_user
-two:
+ssd_basic_all:
user: basic
- group: all
+ group: ssd_all
diff --git a/test/fixtures/groups.yml b/test/fixtures/groups.yml
index 9044e1228..b3e68a1da 100644
--- a/test/fixtures/groups.yml
+++ b/test/fixtures/groups.yml
@@ -1,20 +1,25 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
-all:
+ssd_all:
name: all
type: AllGroup
tenant: ssd
-admins:
+ssd_admins:
name: admins
type: AdminGroup
tenant: ssd
-basic_user:
- name: "Basic user"
+ssd_basic_user:
+ name: Basic user
type: UserGroup
tenant: ssd
+ssd_signers:
+ name: Podpisovaci
+ type: SignerGroup
+ tenant: ssd
+
solver_admin:
name: admins
type: AdminGroup
diff --git a/test/fixtures/message_threads_tags.yml b/test/fixtures/message_threads_tags.yml
index 4345e6f14..8061d074d 100644
--- a/test/fixtures/message_threads_tags.yml
+++ b/test/fixtures/message_threads_tags.yml
@@ -23,7 +23,3 @@ ssd_main_issue_finance:
ssd_main_issue_hidden:
message_thread: ssd_main_issue
tag: ssd_hidden
-
-solver_main_delivery_notification_delivery_notification:
- message_thread: solver_main_delivery_notification
- tag: solver_delivery_notification
diff --git a/test/fixtures/messages_tags.yml b/test/fixtures/messages_tags.yml
index 0d9c2bfe2..a3642e246 100644
--- a/test/fixtures/messages_tags.yml
+++ b/test/fixtures/messages_tags.yml
@@ -8,6 +8,3 @@ ssd_main_general_two_external:
message: ssd_main_general_two
tag: ssd_external
-solver_main_delivery_notification_one_delivery_notification:
- message: solver_main_delivery_notification_one
- tag: solver_delivery_notification
diff --git a/test/fixtures/tag_groups.yml b/test/fixtures/tag_groups.yml
index c900e2cce..0b4521040 100644
--- a/test/fixtures/tag_groups.yml
+++ b/test/fixtures/tag_groups.yml
@@ -2,7 +2,7 @@
finance_basic_user:
tag: ssd_finance
- group: basic_user
+ group: ssd_basic_user
#two:
# tag: two
diff --git a/test/fixtures/tags.yml b/test/fixtures/tags.yml
index d966647fa..21710960b 100644
--- a/test/fixtures/tags.yml
+++ b/test/fixtures/tags.yml
@@ -2,88 +2,98 @@
ssd_finance:
name: Finance
- external: false
+ type: SimpleTag
visible: true
tenant: ssd
ssd_legal:
name: Legal
- external: false
+ type: SimpleTag
visible: true
tenant: ssd
ssd_hidden:
name: Hidden
- external: false
+ type: SimpleTag
visible: false
tenant: ssd
ssd_external:
name: External
- external: true
+ type: SimpleTag
+ external_name: "slovensko.sk:/nieco"
visible: false
tenant: ssd
ssd_external_visible:
name: ExtVisible
- external: true
+ type: SimpleTag
+ external_name: "slovensko.sk:/nieco"
visible: true
tenant: ssd
ssd_drafts:
name: Drafts
- system_name: draft
- external: false
+ type: DraftTag
visible: true
tenant: ssd
-ssd_other:
- name: Other
- external: false
- visible: true
+ssd_everything:
+ name: Everything
+ type: EverythingTag
+ visible: false
tenant: ssd
-ssd_delivery_notification:
- name: DeliveryNotifications
- system_name: delivery_notification
- external: false
+ssd_other:
+ name: Other
+ type: SimpleTag
visible: true
tenant: ssd
ssd_construction:
name: Construction
- external: false
+ type: SimpleTag
visible: true
tenant: ssd
ssd_office:
name: Office
- external: false
+ type: SimpleTag
visible: true
tenant: ssd
ssd_print:
name: Print
- external: false
+ type: SimpleTag
+ visible: true
+ tenant: ssd
+
+ssd_signature_requested:
+ name: Na podpis
+ type: SignatureRequestedTag
+ visible: true
+ tenant: ssd
+
+ssd_signed:
+ name: Podpisane
+ type: SignedTag
visible: true
tenant: ssd
solver_special:
name: Special
- external: false
+ type: SimpleTag
visible: true
tenant: solver
solver_drafts:
name: Drafts
- system_name: draft
- external: false
+ type: DraftTag
visible: true
tenant: solver
-solver_delivery_notification:
- name: DeliveryNotifications
- system_name: delivery_notification
- external: false
- visible: true
- tenant: solver
+solver_everything:
+ name: Everything
+ type: EverythingTag
+ visible: false
+ tenant: solver
\ No newline at end of file
diff --git a/test/helpers/page_parts_helper.rb b/test/helpers/page_parts_helper.rb
index ab2c8bfe0..3f2c0c533 100644
--- a/test/helpers/page_parts_helper.rb
+++ b/test/helpers/page_parts_helper.rb
@@ -26,4 +26,10 @@ def within_tags
yield
end
end
+
+ def within_message_in_thread(message)
+ within("\##{dom_id(message)}") do
+ yield
+ end
+ end
end
diff --git a/test/integration/health_check_test.rb b/test/integration/health_check_test.rb
new file mode 100644
index 000000000..2060ed82e
--- /dev/null
+++ b/test/integration/health_check_test.rb
@@ -0,0 +1,21 @@
+require "test_helper"
+
+class HealthCheckTest < ActionDispatch::IntegrationTest
+ test "healthcheck responds with 200 OK" do
+ get '/health/'
+
+ assert_response :success
+ end
+
+ test "failing jobs healthcheck responds with 200 OK" do
+ get '/health/jobs/failing'
+
+ assert_response :success
+ end
+
+ test "stuck jobs healthcheck responds with 200 OK" do
+ get '/health/jobs/stuck'
+
+ assert_response :success
+ end
+end
diff --git a/test/jobs/govbox/process_message_job_test.rb b/test/jobs/govbox/process_message_job_test.rb
index 04754c1dd..ffd91e35d 100644
--- a/test/jobs/govbox/process_message_job_test.rb
+++ b/test/jobs/govbox/process_message_job_test.rb
@@ -36,4 +36,13 @@ class Govbox::ProcessMessageJobTest < ActiveJob::TestCase
assert outbox_message.reload.collapsed?
end
+
+ test "successfully processes a delivery notification" do
+ inbox_govbox_message = govbox_messages(:solver_delivery_notification)
+ Govbox::ProcessMessageJob.new.perform(inbox_govbox_message)
+
+ message = Message.find_by_uuid(inbox_govbox_message.payload["message_id"])
+
+ assert message
+ end
end
diff --git a/test/jobs/govbox/process_unathorized_delivery_notification_job_test.rb b/test/jobs/govbox/process_unathorized_delivery_notification_job_test.rb
index ff1636bff..519c0f2e7 100644
--- a/test/jobs/govbox/process_unathorized_delivery_notification_job_test.rb
+++ b/test/jobs/govbox/process_unathorized_delivery_notification_job_test.rb
@@ -28,9 +28,8 @@ class Govbox::ProcessMessageJobTest < ActiveJob::TestCase
message = messages(:solver_main_delivery_notification_two)
govbox_message = govbox_messages(:solver_delivery_notification)
- delivery_notification_tag = Tag.find_by!(
- system_name: Govbox::Message::DELIVERY_NOTIFICATION_TAG,
- tenant: message.thread.box.tenant,
+ delivery_notification_tag = Upvs::DeliveryNotificationTag.find_or_create_for_tenant!(
+ message.thread.box.tenant
)
Govbox::ProcessUnauthorizedDeliveryNotificationJob.new.perform(govbox_message)
diff --git a/test/models/everything_tag_test.rb b/test/models/everything_tag_test.rb
new file mode 100644
index 000000000..5ec2dca4f
--- /dev/null
+++ b/test/models/everything_tag_test.rb
@@ -0,0 +1,15 @@
+require "test_helper"
+
+class EverythingTagTest < ActiveSupport::TestCase
+ test "adds everything tag to every thread" do
+ box = boxes(:ssd_main)
+ thread = box.message_threads.create!(
+ title: 'Test',
+ original_title: 'Test',
+ delivered_at: Time.current,
+ last_message_delivered_at: Time.current
+ )
+
+ assert_includes thread.tags, box.tenant.everything_tag
+ end
+end
diff --git a/test/models/govbox/message_test.rb b/test/models/govbox/message_test.rb
index 287375cb6..9c9efb62a 100644
--- a/test/models/govbox/message_test.rb
+++ b/test/models/govbox/message_test.rb
@@ -21,12 +21,12 @@ class Govbox::MessageTest < ActiveSupport::TestCase
assert_equal message.objects.first.message_object_datum.blob, "MyContent"
- assert_equal message.tags.count, 1
- assert_equal message.tags.first.name, "slovensko.sk:#{govbox_message.folder.name}"
- assert_equal message.tags.first.visible, false
- assert_equal message.tags.first.external, true
- assert_equal message.thread.tags.count, 1
- assert_equal message.tags.first, message.thread.tags.first
+ assert_equal 1, message.tags.count
+ assert_equal "slovensko.sk:#{govbox_message.folder.name}", message.tags.first.name
+ assert_equal "slovensko.sk:#{govbox_message.folder.name}", message.tags.first.external_name
+ assert_not message.tags.first.visible
+ assert_equal 1, message.thread.tags.simple.count
+ assert_equal message.tags.first, message.thread.tags.simple.first
end
test "should include general agenda subject in message title" do
@@ -42,23 +42,23 @@ class Govbox::MessageTest < ActiveSupport::TestCase
test "should not create new tag if already exists" do
govbox_message = govbox_messages(:one)
- tag = Tag.create!(system_name: "slovensko.sk:#{govbox_message.folder.name}", name: "slovensko.sk:#{govbox_message.folder.name}", tenant: govbox_message.folder.box.tenant, visible: false, external: true)
+ tag = SimpleTag.create!(external_name: "slovensko.sk:#{govbox_message.folder.name}", name: "slovensko.sk:#{govbox_message.folder.name}", tenant: govbox_message.folder.box.tenant, visible: false)
Govbox::Message.create_message_with_thread!(govbox_message)
message = Message.last
- assert_equal message.tags.count, 1
- assert_equal message.tags.first, tag
- assert_equal message.thread.tags.count, 1
- assert_equal message.thread.tags.first, tag
+ assert_equal 1, message.tags.count
+ assert_equal tag, message.tags.first
+ assert_equal 1, message.thread.tags.simple.count
+ assert_equal tag, message.thread.tags.simple.first
end
test "should not duplicate message thread tags" do
govbox_message1 = govbox_messages(:one)
govbox_message2 = govbox_messages(:three)
- tag = Tag.create!(system_name: "slovensko.sk:#{govbox_message1.folder.name}", name: "slovensko.sk:#{govbox_message1.folder.name}", tenant: govbox_message1.folder.box.tenant, visible: false, external: true)
+ tag = SimpleTag.create!(external_name: "slovensko.sk:#{govbox_message1.folder.name}", name: "slovensko.sk:#{govbox_message1.folder.name}", tenant: govbox_message1.folder.box.tenant, visible: false)
Govbox::Message.create_message_with_thread!(govbox_message1)
message1 = Message.last
@@ -66,15 +66,14 @@ class Govbox::MessageTest < ActiveSupport::TestCase
Govbox::Message.create_message_with_thread!(govbox_message2)
message2 = Message.last
- assert_equal message1.tags.count, 1
- assert_equal message1.tags.first, tag
- assert_equal message1.thread.tags.count, 1
- assert_equal message1.thread.tags.first, tag
+ assert_equal tag, message1.tags.first
+ assert_equal 1, message1.thread.tags.simple.count
+ assert_equal tag, message1.thread.tags.simple.first
- assert_equal message2.tags.count, 1
- assert_equal message2.tags.first, tag
- assert_equal message2.thread.tags.count, 1
- assert_equal message2.thread.tags.first, tag
+ assert_equal 1, message2.tags.simple.count
+ assert_equal tag, message2.tags.simple.first
+ assert_equal 1, message2.thread.tags.simple.count
+ assert_equal tag, message2.thread.tags.simple.first
end
test "should not use delivery notification title for message thread title" do
diff --git a/test/models/group_membership_test.rb b/test/models/group_membership_test.rb
new file mode 100644
index 000000000..6509ed7af
--- /dev/null
+++ b/test/models/group_membership_test.rb
@@ -0,0 +1,50 @@
+require "test_helper"
+
+class GroupMembershipTest < ActiveSupport::TestCase
+ test "creates signature tags for a user if a group is the signers group" do
+ user = users(:basic)
+ signers_group = groups(:ssd_signers)
+
+ GroupMembership.create!(user: user, group: signers_group)
+
+ user.reload
+ assert user.signature_requested_from_tag
+ assert_equal user.signature_requested_from_tag.groups, [user.user_group]
+ assert user.signed_by_tag
+ assert_equal user.signed_by_tag.groups, [user.user_group]
+ end
+
+ test "handles creation signature tags properly if some signing already exists" do
+ tenant = tenants(:ssd)
+ user = users(:basic)
+ signers_group = groups(:ssd_signers)
+
+ SignedByTag.create!(name: "something", groups: [user.user_group], tenant: tenant)
+ SignatureRequestedFromTag.create!(name: "Na podpis: #{user.name}", tenant: tenant)
+
+ GroupMembership.create!(user: user, group: signers_group)
+
+ user.reload
+
+ assert user.signature_requested_from_tag
+ assert_equal user.signature_requested_from_tag.name, "Na podpis: Basic user"
+ assert_equal user.signature_requested_from_tag.groups, [user.user_group]
+
+ assert user.signed_by_tag
+ assert_equal user.signed_by_tag.name, "Podpísané: Basic user"
+ assert_equal user.signed_by_tag.groups, [user.user_group]
+ end
+
+ test "destroys signature_requested_from tags but keeps signed_by tags for a user if a group is the signers group" do
+ user = users(:basic)
+ signers_group = groups(:ssd_signers)
+
+ membership = GroupMembership.create!(user: user, group: signers_group)
+ membership.destroy
+
+ user.reload
+
+ assert_nil user.signature_requested_from_tag
+ assert user.signed_by_tag
+ end
+end
diff --git a/test/models/message_draft_test.rb b/test/models/message_draft_test.rb
index b4c29732b..1db6712a1 100644
--- a/test/models/message_draft_test.rb
+++ b/test/models/message_draft_test.rb
@@ -6,7 +6,7 @@ class MessageDraftTest < ActiveSupport::TestCase
message_draft._run_create_callbacks
message_thread = message_draft.thread
- drafts_tag = message_thread.tags.find_by(system_name: "draft")
+ drafts_tag = message_thread.tags.find_by(type: DraftTag.to_s)
message_draft.destroy
@@ -18,7 +18,7 @@ class MessageDraftTest < ActiveSupport::TestCase
message_draft._run_create_callbacks
message_thread = message_draft.thread
- drafts_tag = message_thread.tags.find_by(name: "draft")
+ drafts_tag = message_thread.tags.find_by(type: DraftTag.to_s)
message_draft.destroy
diff --git a/test/models/message_test.rb b/test/models/message_test.rb
index 4257289ea..a30776cad 100644
--- a/test/models/message_test.rb
+++ b/test/models/message_test.rb
@@ -12,13 +12,18 @@ class MessageTest < ActiveSupport::TestCase
end
test "remove_cascade_tag method should delete tag from message and also message thread if no more messages with the tag" do
- message = messages(:solver_main_delivery_notification_one)
- tag = tags(:solver_delivery_notification)
+ message = messages(:ssd_main_general_one)
+ tag = tags(:ssd_finance)
+
+ message.add_cascading_tag(tag)
+
+ assert message.tags.include?(tag)
+ assert message.thread.tags.include?(tag)
message.remove_cascading_tag(tag)
- assert_equal message.tags.include?(tag), false
- assert_equal message.thread.tags.include?(tag), false
+ assert_not message.tags.include?(tag)
+ assert_not message.thread.tags.include?(tag)
end
test "remove_cascade_tag method should delete tag from message and keep it on message thread if more messages with the tag" do
@@ -27,7 +32,23 @@ class MessageTest < ActiveSupport::TestCase
message.remove_cascading_tag(tag)
- assert_equal message.tags.include?(tag), false
+ assert_not message.tags.include?(tag)
assert message.thread.tags.include?(tag)
end
+
+ test "reply to message should create a valid draft" do
+ message = messages(:ssd_main_general_one)
+ user = users(:basic)
+
+ reply = MessageDraft.create_message_reply(original_message: message, author: user)
+
+ assert_equal reply.sender_name, message.recipient_name
+ assert_equal reply.recipient_name, message.sender_name
+ assert_equal reply.message_thread_id, message.message_thread_id
+ assert_match message.title, reply.title
+ assert_match "Odpoveď", reply.title
+ assert_equal reply.type, "MessageDraft"
+ assert_equal reply.author_id, user.id
+ assert_not reply.collapsed
+ end
end
diff --git a/test/models/tag_test.rb b/test/models/tag_test.rb
index dd3cf2e2a..b4abcd82f 100644
--- a/test/models/tag_test.rb
+++ b/test/models/tag_test.rb
@@ -1,10 +1,4 @@
require "test_helper"
class TagTest < ActiveSupport::TestCase
- test "should mark tag readable by admin groups" do
- tenant = tenants(:ssd)
- tag = Tag.create(name: 'New tag', tenant: tenant)
-
- assert tag.groups == [tenant.admin_group]
- end
end
diff --git a/test/models/tenant_test.rb b/test/models/tenant_test.rb
new file mode 100644
index 000000000..8e20b77a5
--- /dev/null
+++ b/test/models/tenant_test.rb
@@ -0,0 +1,16 @@
+require "test_helper"
+
+class TenantTest < ActiveSupport::TestCase
+ test "all system tags and groups are created with tenant" do
+ tenant = Tenant.create!(name: "new one")
+
+ assert tenant.all_group
+ assert tenant.signer_group
+ assert tenant.admin_group
+ assert tenant.draft_tag
+ assert tenant.everything_tag
+ assert tenant.signature_requested_tag
+ assert tenant.signed_tag
+ assert_equal tenant.everything_tag.groups, [tenant.admin_group]
+ end
+end
diff --git a/test/system/message_threads_test.rb b/test/system/message_threads_test.rb
index b36f2dea2..9a4b2adc6 100644
--- a/test/system/message_threads_test.rb
+++ b/test/system/message_threads_test.rb
@@ -170,4 +170,22 @@ class MessageThreadsTest < ApplicationSystemTestCase
end
end
end
+
+ test "a user can go to a thread detail and reply to message" do
+ thread_issue = message_threads(:ssd_main_issue)
+ message_one = messages(:ssd_main_issue_one)
+
+ visit message_thread_path thread_issue
+ within_message_in_thread message_one do
+ click_on("Odpovedať")
+ end
+
+ within '#new_drafts' do
+ fill_in "Text", with: "Testovacie telo"
+ fill_in "Predmet", with: "Testovaci predmet"
+ click_button "Odoslať"
+ end
+
+ assert_text "Správa bola zaradená na odoslanie"
+ end
end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index b8a342cfa..68d7080f1 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -1,3 +1,6 @@
+require 'simplecov'
+SimpleCov.start 'rails'
+
ENV['RAILS_ENV'] ||= 'test'
require_relative "../config/environment"
require "rails/test_help"
diff --git a/yarn.lock b/yarn.lock
index 51d9b9e00..d2f0df489 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7,122 +7,122 @@
resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
-"@esbuild/android-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
- integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==
-
-"@esbuild/android-arm@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d"
- integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==
-
-"@esbuild/android-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1"
- integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==
-
-"@esbuild/darwin-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz#584c34c5991b95d4d48d333300b1a4e2ff7be276"
- integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==
-
-"@esbuild/darwin-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb"
- integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==
-
-"@esbuild/freebsd-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2"
- integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==
-
-"@esbuild/freebsd-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4"
- integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==
-
-"@esbuild/linux-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb"
- integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==
-
-"@esbuild/linux-arm@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a"
- integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==
-
-"@esbuild/linux-ia32@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a"
- integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==
-
-"@esbuild/linux-loong64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72"
- integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==
-
-"@esbuild/linux-mips64el@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289"
- integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==
-
-"@esbuild/linux-ppc64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7"
- integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==
-
-"@esbuild/linux-riscv64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09"
- integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==
-
-"@esbuild/linux-s390x@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829"
- integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==
-
-"@esbuild/linux-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4"
- integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==
-
-"@esbuild/netbsd-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462"
- integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==
-
-"@esbuild/openbsd-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691"
- integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==
-
-"@esbuild/sunos-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273"
- integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==
-
-"@esbuild/win32-arm64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f"
- integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==
-
-"@esbuild/win32-ia32@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03"
- integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==
-
-"@esbuild/win32-x64@0.17.19":
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061"
- integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==
+"@esbuild/android-arm64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz#fb7130103835b6d43ea499c3f30cfb2b2ed58456"
+ integrity sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA==
+
+"@esbuild/android-arm@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.8.tgz#b46e4d9e984e6d6db6c4224d72c86b7757e35bcb"
+ integrity sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA==
+
+"@esbuild/android-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.8.tgz#a13db9441b5a4f4e4fec4a6f8ffacfea07888db7"
+ integrity sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A==
+
+"@esbuild/darwin-arm64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz#49f5718d36541f40dd62bfdf84da9c65168a0fc2"
+ integrity sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw==
+
+"@esbuild/darwin-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz#75c5c88371eea4bfc1f9ecfd0e75104c74a481ac"
+ integrity sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q==
+
+"@esbuild/freebsd-arm64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz#9d7259fea4fd2b5f7437b52b542816e89d7c8575"
+ integrity sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw==
+
+"@esbuild/freebsd-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz#abac03e1c4c7c75ee8add6d76ec592f46dbb39e3"
+ integrity sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg==
+
+"@esbuild/linux-arm64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz#c577932cf4feeaa43cb9cec27b89cbe0df7d9098"
+ integrity sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ==
+
+"@esbuild/linux-arm@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz#d6014d8b98b5cbc96b95dad3d14d75bb364fdc0f"
+ integrity sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ==
+
+"@esbuild/linux-ia32@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz#2379a0554307d19ac4a6cdc15b08f0ea28e7a40d"
+ integrity sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ==
+
+"@esbuild/linux-loong64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz#e2a5bbffe15748b49356a6cd7b2d5bf60c5a7123"
+ integrity sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ==
+
+"@esbuild/linux-mips64el@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz#1359331e6f6214f26f4b08db9b9df661c57cfa24"
+ integrity sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q==
+
+"@esbuild/linux-ppc64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz#9ba436addc1646dc89dae48c62d3e951ffe70951"
+ integrity sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg==
+
+"@esbuild/linux-riscv64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz#fbcf0c3a0b20f40b5fc31c3b7695f0769f9de66b"
+ integrity sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg==
+
+"@esbuild/linux-s390x@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz#989e8a05f7792d139d5564ffa7ff898ac6f20a4a"
+ integrity sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg==
+
+"@esbuild/linux-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz#b187295393a59323397fe5ff51e769ec4e72212b"
+ integrity sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg==
+
+"@esbuild/netbsd-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz#c1ec0e24ea82313cb1c7bae176bd5acd5bde7137"
+ integrity sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw==
+
+"@esbuild/openbsd-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz#0c5b696ac66c6d70cf9ee17073a581a28af9e18d"
+ integrity sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ==
+
+"@esbuild/sunos-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz#2a697e1f77926ff09fcc457d8f29916d6cd48fb1"
+ integrity sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w==
+
+"@esbuild/win32-arm64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz#ec029e62a2fca8c071842ecb1bc5c2dd20b066f1"
+ integrity sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg==
+
+"@esbuild/win32-ia32@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz#cbb9a3146bde64dc15543e48afe418c7a3214851"
+ integrity sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw==
+
+"@esbuild/win32-x64@0.19.8":
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz#c8285183dbdb17008578dbacb6e22748709b4822"
+ integrity sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA==
"@hotwired/stimulus@^3.2.1":
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.1.tgz#e3de23623b0c52c247aba4cd5d530d257008676b"
- integrity sha512-HGlzDcf9vv/EQrMJ5ZG6VWNs8Z/xMN+1o2OhV1gKiSG6CqZt5MCBB1gRg5ILiN3U0jEAxuDTNPRfBcnZBDmupQ==
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608"
+ integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A==
-"@hotwired/turbo-rails@^7.3.0":
+"@hotwired/turbo-rails@^7.0.0":
version "7.3.0"
resolved "https://registry.yarnpkg.com/@hotwired/turbo-rails/-/turbo-rails-7.3.0.tgz#422c21752509f3edcd6c7b2725bbe9e157815f51"
integrity sha512-fvhO64vp/a2UVQ3jue9WTc2JisMv9XilIC7ViZmXAREVwiQ2S4UC7Go8f9A1j4Xu7DBI6SbFdqILk5ImqVoqyA==
@@ -160,9 +160,9 @@
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
"@jridgewell/trace-mapping@^0.3.9":
- version "0.3.19"
- resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811"
- integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==
+ version "0.3.20"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f"
+ integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==
dependencies:
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
@@ -189,14 +189,14 @@
fastq "^1.6.0"
"@rails/actioncable@^7.0":
- version "7.0.5"
- resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.5.tgz#bbc11203e0d3d5084002abfcf01d621fdf5f3a9d"
- integrity sha512-SOBA2heB9lTw0VYIx8M/ed7inSf4I9sR8OIlJprhgkfQ3WJtrxPJ6DDATR1Z3RYaIR7HlT2Olj08v1lfGIGuHA==
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.1.2.tgz#d261ff4b72844f5af496671346ec478798f4ac2c"
+ integrity sha512-KGziTZfbmGm8/fHOpj515xupbYU+49hsp4etfdpoDJ/CEY2bRZR0cyFcJkpK6n0t/sxOHNWY6bo9vSgXZvT7Mg==
-"@rails/request.js@^0.0.8":
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/@rails/request.js/-/request.js-0.0.8.tgz#5e2e8da15013b1af7f04d759e4e9d1cff981865c"
- integrity sha512-ysHYZDl+XjBwFVXz7EI7XW+ZWiTFY8t7TrC/ahpAPt0p7NE4DZxm1nJQY9gmF4PBf+4pAYa+D/rLIGmrn1ZMvg==
+"@rails/request.js@^0.0.9":
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/@rails/request.js/-/request.js-0.0.9.tgz#89e2a575405dc07eb8a9b3d2fe04289e1f057cd0"
+ integrity sha512-VleYUyrA3rwKMvYnz7MI9Ada85Vekjb/WVz7NuGgDO24Y3Zy9FFSpDMQW+ea/tlftD+CdX/W/sUosRA9/HkDOQ==
"@tailwindcss/aspect-ratio@^0.4.2":
version "0.4.2"
@@ -204,9 +204,9 @@
integrity sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==
"@tailwindcss/forms@^0.5.6":
- version "0.5.6"
- resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.6.tgz#29c6c2b032b363e0c5110efed1499867f6d7e868"
- integrity sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821"
+ integrity sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==
dependencies:
mini-svg-data-uri "^1.2.3"
@@ -308,38 +308,38 @@ dlv@^1.1.3:
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
-esbuild@^0.17.19:
- version "0.17.19"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.19.tgz#087a727e98299f0462a3d0bcdd9cd7ff100bd955"
- integrity sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==
+esbuild@^0.19.8:
+ version "0.19.8"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.8.tgz#ad05b72281d84483fa6b5345bd246c27a207b8f1"
+ integrity sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w==
optionalDependencies:
- "@esbuild/android-arm" "0.17.19"
- "@esbuild/android-arm64" "0.17.19"
- "@esbuild/android-x64" "0.17.19"
- "@esbuild/darwin-arm64" "0.17.19"
- "@esbuild/darwin-x64" "0.17.19"
- "@esbuild/freebsd-arm64" "0.17.19"
- "@esbuild/freebsd-x64" "0.17.19"
- "@esbuild/linux-arm" "0.17.19"
- "@esbuild/linux-arm64" "0.17.19"
- "@esbuild/linux-ia32" "0.17.19"
- "@esbuild/linux-loong64" "0.17.19"
- "@esbuild/linux-mips64el" "0.17.19"
- "@esbuild/linux-ppc64" "0.17.19"
- "@esbuild/linux-riscv64" "0.17.19"
- "@esbuild/linux-s390x" "0.17.19"
- "@esbuild/linux-x64" "0.17.19"
- "@esbuild/netbsd-x64" "0.17.19"
- "@esbuild/openbsd-x64" "0.17.19"
- "@esbuild/sunos-x64" "0.17.19"
- "@esbuild/win32-arm64" "0.17.19"
- "@esbuild/win32-ia32" "0.17.19"
- "@esbuild/win32-x64" "0.17.19"
-
-fast-glob@^3.2.12:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4"
- integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==
+ "@esbuild/android-arm" "0.19.8"
+ "@esbuild/android-arm64" "0.19.8"
+ "@esbuild/android-x64" "0.19.8"
+ "@esbuild/darwin-arm64" "0.19.8"
+ "@esbuild/darwin-x64" "0.19.8"
+ "@esbuild/freebsd-arm64" "0.19.8"
+ "@esbuild/freebsd-x64" "0.19.8"
+ "@esbuild/linux-arm" "0.19.8"
+ "@esbuild/linux-arm64" "0.19.8"
+ "@esbuild/linux-ia32" "0.19.8"
+ "@esbuild/linux-loong64" "0.19.8"
+ "@esbuild/linux-mips64el" "0.19.8"
+ "@esbuild/linux-ppc64" "0.19.8"
+ "@esbuild/linux-riscv64" "0.19.8"
+ "@esbuild/linux-s390x" "0.19.8"
+ "@esbuild/linux-x64" "0.19.8"
+ "@esbuild/netbsd-x64" "0.19.8"
+ "@esbuild/openbsd-x64" "0.19.8"
+ "@esbuild/sunos-x64" "0.19.8"
+ "@esbuild/win32-arm64" "0.19.8"
+ "@esbuild/win32-ia32" "0.19.8"
+ "@esbuild/win32-x64" "0.19.8"
+
+fast-glob@^3.3.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
@@ -371,6 +371,11 @@ fsevents@~2.3.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
glob-parent@^5.1.2, glob-parent@~5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@@ -397,10 +402,12 @@ glob@7.1.6:
once "^1.3.0"
path-is-absolute "^1.0.0"
-has@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6"
- integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==
+hasown@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c"
+ integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==
+ dependencies:
+ function-bind "^1.1.2"
inflight@^1.0.4:
version "1.0.6"
@@ -423,11 +430,11 @@ is-binary-path@~2.1.0:
binary-extensions "^2.0.0"
is-core-module@^2.13.0:
- version "2.13.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
- integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
+ integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
dependencies:
- has "^1.0.3"
+ hasown "^2.0.0"
is-extglob@^2.1.1:
version "2.1.1"
@@ -446,16 +453,21 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-jiti@^1.18.2:
- version "1.20.0"
- resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42"
- integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==
+jiti@^1.19.1:
+ version "1.21.0"
+ resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
+ integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
-lilconfig@^2.0.5, lilconfig@^2.1.0:
+lilconfig@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
+lilconfig@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc"
+ integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==
+
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -510,10 +522,10 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
-nanoid@^3.3.6:
- version "3.3.6"
- resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
- integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==
+nanoid@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
@@ -584,12 +596,12 @@ postcss-js@^4.0.1:
camelcase-css "^2.0.1"
postcss-load-config@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd"
- integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
+ integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
dependencies:
- lilconfig "^2.0.5"
- yaml "^2.1.1"
+ lilconfig "^3.0.0"
+ yaml "^2.3.4"
postcss-nested@^6.0.1:
version "6.0.1"
@@ -620,11 +632,11 @@ postcss-value-parser@^4.0.0:
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8.4.23:
- version "8.4.31"
- resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
- integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+ version "8.4.32"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9"
+ integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==
dependencies:
- nanoid "^3.3.6"
+ nanoid "^3.3.7"
picocolors "^1.0.0"
source-map-js "^1.0.2"
@@ -697,19 +709,19 @@ tailwindcss-stimulus-components@^4.0.4:
integrity sha512-xNlMs1WufKiTMQtVklwHfrR/iuPVaFA0Mk5uefRnHztmr7w4g6BzKAWHyfte60pjhcQbmlbshHMOZiq/dkXnhw==
tailwindcss@^3.3.3:
- version "3.3.3"
- resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf"
- integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.6.tgz#4dd7986bf4902ad385d90d45fd4b2fa5fab26d5f"
+ integrity sha512-AKjF7qbbLvLaPieoKeTjG1+FyNZT6KaJMJPFeQyLfIp7l82ggH1fbHJSsYIvnbTFQOlkh+gBYpyby5GT1LIdLw==
dependencies:
"@alloc/quick-lru" "^5.2.0"
arg "^5.0.2"
chokidar "^3.5.3"
didyoumean "^1.2.2"
dlv "^1.1.3"
- fast-glob "^3.2.12"
+ fast-glob "^3.3.0"
glob-parent "^6.0.2"
is-glob "^4.0.3"
- jiti "^1.18.2"
+ jiti "^1.19.1"
lilconfig "^2.1.0"
micromatch "^4.0.5"
normalize-path "^3.0.0"
@@ -760,7 +772,7 @@ wrappy@1:
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
-yaml@^2.1.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.2.tgz#f522db4313c671a0ca963a75670f1c12ea909144"
- integrity sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==
+yaml@^2.3.4:
+ version "2.3.4"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2"
+ integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==