releaf-permissions 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|