diff --git a/app/components/admin/permissions/groups_list_row_component.html.erb b/app/components/admin/permissions/groups_list_row_component.html.erb
index a06b6b7c6..9ac1df95f 100644
--- a/app/components/admin/permissions/groups_list_row_component.html.erb
+++ b/app/components/admin/permissions/groups_list_row_component.html.erb
@@ -5,14 +5,10 @@
- <% if @group.is_modifiable? %>
- <%= render Admin::Groups::GroupRenameComponent.new(@group) if @group.is_modifiable? %>
- <% else %>
- <%= @group.name %>
- <% end %>
+ <%= @group.name %>
- <%= t :user, count: @group.users.count %>
+ <%= t("user", count: @group.users.count) %>
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 11578d6d2..a466ed6db 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -3,40 +3,39 @@ class Admin::GroupsController < ApplicationController
def index
authorize([:admin, Group])
- @custom_groups = policy_scope([:admin, Group]).where(tenant_id: Current.tenant.id).where.not(group_type: %w[ALL USER])
- @system_groups = policy_scope([:admin, Group]).where(tenant_id: Current.tenant.id, group_type: %w[ALL USER])
+
+ @editable_groups = group_policy_scope.where(tenant_id: Current.tenant.id).editable
+ @non_editable_groups = group_policy_scope.where(tenant_id: Current.tenant.id).where.not(id: @editable_groups.pluck(:id))
end
def show
- authorize([:admin, @group])
- @other_tags = other_tags
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
end
def new
- @group = Current.tenant.groups.new
- authorize([:admin, @group])
+ @group = Current.tenant.custom_groups.new
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
end
def edit
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
end
def edit_members
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
end
def show_members
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
end
def edit_permissions
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
end
def create
- @group = Current.tenant.groups.new(group_params)
- @group.group_type = 'CUSTOM'
- authorize([:admin, @group])
+ @group = Current.tenant.custom_groups.new(group_params)
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
if @group.save
redirect_to edit_members_admin_tenant_group_url(Current.tenant, @group, step: :new), notice: 'Group was successfully created'
@@ -46,7 +45,7 @@ def create
end
def update
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
if @group.update(group_params)
redirect_to admin_tenant_groups_url(Current.tenant), notice: 'Group was successfully updated'
else
@@ -55,20 +54,20 @@ def update
end
def destroy
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
@group.destroy
redirect_to admin_tenant_groups_url(Current.tenant), notice: 'Group was successfully destroyed'
end
def search_non_members
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
return if params[:name_search].blank?
@users = non_members_search_clause
end
def search_non_tags
- authorize([:admin, @group])
+ authorize([:admin, @group], policy_class: Admin::GroupPolicy)
return if params[:name_search].blank?
@tags = non_tags_search_clause
@@ -77,7 +76,7 @@ def search_non_tags
private
def non_members_search_clause
- policy_scope([:admin, User])
+ user_policy_scope
.where(tenant: Current.tenant.id)
.where.not(id: User.joins(:group_memberships).where(group_memberships: { group_id: @group.id }))
.where('unaccent(name) ILIKE unaccent(?)', "%#{params[:name_search]}%")
@@ -85,7 +84,7 @@ def non_members_search_clause
end
def non_tags_search_clause
- policy_scope([:admin, Tag])
+ tag_policy_scope
.where(tenant: Current.tenant.id)
.where.not(id: Tag.joins(:tag_groups).where(tag_groups: { group_id: @group.id }))
.where('unaccent(name) ILIKE unaccent(?)', "%#{params[:name_search]}%")
@@ -93,10 +92,22 @@ def non_tags_search_clause
end
def set_group
- @group = policy_scope([:admin, Group]).find(params[:id])
+ @group = group_policy_scope.find(params[:id])
end
def group_params
- params.require(:group).permit(:name, :group_type)
+ params.require(:custom_group).permit(:name)
+ end
+
+ def group_policy_scope
+ policy_scope([:admin, Group])
+ end
+
+ def user_policy_scope
+ policy_scope([:admin, User])
+ end
+
+ def tag_policy_scope
+ policy_scope([:admin, Tag])
end
end
diff --git a/app/models/admin_group.rb b/app/models/admin_group.rb
new file mode 100644
index 000000000..6c5cd7c78
--- /dev/null
+++ b/app/models/admin_group.rb
@@ -0,0 +1,17 @@
+# == Schema Information
+#
+# Table name: groups
+#
+# id :bigint not null, primary key
+# group_type :enum
+# name :string not null
+# type :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# tenant_id :bigint not null
+#
+class AdminGroup < Group
+ def name
+ I18n.t("group.names.admin")
+ end
+end
diff --git a/app/models/all_group.rb b/app/models/all_group.rb
new file mode 100644
index 000000000..06c77c9f7
--- /dev/null
+++ b/app/models/all_group.rb
@@ -0,0 +1,17 @@
+# == Schema Information
+#
+# Table name: groups
+#
+# id :bigint not null, primary key
+# group_type :enum
+# name :string not null
+# type :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# tenant_id :bigint not null
+#
+class AllGroup < Group
+ def name
+ I18n.t("group.names.all")
+ end
+end
diff --git a/app/models/audit_log.rb b/app/models/audit_log.rb
index 6ec004c54..1289ca0b2 100644
--- a/app/models/audit_log.rb
+++ b/app/models/audit_log.rb
@@ -1,3 +1,22 @@
+# == Schema Information
+#
+# Table name: audit_logs
+#
+# id :bigint not null, primary key
+# actor_name :string
+# changeset :jsonb
+# happened_at :datetime not null
+# new_value :string
+# previous_value :string
+# thread_id_archived :integer
+# thread_title :string
+# type :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# actor_id :bigint
+# message_thread_id :bigint
+# tenant_id :bigint
+#
require "csv"
class AuditLog < ApplicationRecord
diff --git a/app/models/custom_group.rb b/app/models/custom_group.rb
new file mode 100644
index 000000000..cd83ccae9
--- /dev/null
+++ b/app/models/custom_group.rb
@@ -0,0 +1,14 @@
+# == Schema Information
+#
+# Table name: groups
+#
+# id :bigint not null, primary key
+# group_type :enum
+# name :string not null
+# type :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# tenant_id :bigint not null
+#
+class CustomGroup < Group
+end
diff --git a/app/models/group.rb b/app/models/group.rb
index 4c473143c..0ce00e218 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -3,8 +3,9 @@
# Table name: groups
#
# id :bigint not null, primary key
-# group_type :enum not null
+# group_type :enum
# name :string not null
+# type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# tenant_id :bigint not null
@@ -16,11 +17,26 @@ class Group < ApplicationRecord
has_many :tag_groups, dependent: :destroy
has_many :tags, through: :tag_groups
+ EDITABLE_GROUP_TYPES = %w[AdminGroup SignerGroup CustomGroup]
+
+ scope :editable, -> { where(type: EDITABLE_GROUP_TYPES) }
+
validates_presence_of :name
validates_uniqueness_of :name, scope: :tenant_id
- validates :group_type, inclusion: { in: ['ALL', 'USER', 'ADMIN', 'CUSTOM'], allow_blank: false }
- def is_modifiable?
- !group_type.in? %w[ALL USER]
+ def editable?
+ type.in? EDITABLE_GROUP_TYPES
+ end
+
+ def system?
+ !is_a?(CustomGroup)
+ end
+
+ def destroyable?
+ !system?
+ end
+
+ def renamable?
+ !system?
end
end
diff --git a/app/models/group_membership.rb b/app/models/group_membership.rb
index f1b1e4712..858b5b9c4 100644
--- a/app/models/group_membership.rb
+++ b/app/models/group_membership.rb
@@ -11,9 +11,4 @@
class GroupMembership < ApplicationRecord
belongs_to :group
belongs_to :user
-
- def group_membership_modifiable?
- # can't be removed from default groups - "TENANT_NAME"_ALL group and named user default group "USER_NAME"_USER
- !group.group_type.in? ['ALL', 'USER']
- end
end
diff --git a/app/models/signer_group.rb b/app/models/signer_group.rb
new file mode 100644
index 000000000..a87ba561b
--- /dev/null
+++ b/app/models/signer_group.rb
@@ -0,0 +1,17 @@
+# == Schema Information
+#
+# Table name: groups
+#
+# id :bigint not null, primary key
+# group_type :enum
+# name :string not null
+# type :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# tenant_id :bigint not null
+#
+class SignerGroup < Group
+ def name
+ I18n.t("group.names.signer")
+ end
+end
diff --git a/app/models/tag.rb b/app/models/tag.rb
index bb0a62554..165d294ad 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -28,7 +28,7 @@ class Tag < ApplicationRecord
scope :visible, -> { where(visible: true) }
- after_create_commit ->(tag) { tag.mark_readable_by_groups(tag.tenant.admin_groups) }
+ 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) }
diff --git a/app/models/tenant.rb b/app/models/tenant.rb
index 30c5a0d54..fb3f9d99d 100644
--- a/app/models/tenant.rb
+++ b/app/models/tenant.rb
@@ -11,11 +11,13 @@ class Tenant < ApplicationRecord
has_many :users, dependent: :destroy
has_many :groups, dependent: :destroy
- has_one :all_group, -> { where(group_type: 'ALL') }, class_name: 'Group'
- has_many :admin_groups, -> { where(group_type: 'ADMIN') }, class_name: 'Group'
+ has_one :all_group
+ has_one :signer_group
+ has_one :admin_group
+ has_many :custom_groups
has_many :boxes, dependent: :destroy
- has_many :automation_rules, class_name: 'Automation::Rule', 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
@@ -25,8 +27,9 @@ class Tenant < ApplicationRecord
private
def create_default_objects
- groups.create!(name: 'all', group_type: 'ALL')
- groups.create!(name: 'admins', group_type: 'ADMIN')
+ 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)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 53d0d7286..7bf81e460 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -11,6 +11,7 @@
#
class User < ApplicationRecord
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
@@ -29,21 +30,21 @@ def site_admin?
end
def admin?
- groups.exists?(group_type: 'ADMIN')
+ groups.exists?(type: "AdminGroup")
end
def user_group
- groups.where(group_type: 'USER').first
+ groups.where(type: "UserGroup").first
end
private
def delete_user_group
- groups.destroy_by(group_type: 'USER')
+ user_group.destroy
end
def handle_default_groups
- groups.create!(name: name, group_type: 'USER', tenant_id: tenant_id)
+ groups.create!(name: name, type: "UserGroup", tenant_id: tenant_id)
group_memberships.create!(group: tenant.all_group)
end
end
diff --git a/app/models/user_group.rb b/app/models/user_group.rb
new file mode 100644
index 000000000..21f27c2b5
--- /dev/null
+++ b/app/models/user_group.rb
@@ -0,0 +1,14 @@
+# == Schema Information
+#
+# Table name: groups
+#
+# id :bigint not null, primary key
+# group_type :enum
+# name :string not null
+# type :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# tenant_id :bigint not null
+#
+class UserGroup < Group
+end
diff --git a/app/policies/admin/group_policy.rb b/app/policies/admin/group_policy.rb
index b4b4ec855..9800bba87 100644
--- a/app/policies/admin/group_policy.rb
+++ b/app/policies/admin/group_policy.rb
@@ -35,6 +35,8 @@ def new?
end
def update?
+ return false unless @group.editable?
+
@user.site_admin? || @user.admin?
end
@@ -47,14 +49,16 @@ def edit_members?
end
def show_members?
- update?
+ @user.site_admin? || @user.admin?
end
def edit_permissions?
- update?
+ @user.site_admin? || @user.admin?
end
def destroy?
+ return false if @group.system?
+
@user.site_admin? || @user.admin?
end
diff --git a/app/views/admin/groups/_form.html.erb b/app/views/admin/groups/_form.html.erb
index 9a9aa22b7..d203d8e38 100644
--- a/app/views/admin/groups/_form.html.erb
+++ b/app/views/admin/groups/_form.html.erb
@@ -13,10 +13,6 @@
<%= 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.label :group_type %>
- <%= form.select :group_type, ['CUSTOM', 'ADMIN'], class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
-
<%= form.label :tenant_id %>
<%= form.text_field :tenant_id, class: "block shadow rounded-md border border-gray-200 outline-none px-3 py-2 mt-2 w-full" %>
diff --git a/app/views/admin/groups/_group.html.erb b/app/views/admin/groups/_group.html.erb
index f3e86a6cf..98f25b147 100644
--- a/app/views/admin/groups/_group.html.erb
+++ b/app/views/admin/groups/_group.html.erb
@@ -4,8 +4,8 @@
<%= group.name %>
- Group type:
- <%= group.group_type %>
+ Type:
+ <%= group.type.to_s %>
Tenant:
diff --git a/app/views/admin/groups/index.html.erb b/app/views/admin/groups/index.html.erb
index f71494a6c..7e091c0c1 100644
--- a/app/views/admin/groups/index.html.erb
+++ b/app/views/admin/groups/index.html.erb
@@ -1 +1 @@
-<%= render Admin::Groups::GroupsListComponent.new(custom_groups: @custom_groups, system_groups: @system_groups) %>
+<%= render Admin::Groups::GroupsListComponent.new(editable_groups: @editable_groups, non_editable_groups: @non_editable_groups) %>
diff --git a/app/views/admin/groups/show.html.erb b/app/views/admin/groups/show.html.erb
index 94ba4829b..324ae5e4a 100644
--- a/app/views/admin/groups/show.html.erb
+++ b/app/views/admin/groups/show.html.erb
@@ -1 +1 @@
-<%= render Admin::Groups::GroupFormComponent.new(group: @group, step: :show)%>
+<%= render Admin::Groups::GroupFormComponent.new(group: @group, readonly: true)%>
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 950c6b690..3b25971c4 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -239,6 +239,11 @@ sk:
"Automation::BoxCondition": "je"
"Automation::AddMessageThreadTagAction": "Pridaj štítok na vlákno"
"Automation::AddTagAction": "Pridaj štítok"
+ group:
+ names:
+ all: "Všetci"
+ admin: "Administrátori"
+ signer: "Podpisovatelia"
title: "Názov"
tag_editing_in_message_threads:
one: "Úprava štítkov v jednom vlákne"
diff --git a/db/migrate/20231127215006_convert_groups_to_sti.rb b/db/migrate/20231127215006_convert_groups_to_sti.rb
new file mode 100644
index 000000000..b91ba4d1c
--- /dev/null
+++ b/db/migrate/20231127215006_convert_groups_to_sti.rb
@@ -0,0 +1,28 @@
+class ConvertGroupsToSti < ActiveRecord::Migration[7.0]
+ def up
+ add_column :groups, :type, :string, null: true
+
+ Group.find_each do |group|
+ type = case group.group_type
+ when "ALL"
+ "AllGroup"
+ when "ADMIN"
+ "AdminGroup"
+ when "USER"
+ "UserGroup"
+ when "CUSTOM"
+ "CustomGroup"
+ end
+
+ group.update_column(:type, type)
+ end
+
+ change_column_null :groups, :type, false
+ change_column_null :groups, :group_type, true
+ end
+
+ def down
+ change_column_null :groups, :group_type, false
+ remove_column :groups, :type
+ end
+end
diff --git a/db/migrate/20231127223506_generate_signing_groups_for_existing_tenants.rb b/db/migrate/20231127223506_generate_signing_groups_for_existing_tenants.rb
new file mode 100644
index 000000000..a11b1a7fc
--- /dev/null
+++ b/db/migrate/20231127223506_generate_signing_groups_for_existing_tenants.rb
@@ -0,0 +1,11 @@
+class GenerateSigningGroupsForExistingTenants < ActiveRecord::Migration[7.0]
+ def up
+ Tenant.find_each do |tenant|
+ tenant.create_signer_group!(name: "signers")
+ end
+ end
+
+ def down
+ SignerGroup.destroy_all
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index a64d6eb8d..87bdaf763 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_23_085142) do
+ActiveRecord::Schema[7.0].define(version: 2023_11_27_223506) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
@@ -268,9 +268,10 @@
create_table "groups", force: :cascade do |t|
t.string "name", null: false
t.bigint "tenant_id", null: false
- t.enum "group_type", null: false, enum_type: "group_type"
+ t.enum "group_type", enum_type: "group_type"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.string "type", null: false
t.index ["tenant_id"], name: "index_groups_on_tenant_id"
end
diff --git a/test/fixtures/groups.yml b/test/fixtures/groups.yml
index 50a9de531..9044e1228 100644
--- a/test/fixtures/groups.yml
+++ b/test/fixtures/groups.yml
@@ -2,15 +2,20 @@
all:
name: all
- group_type: ALL
+ type: AllGroup
tenant: ssd
admins:
name: admins
- group_type: ADMIN
+ type: AdminGroup
tenant: ssd
basic_user:
name: "Basic user"
- group_type: USER
+ type: UserGroup
tenant: ssd
+
+solver_admin:
+ name: admins
+ type: AdminGroup
+ tenant: solver
diff --git a/test/models/tag_test.rb b/test/models/tag_test.rb
index dda6ca210..dd3cf2e2a 100644
--- a/test/models/tag_test.rb
+++ b/test/models/tag_test.rb
@@ -5,6 +5,6 @@ class TagTest < ActiveSupport::TestCase
tenant = tenants(:ssd)
tag = Tag.create(name: 'New tag', tenant: tenant)
- assert tenant.admin_groups == tag.groups
+ assert tag.groups == [tenant.admin_group]
end
end