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.
Files changed (29) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/javascripts/redmine_nonproject_modules.js +1 -0
  3. data/app/assets/stylesheets/redmine_nonproject_modules.css +1 -0
  4. data/app/controllers/group_merge_controller.rb +35 -0
  5. data/app/controllers/group_permissions_controller.rb +35 -0
  6. data/app/helpers/group_merge_helper.rb +31 -0
  7. data/app/models/group_merge.rb +88 -0
  8. data/app/models/group_permission.rb +106 -0
  9. data/app/models/group_permissions_setup.rb +20 -0
  10. data/app/views/group_merge/check.html.erb +35 -0
  11. data/app/views/group_merge/index.html.erb +12 -0
  12. data/app/views/group_permissions/_dependencies.html.erb +10 -0
  13. data/app/views/group_permissions/_member_context.html.erb +5 -0
  14. data/app/views/group_permissions/index.html.erb +24 -0
  15. data/app/views/group_permissions/show.html.erb +36 -0
  16. data/config/initializers/000_dependencies.rb +4 -0
  17. data/config/locales/en.yml +10 -0
  18. data/config/locales/pt-BR.yml +12 -0
  19. data/config/routes.rb +6 -0
  20. data/init.rb +34 -0
  21. data/lib/redmine_nonproject_modules.rb +6 -0
  22. data/lib/redmine_nonproject_modules/dispatcher_finder.rb +32 -0
  23. data/lib/redmine_nonproject_modules/patches/controller_patch.rb +29 -0
  24. data/lib/redmine_nonproject_modules/patches/group_patch.rb +24 -0
  25. data/lib/redmine_nonproject_modules/patches/redmine/i18n_patch.rb +29 -0
  26. data/lib/redmine_nonproject_modules/patches/redmine/menu_manager_patch.rb +91 -0
  27. data/lib/redmine_nonproject_modules/patches/user_patch.rb +19 -0
  28. data/lib/redmine_nonproject_modules/version.rb +8 -0
  29. metadata +137 -0
@@ -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,10 @@
1
+ <ul>
2
+ <% permission.dependencies.each do |d| %>
3
+ <li>
4
+ <%= d %>
5
+ <% if d.dependencies.any? %>
6
+ <%= render partial: 'dependencies', locals: {permission: d } %>
7
+ <% end %>
8
+ </li>
9
+ <% end %>
10
+ </ul>
@@ -0,0 +1,5 @@
1
+ <% if GroupPermission.permission?('group_merge') %>
2
+ <div class="contextual">
3
+ <%= link_to t(:merge), merge_group_path(group) %>
4
+ </div>
5
+ <% 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,4 @@
1
+ Redmine::Plugin.post_register :redmine_nonproject_modules do
2
+ # Source: https://github.com/esquilo-azul/redmine_plugins_helper
3
+ requires_redmine_plugin(:redmine_plugins_helper, version_or_higher: '0.5.2')
4
+ 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.
@@ -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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_scaffold'
4
+
5
+ module RedmineNonprojectModules
6
+ 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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedmineNonprojectModules
4
+ AUTHOR = 'Eduardo Henrique Bogoni'
5
+ HOMEPAGE = 'https://github.com/esquilo-azul/redmine_nonproject_modules'
6
+ SUMMARY = 'Support to non-project modules.'
7
+ VERSION = '0.2.1'
8
+ 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: []