Skip to content

Commit

Permalink
Merge pull request #128 from npauzenga/features/roles-and-policies
Browse files Browse the repository at this point in the history
Features/roles and policies
  • Loading branch information
npauzenga committed Jan 31, 2016
2 parents b322c58 + 31050b1 commit bd125d8
Show file tree
Hide file tree
Showing 24 changed files with 224 additions and 42 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ gem "interactor"
gem "figaro"
gem "knock"
gem "active_model_serializers"
gem "rolify"

group :developemnt, :test do
gem "pry-byebug"
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ GEM
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rolify (5.0.0)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
Expand Down Expand Up @@ -272,6 +273,7 @@ DEPENDENCIES
puma
rails (= 4.2.4)
rails-api
rolify
rspec-rails (~> 3.0)
rspec_api_documentation
rubocop
Expand Down
9 changes: 5 additions & 4 deletions app/controllers/game_nights_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
class GameNightsController < AuthenticationController
# POST /game_nights
def create
result = CreateGameNight.call(user: current_user,
game_night_params: game_night_params)
result = CreateGameNightOrganizer.call(user: current_user,
role: :organizer,
game_night_params: game_night_params)

if result.success?
render json: result.game_night, status: :created
render json: result.resource, status: :created
else
render json: result.game_night.errors, status: :unprocessable_entity
render json: result.errors, status: :unprocessable_entity
end
end

Expand Down
6 changes: 4 additions & 2 deletions app/controllers/groups_controller.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
class GroupsController < AuthenticationController
# POST /groups
def create
result = CreateGroup.call(user: current_user, group_params: group_params)
result = CreateGroupOrganizer.call(user: current_user,
group_params: group_params,
role: :moderator)

if result.success?
render json: result.group, status: :created
render json: result.resource, status: :created
else
render json: result.errors, status: :unprocessable_entity
end
Expand Down
23 changes: 23 additions & 0 deletions app/interactors/add_role_to_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class AddRoleToUser < StandardInteraction
def validate_input
context.fail!(errors: "invalid input") unless valid_input?
end

def execute
context.user.add_role context.role, context.resource
end

def validate_output
context.fail!(errors: "invalid output") unless rolified?
end

private

def rolified?
context.user.has_role? context.role, context.resource
end

def valid_input?
context.resource && context.user && context.role
end
end
6 changes: 3 additions & 3 deletions app/interactors/create_game_night.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ def validate_input
end

def execute
context.game_night = create_game_night
context.resource = create_game_night
end

def validate_output
context.fail!(errors: context.game_night.errors) unless game_night_saved?
context.fail!(errors: context.resource.errors) unless game_night_saved?
end

private

def game_night_saved?
context.game_night.persisted?
context.resource.persisted?
end

def valid_input?
Expand Down
5 changes: 5 additions & 0 deletions app/interactors/create_game_night_organizer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class CreateGameNightOrganizer
include Interactor::Organizer

organize CreateGameNight, AddRoleToUser
end
8 changes: 6 additions & 2 deletions app/interactors/create_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@ def validate_input
end

def execute
context.group = context.user.groups.create(context.group_params)
context.resource = context.user.groups.create(context.group_params)
end

def validate_output
context.fail!(errors: context.group.errors) unless context.group.persisted?
context.fail!(errors: context.resource.errors) unless resource_persisted?
end

private

def resource_persisted?
context.resource.persisted?
end

def valid_input?
context.group_params && context.user
end
Expand Down
5 changes: 5 additions & 0 deletions app/interactors/create_group_organizer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class CreateGroupOrganizer
include Interactor::Organizer

organize CreateGroup, AddRoleToUser
end
2 changes: 2 additions & 0 deletions app/models/game_night.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class GameNight < ActiveRecord::Base
resourcify

validates :time, presence: true
validates :location_name, presence: true

Expand Down
2 changes: 2 additions & 0 deletions app/models/group.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
class Group < ActiveRecord::Base
resourcify

has_many :user_group_memberships
has_many :users, through: :user_group_memberships

Expand Down
10 changes: 10 additions & 0 deletions app/models/role.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, join_table: :users_roles
belongs_to :resource, polymorphic: true

validates :resource_type,
inclusion: { in: Rolify.resource_types },
allow_nil: true

scopify
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class User < ActiveRecord::Base
rolify
attr_accessor :reset_token

has_secure_password
Expand Down
7 changes: 7 additions & 0 deletions config/initializers/rolify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Rolify.configure do |config|
# By default ORM adapter is ActiveRecord. uncomment to use mongoid
# config.use_mongoid

# Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
# config.use_dynamic_shortcuts
end
19 changes: 19 additions & 0 deletions db/migrate/20160131181506_rolify_create_roles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class RolifyCreateRoles < ActiveRecord::Migration
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, :polymorphic => true

