Authorisation management using CanCanCan added

This commit is contained in:
Christoph Haas 2021-02-28 21:36:46 +01:00
parent 51be4a4777
commit 7a3b65fe50
24 changed files with 211 additions and 295 deletions

View file

@ -143,3 +143,6 @@ gem 'omniauth_openid_connect'
# Mitigate CVE-2015-9284 # Mitigate CVE-2015-9284
# https://github.com/cookpad/omniauth-rails_csrf_protection # https://github.com/cookpad/omniauth-rails_csrf_protection
gem 'omniauth-rails_csrf_protection' gem 'omniauth-rails_csrf_protection'
# Role-based access
gem 'cancancan'

View file

@ -90,6 +90,7 @@ GEM
msgpack (~> 1.0) msgpack (~> 1.0)
builder (3.2.4) builder (3.2.4)
byebug (11.1.3) byebug (11.1.3)
cancancan (3.2.1)
capybara (3.35.3) capybara (3.35.3)
addressable addressable
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
@ -430,6 +431,7 @@ DEPENDENCIES
bootsnap bootsnap
byebug byebug
bzip2-ruby! bzip2-ruby!
cancancan
capybara capybara
cookies_eu cookies_eu
devise devise

View file

@ -1,38 +1,38 @@
class AdminController < ApplicationController class AdminController < ApplicationController
before_action :authenticate_user! # before_action :authenticate_user!
before_action :admin_only # before_action :admin_only
def status # def status
end # end
def screenshots # def screenshots
end # end
def integration # def integration
end # end
def moderate_list # def moderate_list
end # end
def logs # def logs
logs = Log # logs = Log
if params[:search].present? # if params[:search].present?
logger.debug "Searching for #{params[:search]}" # logger.debug "Searching for #{params[:search]}"
logs = logs.where("message ilike ?", "%#{params[:search]}%") # logs = logs.where("message ilike ?", "%#{params[:search]}%")
end # end
@logs = logs.paginate(page: params[:page], per_page: 20) # @logs = logs.paginate(page: params[:page], per_page: 20)
end # end
private # private
def admin_only # def admin_only
unless current_user.is_admin? # unless current_user.is_admin?
head :forbidden # head :forbidden
# redirect_to :back, :alert => "Access denied." # # redirect_to :back, :alert => "Access denied."
end # end
end # end
end end

View file

@ -22,7 +22,7 @@ class ApplicationController < ActionController::Base
# the navigation bar that contains a paginator of packages that contain # the navigation bar that contains a paginator of packages that contain
# screenshots that require moderation. # screenshots that require moderation.
def moderate_packages def moderate_packages
if user_signed_in? and current_user.is_admin? and Package.need_moderation.any? if can? :approve, Screenshot and Package.need_moderation.any?
@moderate_packages = Package.need_moderation @moderate_packages = Package.need_moderation
end end
end end

View file

@ -1,27 +1,22 @@
class ModerateController < ApplicationController # class ModerateController < ApplicationController
before_action :authenticate_user! # before_action :authenticate_user!
def index # def index
# First package with pending screenshots # # First package with pending screenshots
@package = Package.joins(:screenshots).where('screenshots.approved=false or screenshots.markedfordelete=true').distinct(:name).first # @package = Package.joins(:screenshots).where('screenshots.approved=false').distinct(:name).first
# # List of screenshots that were reported (to be removed) # if @package
# @reported_screenshots = Screenshot.where(markedfordelete: true) # # List of screenshots to be moderated
# # First package with reported screenshots # @pending_screenshots = @package.screenshots_pending
# @reported_package = Package.joins(:screenshots).where('screenshots.markedfordelete=true').distinct(:name).first # # Number of screenshots that were already moderated (during this session)
# session[:already_moderated] ||= 0
# @moderated_screenshots = session[:already_moderated]
if @package # # BUG: calculation is wrong when pending and reported screenshots are in the queue
# List of screenshots to be moderated # # Percentage of already moderated screenshots
@pending_screenshots = @package.screenshots_pending # @percent_moderated = 100 * (@moderated_screenshots+1) / (@moderated_screenshots + @pending_screenshots.count)
# Number of screenshots that were already moderated (during this session) # # @percent_moderated = 100 * (@moderated_screenshots+1) / (@moderated_screenshots + @pending_screenshots.count + @reported_screenshots.count)
session[:already_moderated] ||= 0 # end
@moderated_screenshots = session[:already_moderated] # end
# end
# BUG: calculation is wrong when pending and reported screenshots are in the queue
# Percentage of already moderated screenshots
@percent_moderated = 100 * (@moderated_screenshots+1) / (@moderated_screenshots + @pending_screenshots.count)
# @percent_moderated = 100 * (@moderated_screenshots+1) / (@moderated_screenshots + @pending_screenshots.count + @reported_screenshots.count)
end
end
end

View file

@ -37,10 +37,6 @@ class PackagesController < ApplicationController
# This action saves the screenshots already if they are valid. The user is # This action saves the screenshots already if they are valid. The user is
# then given the chance to comment on and delete the screenshots again. # then given the chance to comment on and delete the screenshots again.
def upload_receive def upload_receive
# Create a pseudo user account for the user.
# The user won't know that an account is created.
# But this makes it easier to track who screenshots belong to.
# User.create_pseudo_user unless user_signed_in?
@package = Package.find_by!(name: params[:name]) @package = Package.find_by!(name: params[:name])
@valid_images = [] @valid_images = []
@invalid_images = [] @invalid_images = []
@ -65,7 +61,7 @@ class PackagesController < ApplicationController
# Check if the image was valid # Check if the image was valid
if new_screenshot.valid? if new_screenshot.valid?
new_screenshot.uploaderhash = session.id.to_s # new_screenshot.uploaderhash = session.id.to_s
new_screenshot.uploaderip = request.remote_ip new_screenshot.uploaderip = request.remote_ip
new_screenshot.version = @package.version new_screenshot.version = @package.version
# ActiveStorage does not yet create a file checksum automatically. # ActiveStorage does not yet create a file checksum automatically.
@ -77,19 +73,25 @@ class PackagesController < ApplicationController
Log.log "Duplicate image with fingerprint #{new_screenshot.image_fingerprint} found. Rejecting." Log.log "Duplicate image with fingerprint #{new_screenshot.image_fingerprint} found. Rejecting."
all_errors << "Your file #{img.original_filename} is a duplicate. Sorry." all_errors << "Your file #{img.original_filename} is a duplicate. Sorry."
else else
# Can the upload get approved automatically? # TODO: Can the upload get approved automatically?
if user_signed_in?
new_screenshot.user = current_user
new_screenshot.approve! if auto_approve?
end
# Create a pseudo user account for the user.
# The user won't know that an account is created.
# But this makes it easier to track who screenshots belong to.
unless user_signed_in?
sign_in User.create_pseudo_user
end
new_screenshot.user = current_user
new_screenshot.approve! if can?(:approve, new_screenshot)
# Pre-render screenshot in different sizes
new_screenshot.simage_derivatives! new_screenshot.simage_derivatives!
Log.log "Derivatives created" Log.log "Derivatives created"
new_screenshot.save! new_screenshot.save!
Log.log "Screenshot #{new_screenshot.id} uploaded successfully. " + \ Log.log "Screenshot #{new_screenshot.id} uploaded successfully. " + \
"ip=#{new_screenshot.uploaderip}. "+ \ "ip=#{new_screenshot.uploaderip}. "+ \
"user-hash=#{new_screenshot.uploaderhash}. "+ \ #"user-hash=#{new_screenshot.uploaderhash}. "+ \
"user-name=#{current_user} "+ \ "user-name=#{current_user} "+ \
"image-fingerprint=#{new_screenshot.image_fingerprint} "+ \ "image-fingerprint=#{new_screenshot.image_fingerprint} "+ \
"image-path=#{img.path}" "image-path=#{img.path}"
@ -174,7 +176,7 @@ class PackagesController < ApplicationController
# Check if the user is allowed to change this screenshot # Check if the user is allowed to change this screenshot
# - Is this the user's own screenshot? (anonymous) # - Is this the user's own screenshot? (anonymous)
if @screenshot.user == current_user or current_user.is_admin? if (@screenshot.user == current_user) || (can? :detroy, @screenshot)
logger.debug "User #{current_user} deletes screenshot #{@screenshot}" logger.debug "User #{current_user} deletes screenshot #{@screenshot}"
@screenshot.destroy @screenshot.destroy
flash['notice'] = "Screenshot deleted." flash['notice'] = "Screenshot deleted."
@ -185,8 +187,9 @@ class PackagesController < ApplicationController
end end
def approve_screenshot def approve_screenshot
if current_user && current_user.is_admin? @screenshot = Screenshot.find(params[:id])
@screenshot = Screenshot.find(params[:id])
if can? :approve, @screenshot
@screenshot.approve! @screenshot.approve!
flash['notice'] = "Screenshot approved." flash['notice'] = "Screenshot approved."
redirect_back(fallback_location: package_path(name: @screenshot.package.name)) redirect_back(fallback_location: package_path(name: @screenshot.package.name))
@ -263,23 +266,6 @@ class PackagesController < ApplicationController
redirect_back(fallback_location: package_path(name: @screenshot.package.name)) redirect_back(fallback_location: package_path(name: @screenshot.package.name))
end end
# Receive an anonymous report from a user to have a screenshot removed.
# def report_screenshot
# @screenshot = Screenshot.find(params[:id])
# # if verify_recaptcha
# @screenshot.delete_reason = params[:delete_reason]
# @screenshot.markedfordelete = true
# if @screenshot.valid?
# @screenshot.save!
# flash['notice'] = "Screenshot reported. The moderators will deal with it."
# else
# errors = @screenshot.errors.to_a.join(' and ')
# flash['alert'] = "Sorry. #{errors}"
# end
# # end
# redirect_back(fallback_location: package_path)
# end
# Show an HTML partial with reviews of this package from the Ubuntu API # Show an HTML partial with reviews of this package from the Ubuntu API
# def reviews # def reviews
# expires_in 1.day, public: true # expires_in 1.day, public: true
@ -350,37 +336,7 @@ class PackagesController < ApplicationController
params.require(:screenshot).permit(:description) params.require(:screenshot).permit(:description)
end end
# Do uploads from this user get approved automatically?
def auto_approve?
# Anonymous users need to go through moderation
return false unless user_signed_in?
# Admins do not need moderation
return true if current_user.is_admin?
# Debian developers do not need moderation
return true if current_user.provider == 'debian-sso'
# After one successfully approved screenshot users do not need moderation
# return true if current_user.approved_screenshots.count > 0
# Any other user's upload must be moderated
return false
end
def screenshots_visible_to_user(package) def screenshots_visible_to_user(package)
if user_signed_in? and current_user.is_admin? package.screenshots.accessible_by(current_ability, :view).order('created_at DESC')
# User is an admin and can view all screenshots
package.screenshots
# TODO: User logins and assigned screenshots will come in a later version
# elsif user_signed_in?
# package.screenshots.where(id: (current_user.screenshots.select(:id))) | \
# package.screenshots.where(approved: true).order('created_at DESC')
else
package.screenshots.where(uploaderhash: session.id.to_s).or(
package.screenshots.where(approved: true)
)
.order('created_at DESC')
end
end end
end end

