releaf-permissions 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/LICENSE +24 -0
- data/app/assets/stylesheets/releaf/controllers/releaf/permissions/sessions.scss +70 -0
- data/app/builders/releaf/permissions/profile/form_builder.rb +7 -0
- data/app/builders/releaf/permissions/roles/form_builder.rb +28 -0
- data/app/builders/releaf/permissions/roles/table_builder.rb +16 -0
- data/app/builders/releaf/permissions/users/form_builder.rb +11 -0
- data/app/builders/releaf/permissions/users/table_builder.rb +11 -0
- data/app/controllers/releaf/permissions/home_controller.rb +32 -0
- data/app/controllers/releaf/permissions/profile_controller.rb +56 -0
- data/app/controllers/releaf/permissions/roles_controller.rb +7 -0
- data/app/controllers/releaf/permissions/sessions_controller.rb +34 -0
- data/app/controllers/releaf/permissions/users_controller.rb +19 -0
- data/app/lib/releaf/permissions/access_control.rb +36 -0
- data/app/models/releaf/permissions/permission.rb +6 -0
- data/app/models/releaf/permissions/role.rb +38 -0
- data/app/models/releaf/permissions/user.rb +31 -0
- data/app/views/releaf/permissions/sessions/new.html.haml +14 -0
- data/lib/releaf-permissions.rb +32 -0
- data/lib/releaf/permissions/builders_autoload.rb +11 -0
- data/lib/releaf/permissions/devise_component.rb +8 -0
- data/lib/releaf/permissions/engine.rb +24 -0
- data/lib/releaf/permissions/profile_component.rb +9 -0
- data/lib/releaf/permissions/roles_component.rb +7 -0
- data/lib/releaf/permissions/users_component.rb +7 -0
- data/releaf-permissions.gemspec +19 -0
- data/spec/builders/profile/form_builder_spec.rb +18 -0
- data/spec/builders/roles/form_builder_spec.rb +38 -0
- data/spec/builders/roles/table_builder_spec.rb +29 -0
- data/spec/builders/users/form_builder_spec.rb +23 -0
- data/spec/builders/users/table_builder_spec.rb +21 -0
- data/spec/controllers/permissions/home_controller_spec.rb +52 -0
- data/spec/controllers/permissions/profile_controller_spec.rb +66 -0
- data/spec/controllers/permissions/users_controller_spec.rb +28 -0
- data/spec/features/profile_updating_spec.rb +35 -0
- data/spec/features/roles_spec.rb +64 -0
- data/spec/features/users_spec.rb +107 -0
- data/spec/lib/access_control_spec.rb +81 -0
- data/spec/models/permissions/role_spec.rb +41 -0
- data/spec/models/permissions/user_spec.rb +23 -0
- metadata +124 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
.container
|
2
|
+
.box
|
3
|
+
.logo
|
4
|
+
= form_for resource, as: resource_name, builder: Releaf::Builders::FormBuilder, url: session_path(resource_name), html: {class: "login"} do |f|
|
5
|
+
- if params[:redirect_to]
|
6
|
+
= hidden_field_tag :redirect_to, params[:redirect_to]
|
7
|
+
.field
|
8
|
+
%label{for: :email}= t("Email", scope: 'admin.sessions')
|
9
|
+
= f.email_field :email, autofocus: "autofocus", id: :email, class: "text"
|
10
|
+
.field
|
11
|
+
%label{for: :password}= t("Password", scope: 'admin.sessions')
|
12
|
+
= f.password_field :password, id: :password, class: "text"
|
13
|
+
.field
|
14
|
+
%button.button{type: "submit"}= t("Sign in", scope: 'admin.sessions')
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'releaf/permissions/engine'
|
2
|
+
|
3
|
+
module Releaf::Permissions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_filter :authenticate!, :verify_controller_access!, :set_locale
|
8
|
+
end
|
9
|
+
|
10
|
+
# set locale for interface translating from current admin user
|
11
|
+
def set_locale
|
12
|
+
I18n.locale = access_control.user.locale
|
13
|
+
end
|
14
|
+
|
15
|
+
def layout_settings(key)
|
16
|
+
access_control.user.try(:settings).try(:[], key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def authenticate!
|
20
|
+
access_control.authenticate!
|
21
|
+
end
|
22
|
+
|
23
|
+
def verify_controller_access!
|
24
|
+
unless access_control.controller_permitted?(access_control.current_controller_name)
|
25
|
+
raise Releaf::Core::AccessDenied.new(access_control.current_controller_name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def access_control
|
30
|
+
@access_control ||= Releaf::Permissions::AccessControl.new(controller: self)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
root_path = File.expand_path('../..', File.dirname(__dir__))
|
2
|
+
files = %w(
|
3
|
+
roles/form_builder
|
4
|
+
roles/table_builder
|
5
|
+
users/form_builder
|
6
|
+
users/table_builder
|
7
|
+
profile/form_builder
|
8
|
+
)
|
9
|
+
files.each do|file|
|
10
|
+
require "#{root_path}/app/builders/releaf/permissions/#{file}"
|
11
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module Releaf::Permissions::DeviseComponent
|
2
|
+
def self.draw_component_routes router
|
3
|
+
router.devise_for Releaf.application.config.devise_for, path: "", controllers: { sessions: "releaf/permissions/sessions" }
|
4
|
+
router.namespace :releaf, path: nil do
|
5
|
+
router.root to: "permissions/home#home", as: :root
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'devise'
|
2
|
+
|
3
|
+
module Releaf::Permissions
|
4
|
+
require 'releaf/permissions/devise_component'
|
5
|
+
require 'releaf/permissions/profile_component'
|
6
|
+
require 'releaf/permissions/roles_component'
|
7
|
+
require 'releaf/permissions/users_component'
|
8
|
+
require 'releaf/permissions/builders_autoload'
|
9
|
+
|
10
|
+
class Engine < ::Rails::Engine
|
11
|
+
initializer 'precompile', group: :all do |app|
|
12
|
+
app.config.assets.precompile += %w(releaf/controllers/releaf/permissions/*)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.components
|
17
|
+
[
|
18
|
+
Releaf::Permissions::DeviseComponent,
|
19
|
+
Releaf::Permissions::RolesComponent,
|
20
|
+
Releaf::Permissions::UsersComponent,
|
21
|
+
Releaf::Permissions::ProfileComponent
|
22
|
+
]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Releaf::Permissions::ProfileComponent
|
2
|
+
def self.draw_component_routes router
|
3
|
+
router.namespace :releaf, path: nil do
|
4
|
+
router.get "profile", to: "permissions/profile#edit", as: :permissions_user_profile
|
5
|
+
router.patch "profile", to: "permissions/profile#update"
|
6
|
+
router.post "profile/settings", to: "permissions/profile#settings", as: :permissions_user_profile_settings
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.expand_path("../../releaf-core/lib/releaf/version.rb", __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "releaf-permissions"
|
5
|
+
s.version = Releaf::VERSION
|
6
|
+
|
7
|
+
s.summary = "Built-in admin and role support for releaf"
|
8
|
+
s.description = "Admin/role subsystem for releaf"
|
9
|
+
s.authors = ["CubeSystems"]
|
10
|
+
s.email = 'info@cubesystems.lv'
|
11
|
+
s.homepage = 'https://github.com/cubesystems/releaf'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = Dir["spec/**/*"]
|
15
|
+
|
16
|
+
s.add_dependency 'releaf-core', Releaf::VERSION
|
17
|
+
s.add_dependency 'devise'
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Releaf::Permissions::Profile::FormBuilder, type: :class do
|
4
|
+
class FormBuilderTestHelper < ActionView::Base; end
|
5
|
+
let(:template){ FormBuilderTestHelper.new }
|
6
|
+
let(:object){ Releaf::Permissions::User.new }
|
7
|
+
let(:subject){ described_class.new(:resource, object, template, {}) }
|
8
|
+
|
9
|
+
it "inherits Releaf::Permissions::Users::FormBuilder" do
|
10
|
+
expect(described_class.superclass).to eq(Releaf::Permissions::Users::FormBuilder)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#field_names" do
|
14
|
+
it "returns name, surname, locale, email, password and password_confirmation as field names array" do
|
15
|
+
expect(subject.field_names).to eq(%w(name surname locale email password password_confirmation))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Releaf::Permissions::Roles::FormBuilder, type: :class do
|
4
|
+
class FormBuilderTestHelper < ActionView::Base; end
|
5
|
+
let(:template){ FormBuilderTestHelper.new }
|
6
|
+
let(:object){ Releaf::Permissions::Role.new }
|
7
|
+
let(:subject){ described_class.new(:resource, object, template, {}) }
|
8
|
+
|
9
|
+
describe "#render_default_controller" do
|
10
|
+
it "pass localized controller options to releaf item field" do
|
11
|
+
allow(Releaf.application.config).to receive(:available_controllers)
|
12
|
+
.and_return(["releaf/i18n_database/translations", "releaf/content/nodes"])
|
13
|
+
translated_controllers = {"Releaf/i18n database/translations"=>"releaf/i18n_database/translations", "Releaf/content/nodes"=>"releaf/content/nodes"}
|
14
|
+
|
15
|
+
allow(subject).to receive(:releaf_item_field).with(:default_controller, options: {select_options: translated_controllers}).and_return("x")
|
16
|
+
expect(subject.render_default_controller).to eq("x")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#render_permissions" do
|
21
|
+
it "returns associated set field" do
|
22
|
+
options = {association: {items: "x", field: :permission}}
|
23
|
+
allow(subject).to receive(:permission_items).and_return("x")
|
24
|
+
allow(subject).to receive(:releaf_associated_set_field).with(:permissions, options: options).and_return("y")
|
25
|
+
expect(subject.render_permissions).to eq("y")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#permission_items" do
|
30
|
+
it "returns scoped and translated controller values" do
|
31
|
+
allow(Releaf.application.config).to receive(:available_controllers)
|
32
|
+
.and_return(["releaf/content/nodes", "admin/chapters"])
|
33
|
+
allow(subject).to receive(:t).with("releaf/content/nodes", scope: "admin.controllers").and_return("controller 1")
|
34
|
+
allow(subject).to receive(:t).with("admin/chapters", scope: "admin.controllers").and_return("controller 2")
|
35
|
+
expect(subject.permission_items).to eq("controller.releaf/content/nodes" => "controller 1", "controller.admin/chapters" => "controller 2")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Releaf::Permissions::Roles::TableBuilder, type: :class do
|
4
|
+
class TableBuilderTestHelper < ActionView::Base; end
|
5
|
+
let(:template){ TableBuilderTestHelper.new }
|
6
|
+
let(:resource_class){ Releaf::Permissions::Role }
|
7
|
+
let(:subject){ described_class.new([], resource_class, template, {}) }
|
8
|
+
|
9
|
+
describe "#column_names" do
|
10
|
+
it "returns name and default_controller as column names array" do
|
11
|
+
expect(subject.column_names).to eq([:name, :default_controller])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#default_controller_content" do
|
16
|
+
context "when default controller is defined for given resource" do
|
17
|
+
it "returns translated value" do
|
18
|
+
allow(I18n).to receive(:t).with("releaf/i18n/database/translations", scope: "admin.controllers").and_return("x")
|
19
|
+
expect(subject.default_controller_content(resource_class.new(default_controller: "releaf/i18n_database/translations"))).to eq("x")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when default controller is not defined for given resource" do
|
24
|
+
it "returns dash" do
|
25
|
+
expect(subject.default_controller_content(resource_class.new)).to eq("-")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Releaf::Permissions::Users::FormBuilder, type: :class do
|
4
|
+
class FormBuilderTestHelper < ActionView::Base; end
|
5
|
+
let(:template){ FormBuilderTestHelper.new }
|
6
|
+
let(:object){ Releaf::Permissions::Role.new }
|
7
|
+
let(:subject){ described_class.new(:resource, object, template, {}) }
|
8
|
+
|
9
|
+
describe "#field_names" do
|
10
|
+
it "returns name, surname, locale, role_id, email, password and password_confirmation as field names array" do
|
11
|
+
expect(subject.field_names).to eq(%w(name surname locale role_id email password password_confirmation))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#render_locale" do
|
16
|
+
it "pass localized controller options to releaf item field" do
|
17
|
+
allow(Releaf.application.config).to receive(:available_admin_locales).and_return(["de", "ze"])
|
18
|
+
allow(subject).to receive(:locale_options).with(["de", "ze"]).and_return(["xx", "yy"])
|
19
|
+
allow(subject).to receive(:releaf_item_field).with(:locale, options: {select_options: ["xx", "yy"]}).and_return("x")
|
20
|
+
expect(subject.render_locale).to eq("x")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe Releaf::Permissions::Users::TableBuilder, type: :class do
|
4
|
+
class TableBuilderTestHelper < ActionView::Base; end
|
5
|
+
let(:template){ TableBuilderTestHelper.new }
|
6
|
+
let(:resource_class){ Releaf::Permissions::User }
|
7
|
+
let(:subject){ described_class.new([], resource_class, template, {}) }
|
8
|
+
|
9
|
+
describe "#column_names" do
|
10
|
+
it "returns name, surname, role, email and locale as column names array" do
|
11
|
+
expect(subject.column_names).to eq([:name, :surname, :role, :email, :locale])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#locale_content" do
|
16
|
+
it "returns translated locale" do
|
17
|
+
allow(subject).to receive(:translate_locale).with("de").and_return("deutch")
|
18
|
+
expect(subject.locale_content(resource_class.new(locale: "de"))).to eq("deutch")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Releaf::Permissions::HomeController do
|
4
|
+
|
5
|
+
describe "GET home" do
|
6
|
+
context "when authorized as user" do
|
7
|
+
login_as_user :user
|
8
|
+
|
9
|
+
before do
|
10
|
+
@role = subject.current_releaf_permissions_user.role
|
11
|
+
end
|
12
|
+
|
13
|
+
it "redirects to users controller" do
|
14
|
+
get :home
|
15
|
+
expect(response).to redirect_to(url_for(action: 'index', controller: @role.default_controller, only_path: true))
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when users default controller doesn't exist" do
|
19
|
+
before do
|
20
|
+
@role.update_attribute(:default_controller, 'non_existing/controllers_name')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "redirects to first available controller" do
|
24
|
+
get :home
|
25
|
+
expect(response).to redirect_to(url_for(action: 'index', controller: "releaf/content/nodes", only_path: true))
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when no releaf controller is available" do
|
29
|
+
before do
|
30
|
+
@role.permissions = []
|
31
|
+
@role.save!
|
32
|
+
end
|
33
|
+
|
34
|
+
it "redirects to root_path" do
|
35
|
+
get :home
|
36
|
+
expect(response).to redirect_to(root_path)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when authorized as content user" do
|
43
|
+
login_as_user :user
|
44
|
+
|
45
|
+
it "redirects to content controller" do
|
46
|
+
get :home
|
47
|
+
expect(response)
|
48
|
+
.to redirect_to(url_for(action: 'index', controller: subject.current_releaf_permissions_user.role.default_controller, only_path: true))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Releaf::Permissions::ProfileController do
|
4
|
+
let(:another_role){ FactoryGirl.create(:content_role) }
|
5
|
+
let(:user){ subject.current_releaf_permissions_user }
|
6
|
+
login_as_user :user
|
7
|
+
|
8
|
+
describe "#resource_class" do
|
9
|
+
it "returns current releaf user user class" do
|
10
|
+
expect(described_class.new.resource_class).to eq(Releaf::Permissions::User)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "PATCH update" do
|
15
|
+
context 'when attributes contain role_id' do
|
16
|
+
it "does not update it" do
|
17
|
+
expect{ patch :update, {resource: {role_id: another_role.id}} }.to_not change{ user.role_id }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with allowed attributes' do
|
22
|
+
it "saves new attributes" do
|
23
|
+
attributes = {
|
24
|
+
"name" => "new name",
|
25
|
+
"surname" => "new surname",
|
26
|
+
"email" => "new.email@example.com",
|
27
|
+
"locale" => "lv"
|
28
|
+
}
|
29
|
+
|
30
|
+
# This is needed in order to get same instance as we expect.
|
31
|
+
# Otherwise we'll get same record, but different instance and test will fail
|
32
|
+
allow( user ).to receive(:becomes).with(Releaf::Permissions::User).and_return(user)
|
33
|
+
|
34
|
+
expect(user).to receive(:update_attributes).with(attributes)
|
35
|
+
patch :update, {resource: attributes}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "PUT settings", db_strategy: :truncation do
|
41
|
+
context 'when params[:settings] is not Hash' do
|
42
|
+
it "has a 422 status code" do
|
43
|
+
put :settings
|
44
|
+
expect(response.status).to eq(422)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when params[:settings] is Hash' do
|
49
|
+
it "has a 200 status code" do
|
50
|
+
put :settings, {settings: {dummy: 'maybe'}}
|
51
|
+
expect(response.status).to eq(200)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "saves given data within current user settings" do
|
55
|
+
put :settings, {settings: {dummy: 'maybe'}}
|
56
|
+
expect(user.settings.dummy).to eq('maybe')
|
57
|
+
end
|
58
|
+
|
59
|
+
it "casts bolean values from strings to booleans" do
|
60
|
+
put :settings, {settings: {be_true: 'true', be_false: 'false'}}
|
61
|
+
expect(user.settings.be_true).to be true
|
62
|
+
expect(user.settings.be_false).to be false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
# use Admin::BooksController as it inherit Releaf::BaseController and
|
4
|
+
# have no extra methods or overrides
|
5
|
+
describe Releaf::Permissions::UsersController do
|
6
|
+
before do
|
7
|
+
sign_in FactoryGirl.create(:user)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "GET #new" do
|
11
|
+
it "assigns default role" do
|
12
|
+
get :new
|
13
|
+
expect(assigns(:resource).role).to eq(Releaf::Permissions::Role.first)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "GET #index" do
|
18
|
+
before do
|
19
|
+
FactoryGirl.create(:content_user, name: "John")
|
20
|
+
FactoryGirl.create(:content_user, name: "Bill", surname: "Green", email: "another@example.com")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "searches by name, surname and email" do
|
24
|
+
get :index, search: "bill green another@example"
|
25
|
+
expect(assigns(:collection).count).to eq(1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
feature "User profile" do
|
3
|
+
background do
|
4
|
+
auth_as_user(false, FactoryGirl.create(:user, email: "email@example.com"))
|
5
|
+
visit releaf_permissions_user_profile_path
|
6
|
+
end
|
7
|
+
|
8
|
+
scenario "name, surname and locale" do
|
9
|
+
fill_in 'Name', with: "Edward"
|
10
|
+
fill_in 'Surname', with: "Bat"
|
11
|
+
select "Lv", from: "Locale"
|
12
|
+
click_button 'Save'
|
13
|
+
|
14
|
+
expect(page).to have_css('header .profile .name', text: "Edward Bat")
|
15
|
+
end
|
16
|
+
|
17
|
+
scenario "password and email" do
|
18
|
+
# update
|
19
|
+
fill_in 'Email', with: "new.email@example.com"
|
20
|
+
fill_in 'Password', with: "newpassword123", match: :prefer_exact
|
21
|
+
fill_in 'Password confirmation', with: "newpassword123", match: :prefer_exact
|
22
|
+
click_button 'Save'
|
23
|
+
|
24
|
+
# logout
|
25
|
+
find('body > header form.sign-out button').click
|
26
|
+
|
27
|
+
# login
|
28
|
+
visit releaf_root_path
|
29
|
+
fill_in 'Email', with: "new.email@example.com"
|
30
|
+
fill_in 'Password', with: "newpassword123"
|
31
|
+
click_button 'Sign in'
|
32
|
+
|
33
|
+
expect(page).to have_css('.sign-out')
|
34
|
+
end
|
35
|
+
end
|