Merge branch 'atomaka/feature/authorization' into 'master'

Add authorization via Pundit

Also includes some a refactor to null object pattern for guest users.

See merge request !24
This commit is contained in:
Andrew Tomaka 2015-12-23 20:47:12 +00:00
commit 1f9788309b
31 changed files with 678 additions and 231 deletions

View file

@ -4,4 +4,5 @@ test:
- apt-get install -y nodejs libqtwebkit-dev qt4-qmake sqlite3 libsqlite3-dev
- bundle install --path /cache
- bundle exec rake db:create RAILS_ENV=test
- bundle exec rake db:test:prepare
- bundle exec rspec

10
Gemfile
View file

@ -1,13 +1,5 @@
source 'https://rubygems.org'
def darwin_only(require_as)
RbConfig::CONFIG['host_os'] =~ /darwin/ && require_as
end
def linux_only(require_as)
RbConfig::CONFIG['host_os'] =~ /linux/ && require_as
end
gem 'rails', '4.2.3'
gem 'sqlite3'
@ -25,6 +17,8 @@ gem 'ancestry'
gem 'bcrypt'
gem 'pundit'
gem 'sdoc', '~> 0.4.0', group: :doc
group :development do

View file

@ -212,6 +212,8 @@ GEM
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pundit (1.0.1)
activesupport (>= 3.0.0)
quiet_assets (1.1.0)
railties (>= 3.1, < 5.0)
rack (1.6.4)
@ -387,6 +389,7 @@ DEPENDENCIES
launchy
metric_fu
pry
pundit
quiet_assets
rails (= 4.2.3)
rspec-rails
@ -403,4 +406,4 @@ DEPENDENCIES
uglifier (>= 1.3.0)
BUNDLED WITH
1.10.5
1.10.6

View file

@ -6,10 +6,15 @@ class ApplicationController < ActionController::Base
helper_method :current_session
helper_method :logged_in?
include Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
private
def current_user
@current_user ||= User.find(current_session[:user_id]) if current_session
@current_user ||= GuestUser.new
end
def current_session
@ -17,6 +22,11 @@ class ApplicationController < ActionController::Base
end
def logged_in?
!!current_user
current_user.registered?
end
def user_not_authorized
flash[:alert] = 'You are not authorized to perform this action.'
redirect_to(request.referrer || root_path)
end
end

View file

@ -3,22 +3,29 @@ class CommentsController < ApplicationController
before_filter :set_comment, only: [:show, :edit, :update, :destroy]
before_filter :set_post
before_filter :set_subcreddit
after_action :verify_authorized
def show
@comments = @comment
.subtree
.includes(:post, :user)
.arrange(order: :created_at)
authorize @comment
end
def new
@comment = Comment.new(params[:parent_id])
authorize @comment
end
def create
@comment = @post.comments.build comment_params
@comment.user = current_user
authorize @comment
if @comment.save
flash[:notice] = 'Comment saved'
else
@ -29,9 +36,12 @@ class CommentsController < ApplicationController
end
def edit
authorize @comment
end
def update
authorize @comment
if @comment.update comment_params
redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Comment updated'
@ -41,6 +51,8 @@ class CommentsController < ApplicationController
end
def destroy
authorize @comment
@comment.destroy
redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Comment deleted'

View file

@ -2,23 +2,32 @@
class PostsController < ApplicationController
before_filter :set_post, except: [:index, :new, :create]
before_filter :set_subcreddit
after_action :verify_authorized
def index
@posts = Post.includes(:subcreddit, :user).all
authorize Post
end
def show
@comments = @post.comments.includes(:user).arrange(order: :created_at)
authorize @post
end
def new
@post = Post.new
authorize @post
end
def create
@post = @subcreddit.posts.build(post_params)
@post.user = current_user
authorize @post
if @post.save
redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Post created'
@ -28,9 +37,12 @@ class PostsController < ApplicationController
end
def edit
authorize @post
end
def update
authorize @post
if @post.update(post_params)
redirect_to subcreddit_post_path(@subcreddit, @post),
notice: 'Post was updated'
@ -40,6 +52,8 @@ class PostsController < ApplicationController
end
def destroy
authorize @post
@post.destroy
redirect_to subcreddits_path(@subcreddit), notice: 'Post was deleted'

View file

@ -1,23 +1,32 @@
# controllers/subcreddits_controller.rb
class SubcredditsController < ApplicationController
before_filter :set_subcreddit, only: [:show, :edit, :update]
after_action :verify_authorized
def index
@subcreddits = Subcreddit.all
authorize Subcreddit
end
def show
@posts = @subcreddit.posts
authorize @subcreddit
end
def new
@subcreddit = Subcreddit.new
authorize @subcreddit
end
def create
@subcreddit = Subcreddit.new(create_subcreddit_params)
@subcreddit.owner = current_user
authorize @subcreddit
if @subcreddit.save
redirect_to @subcreddit, notice: 'Subcreddit was created!'
else
@ -26,9 +35,12 @@ class SubcredditsController < ApplicationController
end
def edit
authorize @subcreddit
end
def update
authorize @subcreddit
if @subcreddit.update(update_subcreddit_params)
redirect_to @subcreddit, notice: 'Subcreddit was updated!'
else

6
app/models/guest_user.rb Normal file
View file

@ -0,0 +1,6 @@
# models/guest_user.rb
class GuestUser
def registered?
false
end
end

View file

@ -15,6 +15,10 @@ class User < ActiveRecord::Base
validates :username, presence: true, uniqueness: true, sluguuidless: true
validates :password, length: { minimum: 8 }
def registered?
true
end
private
def downcase_email

View file

@ -0,0 +1,37 @@
# policies/application_policy.rb
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
false
end
def show?
false
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
end

View file

@ -0,0 +1,22 @@
# policies/comment_policy.rb
class CommentPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
user.registered?
end
def update?
record.user == user
end
def destroy?
record.user == user
end
end

View file

@ -0,0 +1,22 @@
# policies/post_policy.rb
class PostPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
user.registered?
end
def update?
record.user == user
end
def destroy?
record.user == user
end
end

View file

@ -0,0 +1,18 @@
# policies/subcreddit_policy.rb
class SubcredditPolicy < ApplicationPolicy
def index?
true
end
def show?
true
end
def create?
user.registered?
end
def update?
record.owner == user
end
end

View file

@ -5,12 +5,14 @@
button.btn.btn-default type="button"
span.glyphicon.glyphicon-search aria-hidden="true"
- if @subcreddit && @subcreddit.id
= link_to 'Submit a new link', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
= link_to 'Submit a new text post', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
= link_to 'Create your own subcreddit', new_subcreddit_path, class: 'button btn btn-primary btn-block'
- if policy(:post).new?
- if @subcreddit && @subcreddit.id
= link_to 'Submit a new link', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
= link_to 'Submit a new text post', new_subcreddit_post_path(@subcreddit), class: 'button btn btn-primary btn-block'
- if policy(:subcreddit).new?
= link_to 'Create your own subcreddit', new_subcreddit_path, class: 'button btn btn-primary btn-block'
- if @subcreddit && @subcreddit.id
- if @subcreddit && @subcreddit.id && policy(@subcreddit).edit?
.title Moderation Tools
.box
ul

View file

@ -3,7 +3,8 @@
.alert.alert-info.in-page
p you are viewing a single comment's thread.
p #{link_to 'view the rest of the comments', subcreddit_post_path(@subcreddit, @post)} →
= "Commenting as: #{current_user.username}"
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment
- if policy(:comment).new?
= "Commenting as: #{current_user.username}"
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: @comment
.comments.contents
== nested_comments(@comments)

View file

@ -4,7 +4,8 @@
.title= "all #{@post.comments_count} comments"
- else
.title= "no comments (yet)"
= "Commenting as: #{current_user.username}"
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
- if policy(:comment).new?
= "Commenting as: #{current_user.username}"
== render 'comments/form', subcreddit: @subcreddit, post: @post, comment: @post.comments.build, parent: nil
.comments.contents
== nested_comments(@comments)

View file

@ -31,7 +31,7 @@ describe ApplicationController, type: :controller do
context 'when not logged in' do
it 'should return nil' do
expect(controller.send(:current_user)).to be_nil
expect(controller.send(:current_user)).to be_a(GuestUser)
end
end
end

View file

@ -99,103 +99,111 @@ describe CommentsController, type: :controller do
end
describe '#edit' do
let!(:comment) { create(:comment) }
before(:each) do
get :edit,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
end
context 'with valid comment' do
it 'should render :edit' do
expect(response).to render_template(:edit)
context 'when owner' do
let!(:comment) { create(:comment, user: user) }
before(:each) do
get :edit,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
end
it 'should assign correct Comment to @comment' do
expect(assigns(:comment)).to eq(comment)
context 'with valid comment' do
it 'should render :edit' do
expect(response).to render_template(:edit)
end
it 'should assign correct Comment to @comment' do
expect(assigns(:comment)).to eq(comment)
end
end
end
end
context '#update' do
let!(:comment) { create(:comment) }
let(:data) { { content: 'Some edited comment content goes here' } }
context 'with valid data' do
before(:each) do
put :update,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit,
comment: data
let!(:comment) { create(:comment, user: user) }
context 'when owner' do
before(:each) do
put :update,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit,
comment: data
end
it 'should assign correct Comment to @comment' do
expect(assigns(:comment)).to eq(comment)
end
it 'should update the comment' do
comment.reload
expect(comment.content).to eq(data[:content])
end
it 'should redirect to the post' do
expect(response)
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
assigns(:post)))
end
it 'should display a notice flash message' do
expect(flash[:notice]).to be_present
end
end
it 'should assign correct Comment to @comment' do
expect(assigns(:comment)).to eq(comment)
end
context 'with invalid data' do
before(:each) { data[:content] = '' }
it 'should update the comment' do
comment.reload
it 'should render :edit' do
put :update,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit,
comment: data
expect(comment.content).to eq(data[:content])
end
it 'should redirect to the post' do
expect(response)
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
assigns(:post)))
end
it 'should display a notice flash message' do
expect(flash[:notice]).to be_present
end
end
context 'with invalid data' do
before(:each) { data[:content] = '' }
it 'should render :edit' do
put :update,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit,
comment: data
expect(response).to render_template(:edit)
expect(response).to render_template(:edit)
end
end
end
end
context '#destroy' do
let!(:comment) { create(:comment) }
context 'when owner' do
let!(:comment) { create(:comment, user: user) }
it 'should delete the post' do
delete :destroy,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
it 'should delete the post' do
delete :destroy,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
comment.reload
expect(comment.destroyed?).to be(true)
end
comment.reload
expect(comment.destroyed?).to be(true)
end
it 'should redirect to the post' do
delete :destroy,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
it 'should redirect to the post' do
delete :destroy,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
expect(response).to redirect_to(subcreddit_post_path(assigns(:subcreddit),
assigns(:post)))
end
expect(response)
.to redirect_to(subcreddit_post_path(assigns(:subcreddit),
assigns(:post)))
end
it 'should send a notice flash message' do
delete :destroy,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
expect(flash[:notice]).to be_present
it 'should send a notice flash message' do
delete :destroy,
id: comment,
post_id: comment.post,
subcreddit_id: comment.post.subcreddit
expect(flash[:notice]).to be_present
end
end
end
end

View file

@ -94,22 +94,23 @@ describe PostsController, type: :controller do
end
context '#edit' do
let!(:post) { create(:post) }
before(:each) { get :edit, id: post, subcreddit_id: post.subcreddit }
context 'when owner' do
let!(:post) { create(:post, user: user) }
before(:each) { get :edit, id: post, subcreddit_id: post.subcreddit }
context 'with valid post' do
it 'should render :edit' do
expect(response).to render_template(:edit)
end
context 'with valid post' do
it 'should render :edit' do
expect(response).to render_template(:edit)
end
it 'should assign correct Post to @post' do
expect(assigns(:post)).to eq(post)
it 'should assign correct Post to @post' do
expect(assigns(:post)).to eq(post)
end
end
end
end
context '#update' do
let!(:post) { create(:post) }
let(:data) do
{
title: 'New title',
@ -117,61 +118,67 @@ describe PostsController, type: :controller do
}
end
context 'with valid data' do
before(:each) do
put :update, id: post, subcreddit_id: post.subcreddit, post: data
context 'when owner' do
let!(:post) { create(:post, user: user) }
context 'with valid data' do
before(:each) do
put :update, id: post, subcreddit_id: post.subcreddit, post: data
end
it 'should assign correct Post to @post' do
expect(assigns(:post)).to eq(post)
end
it 'should update the post' do
post.reload
expect(post.title).to eq(data[:title])
expect(post.content).to eq(data[:content])
end
it 'should redirect to the post' do
expect(response)
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
assigns(:post)))
end
it 'should display a notice flash message' do
expect(flash[:notice]).to be_present
end
end
it 'should assign correct Post to @post' do
expect(assigns(:post)).to eq(post)
end
context 'with invalid data' do
before(:each) { data[:title] = '' }
it 'should update the post' do
post.reload
it 'should render :edit' do
put :update, id: post, subcreddit_id: post.subcreddit, post: data
expect(post.title).to eq(data[:title])
expect(post.content).to eq(data[:content])
end
it 'should redirect to the post' do
expect(response)
.to redirect_to(subcreddit_post_path(assigns(:post).subcreddit,
assigns(:post)))
end
it 'should display a notice flash message' do
expect(flash[:notice]).to be_present
end
end
context 'with invalid data' do
before(:each) { data[:title] = '' }
it 'should render :edit' do
put :update, id: post, subcreddit_id: post.subcreddit, post: data
expect(response).to render_template(:edit)
expect(response).to render_template(:edit)
end
end
end
end
context '#destroy' do
let!(:post) { create(:post, subcreddit: subcreddit) }
context 'when owner' do
let!(:post) { create(:post, user: user, subcreddit: subcreddit) }
it 'should delete the post' do
expect { delete :destroy, subcreddit_id: subcreddit, id: post }
.to change(Post, :count).by(-1)
end
it 'should delete the post' do
expect { delete :destroy, subcreddit_id: subcreddit, id: post }
.to change(Post, :count).by(-1)
end
it 'should redirect to the subcreddit index' do
expect(delete :destroy, subcreddit_id: subcreddit, id: post)
.to redirect_to(subcreddits_path(subcreddit))
end
it 'should redirect to the subcreddit index' do
expect(delete :destroy, subcreddit_id: subcreddit, id: post)
.to redirect_to(subcreddits_path(subcreddit))
end
it 'should flash notify that the post was deleted' do
delete :destroy, subcreddit_id: subcreddit, id: post
it 'should flash notify that the post was deleted' do
delete :destroy, subcreddit_id: subcreddit, id: post
expect(flash[:notice]).to be_present
expect(flash[:notice]).to be_present
end
end
end
end

View file

