Created an admin controller that allows the admin user (only) to view the users on the system and destroy and signup new users. Destroying a user deletes all of their actions, contexts, projects and notes.

The link to the admin page only appears when an admin user is logged in, and the signup link is now on the admin page, rather than appearing in the mini-links at the top of the page.

The page also lists some statistics associated with each user (the number of actions, contexts, projects etc. each user has).

git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@371 a4c988fc-2ded-0310-b66e-134b36920a42
This commit is contained in:
bsag 2006-12-10 19:30:19 +00:00
parent 74ad2b9cc7
commit 26c7a1e6f1
13 changed files with 180 additions and 22 deletions

View file

@ -0,0 +1,51 @@
class AdminController < ApplicationController
before_filter :login_required
before_filter :admin_login_required
layout 'standard'
def index
@user_pages, @users = paginate :users, :order => 'login ASC', :per_page => 10
@total_users = User.find(:all).size
# When we call login/signup from the admin page
# we store the URL so that we get returned here when signup is successful
store_location
end
def destroy
@deleted_user = User.find_by_id(params[:id])
@saved = @deleted_user.destroy
@total_users = User.find(:all).size
respond_to do |wants|
wants.html do
if @saved
notify :notice, "Successfully deleted user #{@deleted_user.login}", 2.0
redirect_to :action => 'index'
else
notify :error, "Failed to delete user #{@deleted_user.login}", 2.0
redirect_to :action => 'index'
end
end
wants.js do
render
end
wants.xml { render :text => '200 OK. User deleted.', :status => 200 }
end
end
protected
def admin_login_required
unless User.find_by_id_and_is_admin(session['user_id'], true)
notify :error, "Only admin users are allowed access to this function"
redirect_to :controller => 'todo', :action => 'index'
return false
end
end
end

View file

@ -0,0 +1,2 @@
module AdminHelper
end

View file

@ -1,10 +1,10 @@
require 'digest/sha1'
class User < ActiveRecord::Base
has_many :contexts, :order => "position ASC"
has_many :projects, :order => "position ASC"
has_many :todos, :order => "completed_at DESC, created_at DESC"
has_many :notes, :order => "created_at DESC"
has_many :contexts, :order => "position ASC", :dependent => :delete_all
has_many :projects, :order => "position ASC", :dependent => :delete_all
has_many :todos, :order => "completed_at DESC, created_at DESC", :dependent => :delete_all
has_many :notes, :order => "created_at DESC", :dependent => :delete_all
has_one :preference
attr_protected :is_admin

View file

@ -0,0 +1,2 @@
<h1>Admin#create</h1>
<p>Find me in app/views/admin/create.rhtml</p>

View file

@ -0,0 +1,7 @@
if @saved
page["user-#{@deleted_user.id}"].remove
page['user_count'].replace_html @total_users.to_s
page.notify :notice, "User #{@deleted_user.login} was successfully destroyed", 2.0
else
page.notify :error, "There was an error deleting the user #{@deleted_user.login}", 8.0
end

View file

@ -0,0 +1 @@
page.notify :error, @error_message || "An error occurred on the server.", 8.0

View file

@ -0,0 +1,36 @@
<h1>Manage users</h1>
<p>You have a total of <span id="user_count"><%= @total_users %></span> users</p>
<table class="users_table">
<tr>
<th>Login</th>
<th>Full name</th>
<th>Authorization type</th>
<th>Open ID URL</th>
<th>Total actions</th>
<th>Total contexts</th>
<th>Total projects</th>
<th>Total notes</th>
<th>&nbsp;</th>
</tr>
<% for user in @users %>
<tr <%= "class=\"highlight\"" if user.is_admin? %> id="user-<%= user.id %>">
<td><%=h user.login %></td>
<td><%=h user.last_name? ? user.display_name : '-' %></td>
<td><%= h user.auth_type %></td>
<td><%= h user.open_id_url || '-' %></td>
<td><%= h user.todos.size %></td>
<td><%= h user.contexts.size %></td>
<td><%= h user.projects.size %></td>
<td><%= h user.notes.size %></td>
<td><%= !user.is_admin? ? link_to_remote( image_tag("blank.png", :title =>"Destroy user", :class=>"delete_item"), {:url => { :controller => 'admin', :action => 'destroy', :id => user.id }, :confirm => "Warning: this will delete user \'#{user.login}\', all their actions, contexts, project and notes. Are you sure that you want to continue?" }, { :class => "icon" } ) : "&nbsp;" %></td>
</tr>
<% end %>
</table>
<p>
<%= link_to "&laquo; Previous page", { :page => @user_pages.current.previous } if @user_pages.current.previous %> &nbsp;
<%= link_to "Next page &raquo;", { :page => @user_pages.current.next } if @user_pages.current.next %>
</p>
<p><%= link_to 'Signup new user', :controller => 'login', :action => 'signup' %></p>

View file

@ -0,0 +1,2 @@
<h1>Admin#update</h1>
<p>Find me in app/views/admin/update.rhtml</p>

View file

@ -35,9 +35,6 @@
page.select('.notes').each { |e| e.toggle }
end
-%>&nbsp;|&nbsp;
<% if @user.is_admin? -%>
<%= link_to "Add users", :controller => "login", :action => "signup" %>&nbsp;|&nbsp;
<% end -%>
<%= link_to "Logout (#{@user.display_name}) »", :controller => "login", :action=>"logout"%>
</div>
@ -50,6 +47,9 @@
<li><%= navigation_link( "Done", {:controller => "todo", :action => "completed"}, {:accesskey=>"d", :title=>"Completed"} ) %></li>
<li><%= navigation_link( "Notes", {:controller => "note", :action => "index"}, {:accesskey => "o", :title => "Show all notes"} ) %></li>
<li><%= navigation_link( "Preferences", {:controller => "user", :action => "preferences"}, {:accesskey => "u", :title => "Show my preferences"} ) %></li>
<% if @user.is_admin? -%>
<li><%= navigation_link("Admin", {:controller => "admin", :action => "index"}, {:accesskey => "a", :title => "Add or delete users"} ) %></li>
<% end -%>
<li><%= navigation_link(image_tag("feed-icon.png", :size => "16X16", :border => 0), {:controller => "feed", :action => "index"}, :title => "See a list of available feeds" ) %></li>
</ul>
</div>

View file

@ -16,6 +16,11 @@ ActionController::Routing::Routes.draw do |map|
# Index Route
map.connect '', :controller => 'todo', :action => 'index'
# Admin Routes
map.connect 'admin', :controller => 'admin', :action => 'index'
# map.connect 'admin/signup', :controller => 'admin', :action => 'create'
map.connect 'admin/destroy/:id', :controller => 'admin', :action => 'destroy', :requirements => {:id => /\d+/}
# Mobile/lite version
map.connect 'mobile', :controller => 'mobile', :action => 'index'

View file

@ -5,10 +5,10 @@
ActiveRecord::Schema.define(:version => 20) do
create_table "contexts", :force => true do |t|
t.column "name", :string, :default => "", :null => false
t.column "hide", :integer, :limit => 4, :default => 0, :null => false
t.column "position", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 0, :null => false
t.column "name", :string, :default => "", :null => false
t.column "position", :integer, :default => 0, :null => false
t.column "hide", :boolean, :default => false
t.column "user_id", :integer, :default => 1
end
create_table "notes", :force => true do |t|
@ -56,7 +56,7 @@ ActiveRecord::Schema.define(:version => 20) do
create_table "projects", :force => true do |t|
t.column "name", :string, :default => "", :null => false
t.column "position", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 1
t.column "description", :text
t.column "state", :string, :limit => 20, :default => "active", :null => false
end
@ -70,23 +70,23 @@ ActiveRecord::Schema.define(:version => 20) do
add_index "sessions", ["session_id"], :name => "sessions_session_id_index"
create_table "todos", :force => true do |t|
t.column "context_id", :integer, :default => 0, :null => false
t.column "description", :string, :limit => 100, :default => "", :null => false
t.column "context_id", :integer, :default => 0, :null => false
t.column "project_id", :integer
t.column "description", :string, :default => "", :null => false
t.column "notes", :text
t.column "created_at", :datetime
t.column "due", :date
t.column "completed_at", :datetime
t.column "project_id", :integer
t.column "user_id", :integer, :default => 0, :null => false
t.column "user_id", :integer, :default => 1
t.column "show_from", :date
t.column "state", :string, :limit => 20, :default => "immediate", :null => false
t.column "state", :string, :limit => 20, :default => "immediate", :null => false
end
create_table "users", :force => true do |t|
t.column "login", :string, :limit => 80
t.column "password", :string, :limit => 40
t.column "login", :string, :limit => 80, :default => "", :null => false
t.column "password", :string, :limit => 40, :default => "", :null => false
t.column "word", :string
t.column "is_admin", :integer, :limit => 4, :default => 0, :null => false
t.column "is_admin", :boolean, :default => false, :null => false
t.column "first_name", :string
t.column "last_name", :string
t.column "auth_type", :string, :default => "database", :null => false

View file

@ -206,7 +206,7 @@ h2 a:hover {
.item-container-drop-target {
border:2px inset black;
}
.container a.icon {
a.icon {
float: left;
vertical-align: middle;
background-color: transparent;
@ -728,4 +728,15 @@ div.page_name_auto_complete ul strong.highlight {
color: #800;
margin: 0;
padding: 0;
}
}
table.users_table {
width: 100%;
text-align: center;
border: 1px solid #666;
background-color: #fff;
border-spacing: 0px;
}
.users_table th {color: #fff; background-color: #000;}
.users_table td {border: none;}

View file

@ -0,0 +1,41 @@
require File.dirname(__FILE__) + '/../test_helper'
require 'admin_controller'
# Re-raise errors caught by the controller.
class AdminController; def rescue_action(e) raise e end; end
class AdminControllerTest < Test::Unit::TestCase
fixtures :users, :preferences, :projects, :contexts, :todos
def setup
@controller = AdminController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_get_index_when_not_logged_in
get :index
assert_redirected_to :controller => 'login', :action => 'login'
end
def test_get_index_by_nonadmin
@request.session['user_id'] = users(:other_user).id
get :index
assert_redirected_to :controller => 'todo', :action => 'index'
end
def test_get_index_by_admin
@request.session['user_id'] = users(:admin_user).id
get :index
assert_response :success
end
def test_destroy_user
@no_users_before = User.find(:all).size
@request.session['user_id'] = users(:admin_user).id
xhr :post, :destroy, :id => 3
assert_rjs :page, "user-3", :remove
assert_equal @no_users_before-1, User.find(:all).size
end
end