Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
62a0542
Implement role-based permissions for editing and deleting custom enti…
Arean82 Oct 30, 2025
2dacaff
Add authorization check to prevent unauthorized deletion of custom en…
Arean82 Oct 30, 2025
4100e8c
Refactor destroy action authorization to restrict access to administr…
Arean82 Oct 30, 2025
16678bf
Refactor authorization check for delete action to include admin role
Arean82 Oct 30, 2025
4a039b1
Remove delete action link for non-admin users from custom entity view
Arean82 Oct 30, 2025
c51ffba
Implement role-based access control for delete actions in custom enti…
Arean82 Oct 30, 2025
2504ca1
Enhance authorization checks for destroy actions to include context m…
Arean82 Oct 30, 2025
cdad81e
updateinguser column creation
Arean82 Oct 30, 2025
141f2b0
DuplicateColumn issue fixed
Arean82 Oct 30, 2025
448ad9e
created restrict_destroy_to_admin_and_manager method
Arean82 Oct 30, 2025
d458171
commented 1 destroy
Arean82 Oct 30, 2025
283daef
dertroy update
Arean82 Oct 30, 2025
947721a
update delete
Arean82 Oct 30, 2025
2543085
updated
Arean82 Oct 30, 2025
07fa44b
added version
Arean82 Oct 30, 2025
03e3208
model
Arean82 Oct 30, 2025
20de462
added followup
Arean82 Oct 30, 2025
b88d178
followups patched
Arean82 Oct 30, 2025
12f9d86
updated
Arean82 Nov 3, 2025
b67851b
updated
Arean82 Nov 3, 2025
e26fca7
updated permissions
Arean82 Nov 4, 2025
3d06d5f
removed duplicate contextual divs
Arean82 Nov 4, 2025
da81ebb
updated
Arean82 Nov 4, 2025
7608ed5
pdf changes
Arean82 Nov 4, 2025
7fe6095
removed unwanted header
Arean82 Nov 4, 2025
5f85c76
view issue
Arean82 Nov 4, 2025
0368fc7
updated permission
Arean82 Nov 4, 2025
2fa3e62
updated Readme
Arean82 Nov 4, 2025
e4194b3
Update README.md
Arean82 Nov 4, 2025
d2d90a4
Update README.md
Arean82 Nov 4, 2025
db51474
Update README.md
Arean82 Nov 4, 2025
e23a9e3
Update README.md
Arean82 Nov 4, 2025
ded4217
readme updated
Arean82 Nov 4, 2025
b8e5024
Update README.md
Arean82 Nov 4, 2025
aaada7c
Update README.md
Arean82 Nov 4, 2025
cfd8039
Update README.md
Arean82 Nov 4, 2025
7fb555e
updated locals
Arean82 Nov 4, 2025
21e3d31
updated locals
Arean82 Nov 4, 2025
d6dd821
update redmine version
Arean82 Nov 4, 2025
ae49578
updated locals
Arean82 Nov 5, 2025
c309404
added api
Arean82 Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Images/custom_table_configure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Images/custom_table_permission.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
100 changes: 94 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@

Redmine Custom Tables
==================

This plugin provides a possibility to create custom tables. The table is built with Redmine custom fields. It allows you to create any databases you need for your business and integrate it into your workflow processes.

<img src="custom_tables_v2.png" width="800"/>
<img src="Images/custom_tables_v2.png" width="800"/>

## πŸ†• Enhanced Features & Modifications

**Custom Modifications Added:**
- **Advanced Permission System** - Configurable group-based access control
- **Role-Based Restrictions** - Fine-grained control over edit/delete permissions
- **Admin Settings Interface** - Easy configuration via plugin settings page
- **Enhanced Security** - Controller-level and view-level permission checks

[Online demo](https://redmineplus.com/sign-up-to-redmine-plus/)
<img src="Images/custom_table_configure.png" width="800"/>
<img src="Images/custom_table_permission.png" width="800"/>

Features
-------------
Expand All @@ -18,6 +28,9 @@ Features
* Commenting entities
* Export CSV/PDF
* API
* **πŸ†• Configurable permission system** - Control which user groups can edit and delete records
* **πŸ†• Role-based access control** - Restrict operations to specific roles (Administrator, Manager)
* **πŸ†• Settings configuration page** - Easy management of permissions via admin interface

Compatibility
-------------
Expand All @@ -26,10 +39,10 @@ Compatibility
Installation and Setup
----------------------

* Clone or [download](https://github.com/frywer/custom_tables/archive/master.zip) this repo into your **redmine_root/plugins/** folder
* Clone or [download](https://github.com/Arean82/custom_tables/archive/refs/heads/master.zip) this repo into your **redmine_root/plugins/** folder

```
$ git clone https://github.com/frywer/custom_tables.git
$ git clone https://github.com/Arean82/custom_tables.git
```
* If you downloaded a tarball / zip from master branch, make sure you rename the extracted folder to `custom_tables`
* You have to run the plugin rake task to provide the assets (from the Redmine root directory):
Expand All @@ -40,7 +53,82 @@ $ bundle exec rake redmine:plugins:migrate RAILS_ENV=production

Usage
----------------------
1) Visit **Administration->Custom tables** to open table constructor.
### Basic Setup
1) Visit **Administration β†’ Custom tables** to open table constructor.
2) Press button **New table**. Fill the name field, select projects you want to enable table on and submit the form.
3) Add custom fields to your new table.
4) Give access to the users **Administration -> Roles and permissions -> Project -> Manage custom tables**
4) Give access to the users **Administration β†’ Roles and permissions β†’ Project β†’ Manage custom tables**
5) **πŸ†• Configure permissions** by going to **Administration β†’ Plugins β†’ Custom Tables plugin β†’ Configure** to set up which user groups can edit and delete records *(All users can view and add records, but only authorized users can edit or delete)*

