0

I'm having some trouble implementing one last step in my pundit authorizations...I have a projects model as well as a project_policy that authorizes which users in the app can view and interact w/ the project. However, my projects have several components - one of which is an index of project versions that is accessed within the project (a project has_many versions)...so I need to be able to restrict users access to this list of versions as well... along with the default project profile (I restrict if a users is not an owner/admin or collaborator). I currently have these 'versions', however, setup in their own model.

Details: Currently if I am not an admin/owner or collaborator, the restrictions work when I try to access the url projects/20 (it will redirect me and say "you're not authorized"), but if i navigate to 'projects/20/versions' or 'projects/20/versions/1' or 'projects/20/versions/new' it does not restrict me. Do I need to create a new version_policy for this or can i just restrict this within the project_policy since technically the versions are a part of the project? & what would the code look like that I need to add?

My code is as follows - thanks in advance for any and all help...

PROJECT_POLICY.RB

  class Scope < Struct.new(:user, :scope)

  end

    def update?
      user.project_admin? or user.project_collaborator?
    end

    # method used in projects controller, (study pundit docs)
    def visit?
      if project.is_private?
        user.project_admin?(project) || user.project_owner?(project) || user.project_collaborator?(project)
      else
        true
      end
    end

    def main_profile?
      true
    end

    def projectversions?
      user.project_admin?(project) || user.project_owner?(project)
    end

    def settings?
      user.project_admin?(project) || user.project_owner?(project)
    end

    def collaboration?
      user.project_admin?(project) || user.project_owner?(project)
    end

    def invite_admin?
      user.project_admin?(project) || user.project_owner?(project)
    end

    def invite_collaborator?
      user.project_admin?(project) || user.project_owner?(project)
    end
end

PROJECT.RB (PROJECTS MODEL)

class Project < ActiveRecord::Base

  ...
  ...      

  has_many :versions, dependent: :destroy

  validates :title, presence: true, length: { maximum: 100 }
  validates :background, presence: true
  validates :user_id, presence: true

  default_scope -> { order('created_at DESC') }

  def user_name
    owner.try(:name)
  end

  def user_name=(name)
    self.user = User.find_by_name(name) if name.present?
  end

  def private?
    self.is_private == true
  end

  def public?
    self.is_private == false
  end

end

PROJECTS_CONTROLLER.RB

class ProjectsController < ApplicationController
  before_filter :signed_in_user, only: [:create, :new, :edit, :update]

  # Creates redirect and alert when pundit sees someone is not authorized (via :not_authorized_in_project below)
  rescue_from Pundit::NotAuthorizedError, :with=>:not_authorized_in_project

  def new
    @project = Project.new
  end

  def show
    @project = Project.find(params[:id])
    authorize @project, :visit?
    @user = User.where(:id => @project.user_id).first
  rescue Pundit::NotAuthorizedError
    flash[:danger] = "You are not authorized to access this page."
    redirect_to projects_path || root_path
  end

  def create
    @project = current_user.own_projects.build(project_params)
    if @project.save
      flash[:success] = "Welcome to your new project."
      redirect_to @project
    else
      render 'new'
    end
  end

  def update
    @project = Project.find(params[:id])
    if @project.update_attributes(project_params)
      flash[:success] = "Project Created"
      redirect_to @project
    else
      render 'edit'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "Project destroyed"
    redirect_to users_path
  end

  def projectadmins
    @title = "Project Admins"
    @project = Project.find(params[:id])
    authorize @project, :visit?
    @projects = @project.projectadmins.paginate(page: params[:page])
    render 'show_projectadmin_project'
  rescue Pundit::NotAuthorizedError
    flash[:danger] = "You are not authorized to access this page."
    redirect_to projects_path || root_path
  end

  def projectversions
    *# If I should place the authorizations in this controller...What code should go here?  And how would I also restrict the new/show actions for projects/versions i.e, 'projects/20/versions/new', etc?*
  end

  def settings
    @project = Project.find(params[:project_id])
    authorize @project
    render 'settings'
  end

  private

  def project_params
    params.require(:project).permit(:title, :background, :is_private)
  end

  # USED FOR PUNDIT REDIRECT & ALERT FLASH WHEN SOMEONE IS NOT AUTHORIZED TO ACCESS SOMETHING
  def not_authorized_in_project
    flash[:danger] = "You are not authorized to access this page."
    redirect_to project_path(@project) || root_path
  end
end

ROUTES.RB

ProductionApp::Application.routes.draw do
  resources :users
  resources :sessions, only: [:new, :create, :destroy]

  resources :projects do
    resources :versions
    match '/settings'=>'projects#settings', :via=>:get, :as=>:settings
    match '/collaboration'=>'projects#collaboration', :via=>:get, :as=>:collaboration
    match '/invite_admin'=>'projects#invite_admin', :via=>:patch, :as=>:invite_admin
    match '/invite_collaborator'=>'projects#invite_collaborator', :via=>:patch, :as=>:invite_collaborator
    get :autocomplete_user_name, :on=>:collection
  end

  resources :versions do
    resources :users
  end

  resources :projects do
    member do
      get :projectadmins
    end
  end

  resources :admin_relationships, only: [:create, :destroy]
  resources :collaborator_relationships, only: [:create, :destroy]

  # get "static_pages/home"
  # get "static_pages/help"
  # get "static_pages/about"

end

much appreciated...let me know if anything else I missed would be helpful to see.

BB500
  • 549
  • 2
  • 6
  • 24
  • 1
    I would create a new policy `VersionPolicy` and on top of that restric the `Scope` that the version policy can see based on the user and their project. – dasnixon Jun 07 '14 at 18:08
  • Thanks Liam...could you show me how you'd go about restricting the scope in the way you described? that's an epic name by the way. – BB500 Jun 08 '14 at 00:07
  • Did you figure this out? – jcuenod Mar 18 '15 at 14:23
  • @jcuenod pretty sure i did as dasnixon said & created a VersionPolicy, but it was long time ago (I don't have access to the code any longer). sorry for the very late reply. – BB500 Dec 28 '15 at 05:40

0 Answers0