View file

@ -1,45 +1,5 @@
module PackagesHelper module PackagesHelper
# Return a query of all screenshots that the current user may see
# Consists of:
# - approved (public) screenshots
# - screenshots uploaded by the user
# - all screenshots if the user is an admin
# def screenshots_visible_to_user(package)
# if user_signed_in? and current_user.is_admin?
# # User is an admin and can view all screenshots
# package.screenshots
# # TODO: User logins and assigned screenshots will come in a later version
# # elsif user_signed_in?
# # package.screenshots.where(id: (current_user.screenshots.select(:id))) | \
# # package.screenshots.where(approved: true).order('created_at DESC')
# else
# package.screenshots.where(uploaderhash: session.id.to_s) | \
# package.screenshots.where(approved: true).order('created_at DESC')
# end
# end
def screenshots_visible_to_user(package, user_session)
# Show all screenshots to admins
if current_user && current_user.is_admin?
package.screenshots
# Show screenshots belonging to the user or public/approved
else
package.screenshots.where(
uploaderhash: user_session.id.to_s
).or(
package.screenshots.where(
approved: true
)
)
end
end
def screenshot_uploaded_by_current_user?(screenshot)
screenshot.uploaderhash == session.id.to_s
end
# Return the description and/or the version of the package # Return the description and/or the version of the package
def screenshot_caption(screenshot) def screenshot_caption(screenshot)
str = [] str = []
@ -78,9 +38,7 @@ module PackagesHelper
def status_text(screenshot) def status_text(screenshot)
# TODO: markedfordelete/reporting will be removed # TODO: markedfordelete/reporting will be removed
if screenshot.markedfordelete if screenshot.approved
"Removal requested > #{screenshot.delete_reason}"
elsif screenshot.approved
fa_icon('check-square') + ' Public' fa_icon('check-square') + ' Public'
else else
fa_icon('hourglass') + ' Waiting for approval' fa_icon('hourglass') + ' Waiting for approval'

