Merge blocking branch to head.
This commit is contained in:
commit
32f8631671
37 changed files with 948 additions and 24 deletions
|
@ -178,6 +178,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'startchangeset'",nil,nil) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so Potlatch can't write any changes to the database." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
|
||||
# close previous changeset and add comment
|
||||
if closeid
|
||||
|
@ -472,7 +473,8 @@ class AmfController < ApplicationController
|
|||
def findgpx(searchterm, usertoken)
|
||||
amf_handle_error_with_timeout("'findgpx'" ,nil,nil) do
|
||||
user = getuser(usertoken)
|
||||
if !uid then return -1,"You must be logged in to search for GPX traces.",[] end
|
||||
if !user then return -1,"You must be logged in to search for GPX traces.",[] end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked'),[] end
|
||||
|
||||
gpxs = []
|
||||
if searchterm.to_i>0 then
|
||||
|
@ -538,6 +540,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'putrelation' #{relid}" ,'relation',relid) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so the relation could not be saved." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if !tags_ok(tags) then return -1,"One of the tags is invalid. Please pester Adobe to fix Flash on Linux." end
|
||||
tags = strip_non_xml_chars tags
|
||||
|
||||
|
@ -625,6 +628,7 @@ class AmfController < ApplicationController
|
|||
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so the way could not be saved." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if pointlist.length < 2 then return -2,"Server error - way is only #{points.length} points long." end
|
||||
if !tags_ok(attributes) then return -1,"One of the tags is invalid. Please pester Adobe to fix Flash on Linux." end
|
||||
attributes = strip_non_xml_chars attributes
|
||||
|
@ -729,6 +733,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'putpoi' #{id}", 'node',id) do
|
||||
user = getuser(usertoken)
|
||||
if !user then return -1,"You are not logged in, so the point could not be saved." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
if !tags_ok(tags) then return -1,"One of the tags is invalid. Please pester Adobe to fix Flash on Linux." end
|
||||
tags = strip_non_xml_chars tags
|
||||
|
||||
|
@ -811,6 +816,7 @@ class AmfController < ApplicationController
|
|||
amf_handle_error("'deleteway' #{way_id}" ,'way',id) do
|
||||
user = getuser(usertoken)
|
||||
unless user then return -1,"You are not logged in, so the way could not be deleted." end
|
||||
unless user.active_blocks.empty? then return -1,t('application.setup_user_auth.blocked') end
|
||||
|
||||
way_id = way_id.to_i
|
||||
nodeversions = {}
|
||||
|
|
|
@ -78,6 +78,12 @@ class ApplicationController < ActionController::Base
|
|||
@user = User.authenticate(:username => username, :password => passwd) # basic auth
|
||||
end
|
||||
end
|
||||
|
||||
# check if the user has been banned
|
||||
unless @user.nil? or @user.active_blocks.empty?
|
||||
# NOTE: need slightly more helpful message than this.
|
||||
render :text => t('application.setup_user_auth.blocked'), :status => :forbidden
|
||||
end
|
||||
end
|
||||
|
||||
def authorize(realm='Web Password', errormessage="Couldn't authenticate you")
|
||||
|
|
156
app/controllers/user_blocks_controller.rb
Normal file
156
app/controllers/user_blocks_controller.rb
Normal file
|
@ -0,0 +1,156 @@
|
|||
class UserBlocksController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
before_filter :require_user, :only => [:new, :create, :edit, :update, :revoke]
|
||||
before_filter :require_moderator, :only => [:create, :update, :revoke]
|
||||
before_filter :lookup_this_user, :only => [:new, :create, :blocks_on, :blocks_by]
|
||||
before_filter :lookup_user_block, :only => [:show, :edit, :update, :revoke]
|
||||
before_filter :require_valid_params, :only => [:create, :update]
|
||||
before_filter :check_database_readable
|
||||
before_filter :check_database_writable, :only => [:create, :update, :revoke]
|
||||
|
||||
def index
|
||||
@user_blocks_pages, @user_blocks = paginate(:user_blocks,
|
||||
:include => [:user, :creator, :revoker],
|
||||
:order => "user_blocks.ends_at DESC",
|
||||
:per_page => 20)
|
||||
end
|
||||
|
||||
def show
|
||||
if @user and @user.id == @user_block.user_id
|
||||
@user_block.needs_view = false
|
||||
@user_block.save!
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@user_block = UserBlock.new
|
||||
end
|
||||
|
||||
def edit
|
||||
params[:user_block_period] = ((@user_block.ends_at - Time.now.getutc) / 1.hour).ceil.to_s
|
||||
end
|
||||
|
||||
def create
|
||||
unless @valid_params
|
||||
redirect_to :action => "new"
|
||||
return
|
||||
end
|
||||
|
||||
@user_block = UserBlock.new(:user_id => @this_user.id,
|
||||
:creator_id => @user.id,
|
||||
:reason => params[:user_block][:reason],
|
||||
:ends_at => Time.now.getutc() + @block_period.hours,
|
||||
:needs_view => params[:user_block][:needs_view])
|
||||
|
||||
if @user_block.save
|
||||
flash[:notice] = t('user_block.create.flash', :name => @this_user.display_name)
|
||||
redirect_to @user_block
|
||||
else
|
||||
render :action => "new"
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
unless @valid_params
|
||||
redirect_to :action => "edit"
|
||||
return
|
||||
end
|
||||
|
||||
if @user_block.creator_id != @user.id
|
||||
flash[:notice] = t('user_block.update.only_creator_can_edit')
|
||||
redirect_to :action => "edit"
|
||||
return
|
||||
end
|
||||
|
||||
if @user_block.update_attributes({ :ends_at => Time.now.getutc() + @block_period.hours,
|
||||
:reason => params[:user_block][:reason],
|
||||
:needs_view => params[:user_block][:needs_view] })
|
||||
flash[:notice] = t('user_block.update.success')
|
||||
redirect_to(@user_block)
|
||||
else
|
||||
render :action => "edit"
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# revokes the block, setting the end_time to now
|
||||
def revoke
|
||||
if params[:confirm]
|
||||
if @user_block.revoke! @user
|
||||
flash[:notice] = t'user_block.revoke.flash'
|
||||
redirect_to(@user_block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# shows a list of all the blocks on the given user
|
||||
def blocks_on
|
||||
@user_blocks_pages, @user_blocks = paginate(:user_blocks,
|
||||
:include => [:user, :creator, :revoker],
|
||||
:conditions => {:user_id => @this_user.id},
|
||||
:order => "user_blocks.ends_at DESC",
|
||||
:per_page => 20)
|
||||
end
|
||||
|
||||
##
|
||||
# shows a list of all the blocks by the given user.
|
||||
def blocks_by
|
||||
@user_blocks_pages, @user_blocks = paginate(:user_blocks,
|
||||
:include => [:user, :creator, :revoker],
|
||||
:conditions => {:creator_id => @this_user.id},
|
||||
:order => "user_blocks.ends_at DESC",
|
||||
:per_page => 20)
|
||||
end
|
||||
|
||||
private
|
||||
##
|
||||
# require that the user is a moderator, or fill out a helpful error message
|
||||
# and return them to the blocks index.
|
||||
def require_moderator
|
||||
unless @user.moderator?
|
||||
flash[:notice] = t('user_block.filter.not_a_moderator')
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "this_user" instance variable
|
||||
def lookup_this_user
|
||||
@this_user = User.find_by_display_name(params[:display_name])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] unless @this_user
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "user_block" instance variable
|
||||
def lookup_user_block
|
||||
@user_block = UserBlock.find(params[:id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render :action => "not_found", :status => :not_found
|
||||
end
|
||||
|
||||
##
|
||||
# check that the input parameters are valid, setting an instance
|
||||
# variable if not. note that this doesn't do any redirection, as it's
|
||||
# called before two different actions, each of which should redirect
|
||||
# to a different place.
|
||||
def require_valid_params
|
||||
@block_period = params[:user_block_period].to_i
|
||||
@valid_params = false
|
||||
|
||||
if !UserBlock::PERIODS.include?(@block_period)
|
||||
flash[:notice] = t('user_block.filter.block_period')
|
||||
|
||||
elsif @user_block and !@user_block.active?
|
||||
flash[:notice] = t('user_block.filter.block_expired')
|
||||
|
||||
else
|
||||
@valid_params = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -142,9 +142,28 @@ class UserController < ApplicationController
|
|||
end
|
||||
|
||||
def login
|
||||
if params[:user] and session[:user].nil?
|
||||
email_or_display_name = params[:user][:email]
|
||||
pass = params[:user][:password]
|
||||
user = User.authenticate(:username => email_or_display_name, :password => pass)
|
||||
if user
|
||||
session[:user] = user.id
|
||||
elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true)
|
||||
@notice = t 'user.login.account not active'
|
||||
else
|
||||
@notice = t 'user.login.auth failure'
|
||||
end
|
||||
end
|
||||
|
||||
if session[:user]
|
||||
# The user is logged in already, if the referer param exists, redirect them to that
|
||||
if params[:referer]
|
||||
# The user is logged in, if the referer param exists, redirect them to that
|
||||
# unless they've also got a block on them, in which case redirect them to
|
||||
# the block so they can clear it.
|
||||
user = User.find(session[:user])
|
||||
block = user.blocked_on_view
|
||||
if block
|
||||
redirect_to block, :referrer => params[:referrer]
|
||||
elsif params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'site', :action => 'index'
|
||||
|
@ -153,25 +172,6 @@ class UserController < ApplicationController
|
|||
end
|
||||
|
||||
@title = t 'user.login.title'
|
||||
|
||||
if params[:user]
|
||||
email_or_display_name = params[:user][:email]
|
||||
pass = params[:user][:password]
|
||||
user = User.authenticate(:username => email_or_display_name, :password => pass)
|
||||
if user
|
||||
session[:user] = user.id
|
||||
if params[:referer]
|
||||
redirect_to params[:referer]
|
||||
else
|
||||
redirect_to :controller => 'site', :action => 'index'
|
||||
end
|
||||
return
|
||||
elsif User.authenticate(:username => email_or_display_name, :password => pass, :inactive => true)
|
||||
@notice = t 'user.login.account not active'
|
||||
else
|
||||
@notice = t 'user.login.auth failure'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def logout
|
||||
|
|
83
app/controllers/user_roles_controller.rb
Normal file
83
app/controllers/user_roles_controller.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
class UserRolesController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :require_user
|
||||
before_filter :lookup_this_user
|
||||
before_filter :require_administrator
|
||||
before_filter :require_valid_role
|
||||
before_filter :not_in_role, :only => [:grant]
|
||||
before_filter :in_role, :only => [:revoke]
|
||||
around_filter :setup_nonce
|
||||
|
||||
def grant
|
||||
@this_user.roles.create(:role => @role, :granter_id => @user.id)
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => @this_user.display_name
|
||||
end
|
||||
|
||||
def revoke
|
||||
UserRole.delete_all({:user_id => @this_user.id, :role => @role})
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => @this_user.display_name
|
||||
end
|
||||
|
||||
private
|
||||
def require_administrator
|
||||
unless @user.administrator?
|
||||
flash[:notice] = t'user_role.filter.not_an_administrator'
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => @this_user.display_name
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# ensure that there is a "this_user" instance variable
|
||||
def lookup_this_user
|
||||
@this_user = User.find_by_display_name(params[:display_name])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name] unless @this_user
|
||||
end
|
||||
|
||||
##
|
||||
# the random nonce here which isn't predictable, making an CSRF
|
||||
# procedure much, much more difficult. setup the nonce. if the given
|
||||
# nonce matches the session nonce then yield into the actual method.
|
||||
# otherwise, just sets up the nonce for the form.
|
||||
def setup_nonce
|
||||
if params[:nonce] and params[:nonce] == session[:nonce]
|
||||
@nonce = params[:nonce]
|
||||
yield
|
||||
else
|
||||
@nonce = OAuth::Helper.generate_nonce
|
||||
session[:nonce] = @nonce
|
||||
render
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# require that the given role is valid. the role is a URL
|
||||
# parameter, so should always be present.
|
||||
def require_valid_role
|
||||
@role = params[:role]
|
||||
unless UserRole::ALL_ROLES.include?(@role)
|
||||
flash[:notice] = t('user_role.filter.not_a_role', :role => @role)
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => @this_user.display_name
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# checks that the user doesn't already have this role
|
||||
def not_in_role
|
||||
if @this_user.has_role? @role
|
||||
flash[:notice] = t('user_role.filter.already_has_role', :role => @role)
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => @this_user.display_name
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# checks that the user already has this role
|
||||
def in_role
|
||||
unless @this_user.has_role? @role
|
||||
flash[:notice] = t('user_role.filter.doesnt_have_role', :role => @role)
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => @this_user.display_name
|
||||
end
|
||||
end
|
||||
end
|
20
app/helpers/user_blocks_helper.rb
Normal file
20
app/helpers/user_blocks_helper.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
module UserBlocksHelper
|
||||
##
|
||||
# returns a translated string representing the status of the
|
||||
# user block (i.e: whether it's active, what the expiry time is)
|
||||
def block_status(block)
|
||||
if block.active?
|
||||
if block.needs_view?
|
||||
I18n.t('user_block.helper.until_login')
|
||||
else
|
||||
I18n.t('user_block.helper.time_future', :time => distance_of_time_in_words_to_now(block.ends_at))
|
||||
end
|
||||
else
|
||||
# the max of the last update time or the ends_at time is when this block finished
|
||||
# either because the user viewed the block (updated_at) or it expired or was
|
||||
# revoked (ends_at)
|
||||
last_time = [block.ends_at, block.updated_at].max
|
||||
I18n.t('user_block.helper.time_past', :time => distance_of_time_in_words_to_now(last_time))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,6 +14,9 @@ class User < ActiveRecord::Base
|
|||
has_many :client_applications
|
||||
has_many :oauth_tokens, :class_name => "OauthToken", :order => "authorized_at desc", :include => [:client_application]
|
||||
|
||||
has_many :active_blocks, :class_name => "UserBlock", :conditions => ['user_blocks.ends_at > \'#{Time.now.getutc.xmlschema(5)}\' or user_blocks.needs_view']
|
||||
has_many :roles, :class_name => "UserRole"
|
||||
|
||||
validates_presence_of :email, :display_name
|
||||
validates_confirmation_of :email#, :message => ' addresses must match'
|
||||
validates_confirmation_of :pass_crypt#, :message => ' must match the confirmation password'
|
||||
|
@ -125,6 +128,31 @@ class User < ActiveRecord::Base
|
|||
return false
|
||||
end
|
||||
|
||||
##
|
||||
# returns true if the user has the moderator role, false otherwise
|
||||
def moderator?
|
||||
has_role? 'moderator'
|
||||
end
|
||||
|
||||
##
|
||||
# returns true if the user has the administrator role, false otherwise
|
||||
def administrator?
|
||||
has_role? 'administrator'
|
||||
end
|
||||
|
||||
##
|
||||
# returns true if the user has the requested role
|
||||
def has_role?(role)
|
||||
roles.any? { |r| r.role == role }
|
||||
end
|
||||
|
||||
##
|
||||
# returns the first active block which would require users to view
|
||||
# a message, or nil if there are none.
|
||||
def blocked_on_view
|
||||
active_blocks.detect { |b| b.needs_view? }
|
||||
end
|
||||
|
||||
def delete
|
||||
self.active = false
|
||||
self.display_name = "user_#{self.id}"
|
||||
|
|
35
app/models/user_block.rb
Normal file
35
app/models/user_block.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
class UserBlock < ActiveRecord::Base
|
||||
validate :moderator_permissions
|
||||
|
||||
belongs_to :user, :class_name => "User", :foreign_key => :user_id
|
||||
belongs_to :creator, :class_name => "User", :foreign_key => :creator_id
|
||||
belongs_to :revoker, :class_name => "User", :foreign_key => :revoker_id
|
||||
|
||||
PERIODS = APP_CONFIG['user_block_periods']
|
||||
|
||||
##
|
||||
# returns true if the block is currently active (i.e: the user can't
|
||||
# use the API).
|
||||
def active?
|
||||
needs_view or ends_at > Time.now.getutc
|
||||
end
|
||||
|
||||
##
|
||||
# revokes the block, allowing the user to use the API again. the argument
|
||||
# is the user object who is revoking the ban.
|
||||
def revoke!(revoker)
|
||||
update_attributes({ :ends_at => Time.now.getutc(),
|
||||
:revoker_id => revoker.id,
|
||||
:needs_view => false })
|
||||
end
|
||||
|
||||
private
|
||||
##
|
||||
# validate that only moderators are allowed to change the
|
||||
# block. this should be caught and dealt with in the controller,
|
||||
# but i've also included it here just in case.
|
||||
def moderator_permissions
|
||||
errors.add_to_base(I18n.t('user_block.model.non_moderator_update')) if creator_id_changed? and !creator.moderator?
|
||||
errors.add_to_base(I18n.t('user_block.model.non_moderator_revoke')) unless revoker_id.nil? or revoker.moderator?
|
||||
end
|
||||
end
|
8
app/models/user_role.rb
Normal file
8
app/models/user_role.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
class UserRole < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
ALL_ROLES = ['administrator', 'moderator']
|
||||
|
||||
validates_inclusion_of :role, :in => ALL_ROLES
|
||||
validates_uniqueness_of :role, :scope => :user_id
|
||||
end
|
|
@ -1,4 +1,15 @@
|
|||
<h2><%= h(@this_user.display_name) %></h2>
|
||||
<h2><%= h(@this_user.display_name) %>
|
||||
<% UserRole::ALL_ROLES.each do |role| %>
|
||||
<% if @user and @user.administrator? %>
|
||||
<% if @this_user.has_role? role %>
|
||||
<%= link_to(image_tag("roles/#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.revoke.#{role}"), :title => t("user.view.role.revoke.#{role}")), :controller => 'user_roles', :action => 'revoke', :display_name => @this_user.display_name, :role => role) %>
|
||||
<% else %>
|
||||
<%= link_to(image_tag("roles/blank_#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.grant.#{role}"), :title => t("user.view.role.grant.#{role}")), :controller => 'user_roles', :action => 'grant', :display_name => @this_user.display_name, :role => role) %>
|
||||
<% end %>
|
||||
<% elsif @this_user.has_role? role %>
|
||||
<%= image_tag("roles/#{role}.png", :size => "20x20", :border => 0, :alt => t("user.view.role.#{role}"), :title => t("user.view.role.#{role}")) %>
|
||||
<% end %>
|
||||
<% end %></h2>
|
||||
<div id="userinformation">
|
||||
<% if @user and @this_user.id == @user.id %>
|
||||
<!-- Displaying user's own profile page -->
|
||||
|
@ -7,6 +18,10 @@
|
|||
| <%= link_to t('user.view.my edits'), :controller => 'changeset', :action => 'list', :display_name => @user.display_name %>
|
||||
| <%= link_to t('user.view.my traces'), :controller => 'trace', :action=>'mine' %>
|
||||
| <%= link_to t('user.view.my settings'), :controller => 'user', :action => 'account', :display_name => @user.display_name %>
|
||||
| <%= link_to t('user.view.blocks on me'), :controller => 'user_blocks', :action => 'blocks_on', :display_name => @user.display_name %>
|
||||
<% if @user and @user.moderator? %>
|
||||
| <%= link_to t('user.view.blocks by me'), :controller => 'user_blocks', :action => 'blocks_by', :display_name => @user.display_name %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<!-- Displaying another user's profile page -->
|
||||
<%= link_to t('user.view.send message'), :controller => 'message', :action => 'new', :display_name => @this_user.display_name %>
|
||||
|
@ -18,6 +33,13 @@
|
|||
<% else %>
|
||||
<%= link_to t('user.view.add as friend'), :controller => 'user', :action => 'make_friend', :display_name => @this_user.display_name %>
|
||||
<% end %>
|
||||
| <%= link_to t('user.view.block_history'), :controller => 'user_blocks', :action => 'blocks_on', :display_name => @this_user.display_name %>
|
||||
<% if @this_user.moderator? %>
|
||||
| <%= link_to t('user.view.moderator_history'), :controller => 'user_blocks', :action => 'blocks_by', :display_name => @this_user.display_name %>
|
||||
<% end %>
|
||||
<% if @user and @user.moderator? %>
|
||||
| <%= link_to t('user.view.create_block'), :controller => 'user_blocks', :action => 'new', :display_name => @this_user.display_name %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
24
app/views/user_blocks/_block.html.erb
Normal file
24
app/views/user_blocks/_block.html.erb
Normal file
|
@ -0,0 +1,24 @@
|
|||
<tr>
|
||||
<% c1 = cycle('table0', 'table1') %>
|
||||
|
||||
<% if show_user_name %>
|
||||
<td class="<%= c1 %>"><%= link_to h(block.user.display_name), :controller => 'user', :action => 'view', :display_name => block.user.display_name %></td>
|
||||
<% end %>
|
||||
<% if show_creator_name %>
|
||||
<td class="<%= c1 %>"><%= link_to h(block.creator.display_name), :controller => 'user', :action => 'view', :display_name => block.creator.display_name %></td>
|
||||
<% end %>
|
||||
<td class="<%= c1 %>"><%=h truncate(block.reason) %></td>
|
||||
<td class="<%= c1 %>"><%=h block_status(block) %></td>
|
||||
<td class="<%= c1 %>">
|
||||
<% if block.revoker_id.nil? %>
|
||||
<%= t('user_block.partial.not_revoked') %>
|
||||
<% else %>
|
||||
<%= link_to h(block.revoker.display_name), :controller => 'user', :action => 'view', :display_name => block.revoker.display_name %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td class="<%= c1 %>"><%= link_to t('user_block.partial.show'), block %></td>
|
||||
<td class="<%= c1 %>"><% if @user and @user.id == block.creator_id and block.active? %><%= link_to t('user_block.partial.edit'), edit_user_block_path(block) %><% end %></td>
|
||||
<% if show_revoke_link %>
|
||||
<td class="<%= c1 %>"><% if block.active? %><%= link_to t('user_block.partial.revoke'), block, :confirm => t('user_block.partial.confirm'), :action => :revoke %><% end %></td>
|
||||
<% end %>
|
||||
</tr>
|
23
app/views/user_blocks/_blocks.html.erb
Normal file
23
app/views/user_blocks/_blocks.html.erb
Normal file
|
@ -0,0 +1,23 @@
|
|||
<% unless @user_blocks.empty? %>
|
||||
<table id="block_list" cellpadding="3">
|
||||
<tr>
|
||||
<% if show_user_name %>
|
||||
<th><%= t'user_block.partial.display_name' %></th>
|
||||
<% end %>
|
||||
<% if show_creator_name %>
|
||||
<th><%= t'user_block.partial.creator_name' %></th>
|
||||
<% end %>
|
||||
<th><%= t'user_block.partial.reason' %></th>
|
||||
<th><%= t'user_block.partial.status' %></th>
|
||||
<th><%= t'user_block.partial.revoker_name' %></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<% if show_revoke_link %>
|
||||
<th></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
<%= render :partial => 'block', :locals => {:show_revoke_link => show_revoke_link, :show_user_name => show_user_name, :show_creator_name => show_creator_name }, :collection => @user_blocks %>
|
||||
</table>
|
||||
<% else %>
|
||||
<p><%= t "user_block.#{blocks_by_on}.empty", :name => h(@this_user.display_name) %></p>
|
||||
<% end %>
|
4
app/views/user_blocks/blocks_by.html.erb
Normal file
4
app/views/user_blocks/blocks_by.html.erb
Normal file
|
@ -0,0 +1,4 @@
|
|||
<% @title = t('user_block.blocks_by.title', :name => h(@this_user.display_name)) %>
|
||||
<h1><%= t('user_block.blocks_by.heading', :name => link_to(h(@this_user.display_name), {:controller => 'user', :action => 'view', :display_name => @this_user.display_name})) %></h1>
|
||||
|
||||
<%= render :partial => 'blocks', :locals => { :blocks_by_on => 'blocks_by', :show_revoke_link => (@user and @user.moderator?), :show_user_name => true, :show_creator_name => false } %>
|
4
app/views/user_blocks/blocks_on.html.erb
Normal file
4
app/views/user_blocks/blocks_on.html.erb
Normal file
|
@ -0,0 +1,4 @@
|
|||
<% @title = t('user_block.blocks_on.title', :name => h(@this_user.display_name)) %>
|
||||
<h1><%= t('user_block.blocks_on.heading', :name => link_to(h(@this_user.display_name), {:controller => 'user', :action => 'view', :display_name => @this_user.display_name})) %></h1>
|
||||
|
||||
<%= render :partial => 'blocks', :locals => { :blocks_by_on => 'blocks_on', :show_revoke_link => (@user and @user.moderator?), :show_user_name => false, :show_creator_name => true } %>
|
28
app/views/user_blocks/edit.html.erb
Normal file
28
app/views/user_blocks/edit.html.erb
Normal file
|
@ -0,0 +1,28 @@
|
|||
<% @title = t 'user_block.edit.title', :name => h(@user_block.user.display_name) %>
|
||||
<h1><%= t('user_block.edit.title',
|
||||
:name => link_to(
|
||||
h(@user_block.user.display_name),
|
||||
{:controller => 'user', :action => 'view', :display_name => @user_block.user.display_name})) %></h1>
|
||||
|
||||
<% form_for(@user_block) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
|
||||
<p>
|
||||
<%= f.label :reason, t('user_block.edit.reason', :name => h(@user_block.user.display_name)) %><br />
|
||||
<%= f.text_area :reason, :cols => 80, :rows => 5 %>
|
||||
</p>
|
||||
<p>
|
||||
<%= label_tag 'user_block_period', t('user_block.edit.period') %><br />
|
||||
<%= select_tag('user_block_period', options_for_select(UserBlock::PERIODS.collect { |h| [t('user_block.period', :count => h), h.to_s] }, params[:user_block_period])) %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.check_box :needs_view %>
|
||||
<%= f.label :needs_view, t('user_block.edit.needs_view') %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.submit t('user_block.edit.submit') %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= link_to t('user_block.edit.show'), @user_block %> |
|
||||
<%= link_to t('user_block.edit.back'), user_blocks_path %>
|
4
app/views/user_blocks/index.html.erb
Normal file
4
app/views/user_blocks/index.html.erb
Normal file
|
@ -0,0 +1,4 @@
|
|||
<% @title = t('user_block.index.title') %>
|
||||
<h1><%= t('user_block.index.heading') %></h1>
|
||||
|
||||
<%= render :partial => 'blocks', :locals => { :show_revoke_link => (@user and @user.moderator?), :show_user_name => true, :show_creator_name => true } %>
|
28
app/views/user_blocks/new.html.erb
Normal file
28
app/views/user_blocks/new.html.erb
Normal file
|
@ -0,0 +1,28 @@
|
|||
<% @title = t 'user_block.new.title', :name => h(@this_user.display_name) %>
|
||||
<h1><%= t('user_block.new.heading',
|
||||
:name => link_to(
|
||||
h(@this_user.display_name),
|
||||
{:controller => 'user', :action => 'view', :display_name => @this_user.display_name})) %></h1>
|
||||
|
||||
<% form_for(@user_block) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
|
||||
<p>
|
||||
<%= f.label :reason, t('user_block.new.reason', :name => @this_user.display_name) %><br />
|
||||
<%= f.text_area :reason, :cols => 80, :rows => 5 %>
|
||||
</p>
|
||||
<p>
|
||||
<%= label_tag 'user_block_period', t('user_block.new.period') %><br />
|
||||
<%= select_tag('user_block_period', options_for_select(UserBlock::PERIODS.collect { |h| [t('user_block.period', :count => h), h.to_s] }, params[:user_block_period] )) %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.check_box :needs_view %>
|
||||
<%= f.label :needs_view, t('user_block.new.needs_view') %>
|
||||
</p>
|
||||
<p>
|
||||
<%= hidden_field_tag 'display_name', @this_user.display_name %>
|
||||
<%= f.submit t('user_block.new.submit') %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= link_to t('user_block.new.back'), user_blocks_path %>
|
3
app/views/user_blocks/not_found.html.erb
Normal file
3
app/views/user_blocks/not_found.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<p><%= t'user_block.not_found.sorry', :id => params[:id] %></p>
|
||||
|
||||
<%= link_to t('user_block.not_found.back'), user_blocks_path %>
|
32
app/views/user_blocks/revoke.html.erb
Normal file
32
app/views/user_blocks/revoke.html.erb
Normal file
|
@ -0,0 +1,32 @@
|
|||
<% @title = t('user_block.revoke.title',
|
||||
:block_on => h(@user_block.user.display_name),
|
||||
:block_by => h(@user_block.creator.display_name)) %>
|
||||
<h1><%= t('user_block.revoke.heading',
|
||||
:block_on => link_to(
|
||||
h(@user_block.user.display_name),
|
||||
{:controller => 'user', :action => 'view', :display_name => @user_block.user.display_name}),
|
||||
:block_by => link_to(
|
||||
h(@user_block.creator.display_name),
|
||||
{:controller => 'user', :action => 'view', :display_name => @user_block.creator.display_name})) %></h1>
|
||||
|
||||
<% if @user_block.ends_at > Time.now %>
|
||||
<p><b>
|
||||
<%= t('user_block.revoke.time_future', :time => distance_of_time_in_words_to_now(@user_block.ends_at)) %>
|
||||
</b></p>
|
||||
|
||||
<% form_for :revoke, :url => { :action => "revoke" } do |f| %>
|
||||
<%= f.error_messages %>
|
||||
<p>
|
||||
<%= check_box_tag 'confirm', 'yes' %>
|
||||
<%= label_tag 'confirm', t('user_block.revoke.confirm') %>
|
||||
</p>
|
||||
<p>
|
||||
<%= submit_tag t('user_block.revoke.revoke') %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<% else %>
|
||||
<p>
|
||||
<%= t('user_block.revoke.past', :time => distance_of_time_in_words_to_now(@user_block.ends_at)) %>
|
||||
</p>
|
||||
<% end %>
|
34
app/views/user_blocks/show.html.erb
Normal file
34
app/views/user_blocks/show.html.erb
Normal file
|
@ -0,0 +1,34 @@
|
|||
<% @title = t('user_block.show.title',
|
||||
:block_on => @user_block.user.display_name,
|
||||
:block_by => @user_block.creator.display_name) %>
|
||||
<h1><%= t('user_block.show.heading',
|
||||
:block_on => link_to(
|
||||
h(@user_block.user.display_name),
|
||||
{:controller => 'user', :action => 'view', :display_name => @user_block.user.display_name}),
|
||||
:block_by => link_to(
|
||||
h(@user_block.creator.display_name),
|
||||
{:controller => 'user', :action => 'view', :display_name => @user_block.creator.display_name})) %></h1>
|
||||
<% if @user_block.revoker %>
|
||||
<p>
|
||||
<b><%= t'user_block.show.revoker' %></b>
|
||||
<%= link_to h(@user_block.revoker.display_name), :controller => 'user', :action => 'view', :display_name => @user_block.revoker.display_name %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p><b><%= t'user_block.show.status' %></b>: <%= block_status(@user_block) %></p>
|
||||
|
||||
<p>
|
||||
<b><%= t'user_block.show.reason' %></b>
|
||||
<%=h @user_block.reason %>
|
||||
</p>
|
||||
|
||||
|
||||
<% if @user_block.ends_at > Time.now.getutc %>
|
||||
<% if @user and @user.id == @user_block.creator_id %>
|
||||
<%= link_to t('user_block.show.edit'), edit_user_block_path(@user_block) %> |
|
||||
<% end %>
|
||||
<% if @user and @user.moderator? %>
|
||||
<%= link_to(t('user_block.show.revoke'),{:controller => 'user_blocks', :action => 'revoke', :id => @user_block.id}) %> |
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= link_to t('user_block.show.back'), user_blocks_path %>
|
7
app/views/user_roles/grant.html.erb
Normal file
7
app/views/user_roles/grant.html.erb
Normal file
|
@ -0,0 +1,7 @@
|
|||
<% form_tag request.request_uri do %>
|
||||
<%= hidden_field_tag 'nonce', @nonce %>
|
||||
<% @title = t('user_role.grant.heading') %>
|
||||
<h1><%= t('user_role.grant.heading') %></h1>
|
||||
<p><%= t('user_role.grant.are_you_sure', :name => params[:display_name], :role => params[:role]) %></p>
|
||||
<p><%= submit_tag t('user_role.grant.confirm') %></p>
|
||||
<% end %>
|
7
app/views/user_roles/revoke.html.erb
Normal file
7
app/views/user_roles/revoke.html.erb
Normal file
|
@ -0,0 +1,7 @@
|
|||
<% form_tag request.request_uri do %>
|
||||
<%= hidden_field_tag 'nonce', @nonce %>
|
||||
<% @title = t('user_role.revoke.heading') %>
|
||||
<h1><%= t('user_role.revoke.heading') %></h1>
|
||||
<p><%= t('user_role.revoke.are_you_sure', :name => params[:display_name], :role => params[:role]) %></p>
|
||||
<p><%= submit_tag t'user_role.revoke.confirm' %></p>
|
||||
<% end %>
|
|
@ -13,6 +13,8 @@ standard_settings: &standard_settings
|
|||
geonames_zoom: 12
|
||||
# Timeout for API calls in seconds
|
||||
api_timeout: 300
|
||||
# Periods (in hours) which are allowed for user blocks
|
||||
user_block_periods: [0, 1, 3, 6, 12, 24, 48, 96]
|
||||
|
||||
development:
|
||||
<<: *standard_settings
|
||||
|
|
|
@ -805,6 +805,9 @@ en:
|
|||
scheduled_for_deletion: "Track scheduled for deletion"
|
||||
make_public:
|
||||
made_public: "Track made public"
|
||||
application:
|
||||
setup_user_auth:
|
||||
blocked: "Your access to the API has been blocked. Please log-in to the web interface to find out more."
|
||||
oauth:
|
||||
oauthorize:
|
||||
request_access: "The application {{app_name}} is requesting access to your account. Please check whether you would like the application to have the following capabilities. You may choose as many or as few as you like."
|
||||
|
@ -924,6 +927,8 @@ en:
|
|||
my edits: my edits
|
||||
my traces: my traces
|
||||
my settings: my settings
|
||||
blocks on me: blocks on me
|
||||
blocks by me: blocks by me
|
||||
send message: send message
|
||||
diary: diary
|
||||
edits: edits
|
||||
|
@ -949,6 +954,18 @@ en:
|
|||
no nearby users: "There are no users who admit to mapping nearby yet."
|
||||
change your settings: change your settings
|
||||
my_oauth_details: "View my OAuth details"
|
||||
role:
|
||||
administrator: "This user is an administrator"
|
||||
moderator: "This user is a moderator"
|
||||
grant:
|
||||
administrator: "Grant administrator access"
|
||||
moderator: "Grant moderator access"
|
||||
revoke:
|
||||
administrator: "Revoke administrator access"
|
||||
moderator: "Revoke moderator access"
|
||||
block_history: "view blocks received"
|
||||
moderator_history: "view blocks given"
|
||||
create_block: "block this user"
|
||||
friend_map:
|
||||
your location: Your location
|
||||
nearby mapper: "Nearby mapper: [[nearby_user]]"
|
||||
|
@ -998,6 +1015,112 @@ en:
|
|||
remove_friend:
|
||||
success: "{{name}} was removed from your friends."
|
||||
not_a_friend: "{{name}} is not one of your friends."
|
||||
user_role:
|
||||
filter:
|
||||
not_an_administrator: "Only administrators can perform user role management, and you are not an administrator."
|
||||
not_a_role: "The string `{{role}}' isn't a valid role."
|
||||
already_has_role: "The user already has role {{role}}."
|
||||
doesnt_have_role: "The user does not have role {{role}}."
|
||||
grant:
|
||||
title: Confirm role granting
|
||||
heading: Confirm role granting
|
||||
are_you_sure: "Are you sure you want to grant the role `{{role}}' to the user `{{name}}'?"
|
||||
confirm: "Confirm"
|
||||
fail: "Couldn't grant role `{{role}}' to user `{{name}}'. Please check that the user and role are both valid."
|
||||
revoke:
|
||||
title: Confirm role revoking
|
||||
heading: Confirm role revoking
|
||||
are_you_sure: "Are you sure you want to revoke the role `{{role}}' from the user `{{name}}'?"
|
||||
confirm: "Confirm"
|
||||
fail: "Couldn't revoke role `{{role}}' from user `{{name}}'. Please check that the user and role are both valid."
|
||||
user_block:
|
||||
model:
|
||||
non_moderator_update: "Must be a moderator to create or update a block."
|
||||
non_moderator_revoke: "Must be a moderator to revoke a block."
|
||||
not_found:
|
||||
sorry: "Sorry, the user block with ID {{id}} could not be found."
|
||||
back: "Back to index"
|
||||
new:
|
||||
title: "Creating block on {{name}}"
|
||||
heading: "Creating block on {{name}}"
|
||||
reason: "The reason why {{name}} is being blocked. Please be as calm and as reasonable as possible, giving as much detail as you can about the situation, remembering that the message will be publicly visible. Bear in mind that not all users understand the community jargon, so please try to use laymans terms."
|
||||
period: "How long, starting now, the user will be blocked from the API for."
|
||||
submit: "Create block"
|
||||
tried_contacting: "I have contacted the user and asked them to stop."
|
||||
tried_waiting: "I have given a reasonable amount of time for the user to respond to those communications."
|
||||
needs_view: "Does the user need to log in before this block will be cleared?"
|
||||
back: "View all blocks"
|
||||
edit:
|
||||
title: "Editing block on {{name}}"
|
||||
heading: "Editing block on {{name}}"
|
||||
reason: "The reason why {{name}} is being blocked. Please be as calm and as reasonable as possible, giving as much detail as you can about the situation. Bear in mind that not all users understand the community jargon, so please try to use laymans terms."
|
||||
period: "How long, starting now, the user will be blocked from the API for."
|
||||
submit: "Update block"
|
||||
show: "View this block"
|
||||
back: "View all blocks"
|
||||
needs_view: "Does the user need to log in before this block will be cleared?"
|
||||
filter:
|
||||
not_a_moderator: "You need to be a moderator to perform that action."
|
||||
block_expired: "The block has already expired and cannot be edited."
|
||||
block_period: "The blocking period must be one of the values selectable in the drop-down list."
|
||||
create:
|
||||
try_contacting: "Please try contacting the user before blocking them and giving them a reasonable time to respond."
|
||||
try_waiting: "Please try giving the user a reasonable time to respond before blocking them."
|
||||
flash: "Created a block on user {{name}}."
|
||||
update:
|
||||
only_creator_can_edit: "Only the moderator who created this block can edit it."
|
||||
success: "Block updated."
|
||||
index:
|
||||
title: "User blocks"
|
||||
heading: "List of user blocks"
|
||||
revoke:
|
||||
title: "Revoking block on {{block_on}}"
|
||||
heading: "Revoking block on {{block_on}} by {{block_by}}"
|
||||
time_future: "This block will end in {{time}}."
|
||||
past: "This block ended {{time}} ago and cannot be revoked now."
|
||||
confirm: "Are you sure you wish to revoke this block?"
|
||||
revoke: "Revoke!"
|
||||
flash: "This block has been revoked."
|
||||
period:
|
||||
one: "1 hour"
|
||||
other: "{{count}} hours"
|
||||
partial:
|
||||
show: "Show"
|
||||
edit: "Edit"
|
||||
revoke: "Revoke!"
|
||||
confirm: "Are you sure?"
|
||||
display_name: "Blocked User"
|
||||
creator_name: "Creator"
|
||||
reason: "Reason for block"
|
||||
status: "Status"
|
||||
revoker_name: "Revoked by"
|
||||
not_revoked: "(not revoked)"
|
||||
helper:
|
||||
time_future: "Ends in {{time}}."
|
||||
until_login: "Active until the user logs in."
|
||||
time_past: "Ended {{time}} ago."
|
||||
blocks_on:
|
||||
title: "Blocks on {{name}}"
|
||||
heading: "List of blocks on {{name}}"
|
||||
empty: "{{name}} has not been blocked yet."
|
||||
blocks_by:
|
||||
title: "Blocks by {{name}}"
|
||||
heading: "List of blocks by {{name}}"
|
||||
empty: "{{name}} has not made any blocks yet."
|
||||
show:
|
||||
title: "{{block_on}} blocked by {{block_by}}"
|
||||
heading: "{{block_on}} blocked by {{block_by}}"
|
||||
time_future: "Ends in {{time}}"
|
||||
time_past: "Ended {{time}} ago"
|
||||
status: "Status"
|
||||
show: "Show"
|
||||
edit: "Edit"
|
||||
revoke: "Revoke!"
|
||||
confirm: "Are you sure?"
|
||||
reason: "Reason for block:"
|
||||
back: "View all blocks"
|
||||
revoker: "Revoker:"
|
||||
needs_view: "The user needs to log in before this block will be cleared."
|
||||
javascripts:
|
||||
map:
|
||||
base:
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
ActionController::Routing::Routes.draw do |map|
|
||||
|
||||
# API
|
||||
map.connect "api/capabilities", :controller => 'api', :action => 'capabilities'
|
||||
map.connect "api/#{API_VERSION}/capabilities", :controller => 'api', :action => 'capabilities'
|
||||
|
@ -202,6 +201,15 @@ ActionController::Routing::Routes.draw do |map|
|
|||
map.access_token '/oauth/access_token', :controller => 'oauth', :action => 'access_token'
|
||||
map.test_request '/oauth/test_request', :controller => 'oauth', :action => 'test_request'
|
||||
|
||||
# roles and banning pages
|
||||
map.connect '/user/:display_name/role/:role/grant', :controller => 'user_roles', :action => 'grant'
|
||||
map.connect '/user/:display_name/role/:role/revoke', :controller => 'user_roles', :action => 'revoke'
|
||||
map.connect '/user/:display_name/blocks', :controller => 'user_blocks', :action => 'blocks_on'
|
||||
map.connect '/user/:display_name/blocks_by', :controller => 'user_blocks', :action => 'blocks_by'
|
||||
map.resources :user_blocks, :as => 'blocks'
|
||||
map.connect '/blocks/:id/revoke', :controller => 'user_blocks', :action => 'revoke'
|
||||
map.connect '/blocks/new/:display_name', :controller => 'user_blocks', :action => 'new'
|
||||
|
||||
# fall through
|
||||
map.connect ':controller/:id/:action'
|
||||
map.connect ':controller/:action'
|
||||
|
|
32
db/migrate/044_create_user_roles.rb
Normal file
32
db/migrate/044_create_user_roles.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
require 'lib/migrate'
|
||||
|
||||
class CreateUserRoles < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_enumeration :user_role_enum, ["administrator", "moderator"]
|
||||
|
||||
create_table :user_roles do |t|
|
||||
t.column :user_id, :bigint, :null => false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
add_column :user_roles, :role, :user_role_enum, :null => false
|
||||
|
||||
User.all(:conditions => ['administrator = ?', true]).each do |user|
|
||||
UserRole.create(:user_id => user.id, :role => "administrator")
|
||||
end
|
||||
remove_column :users, :administrator
|
||||
|
||||
add_foreign_key :user_roles, [:user_id], :users, [:id]
|
||||
end
|
||||
|
||||
def self.down
|
||||
add_column :users, :administrator, :boolean, :default => false, :null => false
|
||||
UserRole.all(:conditions => ['role = ?', "administrator"]).each do |role|
|
||||
user = User.find(role.user_id)
|
||||
user.administrator = true
|
||||
user.save!
|
||||
end
|
||||
drop_table :user_roles
|
||||
drop_enumeration :user_role_enum
|
||||
end
|
||||
end
|
26
db/migrate/045_create_user_blocks.rb
Normal file
26
db/migrate/045_create_user_blocks.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require 'lib/migrate'
|
||||
|
||||
class CreateUserBlocks < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :user_blocks do |t|
|
||||
t.column :user_id, :bigint, :null => false
|
||||
t.column :moderator_id, :bigint, :null => false
|
||||
t.column :reason, :text, :null => false
|
||||
t.column :end_at, :datetime, :null => false
|
||||
t.column :needs_view, :boolean, :null => false, :default => false
|
||||
t.column :revoker_id, :bigint
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_foreign_key :user_blocks, [:user_id], :users, [:id]
|
||||
add_foreign_key :user_blocks, [:moderator_id], :users, [:id]
|
||||
add_foreign_key :user_blocks, [:revoker_id], :users, [:id]
|
||||
|
||||
add_index :user_blocks, [:user_id]
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :user_blocks
|
||||
end
|
||||
end
|
29
db/migrate/046_alter_user_roles_and_blocks.rb
Normal file
29
db/migrate/046_alter_user_roles_and_blocks.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
require 'lib/migrate'
|
||||
|
||||
class AlterUserRolesAndBlocks < ActiveRecord::Migration
|
||||
def self.up
|
||||
# the initial granter IDs can be "self" - there are none of these
|
||||
# in the current live DB, but there may be some in people's own local
|
||||
# copies.
|
||||
add_column :user_roles, :granter_id, :bigint
|
||||
UserRole.update_all("granter_id = user_id")
|
||||
change_column :user_roles, :granter_id, :bigint, :null => false
|
||||
add_foreign_key :user_roles, [:granter_id], :users, [:id]
|
||||
|
||||
# make sure that [user_id, role] is unique
|
||||
add_index :user_roles, [:user_id, :role], :name => "user_roles_id_role_unique", :unique => true
|
||||
|
||||
# change the user_blocks to have a creator_id rather than moderator_id
|
||||
rename_column :user_blocks, :moderator_id, :creator_id
|
||||
|
||||
# change the "end_at" column to the more grammatically correct "ends_at"
|
||||
rename_column :user_blocks, :end_at, :ends_at
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :user_roles, :granter_id
|
||||
remove_index :user_roles, :name => "user_roles_id_role_unique"
|
||||
rename_column :user_blocks, :creator_id, :moderator_id
|
||||
rename_column :user_blocks, :ends_at, :end_at
|
||||
end
|
||||
end
|
12
public/403.html
Normal file
12
public/403.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<body>
|
||||
<img src="http://www.openstreetmap.org/images/osm_logo.png" style="float:left; margin:10px">
|
||||
<div style="float:left;">
|
||||
<h1>Forbidden</h1>
|
||||
<p>The operation you requested on the OpenStreetMap server is only available to administrators (HTTP 403)</p>
|
||||
<p>Feel free to <a href="http://wiki.openstreetmap.org/wiki/Contact" title="Various contact channels explained">contact</a> the OpenStreetMap community if you have found a broken link / bug. Make a note of the exact URL of your request.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
BIN
public/images/roles/administrator.png
Normal file
BIN
public/images/roles/administrator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 910 B |
BIN
public/images/roles/blank_administrator.png
Normal file
BIN
public/images/roles/blank_administrator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 824 B |
BIN
public/images/roles/blank_moderator.png
Normal file
BIN
public/images/roles/blank_moderator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 839 B |
BIN
public/images/roles/moderator.png
Normal file
BIN
public/images/roles/moderator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 958 B |
11
test/fixtures/user_roles.yml
vendored
Normal file
11
test/fixtures/user_roles.yml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
|
||||
administrator:
|
||||
user_id: 6
|
||||
role: administrator
|
||||
granter_id: 6
|
||||
|
||||
moderator:
|
||||
user_id: 5
|
||||
role: moderator
|
||||
granter_id: 6
|
17
test/fixtures/users.yml
vendored
17
test/fixtures/users.yml
vendored
|
@ -51,3 +51,20 @@ second_public_user:
|
|||
home_lon: 87
|
||||
home_zoom: 12
|
||||
|
||||
moderator_user:
|
||||
id: 5
|
||||
email: moderator@example.com
|
||||
active: true
|
||||
pass_crypt: <%= Digest::MD5.hexdigest('test') %>
|
||||
creation_time: "2008-05-01 01:23:45"
|
||||
display_name: moderator
|
||||
data_public: true
|
||||
|
||||
administrator_user:
|
||||
id: 6
|
||||
email: administrator@example.com
|
||||
active: true
|
||||
pass_crypt: <%= Digest::MD5.hexdigest('test') %>
|
||||
creation_time: "2008-05-01 01:23:45"
|
||||
display_name: administrator
|
||||
data_public: true
|
||||
|
|
56
test/integration/user_blocks_test.rb
Normal file
56
test/integration/user_blocks_test.rb
Normal file
|
@ -0,0 +1,56 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class UserBlocksTest < ActionController::IntegrationTest
|
||||
fixtures :users, :user_blocks, :user_roles
|
||||
|
||||
def auth_header(user, pass)
|
||||
{"HTTP_AUTHORIZATION" => "Basic %s" % Base64.encode64("#{user}:#{pass}")}
|
||||
end
|
||||
|
||||
def test_api_blocked
|
||||
blocked_user = users(:public_user)
|
||||
|
||||
get "/api/#{API_VERSION}/user/details"
|
||||
assert_response :unauthorized
|
||||
|
||||
get "/api/#{API_VERSION}/user/details", nil, auth_header(blocked_user.display_name, "test")
|
||||
assert_response :success
|
||||
|
||||
# now block the user
|
||||
UserBlock.create(:user_id => blocked_user.id,
|
||||
:creator_id => users(:moderator_user).id,
|
||||
:reason => "testing",
|
||||
:ends_at => Time.now.getutc + 5.minutes)
|
||||
get "/api/#{API_VERSION}/user/details", nil, auth_header(blocked_user.display_name, "test")
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
def test_api_revoke
|
||||
blocked_user = users(:public_user)
|
||||
moderator = users(:moderator_user)
|
||||
|
||||
block = UserBlock.create(:user_id => blocked_user.id,
|
||||
:creator_id => moderator.id,
|
||||
:reason => "testing",
|
||||
:ends_at => Time.now.getutc + 5.minutes)
|
||||
get "/api/#{API_VERSION}/user/details", nil, auth_header(blocked_user.display_name, "test")
|
||||
assert_response :forbidden
|
||||
|
||||
# revoke the ban
|
||||
post '/login', {'user[email]' => moderator.email, 'user[password]' => "test", :referer => "/blocks/#{block.id}/revoke"}
|
||||
assert_response :redirect
|
||||
follow_redirect!
|
||||
assert_response :success
|
||||
assert_template 'user_blocks/revoke'
|
||||
post "/blocks/#{block.id}/revoke", {'confirm' => "yes"}
|
||||
assert_response :redirect
|
||||
follow_redirect!
|
||||
assert_response :success
|
||||
assert_template 'user_blocks/show'
|
||||
reset!
|
||||
|
||||
# access the API again. this time it should work
|
||||
get "/api/#{API_VERSION}/user/details", nil, auth_header(blocked_user.display_name, "test")
|
||||
assert_response :success
|
||||
end
|
||||
end
|
46
test/integration/user_roles_test.rb
Normal file
46
test/integration/user_roles_test.rb
Normal file
|
@ -0,0 +1,46 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class UserRolesControllerTest < ActionController::IntegrationTest
|
||||
fixtures :users, :user_roles
|
||||
|
||||
test "grant" do
|
||||
check_fail(:grant, :public_user, :moderator)
|
||||
check_fail(:grant, :moderator_user, :moderator)
|
||||
check_success(:grant, :administrator_user, :moderator)
|
||||
end
|
||||
|
||||
test "revoke" do
|
||||
check_fail(:revoke, :public_user, :moderator)
|
||||
check_fail(:revoke, :moderator_user, :moderator)
|
||||
# this other user doesn't have moderator role, so this fails
|
||||
check_fail(:revoke, :administrator_user, :moderator)
|
||||
end
|
||||
|
||||
def check_fail(action, user, role)
|
||||
post '/login', {'user[email]' => users(user).email, 'user[password]' => "test", :referer => "/"}
|
||||
assert_response :redirect
|
||||
follow_redirect!
|
||||
assert_response :success
|
||||
|
||||
get "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}"
|
||||
assert_response :redirect
|
||||
assert_redirected_to :controller => 'user', :action => 'view', :display_name => users(:second_public_user).display_name
|
||||
|
||||
reset!
|
||||
end
|
||||
|
||||
def check_success(action, user, role)
|
||||
post '/login', {'user[email]' => users(user).email, 'user[password]' => "test", :referer => "/"}
|
||||
assert_response :redirect
|
||||
follow_redirect!
|
||||
assert_response :success
|
||||
|
||||
get "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}"
|
||||
assert_response :success
|
||||
post "/user/#{users(:second_public_user).display_name}/role/#{role}/#{action}", {:confirm => "yes", :nonce => session[:nonce]}
|
||||
assert_response :redirect
|
||||
assert_redirected_to :controller => 'user', :action => 'view', :display_name => users(:second_public_user).display_name
|
||||
|
||||
reset!
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue