diff --git a/Gemfile b/Gemfile index 9eebefb9..0bc2144e 100644 --- a/Gemfile +++ b/Gemfile @@ -34,7 +34,7 @@ gem "redis", "~> 4.0" # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] # gem "kredis" - +gem "pundit" # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] # gem "bcrypt", "~> 3.1.7" diff --git a/Gemfile.lock b/Gemfile.lock index 42668dd8..e73e59d4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) @@ -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 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index bd664b1d..f9e0698c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,12 +1,27 @@ class ApplicationController < ActionController::Base + include Pundit before_action :authenticate_user! before_action :configure_permitted_parameters, if: :devise_controller? + #dont work if i enable the following, so commented them out. + after_action :verify_authorized, unless: :devise_controller? + after_action :verify_policy_scoped, only: :index, unless: :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 diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 046a8e5d..7bcf52c6 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,6 +1,14 @@ class CommentsController < ApplicationController before_action :set_comment, only: %i[ show edit update destroy ] + before_action :is_authorized + after_action :verify_authorized, except: [:home] + def is_authorized + @photo = Photo.find(params.fetch(:comment).fetch(:photo_id)) + if !@photo.owner.private? || @photo.owner == current_user || current_user.leaders.include?(@photo.owner) + redirect_back(fallback_location: root_url, alert: "Not allowed") + end + end # GET /comments or /comments.json def index @comments = Comment.all diff --git a/app/controllers/likes_controller.rb b/app/controllers/likes_controller.rb index 2391ddd7..1927216a 100644 --- a/app/controllers/likes_controller.rb +++ b/app/controllers/likes_controller.rb @@ -1,6 +1,15 @@ class LikesController < ApplicationController before_action :set_like, only: %i[ show edit update destroy ] + before_action :is_authorized, only: [:destroy, :create] + + after_action :verify_authorized, except: [:home] + def is_authorized + if !@like.owner.private? || current_user.leaders.include?(@like.owner)|| @like.owner ==current_user + redirect_back(fallback_location: root_url, alert: "not authorized") + end + + # GET /likes or /likes.json def index @likes = Like.all diff --git a/app/controllers/photos_controller.rb b/app/controllers/photos_controller.rb index 78e53163..73330778 100644 --- a/app/controllers/photos_controller.rb +++ b/app/controllers/photos_controller.rb @@ -1,6 +1,24 @@ class PhotosController < ApplicationController before_action :set_photo, only: %i[ show edit update destroy ] + before_action :ensure_current_user_is_owner, only: [:edit, :update, :destroy] + + before_action :ensure_user_is_authorized, only: [:show] + + before_action :ensure_user_is_authorized, only: [:show] + + after_action :verify_authorized, except: [:home] + def ensure_current_user_is_owner + if current_user != @photo.owner + redirect_back(fallback_location: root_url, alert: "Not allowed") + end + end + def ensure_user_is_authorized + if !PhotoPolicy.new(current_user, @photo).show? + raise Pundit::NotAuthorizedError, "not allowed" + end + end + # GET /photos or /photos.json def index @photos = Photo.all @@ -8,22 +26,26 @@ def index # GET /photos/1 or /photos/1.json def show + authorize @photo end # GET /photos/new def new @photo = Photo.new + authorize @photo end # GET /photos/1/edit def edit + + authorize @photo end # POST /photos or /photos.json def create @photo = Photo.new(photo_params) @photo.owner = current_user - + authorize @photo respond_to do |format| if @photo.save format.html { redirect_to @photo, notice: "Photo was successfully created." } @@ -50,6 +72,7 @@ def update # DELETE /photos/1 or /photos/1.json def destroy + authorize @photo @photo.destroy respond_to do |format| format.html { redirect_back fallback_location: root_url, notice: "Photo was successfully destroyed." } @@ -58,13 +81,14 @@ def destroy 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) - end + # 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) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 31db66e9..a5ea6f93 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,8 @@ class UsersController < ApplicationController + before_action :set_user, only: %i[ show liked feed followers following discover ] - + + before_action { authorize(@user || User) } private def set_user @@ -10,4 +12,4 @@ def set_user @user = current_user end end -end \ No newline at end of file +end diff --git a/app/models/like.rb b/app/models/like.rb index 1b885ab9..6fc67da0 100644 --- a/app/models/like.rb +++ b/app/models/like.rb @@ -21,6 +21,7 @@ class Like < ApplicationRecord belongs_to :fan, class_name: "User", counter_cache: true belongs_to :photo, counter_cache: true + has_one :owner, through: :photo validates :fan_id, uniqueness: { scope: :photo_id, message: "has already liked this photo" } end diff --git a/app/policies/photo_policy.rb b/app/policies/photo_policy.rb new file mode 100644 index 00000000..ede7ec6c --- /dev/null +++ b/app/policies/photo_policy.rb @@ -0,0 +1,31 @@ + +class PhotoPolicy + attr_reader :user, :photo + + def initialize(user, photo) + @user = user + @photo = photo + end + + def new? + user.present? + end + + def create? + new? + end + + def show? + user.present? + end + + def liked? + user.present? + end + def edit? + user.present? + end + def destroy? + user.present? + end +end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb new file mode 100644 index 00000000..369dd3d2 --- /dev/null +++ b/app/policies/user_policy.rb @@ -0,0 +1,27 @@ + +class UserPolicy + attr_reader :current_user, :user + + def feed? + true + end + + def initialize(current_user, user) + @current_user = current_user + @user = user + end + + def show? + user == current_user || + !user.private? || + user.followers.include?(current_user) + end + def liked? + user.present? + end + def discover? + user.present? + end + + +end diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb index a7ee4c56..edc790d7 100644 --- a/app/views/comments/_comment.html.erb +++ b/app/views/comments/_comment.html.erb @@ -9,14 +9,17 @@

<%= comment.body %>

-
- <%= link_to edit_comment_path(comment), class: "btn btn-link btn-sm text-muted" do %> - - <% end %> + <% if current_user == comment.author %> - <%= link_to comment, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %> - - <% end %> -
+
+ <%= link_to edit_comment_path(comment), class: "btn btn-link btn-sm text-muted" do %> + + <% end %> + + <%= link_to comment, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %> + + <% end %> +
+ <% end %> diff --git a/app/views/photos/_photo.html.erb b/app/views/photos/_photo.html.erb index f0de50b8..90f97182 100644 --- a/app/views/photos/_photo.html.erb +++ b/app/views/photos/_photo.html.erb @@ -5,20 +5,24 @@ <%= link_to photo.owner.username, user_path(photo.owner.username), class: "text-dark" %> + <% if current_user == photo.owner %> -
- <%= link_to edit_photo_path(photo), class: "btn btn-link btn-sm text-muted" do %> - - <% end %> +
+ <%= link_to edit_photo_path(photo), class: "btn btn-link btn-sm text-muted" do %> + + <% end %> + + <%= link_to photo, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %> + + <% end %> +
+ + <% end %> - <%= link_to photo, data: { turbo_method: :delete }, class: "btn btn-link btn-sm text-muted" do %> - - <% end %> -
<%= image_tag photo.image, class: "img-fluid" %> - +

<%= photo.caption %>

@@ -28,8 +32,11 @@ <%= render "comments/comment", comment: comment %> <% end %> + <% if current_user.leaders.include?(photo.owner) %> + -
- <%= render "comments/form", comment: photo.comments.build %> -
+
+ <%= render "comments/form", comment: photo.comments.build %> +
+ <% end %> diff --git a/app/views/users/discover.html.erb b/app/views/users/discover.html.erb index 8d132d24..e7232f74 100644 --- a/app/views/users/discover.html.erb +++ b/app/views/users/discover.html.erb @@ -9,7 +9,7 @@ -<% @user.discover.each do |photo| %> +<% @user.discover.reverse_each do |photo| %>
<%= render "photos/photo", photo: photo %> diff --git a/app/views/users/feed.html.erb b/app/views/users/feed.html.erb index 4daa48f2..87143b82 100644 --- a/app/views/users/feed.html.erb +++ b/app/views/users/feed.html.erb @@ -8,7 +8,7 @@
-<% @user.feed.each do |photo| %> +<% @user.feed.reverse_each do |photo| %>
<%= render "photos/photo", photo: photo %> diff --git a/app/views/users/liked.html.erb b/app/views/users/liked.html.erb index ab54e591..271ac1b5 100644 --- a/app/views/users/liked.html.erb +++ b/app/views/users/liked.html.erb @@ -3,17 +3,17 @@ <%= render "users/user", user: @user %>
- -
+<% if policy(@user).show? %>
<%= render "users/profile_nav", user: @user %>
-<% @user.liked_photos.each do |photo| %> +<% @user.liked_photos.reverse_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 5656d7d5..083dbbb7 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -4,16 +4,18 @@
-
-
- <%= render "users/profile_nav", user: @user %> -
-
- -<% @user.own_photos.each do |photo| %> -
+<% if policy(@user).show? %> +
- <%= render "photos/photo", photo: photo %> + <%= render "users/profile_nav", user: @user %>
+ + <% @user.own_photos.reverse_each do |photo| %> +
+
+ <%= render "photos/photo", photo: photo %> +
+
+ <% end %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 47050a54..00261070 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