56
app/models/ability.rb Normal file
View file

@ -0,0 +1,56 @@
# frozen_string_literal: true
class Ability
include CanCan::Ability
def initialize(user)
# Define abilities for the passed in user here. For example:
#
# user ||= User.new # guest user (not logged in)
# if user.admin?
# can :manage, :all
# else
# can :read, :all
# end
#
# The first argument to `can` is the action you are giving the user
# permission to do.
# If you pass :manage it will apply to every action. Other common actions
# here are :read, :create, :update and :destroy.
#
# The second argument is the resource the user can perform the action on.
# If you pass :all it will apply to every resource. Otherwise pass a Ruby
# class of the resource.
#
# The third argument is an optional hash of conditions to further filter the
# objects.
# For example, here the user can only update published articles.
#
# can :update, Article, :published => true
#
# See the wiki for details:
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
if user.present? # Logged-in users
if user.admin_role?
can :approve, Screenshot
can :destroy, Screenshot
can :destroy, User
can :view, Screenshot
can :destroy, Package
end
if user.moderator_role?
can :approve, Screenshot
can :view, Screenshot
can :destroy, Screenshot
end
if user.pseudo?
# Allow to view all public/approved screenshots
can :view, Screenshot, approved: true
# Allow to view any own uploads (even not-yet-approved)
can :view, Screenshot, user_id: user.id
end
end
end
end

View file

@ -53,7 +53,7 @@ class Package < ApplicationRecord
# Return a list of packages that have screenshots to be moderated # Return a list of packages that have screenshots to be moderated
def self.need_moderation def self.need_moderation
Package.joins(:screenshots).where('screenshots.approved=false or screenshots.markedfordelete=true').distinct(:name) Package.joins(:screenshots).where('screenshots.approved=false').distinct(:name)
end end
@ -71,7 +71,7 @@ class Package < ApplicationRecord
# Return a query of all approved/public screenshots of this package # Return a query of all approved/public screenshots of this package
def screenshots_pending def screenshots_pending
self.screenshots.where('approved=false or markedfordelete=true') self.screenshots.where('approved=false')
end end
# Return a list of packages that have unapproved screenshots # Return a list of packages that have unapproved screenshots

View file

@ -10,11 +10,6 @@ class Screenshot < ApplicationRecord
# Shrine # Shrine
include ImageUploader::Attachment(:simage) # adds an `simage` virtual attribute include ImageUploader::Attachment(:simage) # adds an `simage` virtual attribute
# Calculate how many days ago this screenshot has been uploaded
def age
time_ago_in_words(self.created_at)
end
# Return caption for full-screen screenshots. # Return caption for full-screen screenshots.
# Takes the description of a screenshot if available. # Takes the description of a screenshot if available.
# Otherwise it falls back to the general description of its package. # Otherwise it falls back to the general description of its package.
@ -54,19 +49,16 @@ class Screenshot < ApplicationRecord
# Brief text describing the status of this screenshots (for admins) # Brief text describing the status of this screenshots (for admins)
def adminstatus def adminstatus
if self.markedfordelete if self.approved
"Removal requested > #{self.delete_reason}"
elsif self.approved
'Public' 'Public'
else else
fa_icon('hourglass') + 'Waiting for approval' #fa_icon('hourglass') + 'Waiting for approval'
'Waiting for approval'
end end
end end
# Publish a screenshot from the moderation queue # Publish a screenshot from the moderation queue
def approve! def approve!
self.delete_reason = nil
self.markedfordelete = false
self.approved = true self.approved = true
self.save! self.save!
end end
@ -76,35 +68,6 @@ class Screenshot < ApplicationRecord
self.order(created_at: :desc).where(approved: true).first self.order(created_at: :desc).where(approved: true).first
end end
# Returns true if the current user has administrative permissions
# def can_admin?
# self.admin == 1
# end
# Returns true if the current user can upload screenshots without moderation
# def can_upload_without_moderation?
# # Admins can upload without moderation
# true if self.can_admin
# # Authenticated users with at least one approved screenshot
# #true if self.screenshots.where(approved: true).count >= 1
# # Other visitors require moderation
# false
# end
# Returns true if the current user can delete screenshots
# def can_delete?
# # Admins can delete screenshots
# true if self.can_admin
# # Authenticated users with at least one approved screenshot
# #true if self.screenshots.where(approved: true).count >= 1
# # Other visitors require moderation
# false
# end
# Return the part of the version up to the first - or + # Return the part of the version up to the first - or +
def upstream_version def upstream_version
self.version.split(/[\-\+]/).first self.version.split(/[\-\+]/).first

View file

@ -40,10 +40,6 @@ class User < ApplicationRecord
end end
end end
def is_admin?
self.admin == 1
end
# Check if a user has been created on-the-fly and is just an # Check if a user has been created on-the-fly and is just an
# anonymous user who uploaded a screenshot. They can turn this # anonymous user who uploaded a screenshot. They can turn this
# user record into a registered account though. # user record into a registered account though.
@ -59,6 +55,11 @@ class User < ApplicationRecord
user.name = auth.info.name user.name = auth.info.name
# Set a random password # Set a random password
user.password = Devise.friendly_token[0,20] user.password = Devise.friendly_token[0,20]
# Users coming through salsa.debian.net/OpenID-Connect will get moderator role
if user.email.end_with?('@debian.org') && user.provider=='salsa'
user.moderator_role = true
end
end end
end end
@ -66,20 +67,18 @@ class User < ApplicationRecord
self.screenshots.where(approved: true) self.screenshots.where(approved: true)
end end
# Seamlessly create a user account for the current client. # Seamlessly create a user account for the current visitor.
# It helps track uploads because uploaded screenshots get assigned # It helps track uploads because uploaded screenshots get assigned
# to this user record. The user can later decide to use a real # to this user record.
# account and get their screenshots transferred to that. # TODO: The user can later decide to use a real account and get their screenshots transferred to that.
# def self.create_pseudo_user def self.create_pseudo_user
# generated_password = Devise.friendly_token.first(8) generated_password = Devise.friendly_token.first(8)
# new_user = User.create( new_user = User.create(
# name: 'Anonymous', name: 'Anonymous',
# password: generated_password) password: generated_password,
# Log.log "New pseudo user for anonymous upload created: #{new_user}" pseudo: true
# sign_in new_user )
# end Log.log "New pseudo user for anonymous upload created: #{new_user}"
# return new_user
# Currently the approach is different: do not create an account end
# for a user. Instead store the IDs of the uploaded screenshots
# and transfer them if the user decides to do a real login using SSO.
end end

View file

@ -15,6 +15,3 @@
/ ' | Cookie is #{session[:token]} / ' | Cookie is #{session[:token]}
= render 'cookies_eu/consent_banner', link: '/about#cookies' = render 'cookies_eu/consent_banner', link: '/about#cookies'
/ = current_user.is_admin?
/ = session.id

View file

@ -31,12 +31,6 @@
a.button.alert.round href=delete_screenshot_path(screenshot) onclick="return confirm('Really delete the screenshot?');" Reject a.button.alert.round href=delete_screenshot_path(screenshot) onclick="return confirm('Really delete the screenshot?');" Reject
a.button.success.round href=approve_screenshot_path(screenshot) Approve a.button.success.round href=approve_screenshot_path(screenshot) Approve
/ Existing screenshots that was requested for removal
- if screenshot.markedfordelete==true
.button-group
a.button.alert.round href=delete_screenshot_path(screenshot) onclick="return confirm('Really delete the screenshot?');" Remove as requested
a.button.success.round href=approve_screenshot_path(screenshot) Keep the screenshot
.small-6.cell .small-6.cell
p Existing screenshots: p Existing screenshots:

View file

@ -7,11 +7,11 @@
= link_to moderate_list_path = link_to moderate_list_path
= fa_icon 'check 2x', text: 'Moderate' = fa_icon 'check 2x', text: 'Moderate'
// Add link if user has uploaded screenshots // Add link if user has uploaded screenshots
- if @current_users_screenshots and @current_users_screenshots.any? / - if @current_users_screenshots and @current_users_screenshots.any?
li class=('active' if controller_name=='my' and action_name=='uploads') / li class=('active' if controller_name=='my' and action_name=='uploads')
= link_to my_uploads_path / = link_to my_uploads_path
= fa_icon 'image 2x', text: 'My uploads' / = fa_icon 'image 2x', text: 'My uploads'
' My uploads / ' My uploads
li li
= link_to destroy_user_session_path, method: :delete = link_to destroy_user_session_path, method: :delete

