From 6f582dd8fba03a6b72632071b00b28aa260b3217 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 03:52:58 +0000 Subject: [PATCH 1/9] added authorization --- app/controllers/comments_controller.rb | 8 ++++++++ app/controllers/photos_controller.rb | 10 ++++++++++ app/models/comment.rb | 1 + app/views/photos/_photo.html.erb | 2 ++ app/views/users/show.html.erb | 2 ++ config/routes.rb | 8 ++++---- 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 046a8e5d..81a7c53e 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,5 +1,6 @@ class CommentsController < ApplicationController before_action :set_comment, only: %i[ show edit update destroy ] + before_action :is_an_authorized_user, only: %i[ destroy create ] # GET /comments or /comments.json def index @@ -67,4 +68,11 @@ def set_comment def comment_params params.require(:comment).permit(:author_id, :photo_id, :body) 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 end diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 78e53163..acabc62d 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -1,5 +1,6 @@ class PhotosController < ApplicationController before_action :set_photo, only: %i[ show edit update destroy ] + before_action :ensure_current_user_is_owner, only: [:destroy, :update, :edit] # GET /photos or /photos.json def index @@ -50,10 +51,13 @@ def update # DELETE /photos/1 or /photos/1.json def destroy + 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 } + else + redirect_back(fallback_location: root_url, notice: "Nice try, but that is not your photo.") end end @@ -67,4 +71,10 @@ def set_photo def photo_params params.require(:photo).permit(:image, :comments_count, :likes_count, :caption, :owner_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 end diff --git a/app/models/comment.rb b/app/models/comment.rb index 14a8eb00..0761b0e8 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -22,6 +22,7 @@ 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 diff --git a/app/views/photos/_photo.html.erb b/app/views/photos/_photo.html.erb index 98193002..52dfdd8b 100644 --- a/app/views/photos/_photo.html.erb +++ b/app/views/photos/_photo.html.erb @@ -7,6 +7,7 @@
+ <% if current_user == photo.owner %> <%= link_to edit_photo_path(photo), class: "btn btn-link btn-sm text-muted" do %> <% end %> @@ -14,6 +15,7 @@ <%= link_to photo, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %> <% end %> + <% end %>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 5656d7d5..f397da2e 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -4,6 +4,7 @@ +<% if current_user == @user || !@user.private? || current_user.leaders.include?(@user) %>
<%= render "users/profile_nav", user: @user %> @@ -17,3 +18,4 @@
<% end %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 47050a54..53545094 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,9 +4,9 @@ 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 @@ -14,4 +14,4 @@ get ":username/discover" => "users#discover", as: :discover get ":username/followers" => "users#followers", as: :followers get ":username/following" => "users#following", as: :following -end \ No newline at end of file +end From 10400bdc6cc531b621dc63ba7611b57badff646e Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 14:33:40 +0000 Subject: [PATCH 2/9] added user methods --- app/controllers/users_controller.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 31db66e9..5939c799 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,5 +1,18 @@ class UsersController < ApplicationController before_action :set_user, only: %i[ show liked feed followers following discover ] + + def show + end + def liked + end + def feed + end + def followers + end + def following + end + def discover + end private @@ -10,4 +23,4 @@ def set_user @user = current_user end end -end \ No newline at end of file +end From 608e6f3cdf305e886e2fc32e1ceab238518b9546 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 15:10:55 +0000 Subject: [PATCH 3/9] added pundit --- Gemfile | 2 ++ Gemfile.lock | 3 +++ app/controllers/application_controller.rb | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/Gemfile b/Gemfile index 1bd5c98a..3411eae3 100644 --- a/Gemfile +++ b/Gemfile @@ -12,6 +12,8 @@ gem "sprockets-rails" # Use postgresql as the database for Active Record gem "pg", "~> 1.1" +gem "pundit" + # Use the Puma web server [https://github.com/puma/puma] gem "puma" diff --git a/Gemfile.lock b/Gemfile.lock index c4571af4..995b0d6c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -266,6 +266,8 @@ GEM public_suffix (5.0.5) puma (6.4.2) nio4r (~> 2.0) + pundit (2.4.0) + activesupport (>= 3.0.0) racc (1.8.0) rack (3.0.11) rack-session (2.0.0) @@ -464,6 +466,7 @@ DEPENDENCIES pg (~> 1.1) pry-rails puma + pundit rails (~> 7.1.3, >= 7.1.3.2) rails-erd rails_db diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bd664b1d..685986ab 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,12 +1,33 @@ class ApplicationController < ActionController::Base + include Pundit::Authorization + after_action :verify_authorized, unless: :devise_controller? before_action :authenticate_user! before_action :configure_permitted_parameters, if: :devise_controller? + rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized + 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 + + private + + def user_not_authorized + flash[:alert] = "You are not authorized to perform this action." + + redirect_back fallback_location: root_url + end + + 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 + + end From 02d0a075bd25fe8f83dcc98c579e143421c32e56 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 15:11:17 +0000 Subject: [PATCH 4/9] comments policy --- app/controllers/comments_controller.rb | 14 +++++------ app/policies/comment_policy.rb | 32 ++++++++++++++++++++++++++ app/views/comments/_comment.html.erb | 2 ++ app/views/comments/index.html.erb | 6 +++-- app/views/comments/show.html.erb | 2 ++ 5 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 app/policies/comment_policy.rb diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 81a7c53e..539739b1 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,6 +1,5 @@ class CommentsController < ApplicationController before_action :set_comment, only: %i[ show edit update destroy ] - before_action :is_an_authorized_user, only: %i[ destroy create ] # GET /comments or /comments.json def index @@ -9,21 +8,25 @@ def index # GET /comments/1 or /comments/1.json def show + authorize @comment end # GET /comments/new def new @comment = Comment.new + authorize @comment end # GET /comments/1/edit def edit + authorize @comment end # POST /comments or /comments.json def create @comment = Comment.new(comment_params) @comment.author = current_user + authorize @comment respond_to do |format| if @comment.save @@ -38,6 +41,7 @@ def create # PATCH/PUT /comments/1 or /comments/1.json def update + authorize @comment respond_to do |format| if @comment.update(comment_params) format.html { redirect_to root_url, notice: "Comment was successfully updated." } @@ -51,6 +55,7 @@ def update # DELETE /comments/1 or /comments/1.json def destroy + authorize @comment @comment.destroy respond_to do |format| format.html { redirect_back fallback_location: root_url, notice: "Comment was successfully destroyed." } @@ -68,11 +73,4 @@ def set_comment def comment_params params.require(:comment).permit(:author_id, :photo_id, :body) 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 end diff --git a/app/policies/comment_policy.rb b/app/policies/comment_policy.rb new file mode 100644 index 00000000..a152d906 --- /dev/null +++ b/app/policies/comment_policy.rb @@ -0,0 +1,32 @@ +class CommentPolicy < ApplicationPolicy + attr_reader :user, :comment + + def initialize(user, comment) + @user = user + @comment = comment + end + + def show? + @user == @comment.author + end + + def new? + show? + end + + def edit? + show? + end + + def create? + show? + end + + def update? + show? + end + + def destroy? + show? + end +end diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb index a7ee4c56..4ee3e0cb 100644 --- a/app/views/comments/_comment.html.erb +++ b/app/views/comments/_comment.html.erb @@ -10,6 +10,7 @@

<%= comment.body %>

+ <% if policy(comment).show? %> <%= link_to edit_comment_path(comment), class: "btn btn-link btn-sm text-muted" do %> <% end %> @@ -17,6 +18,7 @@ <%= link_to comment, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %> <% end %> + <% end %>
diff --git a/app/views/comments/index.html.erb b/app/views/comments/index.html.erb index 19510d2e..147f3c5e 100644 --- a/app/views/comments/index.html.erb +++ b/app/views/comments/index.html.erb @@ -17,8 +17,10 @@ <%= comment.photo_id %> <%= comment.body %> <%= link_to 'Show', comment %> - <%= link_to 'Edit', edit_comment_path(comment) %> - <%= link_to 'Destroy', comment, data: { turbo_method: :delete }, data: { confirm: 'Are you sure?' } %> + <% if current_user == comment.author %> + <%= link_to 'Edit', edit_comment_path(comment) %> + <%= link_to 'Destroy', comment, data: { turbo_method: :delete }, data: { confirm: 'Are you sure?' } %> + <% end %> <% end %> diff --git a/app/views/comments/show.html.erb b/app/views/comments/show.html.erb index 4594fe67..390b81dd 100644 --- a/app/views/comments/show.html.erb +++ b/app/views/comments/show.html.erb @@ -14,5 +14,7 @@ <%= @comment.body %>

