Commit 544dddab by John Doe

added specs for create_permission

parent ab1c0ca6
# frozen_string_literal: true
class PermissionsController < ApplicationController class PermissionsController < ApplicationController
before_action :set_permission, only: [:show, :update, :destroy] before_action :authenticate_user!
before_action :set_nilm
before_action :authorize_admin
# GET /permissions # GET /permissions
# GET /permissions.json # GET /permissions.json
def index def index
@permissions = Permission.all # return permissions for nilm specified by nilm_id
end @permissions = Permission.find_by_nilm(@nilm)
# GET /permissions/1
# GET /permissions/1.json
def show
end end
# POST /permissions # POST /permissions
# POST /permissions.json # POST /permissions.json
def create def create
@permission = Permission.new(permission_params) # create permission for nilm specified by nilm_id
@service = PermissionService.new
if @permission.save @service.run(@nilm, params[:role], params[:type], params[:target_id])
render :show, status: :created, location: @permission @permission = @service.permission
else render status: @service.success? ? :ok : :unprocessable_entity
render json: @permission.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /permissions/1
# PATCH/PUT /permissions/1.json
def update
if @permission.update(permission_params)
render :show, status: :ok, location: @permission
else
render json: @permission.errors, status: :unprocessable_entity
end
end end
# DELETE /permissions/1 # DELETE /permissions/1
# DELETE /permissions/1.json # DELETE /permissions/1.json
def destroy def destroy
@permission.destroy # remove permission from nilm specified by nilm_id
@service = ServiceStub.new
@service.add_notice("Removed permission")
@nilm.permissions.find(params[:id]).destroy
end end
private private
# Use callbacks to share common setup or constraints between actions.
def set_permission def set_nilm
@permission = Permission.find(params[:id]) @nilm = Nilm.find(params[:nilm_id])
end end
# Never trust parameters from the scary internet, only allow the white list through. # authorization based on nilms
def permission_params def authorize_owner
params.fetch(:permission, {}) head :unauthorized unless current_user.owns_nilm?(@nilm)
end end
end end
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
class Nilm < ApplicationRecord class Nilm < ApplicationRecord
#---Associations----- #---Associations-----
has_one :db has_one :db, dependent: :destroy
has_many :permissions, dependent: :destroy #viewer, owner, admin has_many :permissions, dependent: :destroy #viewer, owner, admin
has_many :users, through: :permissions has_many :users, through: :permissions
has_many :user_groups, through: :permissions has_many :user_groups, through: :permissions
......
...@@ -3,4 +3,30 @@ class Permission < ApplicationRecord ...@@ -3,4 +3,30 @@ class Permission < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :user_group belongs_to :user_group
belongs_to :nilm belongs_to :nilm
#---Validations---
ROLES = %w(admin owner viewer)
validates :role, :inclusion => {:in => ROLES}
validate :user_xor_group
def user_xor_group
unless user.blank? ^ user_group.blank?
errors.add(:base, "specify a user or group not both")
end
end
def target_name
if self.user_id?
return self.user.name
elsif self.user_group_id?
return self.user_group.name
else
return "[no target set]"
end
end
def self.json_keys
[:id, :nilm_id, :role]
end
end end
...@@ -73,6 +73,10 @@ class User < ActiveRecord::Base ...@@ -73,6 +73,10 @@ class User < ActiveRecord::Base
return self.has_permission(["admin","owner","viewer"],nilm) return self.has_permission(["admin","owner","viewer"],nilm)
end end
def name
"#{self.first_name} #{self.last_name}"
end
protected protected
......
...@@ -16,9 +16,7 @@ class EditFolder ...@@ -16,9 +16,7 @@ class EditFolder
# result is valid (eg folder's can't have the same name) # result is valid (eg folder's can't have the same name)
db_folder.assign_attributes(attribs) db_folder.assign_attributes(attribs)
unless db_folder.valid? unless db_folder.valid?
db_folder.errors add_errors(db_folder.errors.full_messages)
.full_messages
.each { |e| add_error(e) }
return self return self
end end
# local model checks out, update the remote NilmDB # local model checks out, update the remote NilmDB
......
# frozen_string_literal: true
# Handles changing DbStream attributes
class CreatePermission
include ServiceStatus
attr_reader :permission
def run(nilm, role, type, target_id)
# create [role] perimssion on [nilm] for
# the user or group specified
# [type]: user|group
# [target_id]: user_id or user_group_id value
#
@permission = Permission.create(nilm: nilm, role: role)
begin
case type
when "user"
if(nilm.permissions.find_by_user_id(target_id))
add_error("user already has permissions on this nilm")
return self
end
@permission.user = User.find(target_id)
when "group"
@permission.user_group = UserGroup.find(target_id)
if(nilm.permissions.find_by_user_group_id(target_id))
add_error("group already has permissions on this nilm")
return self
end
else
add_error("invalid type")
return self
end
rescue ActiveRecord::RecordNotFound
add_error("target does not exist")
return self
end
unless @permission.save
add_errors(@permission.errors.full_messages)
return self
end
set_notice("Created permission")
self
end
end
...@@ -42,6 +42,10 @@ module ServiceStatus ...@@ -42,6 +42,10 @@ module ServiceStatus
@errors << String(message) @errors << String(message)
end end
def add_errors(messages)
messages.each{|m| self.add_error(m)}
end
def errors? def errors?
!@errors.empty? !@errors.empty?
end end
......
json.extract! permission, :id, :created_at, :updated_at json.extract! permission, *Permission.json_keys
json.url permission_url(permission, format: :json) json.name permission.target_name
\ No newline at end of file
...@@ -13,7 +13,7 @@ module ControlPanel ...@@ -13,7 +13,7 @@ module ControlPanel
# -- all .rb files in that directory are automatically loaded. # -- all .rb files in that directory are automatically loaded.
config.api_only = true config.api_only = true
# Add folders under the services and adapters directory # Add folders under the services and adapters directory
%w(nilm db db_folder db_stream).each do |service| %w(nilm db db_folder db_stream permission).each do |service|
config.autoload_paths << Rails.root.join("app/services/#{service}") config.autoload_paths << Rails.root.join("app/services/#{service}")
end end
config.autoload_paths << Rails.root.join("app/adapters") config.autoload_paths << Rails.root.join("app/adapters")
......
...@@ -7,5 +7,5 @@ Rails.application.routes.draw do ...@@ -7,5 +7,5 @@ Rails.application.routes.draw do
mount_devise_token_auth_for 'User', at: 'auth' mount_devise_token_auth_for 'User', at: 'auth'
resources :user_groups resources :user_groups
resources :permissions resources :permissions, only: [:index, :create, :destroy]
end end
FactoryGirl.define do FactoryGirl.define do
factory :permission do factory :permission do
user
nilm nilm
role "admin"
after(:build) do |permission|
# if no user or group specified, create a user
if(permission.user.blank? &&
permission.user_group.blank?)
permission.user = create(:user)
end end
end
end
end end
...@@ -6,7 +6,7 @@ FactoryGirl.define do ...@@ -6,7 +6,7 @@ FactoryGirl.define do
sequence :name do |n| "group#{n}" end sequence :name do |n| "group#{n}" end
description { Faker::Lorem.sentence } description { Faker::Lorem.sentence }
owner { users.first } owner { users.empty? ? create(:user): users.first }
users { members.empty? ? [User.first] : members } users { members.empty? ? [create(:user)] : members }
end end
end end
...@@ -9,4 +9,23 @@ RSpec.describe 'Nilm' do ...@@ -9,4 +9,23 @@ RSpec.describe 'Nilm' do
specify { expect(nilm).to respond_to(:url) } specify { expect(nilm).to respond_to(:url) }
specify { expect(nilm).to respond_to(:db) } specify { expect(nilm).to respond_to(:db) }
end end
it 'removes associated db when destroyed' do
db = Db.create
nilm = Nilm.create(db: db)
nilm.destroy
expect(Db.find_by_id(db.id)).to be nil
end
it 'removes associated permissions when destroyed' do
nilm = create(:nilm)
u = create(:user)
g = create(:user_group)
puser = create(:permission, nilm: nilm, user: u)
pgrp = create(:permission, nilm: nilm, user_group: g)
nilm.destroy
[puser.id, pgrp.id].each do |id|
expect(Permission.find_by_id(id)).to be nil
end
end
end end
# frozen_string_literal: true
require 'rails_helper' require 'rails_helper'
RSpec.describe Permission, type: :model do RSpec.describe Permission, type: :model do
pending "add some examples to (or delete) #{__FILE__}" describe 'object' do
let(:permission) { Permission.new }
specify { expect(permission).to respond_to(:role) }
specify { expect(permission).to respond_to(:nilm) }
specify { expect(permission).to respond_to(:user_group) }
specify { expect(permission).to respond_to(:user) }
end
it 'requires either a user or a group, not both' do
u = create(:user)
g = create(:user_group)
n = create(:nilm)
# valid with a user
p = build(:permission, nilm: n, user: u)
expect(p.valid?).to be true
# valid with a group
p.user = nil
p.user_group = g
expect(p.valid?).to be true
# invalid with neither
p.user_group = nil
expect(p.valid?).to be false
# invalid with both
p.user_group = g
p.user = u
expect(p.valid?).to be false
expect(p.errors.full_messages.first)
.to match(/not both/)
end
it 'requires role to be viewer|owner|admin' do
p = build(:permission)
%w(owner viewer admin).each do |role|
p.role=role
expect(p.valid?).to be true
end
['',nil,'other'].each do |invalid_role|
p.role = invalid_role
expect(p.valid?).to be false
end
end
it 'responds to target_name' do
u = create(:user, first_name: "John", last_name: "Donnal")
p = build(:permission, user: u)
expect(p.target_name).to match('John Donnal')
g = create(:user_group, name: 'a group')
p.user = nil; p.user_group = g
expect(p.target_name).to match('a group')
end
end end
...@@ -9,6 +9,12 @@ RSpec.describe User, type: :model do ...@@ -9,6 +9,12 @@ RSpec.describe User, type: :model do
specify { expect(user).to respond_to(:email) } specify { expect(user).to respond_to(:email) }
end end
it 'responds to name' do
u = build(:user, first_name: 'Bill', last_name: 'Test')
expect(u.name).to match('Bill Test')
end
describe
describe "permission management" do describe "permission management" do
context "Given the Donnal's House and the Lab" do context "Given the Donnal's House and the Lab" do
before(:each) do before(:each) do
......
# frozen_string_literal: true
require 'rails_helper'
describe 'CreatePermission service' do
let(:nilm){ create(:nilm)}
let(:user){ create(:user)}
let(:group){ create(:user_group)}
it 'creates [role] permission for specified user' do
service = CreatePermission.new
service.run(nilm,'admin','user',user.id)
p = service.permission
expect(service.success?).to be true
expect(p.valid?).to be true
expect(p).to have_attributes(nilm: nilm,
user: user,
role: 'admin')
end
it 'creates [role] permission for specified group' do
service = CreatePermission.new
service.run(nilm,'admin','group',group.id)
p = service.permission
expect(service.success?).to be true
expect(p.valid?).to be true
expect(p).to have_attributes(nilm: nilm,
user_group: group,
role: 'admin')
end
it 'does not allow users multiple permissions on a nilm' do
create(:permission, user: user, nilm: nilm, role: 'viewer')
service = CreatePermission.new
service.run(nilm,'admin','user',user.id)
expect(service.success?).to be false
end
it 'does not allow groups multiple permissions on a nilm' do
create(:permission, user_group: group, nilm: nilm, role: 'viewer')
service = CreatePermission.new
service.run(nilm,'admin','group',group.id)
expect(service.success?).to be false
end
it 'verifies type in user|group' do
service = CreatePermission.new
service.run(nilm,'admin','bogus_type',0)
expect(service.success?).to be false
expect(service.errors[0]).to match(/type/)
end
it 'checks if user or group exists' do
['user','group'].each do |target_type|
service = CreatePermission.new
service.run(nilm,'admin',target_type,99)
expect(service.success?).to be false
expect(service.errors[0]).to match(/target/)
end
end
it 'forwards permission errors' do
service = CreatePermission.new
service.run(nilm,'bad_role','user',user.id)
p = service.permission
expect(service.success?).to be false
expect(service.errors).to eq(p.errors.full_messages)
end
end
...@@ -15,8 +15,9 @@ describe 'ServiceStatus' do ...@@ -15,8 +15,9 @@ describe 'ServiceStatus' do
it 'tracks errors' do it 'tracks errors' do
x = ModuleTester.new x = ModuleTester.new
x.add_error('message') x.add_error('message')
x.add_errors(['multiple','messages'])
expect(x.errors?).to be true expect(x.errors?).to be true
expect(x.errors.length).to eq(1) expect(x.errors.length).to eq(3)
end end
it 'tracks warnings' do it 'tracks warnings' do
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment