Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add authorization #4

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby "3.2.1"


gem 'pundit'

gem "simple_form"

# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ GEM
public_suffix (5.0.1)
puma (5.6.5)
nio4r (~> 2.0)
pundit (2.3.1)
activesupport (>= 3.0.0)
racc (1.6.2)
rack (2.2.7)
rack-protection (3.0.6)
Expand Down Expand Up @@ -425,6 +427,7 @@ DEPENDENCIES
pg (~> 1.1)
pry-rails
puma (~> 5.0)
pundit
rails (~> 7.0.4, >= 7.0.4.3)
rails-erd
rails_db
Expand Down
21 changes: 18 additions & 3 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
class ApplicationController < ActionController::Base
include Pundit

after_action :verify_authorized, unless: :devise_controller?
after_action :verify_policy_scoped, only: :index, unless: :devise_controller?

before_action :authenticate_user!

before_action :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :private, :name, :bio, :website, :avatar_image])
devise_parameter_sanitizer.permit(:account_update, keys: [:username, :private, :name, :bio, :website, :avatar_image])
end

rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

private

def user_not_authorized
flash[:alert] = "You are not authorized to perform this action."

redirect_back fallback_location: root_url
end
end
24 changes: 16 additions & 8 deletions app/controllers/comments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class CommentsController < ApplicationController
before_action :set_comment, only: %i[ show edit update destroy ]

before_action :is_an_authorized_user, only: [:destroy, :create]
# GET /comments or /comments.json
def index
@comments = Comment.all
Expand Down Expand Up @@ -58,13 +58,21 @@ def destroy
end

private
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end

# Only allow a list of trusted parameters through.
def comment_params
params.require(:comment).permit(:author_id, :photo_id, :body)
# Use callbacks to share common setup or constraints between actions.
def set_comment
@comment = Comment.find(params[:id])
end

def is_an_authorized_user
@photo = Photo.find(params.fetch(:comment).fetch(:photo_id))
if current_user != @photo.owner && @photo.owner.private? && !current_user.leaders.include?(@photo.owner)
redirect_back fallback_location: root_url, alert: "Not authorized"
end
end

# Only allow a list of trusted parameters through.
def comment_params
params.require(:comment).permit(:author_id, :photo_id, :body)
end
end
43 changes: 32 additions & 11 deletions app/controllers/photos_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class PhotosController < ApplicationController
before_action :set_photo, only: %i[ show edit update destroy ]
before_action :ensure_current_user_is_owner, only: [:destroy, :update, :edit]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't need this anymore since we're using pundit now.

# before_action :ensure_user_is_authorized, only: [:show]

# GET /photos or /photos.json
def index
Expand All @@ -8,6 +10,7 @@ def index

# GET /photos/1 or /photos/1.json
def show
authorize @photo
end

# GET /photos/new
Expand Down Expand Up @@ -50,21 +53,39 @@ def update

# DELETE /photos/1 or /photos/1.json
def destroy
@photo.destroy
respond_to do |format|
format.html { redirect_back fallback_location: root_url, notice: "Photo was successfully destroyed." }
format.json { head :no_content }
if current_user == @photo.owner
@photo.destroy

respond_to do |format|
format.html { redirect_back fallback_location: root_url, notice: "Photo was successfully destroyed." }
format.json { head :no_content }
end
else
redirect_back(fallback_location: root_url, notice: "Nice try, but that is not your photo.")
end
end

private
# Use callbacks to share common setup or constraints between actions.
def set_photo
@photo = Photo.find(params[:id])
end

# Only allow a list of trusted parameters through.
def photo_params
params.require(:photo).permit(:image, :comments_count, :likes_count, :caption, :owner_id)
# Use callbacks to share common setup or constraints between actions.
def set_photo
@photo = Photo.find(params[:id])
end

def ensure_current_user_is_owner
if current_user != @photo.owner
redirect_back fallback_location: root_url, alert: "You're not authorized for that."
end
end

# Only allow a list of trusted parameters through.
def photo_params
params.require(:photo).permit(:image, :comments_count, :likes_count, :caption, :owner_id)
end

# def ensure_user_is_authorized
# if !PhotoPolicy.new(current_user, @photo).show?
# raise Pundit::NotAuthorizedError, "not allowed"
# end
# end
end
3 changes: 2 additions & 1 deletion app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class UsersController < ApplicationController
before_action :set_user, only: %i[ show liked feed followers following discover ]
before_action { authorize(@user || User) }

private