@ -97,24 +97,25 @@ describe SubcredditsController, type: :controller do
describe '#edit' do
context 'with valid subcreddit' do
let(:subcreddit) { create(:subcreddit) }
context 'when owner' do
let(:subcreddit) { create(:subcreddit, owner: user) }
it 'should assign @subcreddit to the existing subcreddit' do
get :edit, id: subcreddit
it 'should assign @subcreddit to the existing subcreddit' do
get :edit, id: subcreddit
expect(assigns(:subcreddit)).to eq(subcreddit)
end
expect(assigns(:subcreddit)).to eq(subcreddit)
end
it 'should render :edit' do
get :edit, id: subcreddit
it 'should render :edit' do
get :edit, id: subcreddit
expect(response).to render_template(:edit)
expect(response).to render_template(:edit)
end
end
end
end
describe '#update' do
let(:subcreddit) { create(:subcreddit) }
let(:data) do
{
closed: '1'
@ -122,39 +123,43 @@ describe SubcredditsController, type: :controller do
end
context 'wth valid data' do
it 'should assign @subcreddit to the existing subcreddit' do
put :update, id: subcreddit, subcreddit: data
context 'when owner' do
let(:subcreddit) { create(:subcreddit, owner: user) }
expect(assigns(:subcreddit)).to eq(subcreddit)
end
it 'should assign @subcreddit to the existing subcreddit' do
put :update, id: subcreddit, subcreddit: data
it 'should update the subcreddit' do
put :update, id: subcreddit, subcreddit: data
subcreddit.reload
expect(assigns(:subcreddit)).to eq(subcreddit)
end
expect(subcreddit.closed_at).to_not eq(nil)
end
it 'should update the subcreddit' do
put :update, id: subcreddit, subcreddit: data
subcreddit.reload
it 'should redirect to the subcreddit' do
put :update, id: subcreddit, subcreddit: data
expect(subcreddit.closed_at).to_not eq(nil)
end
expect(response).to redirect_to(subcreddit_url(subcreddit))
end
it 'should redirect to the subcreddit' do
put :update, id: subcreddit, subcreddit: data
it 'should display a notice flash message' do
put :update, id: subcreddit, subcreddit: data
expect(response).to redirect_to(subcreddit_url(subcreddit))
end
expect(flash[:notice]).to be_present
end
end
it 'should display a notice flash message' do
put :update, id: subcreddit, subcreddit: data
context 'with invalid data' do
before(:each) { data[:closed] = 'bad' }
expect(flash[:notice]).to be_present
end
it 'should render :edit' do
put :update, id: subcreddit, subcreddit: data
context 'with invalid data' do
before(:each) { data[:closed] = 'bad' }
expect(response).to render_template(:edit)
it 'should render :edit' do
put :update, id: subcreddit, subcreddit: data
expect(response).to render_template(:edit)
end
end
end
end
end

View file

@ -3,28 +3,54 @@ require 'rails_helper'
describe 'Edit Comment', type: :feature do
let!(:user) { create(:user) }
let!(:post) { create(:post) }
let!(:comment) { create(:comment, post: post, user: user) }
context 'when signed in' do
let(:content) { 'Some different data' }
let!(:comment) { create(:comment, post: post, user: user) }
before(:each) { signin(user: user) }
context 'with valid data' do
before(:each) do
context 'when owner' do
let(:content) { 'Some different data' }
context 'with valid data' do
before(:each) do
visit edit_subcreddit_post_comment_path(post.subcreddit,
post,
comment)
fill_in :comment_content, with: content
click_button 'Update Comment'
end
it 'should notify that the comment was edited' do
expect(page).to have_content('updated')
end
it 'should update the comment' do
expect(page).to have_content(content)
end
end
end
context 'when not owner' do
let!(:comment) { create(:comment, post: post) }
it 'should not allow editing of comment' do
visit edit_subcreddit_post_comment_path(post.subcreddit, post, comment)
fill_in :comment_content, with: content
click_button 'Update Comment'
end
it 'should notify that the comment was edited' do
expect(page).to have_content('updated')
end
it 'should update the comment' do
expect(page).to have_content(content)
expect(page).to have_content('not authorized')
end
end
end
context 'when not signed in' do
let!(:comment) { create(:comment, post: post) }
it 'should not allow editing of comment' do
visit edit_subcreddit_post_comment_path(post.subcreddit, post, comment)
expect(page).to have_content('not authorized')
end
end
end

View file

@ -1,33 +1,58 @@
require 'rails_helper'
describe 'Edit Post', type: :feature do
let!(:subcreddit) { create(:subcreddit) }
context 'when signed in' do
let!(:user) { create(:user) }
let!(:subcreddit) { create(:subcreddit) }
let!(:post) { create(:post, subcreddit: subcreddit, user: user) }
let(:new_post) { build_stubbed(:post) }
before(:each) { signin(user: user) }
context 'with valid data' do
before(:each) do
context 'when owner' do
let!(:post) { create(:post, subcreddit: subcreddit, user: user) }
context 'with valid data' do
before(:each) do
visit edit_subcreddit_post_path(subcreddit, post)
fill_in :post_title, with: new_post.title
fill_in :post_link, with: new_post.link
fill_in :post_content, with: new_post.content
click_button 'Update Post'
end
it 'should notify that the post was edited' do
expect(page).to have_content('updated')
end
it 'should show the updated post' do
expect(page).to have_content(new_post.title)
expect(page).to have_content(new_post.content)
end
end
end
context 'when not owner' do
let!(:post) { create(:post, subcreddit: subcreddit) }
it 'should notify user that they cannot edit' do
visit edit_subcreddit_post_path(subcreddit, post)
fill_in :post_title, with: new_post.title
fill_in :post_link, with: new_post.link
fill_in :post_content, with: new_post.content
click_button 'Update Post'
end
it 'should notify that the post was edited' do
expect(page).to have_content('updated')
end
it 'should show the updated post' do
expect(page).to have_content(new_post.title)
expect(page).to have_content(new_post.content)
expect(page).to have_content 'not authorized'
end
end
end
context 'when not signed in' do
let!(:user) { GuestUser.new }
let!(:post) { create(:post, subcreddit: subcreddit) }
it 'should notify user they cannot edit' do
visit edit_subcreddit_post_path(subcreddit, post)
expect(page).to have_content 'not authorized'
end
end
end

View file

@ -1,9 +1,10 @@
require 'rails_helper'
describe 'New Post', type: :feature do
let!(:subcreddit) { create(:subcreddit) }
context 'when signed in' do
let!(:user) { create(:user) }
let!(:subcreddit) { create(:subcreddit) }
let!(:post) { build(:post, subcreddit: subcreddit) }
before(:each) { signin(user: user) }
@ -46,4 +47,15 @@ describe 'New Post', type: :feature do
end
end
end
context 'when not signed in' do
let!(:user) { GuestUser.new }
let!(:post) { create(:post, subcreddit: subcreddit) }
it 'should notify user they cannot create' do
visit new_subcreddit_post_path(subcreddit)
expect(page).to have_content 'not authorized'
end
end
end

View file

@ -4,36 +4,60 @@ describe 'Edit Subcreddit', type: :feature do
before(:each) { signout }
context 'when logged in' do
context 'when board is open' do
let!(:subcreddit) { create(:subcreddit) }
before(:each) do
visit subcreddits_path
click_link 'Edit'
check :subcreddit_closed
click_button 'Update Subcreddit'
let!(:user) { create(:user) }
before(:each) { signin(user: user) }
context 'when user is owner' do
let!(:subcreddit) { create(:subcreddit, owner: user) }
context 'when board is open' do
before(:each) do
visit subcreddits_path
click_link 'Edit'
check :subcreddit_closed
click_button 'Update Subcreddit'
end
it 'should be notified the subcreddit was updated' do
expect(page).to have_content('updated')
end
it 'should close the board when closed is checked' do
expect(page).to have_content('closed')
end
end
it 'should be notified the subcreddit was updated' do
expect(page).to have_content('updated')
end
context 'when board is closed' do
let!(:subcreddit) do
create(:subcreddit, owner: user, closed_at: Time.now)
end
it 'should close the board when closed is checked' do
expect(page).to have_content('closed')
before(:each) do
visit subcreddits_path
click_link 'Edit'
uncheck :subcreddit_closed
click_button 'Update Subcreddit'
end
it 'should open the board when closed is checked' do
expect(page).to_not have_content('closed')
end
end
end
context 'when board is closed' do
let!(:subcreddit) { create(:subcreddit, closed_at: Time.now) }
before(:each) do
context 'when not owner' do
let!(:subcreddit) { create(:subcreddit) }
it 'should not allow editing of subcreddit' do
visit subcreddits_path
click_link 'Edit'
uncheck :subcreddit_closed
click_button 'Update Subcreddit'
end
it 'should open the board when closed is checked' do
expect(page).to_not have_content('closed')
expect(page).to have_content('not authorized')
end
end
end
context 'when not logged in' do
end
end

View file

@ -4,7 +4,11 @@ describe 'New Subcreddit', type: :feature do
before(:each) { signout }
context 'when not signed in' do
it 'should not be able to create a new subcreddit'
it 'should not be able to create a new subcreddit' do
visit new_subcreddit_path
expect(page).to have_content('not authorized')
end
end
context 'when signed in' do

View file

@ -0,0 +1,15 @@
require 'rails_helper'
describe ApplicationPolicy do
subject { ApplicationPolicy.new(user, object) }
let(:user) { create(:user) }
let(:object) { double('Object') }
it { should_not grant(:index) }
it { should_not grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end

View file

@ -0,0 +1,48 @@
require 'rails_helper'
describe CommentPolicy do
subject { CommentPolicy.new(user, comment) }
context 'when user is a guest' do
let(:comment) { create(:comment) }
let(:user) { GuestUser.new }
it { should grant(:index) }
it { should grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when user is registered' do
let(:user) { create(:user) }
context 'when not owner' do
let(:comment) { create(:comment) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when owner' do
let(:comment) { create(:comment, user: user) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should grant(:edit) }
it { should grant(:update) }
it { should grant(:destroy) }
end
end
end

View file

@ -0,0 +1,48 @@
require 'rails_helper'
describe PostPolicy do
subject { PostPolicy.new(user, post) }
context 'when user is a guest' do
let(:post) { create(:post) }
let(:user) { GuestUser.new }
it { should grant(:index) }
it { should grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when user is registered' do
let(:user) { create(:user) }
context 'when not owner' do
let(:post) { create(:post) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when owner' do
let(:post) { create(:post, user: user) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should grant(:edit) }
it { should grant(:update) }
it { should grant(:destroy) }
end
end
end

View file

@ -0,0 +1,49 @@
require 'rails_helper'
describe SubcredditPolicy do
subject { SubcredditPolicy.new(user, subcreddit) }
context 'when user is a guest' do
let(:subcreddit) { create(:subcreddit) }
let(:user) { GuestUser.new }
it { should grant(:index) }
it { should grant(:show) }
it { should_not grant(:new) }
it { should_not grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when user is registered' do
let(:user) { create(:user) }
context 'when not owner' do
let(:subcreddit) { create(:subcreddit) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should_not grant(:edit) }
it { should_not grant(:update) }
it { should_not grant(:destroy) }
end
context 'when owner' do
let(:subcreddit) { create(:subcreddit, owner: user) }
it { should grant(:index) }
it { should grant(:show) }
it { should grant(:new) }
it { should grant(:create) }
it { should grant(:edit) }
it { should grant(:update) }
it { should_not grant(:destroy) }
end
end
end

View file

@ -12,11 +12,13 @@ require 'rspec/rails'
require 'shoulda/matchers'
require 'capybara/rails'
require 'capybara/rspec'
require 'pundit/rspec'
require 'support/capybara'
require 'support/database_cleaner'
require 'support/factory_girl'
require 'support/helpers'
require 'support/pundit_matcher'
ActiveRecord::Migration.maintain_test_schema!

View file

@ -0,0 +1,15 @@
RSpec::Matchers.define :grant do |action|
match do |policy|
policy.public_send("#{action}?")
end
failure_message do |policy|
"#{policy.class} does not permit #{action} on #{policy.record} "
+ "for #{policy.user.inspect}."
end
failure_message_when_negated do |policy|
"#{policy.class} does not forbid #{action} on #{policy.record} "
+ "for #{policy.user.inspect}."
end
end