mirror of
https://github.com/astuto/astuto.git
synced 2025-12-15 03:07:52 +01:00
Improve rails controllers (#118)
This commit is contained in:
committed by
GitHub
parent
8e75a85873
commit
94f77517a8
7
Gemfile
7
Gemfile
@@ -4,7 +4,6 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||
ruby '2.6.6'
|
||||
|
||||
gem 'rails', '6.0.4.7'
|
||||
gem 'i18n-js'
|
||||
|
||||
gem 'pg', '>= 0.18', '< 2.0'
|
||||
|
||||
@@ -23,6 +22,12 @@ gem 'bootsnap', '>= 1.4.2', require: false
|
||||
# Authentication
|
||||
gem 'devise', '4.7.3'
|
||||
|
||||
# Authorization
|
||||
gem 'pundit', '2.2.0'
|
||||
|
||||
# I18n (forward locales to JS)
|
||||
gem 'i18n-js'
|
||||
|
||||
# Administration panel
|
||||
gem "administrate", '0.16.0'
|
||||
|
||||
|
||||
@@ -146,18 +146,22 @@ GEM
|
||||
matrix (0.4.2)
|
||||
method_source (1.0.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.0)
|
||||
minitest (5.15.0)
|
||||
momentjs-rails (2.29.1.1)
|
||||
railties (>= 3.1)
|
||||
msgpack (1.5.1)
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.13.3-x86_64-linux)
|
||||
nokogiri (1.13.3)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
orm_adapter (0.5.0)
|
||||
pg (1.3.5)
|
||||
public_suffix (4.0.6)
|
||||
puma (4.3.12)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.2.0)
|
||||
activesupport (>= 3.0.0)
|
||||
racc (1.6.0)
|
||||
rack (2.2.3)
|
||||
rack-proxy (0.7.2)
|
||||
@@ -235,7 +239,7 @@ GEM
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
sassc (2.1.0-x86_64-linux)
|
||||
sassc (2.1.0)
|
||||
ffi (~> 1.9)
|
||||
sassc-rails (2.1.2)
|
||||
railties (>= 4.0.0)
|
||||
@@ -305,6 +309,7 @@ DEPENDENCIES
|
||||
listen (>= 3.0.5, < 3.2)
|
||||
pg (>= 0.18, < 2.0)
|
||||
puma (~> 4.3)
|
||||
pundit (= 2.2.0)
|
||||
rails (= 6.0.4.7)
|
||||
react-rails (~> 2.6.0)
|
||||
rspec-rails (~> 3.8.2)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
class ApplicationController < ActionController::Base
|
||||
include Pundit::Authorization
|
||||
|
||||
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
||||
|
||||
before_action :configure_permitted_parameters, if: :devise_controller?
|
||||
before_action :load_boards
|
||||
|
||||
@@ -12,4 +16,12 @@ class ApplicationController < ActionController::Base
|
||||
def load_boards
|
||||
@boards = Board.select(:id, :name).order(order: :asc)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_not_authorized
|
||||
render json: {
|
||||
error: t('backend.errors.unauthorized')
|
||||
}, status: :unauthorized
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class BoardsController < ApplicationController
|
||||
include ApplicationHelper
|
||||
|
||||
before_action :authenticate_admin, only: [:create, :update, :update_order, :destroy]
|
||||
before_action :authenticate_user!, only: [:create, :update, :update_order, :destroy]
|
||||
|
||||
def index
|
||||
boards = Board.order(order: :asc)
|
||||
@@ -15,6 +15,7 @@ class BoardsController < ApplicationController
|
||||
|
||||
def create
|
||||
board = Board.new(board_params)
|
||||
authorize board
|
||||
|
||||
if board.save
|
||||
render json: board, status: :created
|
||||
@@ -27,13 +28,12 @@ class BoardsController < ApplicationController
|
||||
|
||||
def update
|
||||
board = Board.find(params[:id])
|
||||
authorize board
|
||||
board.assign_attributes(board_params)
|
||||
|
||||
if board.save
|
||||
render json: board, status: :ok
|
||||
else
|
||||
print board.errors.full_messages
|
||||
|
||||
render json: {
|
||||
error: board.errors.full_messages
|
||||
}, status: :unprocessable_entity
|
||||
@@ -42,6 +42,7 @@ class BoardsController < ApplicationController
|
||||
|
||||
def destroy
|
||||
board = Board.find(params[:id])
|
||||
authorize board
|
||||
|
||||
if board.destroy
|
||||
render json: {
|
||||
@@ -55,6 +56,8 @@ class BoardsController < ApplicationController
|
||||
end
|
||||
|
||||
def update_order
|
||||
authorize Board
|
||||
|
||||
workflow_output = ReorderWorkflow.new(
|
||||
entity_classname: Board,
|
||||
column_name: 'order',
|
||||
|
||||
@@ -23,10 +23,10 @@ class CommentsController < ApplicationController
|
||||
comment = Comment.new(comment_params)
|
||||
|
||||
if comment.save
|
||||
send_notifications(comment)
|
||||
SendNotificationForCommentWorkflow.new(comment: comment).run
|
||||
|
||||
render json: comment.attributes.merge(
|
||||
{ user_full_name: current_user.full_name, user_email: current_user.email}
|
||||
{ user_full_name: current_user.full_name, user_email: current_user.email }
|
||||
), status: :created
|
||||
else
|
||||
render json: {
|
||||
@@ -37,17 +37,12 @@ class CommentsController < ApplicationController
|
||||
|
||||
def update
|
||||
comment = Comment.find(params[:id])
|
||||
|
||||
authorize comment
|
||||
comment.assign_attributes(comment_params)
|
||||
|
||||
if !current_user.power_user? && current_user.id != post.user_id
|
||||
render json: t('backend.errors.unauthorized'), status: :unauthorized
|
||||
return
|
||||
end
|
||||
|
||||
if comment.save
|
||||
render json: comment.attributes.merge(
|
||||
{ user_full_name: current_user.full_name, user_email: current_user.email}
|
||||
{ user_full_name: current_user.full_name, user_email: current_user.email }
|
||||
)
|
||||
else
|
||||
render json: {
|
||||
@@ -57,41 +52,14 @@ class CommentsController < ApplicationController
|
||||
end
|
||||
|
||||
private
|
||||
def comment_params
|
||||
params
|
||||
.require(:comment)
|
||||
.permit(:body, :parent_id, :is_post_update)
|
||||
.merge(
|
||||
user_id: current_user.id,
|
||||
post_id: params[:post_id]
|
||||
)
|
||||
end
|
||||
|
||||
def send_notifications(comment)
|
||||
if comment.is_post_update # Post update
|
||||
UserMailer.notify_followers_of_post_update(comment: comment).deliver_later
|
||||
return
|
||||
def comment_params
|
||||
params
|
||||
.require(:comment)
|
||||
.permit(:body, :parent_id, :is_post_update)
|
||||
.merge(
|
||||
user_id: current_user.id,
|
||||
post_id: params[:post_id]
|
||||
)
|
||||
end
|
||||
|
||||
if comment.parent_id == nil # Reply to a post
|
||||
user = comment.post.user
|
||||
|
||||
if comment.user.id != user.id and
|
||||
user.notifications_enabled? and
|
||||
comment.post.follows.exists?(user_id: user.id)
|
||||
|
||||
UserMailer.notify_post_owner(comment: comment).deliver_later
|
||||
end
|
||||
else # Reply to a comment
|
||||
parent_comment = comment.parent
|
||||
user = parent_comment.user
|
||||
|
||||
if user.notifications_enabled? and
|
||||
parent_comment.user.id != comment.user.id
|
||||
|
||||
UserMailer.notify_comment_owner(comment: comment).deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class PostStatusesController < ApplicationController
|
||||
include ApplicationHelper
|
||||
|
||||
before_action :authenticate_admin, only: [:create, :update, :update_order, :destroy]
|
||||
before_action :authenticate_user!, only: [:create, :update, :update_order, :destroy]
|
||||
|
||||
def index
|
||||
post_statuses = PostStatus.order(order: :asc)
|
||||
@@ -11,6 +11,7 @@ class PostStatusesController < ApplicationController
|
||||
|
||||
def create
|
||||
post_status = PostStatus.new(post_status_params)
|
||||
authorize post_status
|
||||
|
||||
if post_status.save
|
||||
render json: post_status, status: :created
|
||||
@@ -23,6 +24,7 @@ class PostStatusesController < ApplicationController
|
||||
|
||||
def update
|
||||
post_status = PostStatus.find(params[:id])
|
||||
authorize post_status
|
||||
post_status.assign_attributes(post_status_params)
|
||||
|
||||
if post_status.save
|
||||
@@ -36,6 +38,7 @@ class PostStatusesController < ApplicationController
|
||||
|
||||
def destroy
|
||||
post_status = PostStatus.find(params[:id])
|
||||
authorize post_status
|
||||
|
||||
if post_status.destroy
|
||||
render json: {
|
||||
@@ -49,6 +52,8 @@ class PostStatusesController < ApplicationController
|
||||
end
|
||||
|
||||
def update_order
|
||||
authorize PostStatus
|
||||
|
||||
workflow_output = ReorderWorkflow.new(
|
||||
entity_classname: PostStatus,
|
||||
column_name: 'order',
|
||||
|
||||
@@ -52,11 +52,7 @@ class PostsController < ApplicationController
|
||||
|
||||
def update
|
||||
post = Post.find(params[:id])
|
||||
|
||||
if !current_user.power_user? && current_user.id != post.user_id
|
||||
render json: t('backend.errors.unauthorized'), status: :unauthorized
|
||||
return
|
||||
end
|
||||
authorize post
|
||||
|
||||
post.board_id = params[:post][:board_id] if params[:post].has_key?(:board_id)
|
||||
|
||||
@@ -91,7 +87,7 @@ class PostsController < ApplicationController
|
||||
private
|
||||
|
||||
def filter_params
|
||||
defaults = { board_id: Board.first.id }
|
||||
defaults = Board.first ? { board_id: Board.first.id } : {}
|
||||
|
||||
params
|
||||
.permit(:board_id, :post_status_id, :page, :search)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
module BoardsHelper
|
||||
end
|
||||
@@ -1,2 +0,0 @@
|
||||
module CommentsHelper
|
||||
end
|
||||
@@ -1,2 +0,0 @@
|
||||
module LikesHelper
|
||||
end
|
||||
@@ -1,2 +0,0 @@
|
||||
module PostsHelper
|
||||
end
|
||||
53
app/policies/application_policy.rb
Normal file
53
app/policies/application_policy.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
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
|
||||
|
||||
class Scope
|
||||
def initialize(user, scope)
|
||||
@user = user
|
||||
@scope = scope
|
||||
end
|
||||
|
||||
def resolve
|
||||
raise NotImplementedError, "You must define #resolve in #{self.class}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :user, :scope
|
||||
end
|
||||
end
|
||||
17
app/policies/board_policy.rb
Normal file
17
app/policies/board_policy.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class BoardPolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update_order?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
5
app/policies/comment_policy.rb
Normal file
5
app/policies/comment_policy.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class CommentPolicy < ApplicationPolicy
|
||||
def update?
|
||||
user == record.user or user.power_user?
|
||||
end
|
||||
end
|
||||
5
app/policies/post_policy.rb
Normal file
5
app/policies/post_policy.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class PostPolicy < ApplicationPolicy
|
||||
def update?
|
||||
user == record.user or user.power_user?
|
||||
end
|
||||
end
|
||||
17
app/policies/post_status_policy.rb
Normal file
17
app/policies/post_status_policy.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
class PostStatusPolicy < ApplicationPolicy
|
||||
def create?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update_order?
|
||||
user.admin?
|
||||
end
|
||||
end
|
||||
34
app/workflows/SendNotificationForCommentWorkflow.rb
Normal file
34
app/workflows/SendNotificationForCommentWorkflow.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
class SendNotificationForCommentWorkflow
|
||||
attr_accessor :comment
|
||||
|
||||
def initialize(comment: "")
|
||||
@comment = comment
|
||||
end
|
||||
|
||||
def run
|
||||
if comment.is_post_update # Post update
|
||||
UserMailer.notify_followers_of_post_update(comment: comment).deliver_later
|
||||
return
|
||||
end
|
||||
|
||||
if comment.parent_id == nil # Reply to a post
|
||||
user = comment.post.user
|
||||
|
||||
if comment.user.id != user.id and
|
||||
user.notifications_enabled? and
|
||||
comment.post.follows.exists?(user_id: user.id)
|
||||
|
||||
UserMailer.notify_post_owner(comment: comment).deliver_later
|
||||
end
|
||||
else # Reply to a comment
|
||||
parent_comment = comment.parent
|
||||
user = parent_comment.user
|
||||
|
||||
if user.notifications_enabled? and
|
||||
parent_comment.user.id != comment.user.id
|
||||
|
||||
UserMailer.notify_comment_owner(comment: comment).deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -251,7 +251,7 @@ Devise.setup do |config|
|
||||
# should add them to the navigational formats lists.
|
||||
#
|
||||
# The "*/*" below is required to match Internet Explorer requests.
|
||||
# config.navigational_formats = ['*/*', :html]
|
||||
config.navigational_formats = ['*/*', :html]
|
||||
|
||||
# The default HTTP method used to sign out a resource. Default is :delete.
|
||||
config.sign_out_via = :delete
|
||||
|
||||
61
spec/requests/posts_controller_auth_spec.rb
Normal file
61
spec/requests/posts_controller_auth_spec.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'requests to posts controller', type: :request do
|
||||
let(:user) { FactoryBot.create(:user) }
|
||||
let(:moderator) { FactoryBot.create(:moderator) }
|
||||
let(:admin) { FactoryBot.create(:admin) }
|
||||
|
||||
let(:p) { FactoryBot.create(:post) }
|
||||
let(:board) { FactoryBot.build_stubbed(:board) }
|
||||
|
||||
let(:headers) { headers = { "ACCEPT" => "application/json" } }
|
||||
|
||||
context 'when user is not logged in' do
|
||||
it 'fulfills index action' do
|
||||
get posts_path
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
it 'fulfills show action' do
|
||||
get posts_path(p)
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
it 'blocks create action' do
|
||||
post posts_path, params: { post: { title: p.title } }, headers: headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
it 'blocks update action' do
|
||||
patch post_path(p), params: { post: { title: p.title } }, headers: headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'user role' do
|
||||
before(:each) do
|
||||
user.confirm
|
||||
sign_in user
|
||||
end
|
||||
|
||||
# it 'fulfills create action' do
|
||||
# post posts_path, params: { post: { title: p.title, board_id: board.id, user_id: user.id } }, headers: headers
|
||||
# expect(response).to have_http_status(:success)
|
||||
# end
|
||||
it 'blocks update action if from different user' do
|
||||
expect(user.id).not_to eq(p.user_id)
|
||||
patch post_path(p), params: { post: { title: p.title } }, headers: headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'moderator role' do
|
||||
before(:each) do
|
||||
moderator.confirm
|
||||
sign_in moderator
|
||||
end
|
||||
|
||||
it 'fulfills update action' do
|
||||
expect(user.id).not_to eq(p.user_id)
|
||||
patch post_path(p), params: { post: { title: p.title } }, headers: headers
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user