Expand All @@ -10,4 +11,4 @@ def set_user
@user = current_user
end
end
end
end
2 changes: 1 addition & 1 deletion app/models/comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
class Comment < ApplicationRecord
belongs_to :author, class_name: "User", counter_cache: true
belongs_to :photo, counter_cache: true

has_one :owner, through: :photo
validates :body, presence: true
end
53 changes: 53 additions & 0 deletions app/policies/application_policy.rb
Original file line number Diff line number Diff line change
@@ -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
16 changes: 16 additions & 0 deletions app/policies/photo_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# app/policies/photo_policy.rb

class PhotoPolicy < ApplicationPolicy
attr_reader :user, :photo

def initialize(user, photo)
@user = user
@photo = photo
end

def show?
user == photo.owner ||
!photo.owner.private? ||
photo.owner.followers.include?(user)
end
end
20 changes: 20 additions & 0 deletions app/policies/user_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# app/policies/user_policy.rb

class UserPolicy < ApplicationPolicy
attr_reader :current_user, :user

def initialize(current_user, user)
@current_user = current_user
@user = user
end

def feed?
true
end

def show?
user == current_user ||
!user.private? ||
user.followers.include?(current_user)
end
end
15 changes: 10 additions & 5 deletions app/views/photos/_photo.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- app/views/photos/_photo.html.erb -->

<div class="card">
<div class="card-body py-3 d-flex align-items-center justify-content-between">
<h2 class="h5 m-0 p-0 d-flex align-items-center">
Expand All @@ -7,13 +9,16 @@
</h2>

<div>
<%= link_to edit_photo_path(photo), class: "btn btn-link btn-sm text-muted" do %>
<i class="fas fa-edit fa-fw"></i>
<% end %>
<% if current_user == photo.owner %>
<%= link_to edit_photo_path(photo), class: "btn btn-link btn-sm text-muted" do %>
<i class="fas fa-edit fa-fw"></i>
<% end %>

<%= link_to photo, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %>
<i class="fas fa-trash fa-fw"></i>
<%= link_to photo, method: :delete, class: "btn btn-link btn-sm text-muted" do %>
<i class="fas fa-trash fa-fw"></i>
<% end %>
<% end %>

</div>
</div>

Expand Down
22 changes: 13 additions & 9 deletions app/views/users/show.html.erb
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
<!-- app/views/users/show.html.erb -->

<div class="row mb-4">
<div class="col-md-6 offset-md-3">
<%= render "users/user", user: @user %>
</div>
</div>

<div class="row mb-2">
<div class="col-md-6 offset-md-3">
<%= render "users/profile_nav", user: @user %>
</div>
</div>

<% @user.own_photos.each do |photo| %>
<div class="row mb-4">
<% if policy(@user).show? %>
<div class="row mb-2">
<div class="col-md-6 offset-md-3">
<%= render "photos/photo", photo: photo %>
<%= render "users/profile_nav", user: @user %>
</div>
</div>

<% @user.own_photos.each do |photo| %>
<div class="row mb-4">
<div class="col-md-6 offset-md-3">
<%= render "photos/photo", photo: photo %>
</div>
</div>
<% end %>
<% end %>
3 changes: 2 additions & 1 deletion config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

Rails.application.configure do
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
# Allow better_errors to work in online IDE
config.hosts.clear
# Allow better_errors to work in online IDE
config.web_console.whitelisted_ips = "0.0.0.0/0.0.0.0"
BetterErrors::Middleware.allow_ip! "0.0.0.0/0.0.0.0"
# Auto-connect to database when rails console opens
Expand Down
14 changes: 9 additions & 5 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
devise_for :users

resources :comments
resources :follow_requests
resources :likes
resources :photos

resources :follow_requests, except: [:index, :show, :new, :edit]
resources :likes, only: [:create, :destroy]
resources :photos, except: [:index]
get ":username" => "users#show", as: :user
get ":username/liked" => "users#liked", as: :liked
get ":username/feed" => "users#feed", as: :feed
get ":username/discover" => "users#discover", as: :discover
get ":username/followers" => "users#followers", as: :followers
get ":username/following" => "users#following", as: :following
end
end



# adding this so this, uh, is technically different from the main branch
2 changes: 1 addition & 1 deletion lib/tasks/dev.rake
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ task sample_data: :environment do
}
end

people << { first_name: "Alice", last_name: "Smith" }
people << { first_name: "Alice", last_name: "Smith", private: true }
people << { first_name: "Bob", last_name: "Smith" }
people << { first_name: "Carol", last_name: "Smith" }
people << { first_name: "Doug", last_name: "Smith" }
Expand Down