t.timestamps
end

create_table(:users_roles, :id => false) do |t|
t.references :user
t.references :role
end

add_index(:roles, :name)
add_index(:roles, [ :name, :resource_type, :resource_id ])
add_index(:users_roles, [ :user_id, :role_id ])
end
end
20 changes: 19 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20160130164214) do
ActiveRecord::Schema.define(version: 20160131181506) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -39,6 +39,17 @@
t.datetime "updated_at", null: false
end

create_table "roles", force: :cascade do |t|
t.string "name"
t.integer "resource_id"
t.string "resource_type"
t.datetime "created_at"
t.datetime "updated_at"
end

add_index "roles", ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id", using: :btree
add_index "roles", ["name"], name: "index_roles_on_name", using: :btree

create_table "user_game_night_attendances", force: :cascade do |t|
t.integer "user_id"
t.integer "game_night_id"
Expand Down Expand Up @@ -75,6 +86,13 @@
t.string "country"
end

create_table "users_roles", id: false, force: :cascade do |t|
t.integer "user_id"
t.integer "role_id"
end

add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree

add_foreign_key "game_nights", "groups"
add_foreign_key "user_game_night_attendances", "game_nights"
add_foreign_key "user_game_night_attendances", "users"
Expand Down
10 changes: 6 additions & 4 deletions spec/acceptance/game_nights_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,21 @@
header "Authorization", :auth_token

example_request "POST /game_nights" do
expect(status).to eq 201

game_night = GameNight.first
json_response = JSON.parse(response_body)

expect(status).to eq 201

expect(json_response["data"]["attributes"]["name"]).
to eq public_send(:name)

expect(authenticated_user.game_nights.first.name).
to eq public_send(:name)

game_night = GameNight.first

expect(game_night.users.first).to eq authenticated_user

expect(authenticated_user.has_role?(:organizer, game_night)).
to be_truthy
end
end

Expand Down
10 changes: 6 additions & 4 deletions spec/acceptance/groups_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,21 @@
header "Authorization", :auth_token

example_request "POST /groups" do
expect(status).to eq 201

group = Group.first
json_response = JSON.parse(response_body)

expect(status).to eq 201

expect(json_response["data"]["attributes"]["name"]).
to eq public_send(:name)

expect(authenticated_user.groups.first.name).
to eq public_send(:name)

group = Group.first

expect(group.users.first).to eq authenticated_user

expect(authenticated_user.has_role?(:moderator, group)).
to be_truthy
end
end

Expand Down
4 changes: 4 additions & 0 deletions spec/acceptance/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@

example_request "POST /user" do
expect(status).to eq 201

json_response = JSON.parse(response_body)

expect(json_response["jwt"]).to include("payload")
end
end
Expand All @@ -66,7 +68,9 @@

example_request "PATCH /user" do
expect(status).to eq 200

user = JSON.parse(response_body)

expect(user["data"]["attributes"]["first_name"]).
to eq public_send(:first_name)
end
Expand Down
22 changes: 12 additions & 10 deletions spec/controllers/game_nights_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@

describe "POST #create" do
let(:params) do
{ game_night: create_game_night_input.fetch(:game_night_params) }
{ game_night: create_game_night_organizer_input[:game_night_params] }
end

let(:create_game_night_input) do
let(:create_game_night_organizer_input) do
{
user: user,
role: :organizer,
game_night_params: {
name: game_night.name,
time: game_night.time,
Expand All @@ -27,18 +28,19 @@
}
end

let(:create_game_night_context) do
Interactor::Context.new(errors: :val, game_night: game_night)
let(:create_game_night_organizer_context) do
Interactor::Context.new(errors: :val, resource: game_night)
end

before do
allow(CreateGameNight).to receive(:call).with(create_game_night_input).
and_return(create_game_night_context)
allow(CreateGameNightOrganizer).to receive(:call).
with(create_game_night_organizer_input).
and_return(create_game_night_organizer_context)
end

context "when called" do
it "calls the CreateGameNight interactor" do
expect(CreateGameNight).to receive(:call)
it "calls the CreateGameNightOrganizer interactor" do
expect(CreateGameNightOrganizer).to receive(:call)
post :create, params
end
end
Expand All @@ -61,8 +63,8 @@
end

context "when CreateGameNight is a failure" do
let(:create_game_night_context) do
double(:context, success?: false, game_night: game_night)
let(:create_game_night_organizer_context) do
double(:context, success?: false, errors: game_night.errors)
end

it "returns HTTP status 422" do
Expand Down
Loading

0 comments on commit bd125d8

Please sign in to comment.