### πŸ†• Enhanced Permission Configuration
The plugin includes a **flexible and configurable permission system** that allows precise control over who can edit and delete custom table records:

#### Default Behavior (When Custom Permissions Disabled)
- **Administrators**: Full access (create, edit, delete)
- **Managers**: Full access (create, edit, delete)
- **Other Users**: View and add records only (edit/delete buttons hidden)

#### πŸ†• Custom Group Permissions (Enhanced Feature)
You can configure specific user groups to have full access via the admin interface:

1. Go to **Administration β†’ Plugins β†’ Custom Tables plugin β†’ Configure**
2. Check **"Enable Custom Group Permissions"** to activate custom group-based access
3. Select the user groups that should have full edit/delete permissions
4. Click **Save** to apply changes

#### πŸ†• Multi-Layer Security
- **View-Level Security**: Delete/edit buttons are hidden from unauthorized users
- **Controller-Level Security**: All destructive actions are blocked at the controller level
- **Role-Based Security**: Built-in support for Administrator and Manager roles
- **Group-Based Security**: Custom group permissions via settings configuration

#### Permission Levels
- **Full Access Users** (Admins, Managers, or selected groups): Can create, edit, and delete tables and records
- **Standard Users**: Can view and add records, but cannot edit or delete existing ones

### πŸ†• Technical Implementation Details
The enhanced permission system includes:
- **CustomTablesPermissionHelper** - Centralized permission logic
- **Controller-level before_actions** - Security at the action level
- **View-level conditionals** - UI element visibility control
- **Settings management** - Persistent configuration storage
- **Role and group validation** - Multi-factor permission checking

### API Access
The plugin provides API endpoints for managing custom tables and entities. API access follows the same permission rules as the web interface.

Support
-------
If you find any bugs, feel free to create an issue on GitHub or make a pull request.
https://github.com/frywer/custom_tables

Contributors
------------
* Ivan Ivon (@frywer)
* **πŸ†• Plugin customization and enhanced permission system** - Added configurable group-based permissions, role restrictions, and admin settings interface

License
-------
The plugin is available under the MIT license.

## πŸ†• Changelog

### Enhanced Version Features:
- βœ… Configurable group-based permission system
- βœ… Admin settings page for easy permission management
- βœ… Role-based restrictions (Administrator, Manager)
- βœ… Multi-layer security (view + controller level)
- βœ… Enhanced UI with conditional button visibility
- βœ… Persistent settings configuration
- βœ… Backward compatibility with existing installations


## Key Highlights of Your Modifications:

1. **πŸ†• Enhanced Features Section** - Clear overview of what you added
2. **πŸ†• Icon indicators** - Visual markers for new features
3. **πŸ†• Technical Details** - Explanation of the multi-layer security
4. **πŸ†• Implementation Details** - Technical architecture of your permission system
5. **πŸ†• Updated Contributors** - Credit for your enhancements
6. **πŸ†• Changelog** - Summary of all new features

87 changes: 75 additions & 12 deletions app/controllers/custom_entities_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#custom_entities_controller.rb

class CustomEntitiesController < ApplicationController
layout 'admin'
self.main_menu = false
Expand All @@ -13,8 +15,14 @@ class CustomEntitiesController < ApplicationController
helper :sort
include SortHelper
helper :custom_tables_pdf
# Add permission helper
helper :custom_tables_permission

#accept_api_auth :show, :create, :update, :destroy
accept_api_auth :index, :show, :create, :update, :destroy

accept_api_auth :show, :create, :update, :destroy
# Use the permission method
before_action :check_destroy_permission, only: [:destroy, :context_menu, :bulk_update]

before_action :authorize_global
before_action :find_custom_entity, only: [:show, :edit, :update, :add_belongs_to, :new_note]
Expand Down Expand Up @@ -57,10 +65,57 @@ def new_note
end
end


def destroy
Rails.logger.info "βœ… ALLOWED: #{User.current.login} deleting CustomEntities: #{@custom_entities.map(&:id).join(', ')}"

custom_table = @custom_entities.first.custom_table
@custom_entities.destroy_all

respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_delete)
redirect_back_or_default custom_table_path(custom_table)
}
format.api { render_api_ok }
end
end

# Use the module method directly
def check_destroy_permission
unless custom_tables_user_has_full_access?
Rails.logger.warn "🚫 DESTROY BLOCKED: #{User.current.login}, needs full access"
render_403
end
end