View file

@ -27,8 +27,8 @@
h2 Number of screenshots you uploaded h2 Number of screenshots you uploaded
p = current_user.screenshots.count p = current_user.screenshots.count
- if current_user.is_admin? / - if current_user.is_admin?
h2 Admin / h2 Admin
p Apparently you are an administrator. Be careful with that thing! / p Apparently you are an administrator. Be careful with that thing!
/ - you can moderate
tt = current_user.inspect / - you can …

View file

@ -16,8 +16,8 @@
- @current_users_screenshots.each do |screenshot| - @current_users_screenshots.each do |screenshot|
.column .column
/ TODO: old Paperclip style / TODO: old Paperclip style
a.black.fancybox href=screenshot.image.variant(resize_to_limit: [800,600], timestamp: false) a.black.fancybox href=screenshot.simage_url(:large)
div.grid-thumbnail div.grid-thumbnail
= image_tag(screenshot.image.variant(resize_to_limit: [160,120]), alt: screenshot.caption, class: 'thumbnail') = image_tag(screenshot.simage_url(:medium), alt: screenshot.caption, class: 'thumbnail')
div div
= screenshot.description = screenshot.description

View file

@ -1,7 +1,13 @@
// Button that reveals a dropdown/modal for moderation/reporting // Button that reveals a dropdown/modal for moderation/reporting
- if can?(:destroy, screenshot) || can?(:approve, screenshot)
.text
span.label.secondary
= status_text(screenshot)
.button-group.small.align-center .button-group.small.align-center
- if (screenshot_uploaded_by_current_user?(screenshot) || (current_user && current_user.is_admin?)) - if can?(:destroy, screenshot)
a.button.small.bordered.radius.alert[ a.button.small.bordered.radius.alert[
href=delete_screenshot_path(screenshot.id) href=delete_screenshot_path(screenshot.id)
onclick="return confirm('Really delete the screenshot?');" onclick="return confirm('Really delete the screenshot?');"
@ -15,29 +21,15 @@
/ href='#' / href='#'
/ ] #{fa_icon 'star'} Make primary / ] #{fa_icon 'star'} Make primary
- if not screenshot.approved - unless screenshot.approved
- if current_user && current_user.is_admin? - if can?(:approve, screenshot)
a.button.small.success[ a.button.small.success[
href=approve_screenshot_path(screenshot.id) href=approve_screenshot_path(screenshot.id)
method='post' method='post'
] Approve ] #{fa_icon 'check'} Approve
/ - elsif screenshot.markedfordelete
/ a.button.small.success[
/ href=approve_screenshot_path(screenshot.id)
/ method='post'
/ ] Keep
/ Display additional information to admins / Display additional information to admins
p Status: #{screenshot.adminstatus} / p Status: #{screenshot.adminstatus}
p Uploader IP=#{screenshot.uploaderip} / p Uploader IP=#{screenshot.uploaderip}
p Uploader Token=#{session[:token]} / p Uploader Token=#{session[:token]}
p Uploaded #{screenshot.age} ago (#{screenshot.created_at}) / p Uploaded #{time_ago_in_words(screenshot.created_at)} ago (#{screenshot.created_at})
/ TODO: Move reporting screenshots to an extra page with a form and captcha
/ - else
/ / Allow anonymous users to report inappropriate screenshots
/ = form_tag(report_screenshot_path(screenshot.id))
/ = text_area_tag 'delete_reason', nil, class: 'input-group-field', maxlength: 100, rows: 3, cols: 50
/ = submit_tag 'Request removal', class: 'button alert'

View file

@ -1,12 +0,0 @@
// Button that reveals a dropdown/modal for users (for their own screenshots)
.text-right
button.small.dropdown.warning.button type="button" data-toggle="admin-info-#{screenshot.id}"
'Request removal
.dropdown-pane data-dropdown=true id="admin-info-#{screenshot.id}"
p If you think this screenshot does not meet the guidelines
or is misleading or not useful then please report it so that
the moderators can review it. Just let us know why you think
the screenshot should get removed:
= form_tag(report_screenshot_path(screenshot.id))
= text_area_tag 'delete_reason', nil, class: 'input-group-field', maxlength: 100, rows: 3, cols: 50
= submit_tag 'Request removal', class: 'button alert'

View file

@ -25,24 +25,13 @@
.text .text
= screenshot.caption = screenshot.caption
// Has the unmoderated screenshot been uploaded by the current user? // Has the unmoderated screenshot been uploaded by the current user?
- if screenshot_uploaded_by_current_user?(screenshot) - if current_user.screenshots.include?(screenshot)
.text .text
span.label.secondary span.label.secondary
' Uploaded by you ' Uploaded by you
- unless screenshot.approved - unless screenshot.approved
' (needs to be approved) ' (needs to be approved)
= render(partial: 'admin_buttons', locals: {screenshot: screenshot}) = render(partial: 'admin_buttons', locals: {screenshot: screenshot})
// Is the user an admin?
// or does the screenshot belong to the user (determined by session cookie)
- if current_user && current_user.is_admin?
hr
.text
span.label.secondary
= status_text(screenshot)
= render(partial: 'admin_buttons', locals: {screenshot: screenshot})
/ - elsif user_signed_in? and screenshot.user == current_user
/ = render(partial: 'user_dropdown', locals: {screenshot: screenshot})
// Second paginator at the bottom so the user does not have to scroll up again // Second paginator at the bottom so the user does not have to scroll up again

View file

@ -0,0 +1,10 @@
class DropDeprecatedScreenshotsFields < ActiveRecord::Migration[6.1]
def change
remove_column :screenshots, :markedfordelete
remove_column :screenshots, :delete_reason
remove_column :screenshots, :image_file_name
remove_column :screenshots, :image_content_type
remove_column :screenshots, :image_file_size
remove_column :screenshots, :image_updated_at
end
end

View file

@ -0,0 +1,14 @@
# Rename the :admin field to :admin_role and change integer to boolean
class AddRolesToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :admin_role, :boolean, default: false
User.find_each do |user|
user.admin_role=true if user.admin>0
user.save!
end
remove_column :users, :admin
add_column :users, :moderator_role, :boolean, default: false
end
end

View file

@ -0,0 +1,8 @@
# Create a pseudo flag for accounts that get automatically created.
# If an anonymous visitor uploads a screenshot he will get a
# pseudo account to assign the screenshots to.
class AddPseudoColumnToUser < ActiveRecord::Migration[6.1]
def change
add_column :users, :pseudo, :boolean, default: false
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_02_22_102719) do ActiveRecord::Schema.define(version: 2021_02_28_191717) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -88,14 +88,8 @@ ActiveRecord::Schema.define(version: 2021_02_22_102719) do
t.datetime "created_at" t.datetime "created_at"
t.string "uploaderhash", limit: 72 t.string "uploaderhash", limit: 72
t.boolean "approved", default: false, null: false t.boolean "approved", default: false, null: false
t.boolean "markedfordelete"
t.string "delete_reason", limit: 100
t.text "description" t.text "description"
t.datetime "updated_at" t.datetime "updated_at"
t.string "image_file_name"
t.string "image_content_type"
t.integer "image_file_size"
t.datetime "image_updated_at"
t.string "image_fingerprint" t.string "image_fingerprint"
t.integer "user_id", default: 0 t.integer "user_id", default: 0
t.text "simage_data" t.text "simage_data"
@ -120,7 +114,9 @@ ActiveRecord::Schema.define(version: 2021_02_22_102719) do
t.datetime "locked_at" t.datetime "locked_at"
t.string "provider" t.string "provider"
t.string "uid" t.string "uid"
t.integer "admin", default: 0 t.boolean "admin_role", default: false
t.boolean "moderator_role", default: false
t.boolean "pseudo", default: false
t.index ["email", "provider"], name: "index_users_on_email_and_provider", unique: true t.index ["email", "provider"], name: "index_users_on_email_and_provider", unique: true
end end

View file

@ -6,8 +6,6 @@
# uploaderhash: MyString # uploaderhash: MyString
# uploaderip: MyString # uploaderip: MyString
# approved: # approved:
# markedfordelete:
# delete_reason: MyString
# description: MyString # description: MyString
# two: # two:
@ -16,6 +14,4 @@
# uploaderhash: MyString # uploaderhash: MyString
# uploaderip: MyString # uploaderip: MyString
# approved: # approved:
# markedfordelete:
# delete_reason: MyString
# description: MyString # description: MyString