redmine_nonproject_modules 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/app/assets/javascripts/redmine_nonproject_modules.js +1 -0
- data/app/assets/stylesheets/redmine_nonproject_modules.css +1 -0
- data/app/controllers/group_merge_controller.rb +35 -0
- data/app/controllers/group_permissions_controller.rb +35 -0
- data/app/helpers/group_merge_helper.rb +31 -0
- data/app/models/group_merge.rb +88 -0
- data/app/models/group_permission.rb +106 -0
- data/app/models/group_permissions_setup.rb +20 -0
- data/app/views/group_merge/check.html.erb +35 -0
- data/app/views/group_merge/index.html.erb +12 -0
- data/app/views/group_permissions/_dependencies.html.erb +10 -0
- data/app/views/group_permissions/_member_context.html.erb +5 -0
- data/app/views/group_permissions/index.html.erb +24 -0
- data/app/views/group_permissions/show.html.erb +36 -0
- data/config/initializers/000_dependencies.rb +4 -0
- data/config/locales/en.yml +10 -0
- data/config/locales/pt-BR.yml +12 -0
- data/config/routes.rb +6 -0
- data/init.rb +34 -0
- data/lib/redmine_nonproject_modules.rb +6 -0
- data/lib/redmine_nonproject_modules/dispatcher_finder.rb +32 -0
- data/lib/redmine_nonproject_modules/patches/controller_patch.rb +29 -0
- data/lib/redmine_nonproject_modules/patches/group_patch.rb +24 -0
- data/lib/redmine_nonproject_modules/patches/redmine/i18n_patch.rb +29 -0
- data/lib/redmine_nonproject_modules/patches/redmine/menu_manager_patch.rb +91 -0
- data/lib/redmine_nonproject_modules/patches/user_patch.rb +19 -0
- data/lib/redmine_nonproject_modules/version.rb +8 -0
- metadata +137 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5376c3a5a50a27ab5825bf4c0d6c6cadc2d672047808792d8b7b2d5b47118443
|
4
|
+
data.tar.gz: b173b20f273e8236950d0ac67641e40b23a88395ad35a7157828a6c29dddc296
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b78a4ccfc86da2be65496081ad35730be443faec2b2da9a299ceb4ae8a31e89ede3f94a8b16098484fc5be448b7835179a386c8d494a2201e31173d92ab1446
|
7
|
+
data.tar.gz: 57bf1adcd605ee92b9d1be876d67c279cee75b90cc49017996c955dd61c81e61a31370958de94db143ac1fdde6b73c2a4152fcc8714aae1edfc90cfb72f1ed47
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require 'active_scaffold'
|
@@ -0,0 +1 @@
|
|
1
|
+
@import 'active_scaffold';
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class GroupMergeController < ApplicationController
|
2
|
+
require_permission 'group_merge'
|
3
|
+
helper GroupMergeHelper
|
4
|
+
|
5
|
+
def index
|
6
|
+
@group_merge = ::GroupMerge.new(source: ::Group.find(params[:id]))
|
7
|
+
build_targets_list
|
8
|
+
end
|
9
|
+
|
10
|
+
def check
|
11
|
+
@group_merge = ::GroupMerge.new(check_parameters)
|
12
|
+
return if @group_merge.valid?
|
13
|
+
build_targets_list
|
14
|
+
render :index
|
15
|
+
end
|
16
|
+
|
17
|
+
def confirm
|
18
|
+
@group_merge = ::GroupMerge.new(check_parameters)
|
19
|
+
@group_merge.save!
|
20
|
+
path = GroupPermission.permission?('group_permissions') ? group_permissions_path : root_path
|
21
|
+
redirect_to path, notice: t(:notice_successful_update)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def check_parameters
|
27
|
+
params[:group_merge].permit(:target_id).merge(source: ::Group.find(params[:id]))
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_targets_list
|
31
|
+
@targets_list = Group.where.not(id: @group_merge.source.id).sorted.map do |g|
|
32
|
+
[g.to_s, g.id]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class GroupPermissionsController < ApplicationController
|
2
|
+
require_permission 'group_permissions'
|
3
|
+
before_action :set_group, only: [:show, :update]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@groups = Group.sorted
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
@gps = GroupPermissionsSetup.new(group: @group)
|
11
|
+
end
|
12
|
+
|
13
|
+
def update
|
14
|
+
@gps = GroupPermissionsSetup.new(gps_params)
|
15
|
+
if @gps.save
|
16
|
+
redirect_to group_permission_path(@group), notice: t(:notice_successful_update)
|
17
|
+
else
|
18
|
+
render :show
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def gps_params
|
25
|
+
p = { permissions: [], group: @group }
|
26
|
+
if params[:group_permissions_setup] && params[:group_permissions_setup][:permissions]
|
27
|
+
p[:permissions] = params[:group_permissions_setup][:permissions]
|
28
|
+
end
|
29
|
+
p
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_group
|
33
|
+
@group = Group.find(params[:id])
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module GroupMergeHelper
|
2
|
+
def group_merge_elements_sorted(group_merge)
|
3
|
+
r = group_merge.to_merge_elements.map do |x|
|
4
|
+
[group_merge_type_element_label(x[0]),
|
5
|
+
group_merge_element_label(x[0]),
|
6
|
+
group_merge_element_class(x)]
|
7
|
+
end
|
8
|
+
r.sort_by { |x| [x[0], x[1]] }
|
9
|
+
end
|
10
|
+
|
11
|
+
def group_merge_element_class(x)
|
12
|
+
"GroupMergeHelper_element_#{x[1]}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def group_merge_type_element_label(element)
|
16
|
+
t("label_#{element.class.model_name.param_key}")
|
17
|
+
end
|
18
|
+
|
19
|
+
def group_merge_element_label(element)
|
20
|
+
m = "group_merge_#{element.class.model_name.param_key}_element_label"
|
21
|
+
respond_to?(m) ? send(m, element) : element.to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def group_merge_member_element_label(m)
|
25
|
+
"#{t(:label_project)}: #{m.project} (#{m.roles.to_a.join(', ')})"
|
26
|
+
end
|
27
|
+
|
28
|
+
def group_merge_group_permission_element_label(gp)
|
29
|
+
gp.permission
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
|
3
|
+
class GroupMerge
|
4
|
+
include ActiveModel::Model
|
5
|
+
include Virtus.model
|
6
|
+
include ActiveModel::Associations
|
7
|
+
|
8
|
+
ONLY_ON_TARGET = :only_on_target
|
9
|
+
ONLY_ON_SOURCE = :only_on_source
|
10
|
+
ON_BOTH = :on_both
|
11
|
+
|
12
|
+
attribute :source_id, Integer
|
13
|
+
attribute :target_id, Integer
|
14
|
+
belongs_to :source, class_name: 'Group'
|
15
|
+
belongs_to :target, class_name: 'Group'
|
16
|
+
|
17
|
+
validates :source, presence: true
|
18
|
+
validates :target, presence: true
|
19
|
+
|
20
|
+
def [](attr)
|
21
|
+
send(attr)
|
22
|
+
end
|
23
|
+
|
24
|
+
def []=(attr, value)
|
25
|
+
send("#{attr}=", value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_merge_elements
|
29
|
+
(target_elements + source_elements).uniq.map do |x|
|
30
|
+
[x[0], element_on_status(x)]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def save!
|
35
|
+
ActiveRecord::Base.transaction do
|
36
|
+
source_new_elements.each { |x| add_element_to_target(x[0], x[1]) }
|
37
|
+
source.destroy!
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def associations_to_merge
|
42
|
+
[:users, :memberships, :permissions]
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def element_on_status(x)
|
48
|
+
return ON_BOTH if target_elements.include?(x) && source_elements.include?(x)
|
49
|
+
return ONLY_ON_TARGET if target_elements.include?(x)
|
50
|
+
return ONLY_ON_SOURCE if source_elements.include?(x)
|
51
|
+
raise "Element is neither on source nor on target: #{x}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def target_elements
|
55
|
+
@target_elements ||= elements(:target)
|
56
|
+
end
|
57
|
+
|
58
|
+
def source_elements
|
59
|
+
@source_elements ||= elements(:source)
|
60
|
+
end
|
61
|
+
|
62
|
+
def elements(sender)
|
63
|
+
associations_to_merge.flat_map do |a|
|
64
|
+
send(sender).send(a).map do |e|
|
65
|
+
[e, a]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def source_new_elements
|
71
|
+
source_elements.select do |x|
|
72
|
+
!target_elements.include?(x)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_element_to_target(element, association_name)
|
77
|
+
method = "add_#{association_name}_element_to_target"
|
78
|
+
if respond_to?(method, true)
|
79
|
+
send(method, element)
|
80
|
+
else
|
81
|
+
target.send(association_name) << element
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def add_permissions_element_to_target(permission)
|
86
|
+
target.add_permission(permission)
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'eac_ruby_utils/simple_cache'
|
2
|
+
|
3
|
+
class GroupPermission < ActiveRecord::Base
|
4
|
+
belongs_to :group
|
5
|
+
|
6
|
+
validates :group, presence: true
|
7
|
+
validates :permission, presence: true, uniqueness: { scope: [:group],
|
8
|
+
case_sensitive: false }
|
9
|
+
|
10
|
+
def permission=(value)
|
11
|
+
self[:permission] = Permission.sanitize_key(value)
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def permissions
|
16
|
+
permissions_hash.values
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_permission(key, options = {})
|
20
|
+
p = Permission.new(key, options)
|
21
|
+
permissions_hash[p.key] = p unless permissions_hash.key?(p.key)
|
22
|
+
end
|
23
|
+
|
24
|
+
def permission_description(key)
|
25
|
+
permission(key).description
|
26
|
+
end
|
27
|
+
|
28
|
+
def permission?(permission, user = false)
|
29
|
+
return permission_by_hash?(permission, user) if permission.is_a?(Hash)
|
30
|
+
permission(permission).user_has?(user || User.current)
|
31
|
+
end
|
32
|
+
|
33
|
+
def permission(key)
|
34
|
+
key = key.to_s
|
35
|
+
return permissions_hash[key] if permissions_hash.key?(key)
|
36
|
+
raise "Not found \"#{key}\" in GroupPermission::permissions"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def permissions_hash
|
42
|
+
@permissions ||= {}.with_indifferent_access
|
43
|
+
end
|
44
|
+
|
45
|
+
def permission_by_hash?(hash, user)
|
46
|
+
raise 'Hasy should have :or parameter' unless hash[:or].present?
|
47
|
+
ps = hash[:or].is_a?(Array) ? hash[:or] : [hash[:or]]
|
48
|
+
ps.any? { |p| permission?(p, user) }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Permission
|
53
|
+
include ::EacRubyUtils::SimpleCache
|
54
|
+
|
55
|
+
class << self
|
56
|
+
def sanitize_key(k)
|
57
|
+
k.to_s.downcase
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader :key, :dependencies
|
62
|
+
|
63
|
+
def initialize(key, options)
|
64
|
+
@key = self.class.sanitize_key(key)
|
65
|
+
@dependencies = (options[:dependencies] || []).map { |k| ::GroupPermission.permission(k) }
|
66
|
+
end
|
67
|
+
|
68
|
+
def description
|
69
|
+
I18n.t("permission_#{key}_description")
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
key
|
74
|
+
end
|
75
|
+
|
76
|
+
def user_has?(user)
|
77
|
+
return true if user.admin
|
78
|
+
GroupPermission.where(group: user_groups(user), permission: depends_recursive.to_a).any?
|
79
|
+
end
|
80
|
+
|
81
|
+
def depends_recursive(visited = Set.new)
|
82
|
+
return [] if visited.include?(key)
|
83
|
+
r = Set.new([key])
|
84
|
+
visited << key
|
85
|
+
depends.each do |d|
|
86
|
+
r += d.depends_recursive(visited)
|
87
|
+
end
|
88
|
+
r
|
89
|
+
end
|
90
|
+
|
91
|
+
def <=>(other)
|
92
|
+
to_s <=> other.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def user_groups(user)
|
98
|
+
return [Group.anonymous] if user.anonymous?
|
99
|
+
[Group.anonymous, Group.non_member] + user.groups
|
100
|
+
end
|
101
|
+
|
102
|
+
def depends
|
103
|
+
::GroupPermission.permissions.select { |p| p.dependencies.include?(self) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class GroupPermissionsSetup
|
2
|
+
include ActiveModel::Model
|
3
|
+
|
4
|
+
attr_accessor :group
|
5
|
+
attr_writer :permissions
|
6
|
+
|
7
|
+
def permissions
|
8
|
+
@permissions ||= GroupPermission.where(group: group).pluck(:permission)
|
9
|
+
end
|
10
|
+
|
11
|
+
def save
|
12
|
+
ActiveRecord::Base.transaction do
|
13
|
+
GroupPermission.where(group: group).destroy_all
|
14
|
+
permissions.each do |p|
|
15
|
+
GroupPermission.create!(group: group, permission: p)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
<%= stylesheet_link_tag 'group_merge', plugin: 'redmine_nonproject_modules' %>
|
2
|
+
<%= title [l(:label_group_permission_plural), group_permission_path],
|
3
|
+
[@group_merge.source, group_permission_path(@group_merge.source)],
|
4
|
+
t(:merge) %>
|
5
|
+
<p>
|
6
|
+
<%= t(:group_will_be_removed, group: @group_merge.source) %>
|
7
|
+
<br/>
|
8
|
+
<%= t(:group_will_receive_elements, group: @group_merge.target) %>
|
9
|
+
</p>
|
10
|
+
<p>
|
11
|
+
<span class="GroupMergeHelper_element_only_on_target">
|
12
|
+
<%= t(:only_in_group, group: @group_merge.target) %>
|
13
|
+
</span>
|
14
|
+
<br/>
|
15
|
+
<span class="GroupMergeHelper_element_only_on_source">
|
16
|
+
<%= t(:only_in_group, group: @group_merge.source) %>
|
17
|
+
</span>
|
18
|
+
<br/>
|
19
|
+
<span class="GroupMergeHelper_element_on_both">
|
20
|
+
<%= t(:in_both_group) %>
|
21
|
+
</span>
|
22
|
+
</p>
|
23
|
+
<ul>
|
24
|
+
<% group_merge_elements_sorted(@group_merge).each do |x| %>
|
25
|
+
<li class="<%= x[2] %>">
|
26
|
+
<strong><%= x[0] %>: </strong><%= x[1] %>
|
27
|
+
</li>
|
28
|
+
<% end %>
|
29
|
+
</ul>
|
30
|
+
<%= labelled_form_for @group_merge, url: merge_confirm_group_path(@group_merge.source) do |f| %>
|
31
|
+
<p><strong>Confirma a mesclagem?</strong></p>
|
32
|
+
<%= f.hidden_field :target_id %>
|
33
|
+
<%= submit_tag t(:merge) %>
|
34
|
+
<%= link_to t(:button_back), merge_group_path(@group_merge.source) %>
|
35
|
+
<% end %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= title [l(:label_group_permission_plural), group_permission_path],
|
2
|
+
[@group_merge.source, group_permission_path(@group_merge.source)],
|
3
|
+
t(:merge) %>
|
4
|
+
<%= labelled_form_for @group_merge, url: merge_check_group_path(@group_merge.source) do |f| %>
|
5
|
+
<%= error_messages_for 'group_merge' %>
|
6
|
+
<div class="box tabular">
|
7
|
+
<p>
|
8
|
+
<%= f.select :target_id, @targets_list, label: t(:field_target) %>
|
9
|
+
</p>
|
10
|
+
</div>
|
11
|
+
<%= submit_tag t(:merge) %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<h2><%= t(:label_group_permission_plural) %></h2>
|
2
|
+
<table class="list groups">
|
3
|
+
<thead>
|
4
|
+
<tr>
|
5
|
+
<th><%= t(:field_name) %></th>
|
6
|
+
<% if GroupPermission.permission?('group_merge') %>
|
7
|
+
<th></th>
|
8
|
+
<% end %>
|
9
|
+
</tr>
|
10
|
+
</thead>
|
11
|
+
<tbody>
|
12
|
+
<% @groups.each do |g| %>
|
13
|
+
<% rowclass = cycle("odd", "even") %>
|
14
|
+
<tr class="<%= rowclass %>">
|
15
|
+
<td style="text-align: left"><%= link_to g, group_permission_path(g) %></td>
|
16
|
+
<% if GroupPermission.permission?('group_merge') %>
|
17
|
+
<td class="buttons">
|
18
|
+
<%= link_to t(:merge), merge_group_path(g) %>
|
19
|
+
</td>
|
20
|
+
<% end %>
|
21
|
+
</tr>
|
22
|
+
<% end %>
|
23
|
+
</tbody>
|
24
|
+
</table>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<%= stylesheet_link_tag 'group_permissions', plugin: 'redmine_nonproject_modules' %>
|
2
|
+
<%= render partial: 'member_context', locals: { group: @group } %>
|
3
|
+
<%= title [l(:label_group_permission_plural), group_permissions_path], @group.name %>
|
4
|
+
<%= form_for(@gps, :url => group_permission_path(@group), :method => :put) do %>
|
5
|
+
<table class="list group_permissions_list">
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th><%= t(:field_id) %></th>
|
9
|
+
<th><%= t(:field_dependencies) %></th>
|
10
|
+
<th><%= t(:field_description) %></th>
|
11
|
+
</tr>
|
12
|
+
</thead>
|
13
|
+
<tbody>
|
14
|
+
<% GroupPermission.permissions.sort.each do |id| %>
|
15
|
+
<tr class="<%= cycle("odd", "even") %>">
|
16
|
+
<td>
|
17
|
+
<%= check_box_tag 'group_permissions_setup[permissions][]', id, @gps.permissions.include?(id.key),
|
18
|
+
:id => nil %>
|
19
|
+
<%= id %>
|
20
|
+
</td>
|
21
|
+
<td class="dependencies">
|
22
|
+
<% if id.dependencies.any? %>
|
23
|
+
<%= render partial: 'dependencies', locals: {permission: id } %>
|
24
|
+
<% else %>
|
25
|
+
-
|
26
|
+
<% end %>
|
27
|
+
</td>
|
28
|
+
<td>
|
29
|
+
<%= GroupPermission.permission_description(id) %>
|
30
|
+
</td>
|
31
|
+
</tr>
|
32
|
+
<% end %>
|
33
|
+
</tbody>
|
34
|
+
</table>
|
35
|
+
<p><%= submit_tag l(:button_change) %></p>
|
36
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
en:
|
2
|
+
field_target: 'Target'
|
3
|
+
group_will_be_removed: 'The group "%{group}" will be removed.'
|
4
|
+
in_both_group: In both groups.
|
5
|
+
label_group_permission: Group permission
|
6
|
+
label_group_permission_plural: Groups / Permissions
|
7
|
+
merge: Merge
|
8
|
+
group_will_receive_elements: 'The group "%{group}" will receive the following elements:'
|
9
|
+
only_in_group: 'Only in "%{group}".'
|
10
|
+
permission_group_permissions_description: Read/write access to groups' permissions.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
pt-BR:
|
2
|
+
field_target: 'Alvo'
|
3
|
+
field_dependencies: Dependências
|
4
|
+
group_will_be_removed: 'O grupo "%{group}" será removido.'
|
5
|
+
in_both_group: Em ambos os grupos.
|
6
|
+
label_group_permission: Permissão de grupo
|
7
|
+
label_group_permission_plural: Grupos / Permissões
|
8
|
+
merge: Mesclar
|
9
|
+
group_will_receive_elements: 'O grupo "%{group}" receberá os seguintes elementos:'
|
10
|
+
only_in_group: 'Somente em "%{group}".'
|
11
|
+
permission_group_permissions_description: Visualização/modificação das
|
12
|
+
permissões de grupo.
|
data/config/routes.rb
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
RedmineApp::Application.routes.draw do
|
2
|
+
resources(:group_permissions, only: [:index, :show, :update])
|
3
|
+
get '/group/:id/merge', to: 'group_merge#index', as: :merge_group
|
4
|
+
post '/group/:id/merge_check', to: 'group_merge#check', as: :merge_check_group
|
5
|
+
post '/group/:id/merge_confirm', to: 'group_merge#confirm', as: :merge_confirm_group
|
6
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'active_scaffold'
|
4
|
+
|
5
|
+
require 'redmine'
|
6
|
+
|
7
|
+
require 'redmine_nonproject_modules/patches/controller_patch'
|
8
|
+
require 'redmine_nonproject_modules/patches/group_patch'
|
9
|
+
require 'redmine_nonproject_modules/patches/redmine/i18n_patch'
|
10
|
+
require 'redmine_nonproject_modules/patches/redmine/menu_manager_patch'
|
11
|
+
require 'redmine_nonproject_modules/version'
|
12
|
+
|
13
|
+
Redmine::Plugin.register :redmine_nonproject_modules do
|
14
|
+
name 'Redmine non-project modules'
|
15
|
+
author ::RedmineNonprojectModules::AUTHOR
|
16
|
+
description ::RedmineNonprojectModules::SUMMARY
|
17
|
+
version ::RedmineNonprojectModules::VERSION
|
18
|
+
url ::RedmineNonprojectModules::HOMEPAGE
|
19
|
+
author_url 'https://github.com/eduardobogoni'
|
20
|
+
|
21
|
+
Redmine::MenuManager.map :admin_menu do |menu|
|
22
|
+
menu.push :group_permissions, { controller: 'group_permissions', action: 'index' },
|
23
|
+
caption: :label_group_permission_plural, after: :groups,
|
24
|
+
if: proc { GroupPermission.permission?('group_permissions') }
|
25
|
+
end
|
26
|
+
|
27
|
+
ActiveScaffold.delayed_setup = true
|
28
|
+
end
|
29
|
+
|
30
|
+
Rails.configuration.to_prepare do
|
31
|
+
GroupPermission.add_permission('group_permissions')
|
32
|
+
GroupPermission.add_permission('group_merge')
|
33
|
+
require_dependency 'redmine_nonproject_modules/patches/user_patch'
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'eac_ruby_utils/simple_cache'
|
2
|
+
|
3
|
+
module RedmineNonprojectModules
|
4
|
+
# https://stackoverflow.com/questions/12088025/detect-if-application-was-started-as...
|
5
|
+
# https://github.com/newrelic/rpm/blob/master/lib/new_relic/local_environment.rb
|
6
|
+
class DispatcherFinder
|
7
|
+
WEBSERVER_DISPATCHERS = %w(webrick passenger).freeze
|
8
|
+
DISPATCHERS = WEBSERVER_DISPATCHERS
|
9
|
+
|
10
|
+
class << self
|
11
|
+
include ::EacRubyUtils::SimpleCache
|
12
|
+
|
13
|
+
def webserver?
|
14
|
+
WEBSERVER_DISPATCHERS.include?(dispatcher)
|
15
|
+
end
|
16
|
+
|
17
|
+
def webrick?
|
18
|
+
defined?(::WEBrick) && defined?(::WEBrick::VERSION)
|
19
|
+
end
|
20
|
+
|
21
|
+
def passenger?
|
22
|
+
defined?(::PhusionPassenger)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def dispatcher_uncached
|
28
|
+
DISPATCHERS.find { |d| send("#{d}?") }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RedmineNonprojectModules
|
2
|
+
module Patches
|
3
|
+
module ControllerPatch
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:extend, ClassMethods)
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def require_permission(permission)
|
11
|
+
before_action { |c| c.before_action_require_permission(permission) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
def before_action_require_permission(permission)
|
17
|
+
return true if GroupPermission.permission?(permission)
|
18
|
+
deny_access
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
unless ActionController::Base.included_modules.include?(
|
26
|
+
RedmineNonprojectModules::Patches::ControllerPatch
|
27
|
+
)
|
28
|
+
ActionController::Base.send(:include, RedmineNonprojectModules::Patches::ControllerPatch)
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RedmineNonprojectModules
|
2
|
+
module Patches
|
3
|
+
module GroupPatch
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
has_many :permissions, class_name: 'GroupPermission', dependent: :destroy
|
7
|
+
end
|
8
|
+
base.include(InstanceMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def add_permission(permission)
|
13
|
+
permission = permission.permission if permission.is_a?(::GroupPermission)
|
14
|
+
return if permissions.pluck(:permission).include?(permission)
|
15
|
+
::GroupPermission.create!(group: self, permission: permission)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
unless ::Group.included_modules.include?(RedmineNonprojectModules::Patches::GroupPatch)
|
23
|
+
::Group.send(:include, RedmineNonprojectModules::Patches::GroupPatch)
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RedmineNonprojectModules
|
4
|
+
module Patches
|
5
|
+
module Redmine
|
6
|
+
module I18nPatch
|
7
|
+
def self.included(base)
|
8
|
+
base.include(InstanceMethods)
|
9
|
+
base.alias_method_chain :l, :active_scaffold
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
def l_with_active_scaffold(*args)
|
14
|
+
if (args.first.is_a?(Time) || args.first.is_a?(Date)) && args.last.is_a?(Hash)
|
15
|
+
::I18n.l(args.first, args.last)
|
16
|
+
else
|
17
|
+
l_without_active_scaffold(*args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
x = ::Redmine::I18n
|
27
|
+
y = ::RedmineNonprojectModules::Patches::Redmine::I18nPatch
|
28
|
+
|
29
|
+
x.send(:include, y) unless x.included_modules.include?(y)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module RedmineNonprojectModules
|
2
|
+
module Patches
|
3
|
+
module Redmine
|
4
|
+
module MenuManagerMapperPatch
|
5
|
+
def self.included(base)
|
6
|
+
base.send(:include, InstanceMethods)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
def push_controller(*args)
|
12
|
+
e = ControllerEntry.new(*args)
|
13
|
+
push(*e.build)
|
14
|
+
e.permissions.each do |p|
|
15
|
+
::GroupPermission.add_permission(p)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class ControllerEntry
|
21
|
+
def initialize(controller, options = {})
|
22
|
+
@controller = controller.to_s
|
23
|
+
@options = options.with_indifferent_access
|
24
|
+
end
|
25
|
+
|
26
|
+
def build
|
27
|
+
[build_name, build_url, build_options]
|
28
|
+
end
|
29
|
+
|
30
|
+
def permissions
|
31
|
+
parse_permissions(permissions_const)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :controller, :options
|
37
|
+
|
38
|
+
def build_name
|
39
|
+
r = controller
|
40
|
+
r = "#{r}_#{action}" unless action == 'index'
|
41
|
+
r.to_sym
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_url
|
45
|
+
{ controller: controller, action: action, id: id }
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_options
|
49
|
+
{
|
50
|
+
caption: build_caption,
|
51
|
+
if: proc { GroupPermission.permission?(permissions_const) }
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_caption
|
56
|
+
"label_#{build_name}".to_sym
|
57
|
+
end
|
58
|
+
|
59
|
+
def controller_class
|
60
|
+
Object.const_get("#{controller.camelize}Controller")
|
61
|
+
end
|
62
|
+
|
63
|
+
def action
|
64
|
+
@options[:action] || 'index'
|
65
|
+
end
|
66
|
+
|
67
|
+
def id
|
68
|
+
@options[:id]
|
69
|
+
end
|
70
|
+
|
71
|
+
def permissions_const
|
72
|
+
controller_class.const_get('PERMISSIONS')
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_permissions(p)
|
76
|
+
return parse_permissions(p.values) if p.is_a?(Hash)
|
77
|
+
return p.flat_map { |v| parse_permissions(v) } if p.is_a?(Enumerable)
|
78
|
+
[p.to_s]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
unless ::Redmine::MenuManager::Mapper.included_modules.include?(
|
86
|
+
::RedmineNonprojectModules::Patches::Redmine::MenuManagerMapperPatch
|
87
|
+
)
|
88
|
+
::Redmine::MenuManager::Mapper.send(
|
89
|
+
:include, ::RedmineNonprojectModules::Patches::Redmine::MenuManagerMapperPatch
|
90
|
+
)
|
91
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module RedmineNonprojectModules
|
2
|
+
module Patches
|
3
|
+
module UserPatch
|
4
|
+
def self.included(base)
|
5
|
+
base.include(InstanceMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module InstanceMethods
|
9
|
+
def permission?(permissions)
|
10
|
+
GroupPermission.permission?(permissions, self)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
unless ::User.included_modules.include?(RedmineNonprojectModules::Patches::UserPatch)
|
18
|
+
::User.send(:include, RedmineNonprojectModules::Patches::UserPatch)
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redmine_nonproject_modules
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- 0.2.1
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-08-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: active_scaffold
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.5'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.5.4
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.5'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.5.4
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activemodel-associations
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: eac_ruby_utils
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0.10'
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 0.10.1
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.10'
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.10.1
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: virtus
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
description:
|
82
|
+
email:
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- app/assets/javascripts/redmine_nonproject_modules.js
|
88
|
+
- app/assets/stylesheets/redmine_nonproject_modules.css
|
89
|
+
- app/controllers/group_merge_controller.rb
|
90
|
+
- app/controllers/group_permissions_controller.rb
|
91
|
+
- app/helpers/group_merge_helper.rb
|
92
|
+
- app/models/group_merge.rb
|
93
|
+
- app/models/group_permission.rb
|
94
|
+
- app/models/group_permissions_setup.rb
|
95
|
+
- app/views/group_merge/check.html.erb
|
96
|
+
- app/views/group_merge/index.html.erb
|
97
|
+
- app/views/group_permissions/_dependencies.html.erb
|
98
|
+
- app/views/group_permissions/_member_context.html.erb
|
99
|
+
- app/views/group_permissions/index.html.erb
|
100
|
+
- app/views/group_permissions/show.html.erb
|
101
|
+
- config/initializers/000_dependencies.rb
|
102
|
+
- config/locales/en.yml
|
103
|
+
- config/locales/pt-BR.yml
|
104
|
+
- config/routes.rb
|
105
|
+
- init.rb
|
106
|
+
- lib/redmine_nonproject_modules.rb
|
107
|
+
- lib/redmine_nonproject_modules/dispatcher_finder.rb
|
108
|
+
- lib/redmine_nonproject_modules/patches/controller_patch.rb
|
109
|
+
- lib/redmine_nonproject_modules/patches/group_patch.rb
|
110
|
+
- lib/redmine_nonproject_modules/patches/redmine/i18n_patch.rb
|
111
|
+
- lib/redmine_nonproject_modules/patches/redmine/menu_manager_patch.rb
|
112
|
+
- lib/redmine_nonproject_modules/patches/user_patch.rb
|
113
|
+
- lib/redmine_nonproject_modules/version.rb
|
114
|
+
homepage: https://github.com/esquilo-azul/redmine_nonproject_modules
|
115
|
+
licenses: []
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubyforge_project:
|
133
|
+
rubygems_version: 2.7.7
|
134
|
+
signing_key:
|
135
|
+
specification_version: 4
|
136
|
+
summary: Support to non-project modules.
|
137
|
+
test_files: []
|