First version of blocking feature. Allows both time-based (for map protection) and notice-based (for education) blocks on users. Also introduces user roles and a simple UI for displaying and administering these.
This commit is contained in:
parent
52fa09ecae
commit
daa2496024
33 changed files with 766 additions and 23 deletions
|
@ -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.blocks.empty?
|
||||
# NOTE: need slightly more helpful message than this.
|
||||
render :text => "You got banned!", :status => :forbidden
|
||||
end
|
||||
end
|
||||
|
||||
def authorize(realm='Web Password', errormessage="Couldn't authenticate you")
|
||||
|
|
145
app/controllers/user_blocks_controller.rb
Normal file
145
app/controllers/user_blocks_controller.rb
Normal file
|
@ -0,0 +1,145 @@
|
|||
class UserBlocksController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :set_locale
|
||||
before_filter :require_user, :only => [:new, :create, :edit, :delete]
|
||||
before_filter :require_moderator, :only => [:new, :create, :edit, :delete]
|
||||
|
||||
def index
|
||||
@user_blocks_pages, @user_blocks = paginate(:user_blocks,
|
||||
:include => [:user, :moderator, :revoker],
|
||||
:order => "user_blocks.end_at DESC",
|
||||
:per_page => 20)
|
||||
end
|
||||
|
||||
def show
|
||||
@user_block = UserBlock.find(params[:id])
|
||||
|
||||
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
|
||||
@display_name = params[:display_name]
|
||||
@this_user = User.find_by_display_name(@display_name, :conditions => {:visible => true})
|
||||
end
|
||||
|
||||
# GET /user_blocks/1/edit
|
||||
def edit
|
||||
@user_block = UserBlock.find(params[:id])
|
||||
params[:user_block_period] = ((@user_block.end_at - Time.now.getutc) / 1.hour).ceil.to_s
|
||||
end
|
||||
|
||||
def create
|
||||
@display_name = params[:display_name]
|
||||
@this_user = User.find_by_display_name(@display_name, :conditions => {:visible => true})
|
||||
block_period = [UserBlock::PERIODS.max, params[:user_block_period].to_i].min
|
||||
|
||||
@user_block = UserBlock.new(:user_id => @this_user.id,
|
||||
:moderator_id => @user.id,
|
||||
:reason => params[:user_block][:reason],
|
||||
:end_at => Time.now.getutc() + block_period.hours,
|
||||
:needs_view => params[:user_block][:needs_view])
|
||||
|
||||
if (@this_user and @user.moderator? and
|
||||
params[:tried_contacting] == "yes" and
|
||||
params[:tried_waiting] == "yes" and
|
||||
block_period >= 0)
|
||||
if @user_block.save
|
||||
flash[:notice] = t('user_block.create.flash', :name => @display_name)
|
||||
redirect_to @user_block
|
||||
else
|
||||
render :action => "new"
|
||||
end
|
||||
else
|
||||
if !@user.moderator?
|
||||
flash[:notice] = t('user_block.create.not_a_moderator')
|
||||
elsif params[:tried_contacting] != "yes"
|
||||
flash[:notice] = t('user_block.create.try_contacting')
|
||||
elsif params[:tried_waiting] != "yes"
|
||||
flash[:notice] = t('user_block.create.try_waiting')
|
||||
else
|
||||
flash[:notice] = t('user_block.create.bad_parameters')
|
||||
end
|
||||
@display_name = @this_user.nil? ? '' : @this_user.display_name
|
||||
|
||||
render :action => "new"
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@user_block = UserBlock.find(params[:id])
|
||||
block_period = [72, params[:user_block_period].to_i].min
|
||||
|
||||
if @user_block.moderator_id != @user.id
|
||||
flash[:notice] = t('user_block.update.only_creator_can_edit')
|
||||
redirect_to(@user_block)
|
||||
|
||||
elsif !@user_block.active?
|
||||
flash[:notice] = t('user_block.update.block_expired')
|
||||
redirect_to(@user_block)
|
||||
|
||||
elsif @user_block.update_attributes({ :end_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
|
||||
@user_block = UserBlock.find(params[:id])
|
||||
|
||||
if !@user.moderator?
|
||||
flash[:notice] = t('user_block.create.not_a_moderator')
|
||||
redirect_to @user_block
|
||||
|
||||
elsif params[:confirm]
|
||||
if @user_block.revoke!
|
||||
flash[:notice] = t'user_block.revoke.flash'
|
||||
redirect_to(@user_block)
|
||||
else
|
||||
flash[:notice] = t'user_block.revoke.error'
|
||||
render :action => "edit"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# shows a list of all the blocks on the given user
|
||||
def blocks_on
|
||||
@this_user = User.find_by_display_name(params[:display_name])
|
||||
|
||||
@user_blocks_pages, @user_blocks = paginate(:user_blocks,
|
||||
:include => [:user, :moderator, :revoker],
|
||||
:conditions => {:user_id => @this_user.id},
|
||||
:order => "user_blocks.end_at DESC",
|
||||
:per_page => 20)
|
||||
end
|
||||
|
||||
##
|
||||
# shows a list of all the blocks by the given user.
|
||||
def blocks_by
|
||||
@this_user = User.find_by_display_name(params[:display_name])
|
||||
|
||||
@user_blocks_pages, @user_blocks = paginate(:user_blocks,
|
||||
:include => [:user, :moderator, :revoker],
|
||||
:conditions => {:moderator_id => @this_user.id},
|
||||
:order => "user_blocks.end_at DESC",
|
||||
:per_page => 20)
|
||||
end
|
||||
|
||||
private
|
||||
def require_moderator
|
||||
redirect_to "/403.html" unless @user.moderator?
|
||||
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
|
||||
|
|
33
app/controllers/user_roles_controller.rb
Normal file
33
app/controllers/user_roles_controller.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
class UserRolesController < ApplicationController
|
||||
layout 'site'
|
||||
|
||||
before_filter :authorize_web
|
||||
before_filter :require_user
|
||||
before_filter :require_administrator
|
||||
|
||||
def grant
|
||||
this_user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
|
||||
if this_user and UserRole::ALL_ROLES.include? params[:role]
|
||||
this_user.roles.create(:role => params[:role])
|
||||
else
|
||||
flash[:notice] = t('user_role.grant.fail', :role => params[:role], :name => params[:display_name])
|
||||
end
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name]
|
||||
end
|
||||
|
||||
def revoke
|
||||
this_user = User.find_by_display_name(params[:display_name], :conditions => {:visible => true})
|
||||
if this_user and UserRole::ALL_ROLES.include? params[:role]
|
||||
UserRole.delete_all({:user_id => this_user.id, :role => params[:role]})
|
||||
else
|
||||
flash[:notice] = t('user_role.revoke.fail', :role => params[:role], :name => params[:display_name])
|
||||
end
|
||||
redirect_to :controller => 'user', :action => 'view', :display_name => params[:display_name]
|
||||
end
|
||||
|
||||
private
|
||||
def require_administrator
|
||||
redirect_to "/403.html" unless @user.administrator?
|
||||
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 :blocks, :class_name => "UserBlock", :conditions => ["user_blocks.end_at > now() 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 moderator role, false otherwise
|
||||
def administrator?
|
||||
has_role? 'administrator'
|
||||
end
|
||||
|
||||
##
|
||||
# returns true if the user has the requested role
|
||||
def has_role?(role)
|
||||
roles.inject(false) { |x, r| x or 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
|
||||
blocks.inject(nil) { |s,x| s || (x.needs_view? ? x : nil) }
|
||||
end
|
||||
|
||||
def delete
|
||||
self.active = false
|
||||
self.display_name = "user_#{self.id}"
|
||||
|
|
36
app/models/user_block.rb
Normal file
36
app/models/user_block.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
class UserBlock < ActiveRecord::Base
|
||||
validate :moderator_permissions
|
||||
|
||||
belongs_to :user, :class_name => "User", :foreign_key => :user_id
|
||||
belongs_to :moderator, :class_name => "User", :foreign_key => :moderator_id
|
||||
belongs_to :revoker, :class_name => "User", :foreign_key => :revoker_id
|
||||
|
||||
PERIODS = [0, 1, 3, 6, 12, 24, 48, 96]
|
||||
|
||||
##
|
||||
# returns true if the block is currently active (i.e: the user can't
|
||||
# use the API).
|
||||
def active?
|
||||
needs_view or end_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)
|
||||
attrs = { :end_at => Time.now.getutc(),
|
||||
:revoker_id => @user.id,
|
||||
:needs_view => false }
|
||||
revoker.moderator? and update_attributes(attrs)
|
||||
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("Must be a moderator to create or update a block.") if moderator_id_changed? and !moderator.moderator?
|
||||
errors.add_to_base("Must be a moderator to revoke a block.") 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
|
||||
|
||||
ALL_ROLES = ['administrator', 'moderator']
|
||||
|
||||
validates_inclusion_of :role, :in => ALL_ROLES
|
||||
belongs_to :user
|
||||
|
||||
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.#{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.#{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}")) %>
|
||||
<% end %>
|
||||
<% end %></h2>
|
||||
<div id="userinformation">
|
||||
<% if @user and @this_user.id == @user.id %>
|
||||
<!-- Displaying user's own profile page -->
|
||||
|
@ -18,6 +29,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>
|
||||
|
||||
|
|
34
app/views/user_blocks/_block.html.erb
Normal file
34
app/views/user_blocks/_block.html.erb
Normal file
|
@ -0,0 +1,34 @@
|
|||
<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_moderator_name %>
|
||||
<td class="<%= c1 %>"><%= link_to h(block.moderator.display_name), :controller => 'user', :action => 'view', :display_name => block.moderator.display_name %></td>
|
||||
<% end %>
|
||||
<td class="<%= c1 %>"><%=h block.reason %></td>
|
||||
<td class="<%= c1 %>">
|
||||
<% if block.active? %>
|
||||
<% if block.needs_view? %>
|
||||
<%= t'user_block.partial.until_login' %>
|
||||
<% else %>
|
||||
<%= t('user_block.partial.time_future', :time => distance_of_time_in_words_to_now(block.end_at)) %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= t'user_block.partial.not_active' %>
|
||||
<% end %>
|
||||
</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.moderator_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>
|
19
app/views/user_blocks/_blocks.html.erb
Normal file
19
app/views/user_blocks/_blocks.html.erb
Normal file
|
@ -0,0 +1,19 @@
|
|||
<table id="block_list" cellpadding="3">
|
||||
<tr>
|
||||
<% if show_user_name %>
|
||||
<th><%= t'user_block.partial.display_name' %></th>
|
||||
<% end %>
|
||||
<% if show_moderator_name %>
|
||||
<th><%= t'user_block.partial.moderator_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_moderator_name => show_moderator_name }, :collection => @user_blocks unless @user_blocks.nil? %>
|
||||
</table>
|
3
app/views/user_blocks/blocks_by.html.erb
Normal file
3
app/views/user_blocks/blocks_by.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<h1><%= t('user_block.blocks_by.heading', :name => @this_user.display_name) %></h1>
|
||||
|
||||
<%= render :partial => 'blocks', :locals => { :show_revoke_link => (@user and @user.moderator?), :show_user_name => true, :show_moderator_name => false } %>
|
3
app/views/user_blocks/blocks_on.html.erb
Normal file
3
app/views/user_blocks/blocks_on.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<h1><%= t('user_block.blocks_on.heading', :name => @this_user.display_name) %></h1>
|
||||
|
||||
<%= render :partial => 'blocks', :locals => { :show_revoke_link => (@user and @user.moderator?), :show_user_name => false, :show_moderator_name => true } %>
|
25
app/views/user_blocks/edit.html.erb
Normal file
25
app/views/user_blocks/edit.html.erb
Normal file
|
@ -0,0 +1,25 @@
|
|||
<h1><%= t('user_block.edit.title', :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 => @user_block.user.display_name) %><br />
|
||||
<%= f.text_area :reason %>
|
||||
</p>
|
||||
<p>
|
||||
<%= label_tag 'user_block_period', t('user_block.edit.period') %><br />
|
||||
<%= hidden_field_tag 'what is the period', params[:user_block_period] %>
|
||||
<%= 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 %>
|
3
app/views/user_blocks/index.html.erb
Normal file
3
app/views/user_blocks/index.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<h1><%= t('user_block.index.heading') %></h1>
|
||||
|
||||
<%= render :partial => 'blocks', :locals => { :show_revoke_link => (@user and @user.moderator?), :show_user_name => true, :show_moderator_name => true } %>
|
32
app/views/user_blocks/new.html.erb
Normal file
32
app/views/user_blocks/new.html.erb
Normal file
|
@ -0,0 +1,32 @@
|
|||
<h1><%= t('user_block.new.title', :name => @display_name) %></h1>
|
||||
|
||||
<% form_for(@user_block) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
|
||||
<p>
|
||||
<%= check_box_tag 'tried_contacting', 'yes', (params[:tried_contacting] == "yes") %>
|
||||
<%= label_tag 'tried_contacting', t('user_block.new.tried_contacting') %>
|
||||
</p>
|
||||
<p>
|
||||
<%= check_box_tag 'tried_waiting', 'yes', (params[:tried_waiting] == "yes") %>
|
||||
<%= label_tag 'tried_waiting', t('user_block.new.tried_waiting') %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.label :reason, t('user_block.new.reason', :name => @display_name) %><br />
|
||||
<%= f.text_area :reason %>
|
||||
</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', @display_name %>
|
||||
<%= f.submit t('user_block.new.submit') %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= link_to 'Back', user_blocks_path %>
|
25
app/views/user_blocks/revoke.html.erb
Normal file
25
app/views/user_blocks/revoke.html.erb
Normal file
|
@ -0,0 +1,25 @@
|
|||
<h1><%= t('user_block.revoke.heading',
|
||||
:block_on => @user_block.user.display_name,
|
||||
:block_by => @user_block.moderator.display_name) %></h1>
|
||||
|
||||
<% if @user_block.end_at > Time.now %>
|
||||
<p><b>
|
||||
<%= t('user_block.revoke.time_future', :time => distance_of_time_in_words_to_now(@user_block.end_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.end_at)) %>
|
||||
</p>
|
||||
<% end %>
|
38
app/views/user_blocks/show.html.erb
Normal file
38
app/views/user_blocks/show.html.erb
Normal file
|
@ -0,0 +1,38 @@
|
|||
<h1><%= t('user_block.show.heading',
|
||||
:block_on => @user_block.user.display_name,
|
||||
:block_by => @user_block.moderator.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>
|
||||
<% if @user_block.end_at > Time.now %>
|
||||
<%= t('user_block.show.time_future', :time => distance_of_time_in_words_to_now(@user_block.end_at)) %>
|
||||
<% else %>
|
||||
<%= t('user_block.show.time_past', :time => distance_of_time_in_words_to_now(@user_block.end_at)) %>
|
||||
<% end %>
|
||||
</p>
|
||||
|
||||
<% if @user_block.needs_view %>
|
||||
<p><%= t'user_block.show.needs_view' %></p>
|
||||
<% end %>
|
||||
|
||||
<p>
|
||||
<b><%= t'user_block.show.reason' %></b>
|
||||
<%=h @user_block.reason %>
|
||||
</p>
|
||||
|
||||
|
||||
<% if @user_block.end_at > Time.now.getutc %>
|
||||
<% if @user and @user.id == @user_block.moderator_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 %>
|
20
app/views/user_roles/edit.html.erb
Normal file
20
app/views/user_roles/edit.html.erb
Normal file
|
@ -0,0 +1,20 @@
|
|||
<h1>Editing user_role</h1>
|
||||
|
||||
<% form_for(@user_role) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
|
||||
<p>
|
||||
<%= f.label :user_id %><br />
|
||||
<%= f.text_field :user_id %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.label :role %><br />
|
||||
<%= f.text_field :role %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.submit 'Update' %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= link_to 'Show', @user_role %> |
|
||||
<%= link_to 'Back', user_roles_path %>
|
22
app/views/user_roles/index.html.erb
Normal file
22
app/views/user_roles/index.html.erb
Normal file
|
@ -0,0 +1,22 @@
|
|||
<h1>Listing user_roles</h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Role</th>
|
||||
</tr>
|
||||
|
||||
<% @user_roles.each do |user_role| %>
|
||||
<tr>
|
||||
<td><%=h user_role.user_id %></td>
|
||||
<td><%=h user_role.role %></td>
|
||||
<td><%= link_to 'Show', user_role %></td>
|
||||
<td><%= link_to 'Edit', edit_user_role_path(user_role) %></td>
|
||||
<td><%= link_to 'Destroy', user_role, :confirm => 'Are you sure?', :method => :delete %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
<%= link_to 'New user_role', new_user_role_path %>
|
19
app/views/user_roles/new.html.erb
Normal file
19
app/views/user_roles/new.html.erb
Normal file
|
@ -0,0 +1,19 @@
|
|||
<h1>New user_role</h1>
|
||||
|
||||
<% form_for(@user_role) do |f| %>
|
||||
<%= f.error_messages %>
|
||||
|
||||
<p>
|
||||
<%= f.label :user_id %><br />
|
||||
<%= f.text_field :user_id %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.label :role %><br />
|
||||
<%= f.text_field :role %>
|
||||
</p>
|
||||
<p>
|
||||
<%= f.submit 'Create' %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%= link_to 'Back', user_roles_path %>
|
13
app/views/user_roles/show.html.erb
Normal file
13
app/views/user_roles/show.html.erb
Normal file
|
@ -0,0 +1,13 @@
|
|||
<p>
|
||||
<b>User:</b>
|
||||
<%=h @user_role.user_id %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Role:</b>
|
||||
<%=h @user_role.role %>
|
||||
</p>
|
||||
|
||||
|
||||
<%= link_to 'Edit', edit_user_role_path(@user_role) %> |
|
||||
<%= link_to 'Back', user_roles_path %>
|
|
@ -944,6 +944,12 @@ 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: "Administrator"
|
||||
moderator: "Moderator"
|
||||
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]]"
|
||||
|
@ -993,3 +999,78 @@ en:
|
|||
remove_friend:
|
||||
success: "{{name}} was removed from your friends."
|
||||
not_a_friend: "{{name}} is not one of your friends."
|
||||
user_role:
|
||||
grant:
|
||||
fail: "Couldn't grant role `{{role}}' to user `{{name}}'. Please check that the user and role are both valid."
|
||||
revoke:
|
||||
fail: "Couldn't revoke role `{{role}}' from user `{{name}}'. Please check that the user and role are both valid."
|
||||
user_block:
|
||||
new:
|
||||
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: "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."
|
||||
title: "Creating block on {{name}}"
|
||||
needs_view: "Does the user need to log in before this block will be cleared?"
|
||||
edit:
|
||||
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: "Show"
|
||||
back: "Back"
|
||||
title: "Editing block on {{name}}"
|
||||
needs_view: "Does the user need to log in before this block will be cleared?"
|
||||
create:
|
||||
not_a_moderator: "User block could not be created: you are not a moderator."
|
||||
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."
|
||||
bad_parameters: "Could not create a new block due to bad parameters. Maybe the blocking period is not valid?"
|
||||
flash: "Created a block on user {{name}}."
|
||||
update:
|
||||
only_creator_can_edit: "Only the moderator who created this block can edit it."
|
||||
block_expired: "The block has already expired and cannot be edited."
|
||||
success: "Block updated."
|
||||
index:
|
||||
heading: "Listing User Blocks"
|
||||
revoke:
|
||||
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"
|
||||
moderator_name: "Moderator"
|
||||
reason: "Reason for block"
|
||||
status: "Status"
|
||||
revoker_name: "Revoked by"
|
||||
not_revoked: "(not revoked)"
|
||||
time_future: "Ends in {{time}}"
|
||||
until_login: "Until the user logs in"
|
||||
not_active: "(not active)"
|
||||
blocks_on:
|
||||
heading: "List blocks on {{name}}"
|
||||
blocks_by:
|
||||
heading: "List blocks by {{name}}"
|
||||
show:
|
||||
heading: "Block on {{block_on}} by {{block_by}}"
|
||||
time_future: "Ends in {{time}}"
|
||||
time_past: "Ended {{time}} ago"
|
||||
show: "Show"
|
||||
edit: "Edit"
|
||||
revoke: "Revoke!"
|
||||
confirm: "Are you sure?"
|
||||
reason: "Reason for block:"
|
||||
back: "Back"
|
||||
revoker: "Revoker:"
|
||||
needs_view: "The user needs to log in before this block will be cleared."
|
||||
|
||||
|
|
|
@ -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,14 @@ 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'
|
||||
|
||||
# fall through
|
||||
map.connect ':controller/:id/:action'
|
||||
map.connect ':controller/:action'
|
||||
|
|
33
db/migrate/044_create_user_roles.rb
Normal file
33
db/migrate/044_create_user_roles.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
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]
|
||||
add_index :user_roles, [:user_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
|
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 |
9
test/fixtures/user_roles.yml
vendored
Normal file
9
test/fixtures/user_roles.yml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
|
||||
administrator:
|
||||
user_id: 6
|
||||
role: administrator
|
||||
|
||||
moderator:
|
||||
user_id: 5
|
||||
role: moderator
|
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
|
||||
|
|
28
test/functional/user_roles_controller_test.rb
Normal file
28
test/functional/user_roles_controller_test.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
|
||||
class UserRolesControllerTest < ActionController::TestCase
|
||||
fixtures :users, :user_roles
|
||||
|
||||
test "grant" do
|
||||
check_redirect(:grant, :public_user, "/403.html")
|
||||
check_redirect(:grant, :moderator_user, "/403.html")
|
||||
check_redirect(:grant, :administrator_user, {:controller => :user, :action => :view})
|
||||
end
|
||||
|
||||
test "revoke" do
|
||||
check_redirect(:revoke, :public_user, "/403.html")
|
||||
check_redirect(:revoke, :moderator_user, "/403.html")
|
||||
check_redirect(:revoke, :administrator_user, {:controller => :user, :action => :view})
|
||||
end
|
||||
|
||||
def check_redirect(action, user, redirect)
|
||||
UserRole::ALL_ROLES.each do |role|
|
||||
u = users(user)
|
||||
basic_authorization(u.email, "test")
|
||||
|
||||
get(action, {:display_name => users(:second_public_user).display_name, :role => role}, {'user' => u.id})
|
||||
assert_response :redirect
|
||||
assert_redirected_to redirect
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue