releaf-permissions 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +24 -0
  3. data/app/assets/stylesheets/releaf/controllers/releaf/permissions/sessions.scss +70 -0
  4. data/app/builders/releaf/permissions/profile/form_builder.rb +7 -0
  5. data/app/builders/releaf/permissions/roles/form_builder.rb +28 -0
  6. data/app/builders/releaf/permissions/roles/table_builder.rb +16 -0
  7. data/app/builders/releaf/permissions/users/form_builder.rb +11 -0
  8. data/app/builders/releaf/permissions/users/table_builder.rb +11 -0
  9. data/app/controllers/releaf/permissions/home_controller.rb +32 -0
  10. data/app/controllers/releaf/permissions/profile_controller.rb +56 -0
  11. data/app/controllers/releaf/permissions/roles_controller.rb +7 -0
  12. data/app/controllers/releaf/permissions/sessions_controller.rb +34 -0
  13. data/app/controllers/releaf/permissions/users_controller.rb +19 -0
  14. data/app/lib/releaf/permissions/access_control.rb +36 -0
  15. data/app/models/releaf/permissions/permission.rb +6 -0
  16. data/app/models/releaf/permissions/role.rb +38 -0
  17. data/app/models/releaf/permissions/user.rb +31 -0
  18. data/app/views/releaf/permissions/sessions/new.html.haml +14 -0
  19. data/lib/releaf-permissions.rb +32 -0
  20. data/lib/releaf/permissions/builders_autoload.rb +11 -0
  21. data/lib/releaf/permissions/devise_component.rb +8 -0
  22. data/lib/releaf/permissions/engine.rb +24 -0
  23. data/lib/releaf/permissions/profile_component.rb +9 -0
  24. data/lib/releaf/permissions/roles_component.rb +7 -0
  25. data/lib/releaf/permissions/users_component.rb +7 -0
  26. data/releaf-permissions.gemspec +19 -0
  27. data/spec/builders/profile/form_builder_spec.rb +18 -0
  28. data/spec/builders/roles/form_builder_spec.rb +38 -0
  29. data/spec/builders/roles/table_builder_spec.rb +29 -0
  30. data/spec/builders/users/form_builder_spec.rb +23 -0
  31. data/spec/builders/users/table_builder_spec.rb +21 -0
  32. data/spec/controllers/permissions/home_controller_spec.rb +52 -0
  33. data/spec/controllers/permissions/profile_controller_spec.rb +66 -0
  34. data/spec/controllers/permissions/users_controller_spec.rb +28 -0
  35. data/spec/features/profile_updating_spec.rb +35 -0
  36. data/spec/features/roles_spec.rb +64 -0
  37. data/spec/features/users_spec.rb +107 -0
  38. data/spec/lib/access_control_spec.rb +81 -0
  39. data/spec/models/permissions/role_spec.rb +41 -0
  40. data/spec/models/permissions/user_spec.rb +23 -0
  41. 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,7 @@
1
+ module Releaf::Permissions::RolesComponent
2
+ extend Releaf::Core::Component
3
+
4
+ def self.draw_component_routes router
5
+ resource_route(router, :permissions, :roles)
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Releaf::Permissions::UsersComponent
2
+ extend Releaf::Core::Component
3
+
4
+ def self.draw_component_routes(router)
5
+ resource_route(router, :permissions, :users)
6
+ end
7
+ 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