def context_menu
if (@custom_entities.size == 1)
@custom_entity = @custom_entities.first
end
@custom_entity_ids = @custom_entities.map(&:id).sort

can_edit = @custom_entities.detect{|c| !c.editable?}.nil?
# Use the module method directly
can_delete = custom_tables_user_has_full_access?
@can = {:edit => can_edit, :delete => can_delete}
@back = back_url

@safe_attributes = @custom_entities.map(&:safe_attribute_names).reduce(:&)

render :layout => false
end


def create
@custom_entity = CustomEntity.new(author: User.current, custom_table_id: params[:custom_entity][:custom_table_id])
@custom_entity.safe_attributes = params[:custom_entity]


@custom_entity.updated_by = User.current # track updater
@custom_entity.updated_at = Time.current # ensure timestamp if not automatically handled


if @custom_entity.save
flash[:notice] = l(:notice_successful_create)
respond_to do |format|
Expand Down Expand Up @@ -88,6 +143,7 @@ def edit
def update
@custom_entity.init_journal(User.current)
@custom_entity.safe_attributes = params[:custom_entity]
@custom_entity.updated_by = User.current # track who updated

if @custom_entity.save
flash[:notice] = l(:notice_successful_update)
Expand All @@ -105,17 +161,24 @@ def update
end
end

def destroy
custom_table = @custom_entities.first.custom_table
@custom_entities.destroy_all

respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_delete)
redirect_back_or_default custom_table_path(custom_table)
}
format.api { render_api_ok }

def custom_tables_user_has_full_access?(user = User.current)
settings = Setting.plugin_custom_tables || {}

# If custom permissions are disabled, use your existing role-based logic
unless settings['enable_custom_permissions']
allowed_roles = ['Administrator', 'Manager']
user_roles = user.roles.map(&:name)
return user.admin? || user_roles.any? { |r| allowed_roles.include?(r) }
end

# Custom permission logic
return true if user.admin?

allowed_group_ids = settings['allowed_groups'] || []
return false if allowed_group_ids.empty?

user.groups.any? { |group| allowed_group_ids.include?(group.id.to_s) }
end

def add_belongs_to
Expand All @@ -134,7 +197,7 @@ def context_menu
@custom_entity_ids = @custom_entities.map(&:id).sort

can_edit = @custom_entities.detect{|c| !c.editable?}.nil?
can_delete = @custom_entities.detect{|c| !c.deletable?}.nil?
can_delete = User.current.admin? || User.current.roles.any? { |r| ['Administrator', 'Manager'].include?(r.name) }
@can = {:edit => can_edit, :delete => can_delete}
@back = back_url

Expand Down
43 changes: 40 additions & 3 deletions app/controllers/custom_tables_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# app/controllers/custom_tables_controller.rb

class CustomTablesController < ApplicationController
layout 'admin'
self.main_menu = false
Expand All @@ -13,12 +15,18 @@ class CustomTablesController < ApplicationController
helper :settings
helper :custom_tables_pdf

# Add permission helper
helper :custom_tables_permission

before_action :find_custom_table, only: [:edit, :update, :show, :destroy, :setting_tabs]
before_action :authorize_global
before_action :find_custom_tables, only: [:context_menu]
before_action :setting_tabs, only: :edit
before_action :export_custom_entities, only: :show

# ADD: Check permissions for table operations
before_action :check_manage_permission, only: [:new, :create, :edit, :update, :destroy, :context_menu]

accept_api_auth :show, :index, :create, :update, :destroy

def index
Expand Down Expand Up @@ -140,16 +148,45 @@ def context_menu
end
@custom_tables_ids = @custom_tables.map(&:id).sort

can_edit = @custom_tables.detect{|c| !c.editable?}.nil?
can_delete = @custom_tables.detect{|c| !c.deletable?}.nil?
@can = {:edit => can_edit, :delete => can_delete}
# Use permission helper
has_full_access = custom_tables_user_has_full_access?
@can = { edit: has_full_access, delete: has_full_access }
@back = back_url

@safe_attributes = @custom_tables.map(&:safe_attribute_names).reduce(:&)

render layout: false
end

private

def check_manage_permission
unless custom_tables_user_has_full_access?
Rails.logger.warn "🚫 MANAGE PERMISSION REQUIRED: #{User.current.login} attempted #{action_name}"
render_403
return false
end
end

def custom_tables_user_has_full_access?(user = User.current)
settings = Setting.plugin_custom_tables || {}

# If custom permissions are disabled, use your existing role-based logic
unless settings['enable_custom_permissions']
allowed_roles = ['Administrator', 'Manager']
user_roles = user.roles.map(&:name)
return user.admin? || user_roles.any? { |r| allowed_roles.include?(r) }
end

# Custom permission logic
return true if user.admin?

allowed_group_ids = settings['allowed_groups'] || []
return false if allowed_group_ids.empty?

user.groups.any? { |group| allowed_group_ids.include?(group.id.to_s) }
end

def setting_tabs
@setting_tabs = [
{name: 'general', partial: 'custom_tables/edit', label: :label_general},
Expand Down
Loading