+<% if current_user == @comment.author %> <%= link_to 'Edit', edit_comment_path(@comment) %> | +<% end %> <%= link_to 'Back', comments_path %> From eeb8feeee40396548f7121f32bb5455878b0442c Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 15:11:46 +0000 Subject: [PATCH 5/9] photo policy --- app/controllers/photos_controller.rb | 2 ++ app/policies/photo_policy.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 app/policies/photo_policy.rb diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index acabc62d..0c4eb5fe 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -9,6 +9,7 @@ def index # GET /photos/1 or /photos/1.json def show + authorize @photo end # GET /photos/new @@ -77,4 +78,5 @@ def ensure_current_user_is_owner redirect_back fallback_location: root_url, alert: "You're not authorized for that." end end + end diff --git a/app/policies/photo_policy.rb b/app/policies/photo_policy.rb new file mode 100644 index 00000000..a21c0fff --- /dev/null +++ b/app/policies/photo_policy.rb @@ -0,0 +1,28 @@ +class PhotoPolicy < ApplicationPolicy + attr_reader :user, :photo + + def initialize(user, photo) + @user = user + @photo = photo + end + + def create? + true + end + + def new? + true + end + + def update? + user == photo.owner + end + + def destroy? + user == photo.owner + end + + def show? + user == photo.owner || !photo.owner.private? || photo.owner.followers.include?(user) + end +end From 7f3bad3e79659c7e17a4b873b855f32131154748 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 15:11:58 +0000 Subject: [PATCH 6/9] follow requests policy --- app/controllers/follow_requests_controller.rb | 6 ++++ app/policies/follow_request_policy.rb | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 app/policies/follow_request_policy.rb diff --git a/app/controllers/follow_requests_controller.rb b/app/controllers/follow_requests_controller.rb index 9c30da7c..4b49a2b4 100644 --- a/app/controllers/follow_requests_controller.rb +++ b/app/controllers/follow_requests_controller.rb @@ -8,21 +8,25 @@ def index # GET /follow_requests/1 or /follow_requests/1.json def show + authorize @follow_request end # GET /follow_requests/new def new @follow_request = FollowRequest.new + authorize @follow_request end # GET /follow_requests/1/edit def edit + authorize @follow_request end # POST /follow_requests or /follow_requests.json def create @follow_request = FollowRequest.new(follow_request_params) @follow_request.sender = current_user + authorize @follow_request respond_to do |format| if @follow_request.save @@ -37,6 +41,7 @@ def create # PATCH/PUT /follow_requests/1 or /follow_requests/1.json def update + authorize @follow_request respond_to do |format| if @follow_request.update(follow_request_params) format.html { redirect_back fallback_location: root_url, notice: "Follow request was successfully updated." } @@ -50,6 +55,7 @@ def update # DELETE /follow_requests/1 or /follow_requests/1.json def destroy + authorize @follow_request @follow_request.destroy respond_to do |format| format.html { redirect_back fallback_location: root_url, notice: "Follow request was successfully destroyed." } diff --git a/app/policies/follow_request_policy.rb b/app/policies/follow_request_policy.rb new file mode 100644 index 00000000..64eb375b --- /dev/null +++ b/app/policies/follow_request_policy.rb @@ -0,0 +1,32 @@ +class FollowRequestPolicy < ApplicationPolicy + attr_reader :user, :follow_request + + def initialize(user, follow_request) + @user = user + @follow_request = follow_request + end + + def show? + @user == @follow_request.recipient + end + + def new? + @user == @follow_request.sender + end + + def edit? + true + end + + def create? + new? + end + + def update? + true + end + + def destroy? + true + end +end From 83580ff453f52df8773072e32a376995d1be5ce3 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 15:12:13 +0000 Subject: [PATCH 7/9] likes policy --- app/controllers/likes_controller.rb | 6 ++++++ app/policies/like_policy.rb | 32 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 app/policies/like_policy.rb diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb index 49affd3e..5c4f19c8 100644 --- a/app/controllers/likes_controller.rb +++ b/app/controllers/likes_controller.rb @@ -8,20 +8,24 @@ def index # GET /likes/1 or /likes/1.json def show + authorize @like end # GET /likes/new def new @like = Like.new + authorize @like end # GET /likes/1/edit def edit + authorize @like end # POST /likes or /likes.json def create @like = Like.new(like_params) + authorize @like respond_to do |format| if @like.save @@ -36,6 +40,7 @@ def create # PATCH/PUT /likes/1 or /likes/1.json def update + authorize @like respond_to do |format| if @like.update(like_params) format.html { redirect_to @like, notice: "Like was successfully updated." } @@ -49,6 +54,7 @@ def update # DELETE /likes/1 or /likes/1.json def destroy + authorize @like @like.destroy respond_to do |format| format.html { redirect_back fallback_location: root_url, notice: "Like was successfully destroyed." } diff --git a/app/policies/like_policy.rb b/app/policies/like_policy.rb new file mode 100644 index 00000000..0744cbda --- /dev/null +++ b/app/policies/like_policy.rb @@ -0,0 +1,32 @@ +class LikePolicy < ApplicationPolicy + attr_reader :user, :like + + def initialize(user, like) + @user = user + @photo = like + end + + def show? + user == like.photo.owner || !like.photo.owner.private? || photo.fans.include?(user) + end + + def create? + true + end + + def new? + create? + end + + def update? + true + end + + def edit? + update? + end + + def destroy? + true + end +end From 0398e54aeff969a41df4fdca4e19c105102be496 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 15:12:30 +0000 Subject: [PATCH 8/9] user policy and application policy --- app/controllers/users_controller.rb | 2 ++ app/policies/application_policy.rb | 53 +++++++++++++++++++++++++++++ app/policies/user_policy.rb | 30 ++++++++++++++++ app/views/users/_user.html.erb | 2 ++ app/views/users/discover.html.erb | 12 ++++--- app/views/users/feed.html.erb | 12 ++++--- app/views/users/show.html.erb | 2 +- 7 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 app/policies/application_policy.rb create mode 100644 app/policies/user_policy.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 5939c799..10443638 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -19,8 +19,10 @@ def discover def set_user if params[:username] @user = User.find_by!(username: params.fetch(:username)) + authorize @user else @user = current_user + authorize @user end end end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb new file mode 100644 index 00000000..be644fe3 --- /dev/null +++ b/app/policies/application_policy.rb @@ -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 NoMethodError, "You must define #resolve in #{self.class}" + end + + private + + attr_reader :user, :scope + end +end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb new file mode 100644 index 00000000..ef630fa3 --- /dev/null +++ b/app/policies/user_policy.rb @@ -0,0 +1,30 @@ +class UserPolicy < ApplicationPolicy + attr_reader :current_user, :user + + def initialize(current_user, user) + @current_user = current_user + @user = user + end + + def feed? + user == current_user + end + + def discover? + feed? + end + + def liked? + feed? + end + + def show? + true + end + + def show_photos? + user == current_user || + !user.private? || + user.followers.include?(current_user) + end +end diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb index 669ec171..119e37a6 100644 --- a/app/views/users/_user.html.erb +++ b/app/views/users/_user.html.erb @@ -49,6 +49,7 @@ <% end %> + <% if @user == current_user %>
<%= link_to "#", @@ -65,6 +66,7 @@ <% end %>
+ <% end %>
diff --git a/app/views/users/discover.html.erb b/app/views/users/discover.html.erb index 8d132d24..3bc563b0 100644 --- a/app/views/users/discover.html.erb +++ b/app/views/users/discover.html.erb @@ -9,10 +9,12 @@
-<% @user.discover.each do |photo| %> -
-
- <%= render "photos/photo", photo: photo %> +<% if policy(@user).discover? %> + <% @user.discover.each do |photo| %> +
+
+ <%= render "photos/photo", photo: photo %> +
-
+ <% end %> <% end %> diff --git a/app/views/users/feed.html.erb b/app/views/users/feed.html.erb index 4daa48f2..b0c0b9c1 100644 --- a/app/views/users/feed.html.erb +++ b/app/views/users/feed.html.erb @@ -8,10 +8,12 @@
-<% @user.feed.each do |photo| %> -
-
- <%= render "photos/photo", photo: photo %> +<% if policy(@user).feed? %> + <% @user.feed.each do |photo| %> +
+
+ <%= render "photos/photo", photo: photo %> +
-
+ <% end %> <% end %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index f397da2e..a136adfb 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -4,7 +4,7 @@
-<% if current_user == @user || !@user.private? || current_user.leaders.include?(@user) %> +<% if policy(@user).show_photos? %>
<%= render "users/profile_nav", user: @user %> From b67f3d32203fea96279495736f94f4cd8ca23064 Mon Sep 17 00:00:00 2001 From: Brian Kim Date: Thu, 6 Feb 2025 16:36:09 +0000 Subject: [PATCH 9/9] adde policy post --- app/views/comments/index.html.erb | 3 ++- app/views/comments/show.html.erb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/comments/index.html.erb b/app/views/comments/index.html.erb index 147f3c5e..00d269d4 100644 --- a/app/views/comments/index.html.erb +++ b/app/views/comments/index.html.erb @@ -11,13 +11,14 @@ + <% @comments.each do |comment| %> <%= comment.author_id %> <%= comment.photo_id %> <%= comment.body %> <%= link_to 'Show', comment %> - <% if current_user == comment.author %> + <% if policy(@post).edit? %> <%= link_to 'Edit', edit_comment_path(comment) %> <%= link_to 'Destroy', comment, data: { turbo_method: :delete }, data: { confirm: 'Are you sure?' } %> <% end %> diff --git a/app/views/comments/show.html.erb b/app/views/comments/show.html.erb index 390b81dd..0ddfe3a4 100644 --- a/app/views/comments/show.html.erb +++ b/app/views/comments/show.html.erb @@ -14,7 +14,7 @@ <%= @comment.body %>

-<% if current_user == @comment.author %> +<% if policy(@post).edit? %> <%= link_to 'Edit', edit_comment_path(@comment) %> | <% end %> <%= link_to 'Back', comments_path %>