Skip to content
Browse files

Merge branch 'add-theme-system' of github.com:adrianshort/nesta-books…

…hare into add-theme-system
  • Loading branch information...
2 parents bbe1fc1 + 1dd5a60 commit 5daad950f3030a3b5d7672670be3665d602ad037 @adrianshort committed
Showing with 998 additions and 129 deletions.
  1. +2 −4 Gemfile
  2. +60 −55 Gemfile.lock
  3. +1 −1 Rakefile
  4. +22 −0 app/controllers/admin_controller.rb
  5. +10 −2 app/controllers/application_controller.rb
  6. +74 −0 app/controllers/bans_controller.rb
  7. +1 −1 app/controllers/user_sessions_controller.rb
  8. +39 −13 app/controllers/users_controller.rb
  9. +2 −0 app/helpers/admin_helper.rb
  10. +4 −0 app/helpers/application_helper.rb
  11. +2 −0 app/helpers/bans_helper.rb
  12. +51 −0 app/models/ban.rb
  13. +11 −1 app/models/loan.rb
  14. +69 −1 app/models/user.rb
  15. +32 −0 app/models/watching.rb
  16. +1 −1 config.ru
  17. +6 −2 config/application.rb
  18. +1 −6 config/environment.rb
  19. +1 −1 config/environments/development.rb
  20. +1 −1 config/environments/production.rb
  21. +1 −1 config/environments/test.rb
  22. +8 −0 config/initializers/config.rb
  23. +1 −1 config/initializers/secret_token.rb
  24. +2 −2 config/initializers/session_store.rb
  25. +14 −4 config/routes.rb
  26. +9 −0 db/migrate/20110817142642_add_status_to_users.rb
  27. +15 −0 db/migrate/20110825153442_create_bans.rb
  28. +9 −0 db/migrate/20110825170855_add_banned_to_users.rb
  29. +11 −0 db/migrate/20110830190734_add_unbanned_by_to_bans.rb
  30. +11 −0 db/migrate/20110830202726_rename_banned_by_and_un_banned_by_in_bans.rb
  31. +22 −10 db/schema.rb
  32. +56 −0 public/stylesheets/scaffold.css
  33. +11 −0 test/fixtures/bans.yml
  34. +15 −0 test/fixtures/books.yml
  35. +27 −0 test/fixtures/users.yml
  36. +8 −0 test/functional/admin_controller_test.rb
  37. +49 −0 test/functional/bans_controller_test.rb
  38. +6 −6 test/functional/pages_controller_test.rb
  39. +84 −0 test/unit/ban_test.rb
  40. +4 −0 test/unit/helpers/admin_helper_test.rb
  41. +4 −0 test/unit/helpers/bans_helper_test.rb
  42. +35 −2 test/unit/watching_test.rb
  43. +1 −1 themes/default/stylesheets/style.css
  44. +7 −0 themes/default/views/admin/index.html.haml
  45. +33 −0 themes/default/views/admin/stats.html.haml
  46. +67 −0 themes/default/views/admin/users.html.haml
  47. +48 −0 themes/default/views/bans/new.html.haml
  48. +3 −3 themes/default/views/layouts/application.html.haml
  49. +46 −2 themes/default/views/users/show.html.haml
  50. +0 −3 themes/sutton/views/layouts/application.html.haml
  51. +0 −4 vendor/plugins/isbn_validation/tasks/isbn_validation_tasks.rake
  52. +1 −1 vendor/plugins/isbn_validation/test/test_helper.rb
View
6 Gemfile
@@ -1,6 +1,6 @@
source 'http://rubygems.org'
-gem 'rails', '3.0.1'
+gem 'rails'
gem 'authlogic'
gem 'rails3-generators'
gem 'dynamic_form'
@@ -12,8 +12,6 @@ gem 'themes_for_rails'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
-gem 'sqlite3-ruby', :require => 'sqlite3'
-
# Use unicorn as the web server
# gem 'unicorn'
@@ -26,7 +24,7 @@ gem 'sqlite3-ruby', :require => 'sqlite3'
# Bundle the extra gems:
# gem 'bj'
# gem 'nokogiri'
-# gem 'sqlite3-ruby', :require => 'sqlite3'
+gem 'sqlite3-ruby', :require => 'sqlite3'
# gem 'aws-s3', :require => 'aws/s3'
gem 'haml'
View
115 Gemfile.lock
@@ -2,84 +2,89 @@ GEM
remote: http://rubygems.org/
specs:
abstract (1.0.0)
- actionmailer (3.0.1)
- actionpack (= 3.0.1)
- mail (~> 2.2.5)
- actionpack (3.0.1)
- activemodel (= 3.0.1)
- activesupport (= 3.0.1)
+ actionmailer (3.0.10)
+ actionpack (= 3.0.10)
+ mail (~> 2.2.19)
+ actionpack (3.0.10)
+ activemodel (= 3.0.10)
+ activesupport (= 3.0.10)
builder (~> 2.1.2)
erubis (~> 2.6.6)
- i18n (~> 0.4.1)
+ i18n (~> 0.5.0)
rack (~> 1.2.1)
- rack-mount (~> 0.6.12)
- rack-test (~> 0.5.4)
+ rack-mount (~> 0.6.14)
+ rack-test (~> 0.5.7)
tzinfo (~> 0.3.23)
- activemodel (3.0.1)
- activesupport (= 3.0.1)
+ activemodel (3.0.10)
+ activesupport (= 3.0.10)
builder (~> 2.1.2)
- i18n (~> 0.4.1)
- activerecord (3.0.1)
- activemodel (= 3.0.1)
- activesupport (= 3.0.1)
- arel (~> 1.0.0)
+ i18n (~> 0.5.0)
+ activerecord (3.0.10)
+ activemodel (= 3.0.10)
+ activesupport (= 3.0.10)
+ arel (~> 2.0.10)
tzinfo (~> 0.3.23)
- activeresource (3.0.1)
- activemodel (= 3.0.1)
- activesupport (= 3.0.1)
- activesupport (3.0.1)
- arel (1.0.1)
- activesupport (~> 3.0.0)
- authlogic (2.1.6)
- activesupport
+ activeresource (3.0.10)
+ activemodel (= 3.0.10)
+ activesupport (= 3.0.10)
+ activesupport (3.0.10)
+ arel (2.0.10)
+ authlogic (3.0.3)
+ activerecord (>= 3.0.7)
+ activerecord (>= 3.0.7)
builder (2.1.2)
cuecat (1.1.0)
ean13 (>= 1.0)
upc (>= 1.0)
- dynamic_form (1.1.3)
+ dynamic_form (1.1.4)
ean13 (1.4.0)
erubis (2.6.6)
abstract (>= 1.0.0)
- haml (3.0.23)
- i18n (0.4.2)
- isbn (2.0.5)
- mail (2.2.9)
+ haml (3.1.2)
+ i18n (0.5.0)
+ isbn (2.0.7)
+ mail (2.2.19)
activesupport (>= 2.3.6)
- i18n (~> 0.4.1)
+ i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.16)
- nokogiri (1.4.3.1)
- polyglot (0.3.1)
- rack (1.2.1)
- rack-mount (0.6.13)
+ nokogiri (1.5.0)
+ polyglot (0.3.2)
+ rack (1.2.3)
+ rack-mount (0.6.14)
rack (>= 1.0.0)
- rack-test (0.5.6)
+ rack-test (0.5.7)
rack (>= 1.0)
- rails (3.0.1)
- actionmailer (= 3.0.1)
- actionpack (= 3.0.1)
- activerecord (= 3.0.1)
- activeresource (= 3.0.1)
- activesupport (= 3.0.1)
- bundler (~> 1.0.0)
- railties (= 3.0.1)
- rails3-generators (0.17.0)
+ rails (3.0.10)
+ actionmailer (= 3.0.10)
+ actionpack (= 3.0.10)
+ activerecord (= 3.0.10)
+ activeresource (= 3.0.10)
+ activesupport (= 3.0.10)
+ bundler (~> 1.0)
+ railties (= 3.0.10)
+ rails3-generators (0.17.4)
railties (>= 3.0.0)
- railties (3.0.1)
- actionpack (= 3.0.1)
- activesupport (= 3.0.1)
- rake (>= 0.8.4)
- thor (~> 0.14.0)
- rake (0.8.7)
- sqlite3-ruby (1.3.1)
+ railties (3.0.10)
+ actionpack (= 3.0.10)
+ activesupport (= 3.0.10)
+ rake (>= 0.8.7)
+ rdoc (~> 3.4)
+ thor (~> 0.14.4)
+ rake (0.9.2)
+ rdoc (3.9.4)
+ sqlite3 (1.3.4)
+ sqlite3-ruby (1.3.3)
+ sqlite3 (>= 1.3.3)
themes_for_rails (0.4.2)
rails (~> 3.0.0)
themes_for_rails
- thor (0.14.3)
- treetop (1.4.8)
+ thor (0.14.6)
+ treetop (1.4.10)
+ polyglot
polyglot (>= 0.3.1)
- tzinfo (0.3.23)
+ tzinfo (0.3.29)
upc (1.0.0)
PLATFORMS
@@ -92,7 +97,7 @@ DEPENDENCIES
haml
isbn
nokogiri
- rails (= 3.0.1)
+ rails
rails3-generators
sqlite3-ruby
themes_for_rails
View
2 Rakefile
@@ -4,4 +4,4 @@
require File.expand_path('../config/application', __FILE__)
require 'rake'
-SuttonOpenLibrary::Application.load_tasks
+NestaBookshare::Application.load_tasks
View
22 app/controllers/admin_controller.rb
@@ -0,0 +1,22 @@
+class AdminController < ApplicationController
+
+ before_filter :require_admin
+
+ def index
+ end
+
+ def stats
+ @users = User.count
+ @books = Title.count
+ @loans = Loan.count
+ @current_loans = Loan.find_all_by_returned(nil).count
+ @watchings = Watching.count
+ end
+
+ def users
+ @admins = User.admins
+ @non_admins = User.non_admins
+ @banned = User.banned
+ end
+
+end
View
12 app/controllers/application_controller.rb
@@ -5,7 +5,6 @@ class ApplicationController < ActionController::Base
theme CONFIG[:theme]
end
- filter_parameter_logging :password, :password_confirmation
helper_method :current_user_session, :current_user
private
@@ -37,8 +36,17 @@ def require_no_user
end
end
+ def require_admin
+ unless current_user && current_user.status == 'admin'
+ store_location
+ flash[:notice] = "You must be an administrator access this page"
+ redirect_to root_url
+ return false
+ end
+ end
+
def store_location
- session[:return_to] = request.request_uri
+ session[:return_to] = request.fullpath
end
def redirect_back_or_default(default)
View
74 app/controllers/bans_controller.rb
@@ -0,0 +1,74 @@
+class BansController < ApplicationController
+
+ before_filter :require_admin
+
+ # GET /bans
+ # GET /bans.xml
+# def index
+# @bans = Ban.all
+#
+# respond_to do |format|
+# format.html # index.html.erb
+# format.xml { render :xml => @bans }
+# end
+# end
+
+ # GET /bans/1
+ # GET /bans/1.xml
+# def show
+# @ban = Ban.find(params[:id])
+#
+# respond_to do |format|
+# format.html # show.html.erb
+# format.xml { render :xml => @ban }
+# end
+# end
+
+ # GET /bans/new
+ # GET /bans/new.xml
+ def new
+ @ban = Ban.new
+ @user = User.find_by_login(params[:login])
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @ban }
+ end
+ end
+
+ # POST /bans
+ # POST /bans.xml
+ def create
+ @ban = Ban.new
+ @ban.user = User.find_by_login(params[:ban][:login])
+ @ban.reason = params[:ban][:reason]
+ @ban.banner = current_user
+
+ respond_to do |format|
+ if @ban.save
+ format.html { redirect_to(:back, :notice => "#{@ban.user.name} (#{@ban.user.login}) has now been banned.") }
+# format.xml { render :xml => @ban, :status => :created, :location => @ban }
+ else
+ format.html { render :action => "new" }
+# format.xml { render :xml => @ban.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /bans/1
+ # PUT /bans/1.xml
+# def update
+# @ban = Ban.find(params[:id])
+#
+# respond_to do |format|
+# if @ban.update_attributes(params[:ban])
+# format.html { redirect_to(@ban, :notice => 'Ban was successfully updated.') }
+# format.xml { head :ok }
+# else
+# format.html { render :action => "edit" }
+# format.xml { render :xml => @ban.errors, :status => :unprocessable_entity }
+# end
+# end
+# end
+
+end
View
2 app/controllers/user_sessions_controller.rb
@@ -10,7 +10,7 @@ def create
@user_session = UserSession.new(params[:user_session])
if @user_session.save
flash[:notice] = "Welcome"
- redirect_back_or_default books_url
+ redirect_back_or_default :root
else
render :action => :new
end
View
52 app/controllers/users_controller.rb
@@ -1,6 +1,7 @@
class UsersController < ApplicationController
- before_filter :require_no_user, :only => [:new, :create, :show]
- before_filter :require_user, :only => [:edit, :update, :watched_books, :loans]
+ before_filter :require_no_user, :only => [ :new, :create ]
+ before_filter :require_user, :only => [ :edit, :update, :watched_books, :loans ]
+ before_filter :require_admin, :only => [ :unban, :promote, :demote, :show ]
def new
@user = User.new
@@ -8,6 +9,10 @@ def new
def create
@user = User.new(params[:user])
+
+ @user.status = 'user'
+ @user.banned = false
+
if @user.save
flash[:notice] = "Thanks for joining #{CONFIG[:sitename]}. Welcome!"
redirect_back_or_default books_path
@@ -17,21 +22,35 @@ def create
end
def show
- @user = @current_user
+ @user = User.find(params[:id])
end
- def edit
- @user = @current_user
+# def edit
+# @user = @current_user
+# end
+
+# def update
+# @user = @current_user # makes our views "cleaner" and more consistent
+# if @user.update_attributes(params[:user])
+# flash[:notice] = "Account updated!"
+# redirect_to account_url
+# else
+# render :action => :edit
+# end
+# end
+
+ def promote
+ @user = User.find_by_login(params[:id])
+ @user.promote
+ flash[:notice] = "#{@user.login} promoted OK"
+ redirect_to :back
end
- def update
- @user = @current_user # makes our views "cleaner" and more consistent
- if @user.update_attributes(params[:user])
- flash[:notice] = "Account updated!"
- redirect_to account_url
- else
- render :action => :edit
- end
+ def demote
+ @user = User.find_by_login(params[:id])
+ @user.demote
+ flash[:notice] = "#{@user.login} demoted OK"
+ redirect_to :back
end
def watched_books
@@ -45,4 +64,11 @@ def loans
def borrowings
@loans = current_user.active_borrowings
end
+
+ def unban
+ @user = User.find(params[:id])
+ @user.unban(current_user)
+ flash[:notice] = "#{@user.login} unbanned OK"
+ redirect_to :back
+ end
end
View
2 app/helpers/admin_helper.rb
@@ -0,0 +1,2 @@
+module AdminHelper
+end
View
4 app/helpers/application_helper.rb
@@ -7,4 +7,8 @@ def nice_date(date)
def set_focus_to_id(id)
javascript_tag("$('#{id}').focus();")
end
+
+ def is_admin?
+ current_user && current_user.status == 'admin'
+ end
end
View
2 app/helpers/bans_helper.rb
@@ -0,0 +1,2 @@
+module BansHelper
+end
View
51 app/models/ban.rb
@@ -0,0 +1,51 @@
+class Ban < ActiveRecord::Base
+
+ belongs_to :user
+
+ # Admin user doing the banning
+ belongs_to :banner,
+ :class_name => "User",
+ :foreign_key => :banner
+
+ # Admin user doing the unbanning
+ belongs_to :unbanner,
+ :class_name => "User",
+ :foreign_key => :unbanner
+
+ attr_accessible :user_id, :banner, :unbanner, :reason
+
+ validates_presence_of :user, :banner, :reason
+
+ before_create :banner_must_be_admin,
+ :banner_must_not_be_banee,
+ :banee_must_not_already_be_banned,
+ :banee_must_not_be_admin
+
+ after_create :set_user_as_banned
+
+ protected
+
+ def set_user_as_banned
+ @user = self.user
+ @user.banned = true
+ @user.save
+ end
+
+ def banner_must_be_admin
+ @banner.admin?
+ end
+
+ # You can't ban yourself
+ def banner_must_not_be_banee
+ @banner != @user
+ end
+
+ def banee_must_not_already_be_banned
+ !@user.banned?
+ end
+
+ def banee_must_not_be_admin
+ !@user.admin?
+ end
+
+end
View
12 app/models/loan.rb
@@ -13,6 +13,8 @@ class Loan < ActiveRecord::Base
validate :borrower_cant_be_lender
validate :lender_must_own_book
+
+ before_create :book_must_be_available
after_create :set_book_status_to_on_loan
@@ -31,6 +33,10 @@ def on_loan?
protected
+ def book_must_be_available
+ book.available?
+ end
+
def set_book_status_to_on_loan
book.update_attribute :status, StaticData::BOOK_STATUS['ONLOAN']
end
@@ -40,7 +46,11 @@ def borrower_cant_be_lender
end
def lender_must_own_book
- errors.add(:lender, "you must own the book you want to lend") unless book.user == lender
+ unless book.nil?
+ errors.add(:lender, "you must own the book you want to lend") unless book.user == lender
+ else
+ false
+ end
end
end
View
70 app/models/user.rb
@@ -26,12 +26,25 @@ class User < ActiveRecord::Base
:foreign_key => :lender_id,
:conditions => { :returned => nil },
:order => 'created_at DESC'
+
+ has_many :bans
+
+ has_many :bannings,
+ :class_name => "Ban",
+ :foreign_key => :banner
+ has_many :unbannings,
+ :class_name => "Ban",
+ :foreign_key => :unbanner
validates_presence_of :first_name, :last_name, :address1, :city, :postcode
- after_create :send_registration_confirmation
+ after_create :send_registration_confirmation, :promote_first_user
+# attr_protected :status, :banned
+
+ attr_accessible :login, :email, :first_name, :last_name, :address1, :address2, :city, :county, :postcode, :phone, :password, :password_confirmation
+
def to_param
login
end
@@ -56,6 +69,26 @@ def name
"#{self.first_name} #{self.last_name}"
end
+ def promote
+ update_attribute(:status, 'admin')
+ end
+
+ def demote
+ update_attribute(:status, 'user')
+ end
+
+ def self.admins
+ User.find_all_by_status('admin', :order => :login)
+ end
+
+ def self.banned
+ User.find_all_by_banned_and_status(true, 'user', :order => :login) # It's implicit that status will be 'user' as admins can't be banned
+ end
+
+ def self.non_admins
+ User.find_all_by_banned_and_status(false, 'user', :order => :login)
+ end
+
def owns?(book)
self.books.include?(book)
end
@@ -66,8 +99,43 @@ def watched?(book)
self.watched_books.include?(book)
end
+ def admin?
+ self.status == 'admin'
+ end
+
+ def unban(unbanner)
+ unless self.banned?
+ return false
+ end
+
+ unless unbanner.admin?
+ return false
+ end
+
+ @ban = self.bans.last
+ @ban.unbanner = unbanner
+ @ban.unbanned_at = Time.now
+
+ if @ban.save
+ self.banned = false
+ self.save
+ return true
+ else
+ return false
+ end
+ end
+
+ protected
+
def send_registration_confirmation
email = MemberMessage.registration_confirmation(self)
email.deliver
end
+
+ # When setting up a new site make the first registered user an admin
+ def promote_first_user
+ if 1 == User.count
+ User.first.promote
+ end
+ end
end
View
32 app/models/watching.rb
@@ -1,4 +1,36 @@
class Watching < ActiveRecord::Base
belongs_to :user
belongs_to :book
+
+ validates_presence_of :book, :user
+
+ before_create :book_must_not_already_be_watched_by_this_user, :cant_watch_your_own_book, :book_must_be_available_or_on_loan
+
+ protected
+
+ def cant_watch_your_own_book
+ user = User.find(@user)
+ if user.books.include?(@book)
+ false
+ else
+ true
+ end
+ end
+
+ def book_must_not_already_be_watched_by_this_user
+ if Watching.find_all_by_book_id_and_user_id(@book.id, @user.id).count > 0
+ false
+ else
+ true
+ end
+ end
+
+ def book_must_be_available_or_on_loan
+ if @book.available? || @book.on_loan?
+ true
+ else
+ false
+ end
+ end
+
end
View
2 config.ru
@@ -1,4 +1,4 @@
# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
-run SuttonOpenLibrary::Application
+run NestaBookshare::Application
View
8 config/application.rb
@@ -6,7 +6,7 @@
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)
-module SuttonOpenLibrary
+module NestaBookshare
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
@@ -37,6 +37,10 @@ class Application < Rails::Application
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
- config.filter_parameters += [:password]
+ config.filter_parameters += [ :password, :password_confirmation ]
+
+ config.generators do |g|
+ g.template_engine :haml
+ end
end
end
View
7 config/environment.rb
@@ -1,11 +1,6 @@
-require 'yaml'
-
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application
-SuttonOpenLibrary::Application.initialize!
+NestaBookshare::Application.initialize!
-# Load the site-specific configuration
-# http://snippets.dzone.com/posts/show/551
-CONFIG = YAML::load(ERB.new((IO.read("#{RAILS_ROOT}/config/config.yml"))).result).symbolize_keys
View
2 config/environments/development.rb
@@ -1,4 +1,4 @@
-SuttonOpenLibrary::Application.configure do
+NestaBookshare::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb
# In the development environment your application's code is reloaded on
View
2 config/environments/production.rb
@@ -1,4 +1,4 @@
-SuttonOpenLibrary::Application.configure do
+NestaBookshare::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb
# The production environment is meant for finished, "live" apps.
View
2 config/environments/test.rb
@@ -1,4 +1,4 @@
-SuttonOpenLibrary::Application.configure do
+NestaBookshare::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb
# The test environment is used exclusively to run your application's
View
8 config/initializers/config.rb
@@ -0,0 +1,8 @@
+CONFIG = {
+ :sitename => ENV['BOOKSHARE_SITENAME'],
+ :theme => ENV['BOOKSHARE_THEME'],
+ :email => ENV['BOOKSHARE_EMAIL'],
+ :no_reply_email => ENV['BOOKSHARE_NO_REPLY_EMAIIL'],
+ :twitter => ENV['BOOKSHARE_TWITTER'],
+ :google_analytics => ENV['BOOKSHARE_GOOGLE_ANALYTICS']
+}
View
2 config/initializers/secret_token.rb
@@ -4,4 +4,4 @@
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
-SuttonOpenLibrary::Application.config.secret_token = '300a39ecb3b6d4e92b403f624a4ec4643d53eb329402bcf9c1feedae7fa5488bcf2c272891e4ac63da7de48b22aeea910c58e138a8fef73a8a56905704a85992'
+NestaBookshare::Application.config.secret_token = '300a39ecb3b6d4e92b403f624a4ec4643d53eb329402bcf9c1feedae7fa5488bcf2c272891e4ac63da7de48b22aeea910c58e138a8fef73a8a56905704a85992'
View
4 config/initializers/session_store.rb
@@ -1,8 +1,8 @@
# Be sure to restart your server when you modify this file.
-SuttonOpenLibrary::Application.config.session_store :cookie_store, :key => '_Sutton-Open-Library_session'
+NestaBookshare::Application.config.session_store :cookie_store, :key => '_Sutton-Open-Library_session'
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
# (create the session table with "rake db:sessions:create")
-# SuttonOpenLibrary::Application.config.session_store :active_record_store
+# NestaBookshare::Application.config.session_store :active_record_store
View
18 config/routes.rb
@@ -1,14 +1,25 @@
-SuttonOpenLibrary::Application.routes.draw do
+NestaBookshare::Application.routes.draw do
+
themes_for_rails
- resources :books
resources :authors
+ resources :bans
+ resources :books
+ resources :loans
resources :subjects
resources :titles
resources :watchings
- resources :users
resource :account, :controller => :users
+
+ resources :users do
+ member do
+ put :promote
+ put :demote
+ put :unban
+ end
+ end
+
root :to => 'pages#home'
resources :user_sessions
@@ -22,7 +33,6 @@
match 'lent' => 'users#loans', :as => :lent
match 'borrowed' => 'users#borrowings', :as => :borrowings
match 'search' => 'search#index', :as => :search
- resources :loans
# The priority is based upon order of creation:
# first created -> highest priority.
View
9 db/migrate/20110817142642_add_status_to_users.rb
@@ -0,0 +1,9 @@
+class AddStatusToUsers < ActiveRecord::Migration
+ def self.up
+ add_column :users, :status, :string, :default => 'user'
+ end
+
+ def self.down
+ remove_column :users, :status
+ end
+end
View
15 db/migrate/20110825153442_create_bans.rb
@@ -0,0 +1,15 @@
+class CreateBans < ActiveRecord::Migration
+ def self.up
+ create_table :bans do |t|
+ t.datetime :unbanned_at
+ t.integer :user_id
+ t.integer :admin_id
+ t.text :reason
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :bans
+ end
+end
View
9 db/migrate/20110825170855_add_banned_to_users.rb
@@ -0,0 +1,9 @@
+class AddBannedToUsers < ActiveRecord::Migration
+ def self.up
+ add_column :users, :banned, :boolean, :default => false
+ end
+
+ def self.down
+ remove_column :users, :banned
+ end
+end
View
11 db/migrate/20110830190734_add_unbanned_by_to_bans.rb
@@ -0,0 +1,11 @@
+class AddUnbannedByToBans < ActiveRecord::Migration
+ def self.up
+ add_column :bans, :unbanned_by, :integer
+ rename_column :bans, :admin_id, :banned_by
+ end
+
+ def self.down
+ rename_column :bans, :banned_by, :admin_id
+ remove_column :bans, :unbanned_by
+ end
+end
View
11 db/migrate/20110830202726_rename_banned_by_and_un_banned_by_in_bans.rb
@@ -0,0 +1,11 @@
+class RenameBannedByAndUnBannedByInBans < ActiveRecord::Migration
+ def self.up
+ rename_column :bans, :banned_by, :banner
+ rename_column :bans, :unbanned_by, :unbanner
+ end
+
+ def self.down
+ rename_column :bans, :banner, :banned_by
+ rename_column :bans, :unbanner, :unbanned_by
+ end
+end
View
32 db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20110323151412) do
+ActiveRecord::Schema.define(:version => 20110830202726) do
create_table "authors", :force => true do |t|
t.string "name", :default => ""
@@ -26,6 +26,16 @@
add_index "authors_titles", ["author_id"], :name => "index_authors_titles_on_author_id"
add_index "authors_titles", ["title_id"], :name => "index_authors_titles_on_title_id"
+ create_table "bans", :force => true do |t|
+ t.datetime "unbanned_at"
+ t.integer "user_id"
+ t.integer "banner"
+ t.text "reason"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "unbanner"
+ end
+
create_table "books", :force => true do |t|
t.integer "title_id"
t.integer "user_id"
@@ -70,15 +80,15 @@
create_table "users", :force => true do |t|
t.datetime "created_at"
t.datetime "updated_at"
- t.string "login", :default => "", :null => false
- t.string "email", :default => "", :null => false
- t.string "crypted_password", :default => "", :null => false
- t.string "password_salt", :default => "", :null => false
- t.string "persistence_token", :default => "", :null => false
- t.string "single_access_token", :default => "", :null => false
- t.string "perishable_token", :default => "", :null => false
- t.integer "login_count", :default => 0, :null => false
- t.integer "failed_login_count", :default => 0, :null => false
+ t.string "login", :default => "", :null => false
+ t.string "email", :default => "", :null => false
+ t.string "crypted_password", :default => "", :null => false
+ t.string "password_salt", :default => "", :null => false
+ t.string "persistence_token", :default => "", :null => false
+ t.string "single_access_token", :default => "", :null => false
+ t.string "perishable_token", :default => "", :null => false
+ t.integer "login_count", :default => 0, :null => false
+ t.integer "failed_login_count", :default => 0, :null => false
t.datetime "last_request_at"
t.datetime "current_login_at"
t.datetime "last_login_at"
@@ -92,6 +102,8 @@
t.string "county"
t.string "postcode"
t.string "phone"
+ t.string "status", :default => "user"
+ t.boolean "banned", :default => false
end
create_table "watchings", :force => true do |t|
View
56 public/stylesheets/scaffold.css
@@ -0,0 +1,56 @@
+body { background-color: #fff; color: #333; }
+
+body, p, ol, ul, td {
+ font-family: verdana, arial, helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+
+pre {
+ background-color: #eee;
+ padding: 10px;
+ font-size: 11px;
+}
+
+a { color: #000; }
+a:visited { color: #666; }
+a:hover { color: #fff; background-color:#000; }
+
+div.field, div.actions {
+ margin-bottom: 10px;
+}
+
+#notice {
+ color: green;
+}
+
+.field_with_errors {
+ padding: 2px;
+ background-color: red;
+ display: table;
+}
+
+#error_explanation {
+ width: 450px;
+ border: 2px solid red;
+ padding: 7px;
+ padding-bottom: 0;
+ margin-bottom: 20px;
+ background-color: #f0f0f0;
+}
+
+#error_explanation h2 {
+ text-align: left;
+ font-weight: bold;
+ padding: 5px 5px 5px 15px;
+ font-size: 12px;
+ margin: -7px;
+ margin-bottom: 0px;
+ background-color: #c00;
+ color: #fff;
+}
+
+#error_explanation ul li {
+ font-size: 12px;
+ list-style: square;
+}
View
11 test/fixtures/bans.yml
@@ -0,0 +1,11 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+one:
+ unbanned_at: 2011-08-25 16:34:42
+ user_id: 1
+ reason: MyText
+
+two:
+ unbanned_at: 2011-08-25 16:34:42
+ user_id: 1
+ reason: MyText
View
15 test/fixtures/books.yml
@@ -6,4 +6,19 @@ thebridge:
outliers:
title: outliers
user: bob
+ status: 1
+
+middlemarch:
+ title: middlemarch
+ user: bob
+ status: 2
+
+plainspace:
+ title: plainspace
+ user: bob
+ status: 3
+
+librarymashups:
+ title: librarymashups
+ user: bob
status: 0
View
27 test/fixtures/users.yml
@@ -23,6 +23,7 @@ alice:
county: Anyshire
postcode: AN1 1AB
phone: 1234567890
+ status: admin
bob:
login: bob
@@ -47,3 +48,29 @@ bob:
county: Anyshire
postcode: AN2 2CD
phone: 0987654321
+ status: user
+
+charlie:
+ login: charlie
+ email: charlie@test.test
+ crypted_password: 12345
+ password_salt: 12345
+ persistence_token: 12345
+ single_access_token: 12345
+ perishable_token: 12345
+ login_count: 0
+ failed_login_count: 0
+ last_request_at:
+ current_login_at:
+ last_login_at:
+ current_login_ip:
+ last_login_ip:
+ first_name: Charlie
+ last_name: Smith
+ address1: 555 Another Road
+ address2:
+ city: Anytown
+ county: Anyshire
+ postcode: AN2 2CD
+ phone: 0287943857
+ status: admin
View
8 test/functional/admin_controller_test.rb
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class AdminControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ test "the truth" do
+ assert true
+ end
+end
View
49 test/functional/bans_controller_test.rb
@@ -0,0 +1,49 @@
+require 'test_helper'
+
+class BansControllerTest < ActionController::TestCase
+# setup do
+# @ban = bans(:one)
+# end
+#
+# test "should get index" do
+# get :index
+# assert_response :success
+# assert_not_nil assigns(:bans)
+# end
+#
+# test "should get new" do
+# get :new
+# assert_response :success
+# end
+#
+# test "should create ban" do
+# assert_difference('Ban.count') do
+# post :create, :ban => @ban.attributes
+# end
+#
+# assert_redirected_to ban_path(assigns(:ban))
+# end
+#
+# test "should show ban" do
+# get :show, :id => @ban.to_param
+# assert_response :success
+# end
+#
+# test "should get edit" do
+# get :edit, :id => @ban.to_param
+# assert_response :success
+# end
+#
+# test "should update ban" do
+# put :update, :id => @ban.to_param, :ban => @ban.attributes
+# assert_redirected_to ban_path(assigns(:ban))
+# end
+#
+# test "should destroy ban" do
+# assert_difference('Ban.count', -1) do
+# delete :destroy, :id => @ban.to_param
+# end
+#
+# assert_redirected_to bans_path
+# end
+end
View
12 test/functional/pages_controller_test.rb
@@ -1,10 +1,10 @@
require 'test_helper'
class PagesControllerTest < ActionController::TestCase
- test "should get home page" do
- get :home
- assert_response :success
- assert_not_nil assigns(:books)
- assert_equal 30, assigns(:books).count
- end
+# test "should get home page" do
+# get :home
+# assert_response :success
+# assert_not_nil assigns(:books)
+# assert_equal 30, assigns(:books).count
+# end
end
View
84 test/unit/ban_test.rb
@@ -0,0 +1,84 @@
+require 'test_helper'
+
+class BanTest < ActiveSupport::TestCase
+ def setup
+ @alice = users(:alice)
+ @bob = users(:bob)
+ @charlie = users(:charlie)
+ end
+
+ test "admin bans a user" do
+ @ban = Ban.new
+ @ban.user = @bob
+ @ban.banner = @alice
+ @ban.reason = "Whatever."
+ assert @ban.save
+ assert @bob.banned?
+ end
+
+ test "non-admin can't ban a user" do
+ @ban = Ban.new
+ @ban.user = @alice
+ @ban.banner = @bob
+ @ban.reason = "Whatever."
+ assert !@ban.save
+ assert !@alice.banned?
+ end
+
+ test "can't ban yourself" do
+ @ban = Ban.new
+ @ban.user = @alice
+ @ban.banner = @alice
+ @ban.reason = "Whatever."
+ assert !@ban.save
+ assert !@alice.banned?
+ end
+
+ test "can't ban someone who's already banned" do
+ # Ban a user
+ @ban = Ban.new
+ @ban.user = @bob
+ @ban.banner = @alice
+ @ban.reason = "Whatever."
+ assert @ban.save
+ assert @bob.banned?
+
+ # Try to ban the same user again
+ @ban2 = Ban.new
+ @ban2.user = @bob
+ @ban2.banner = @alice
+ @ban2.reason = "Whatever."
+ assert !@ban2.save
+ assert @bob.banned?
+ end
+
+ test "can't ban an admin" do
+ @ban = Ban.new
+ @ban.user = @alice
+ @ban.banner = @charlie
+ @ban.reason = "Whatever."
+ assert !@ban.save
+ assert !@alice.banned?
+ end
+
+ test "unban a banned user" do
+ # Ban a user
+ @ban = Ban.new
+ @ban.user = @bob
+ @ban.banner = @alice
+ @ban.reason = "Whatever."
+ assert @ban.save
+ assert @bob.banned?
+
+ # Now unban them
+ assert @bob.unban(@alice)
+ assert !@bob.banned?
+ end
+
+ test "can't unban a user who's not banned" do
+ assert !@bob.banned?
+ assert !@bob.unban(@alice)
+ assert !@bob.banned?
+ end
+
+end
View
4 test/unit/helpers/admin_helper_test.rb
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class AdminHelperTest < ActionView::TestCase
+end
View
4 test/unit/helpers/bans_helper_test.rb
@@ -0,0 +1,4 @@
+require 'test_helper'
+
+class BansHelperTest < ActionView::TestCase
+end
View
37 test/unit/watching_test.rb
@@ -3,9 +3,19 @@
class WatchingTest < ActiveSupport::TestCase
def setup
@thebridge = books(:thebridge) # belongs to alice
- @outliers = books(:outliers) # belongs to bob
+ @outliers = books(:outliers) # belongs to bob, on loan
+ @middlemarch = books(:middlemarch) # belongs to bob, status: deleted
+ @plainspace = books(:plainspace) # belongs to bob, status: lost
+ @librarymashups = books(:librarymashups) # belongs to bob, status: available
@alice = users(:alice)
end
+
+ test "watch another users book" do
+ @watching = Watching.new
+ @watching.user = @alice
+ @watching.book = @outliers
+ assert @watching.save
+ end
test "can't watch your own book" do
@watching = Watching.new
@@ -34,7 +44,30 @@ def setup
end
test "can only watch available or onloan books" do
- flunk
+ # available book
+ @watching = Watching.new
+ @watching.user = @alice
+ @watching.book = @librarymashups
+ assert @watching.save
+
+ # on loan book
+ @watching = Watching.new
+ @watching.user = @alice
+ @watching.book = @outliers
+ assert @watching.save
+
+ # deleted book
+ @watching = Watching.new
+ @watching.user = @alice
+ @watching.book = @middlemarch
+ assert !@watching.save
+
+ # lost book
+ @watching = Watching.new
+ @watching.user = @alice
+ @watching.book = @plainspace
+ assert !@watching.save
+
end
end
View
2 themes/default/stylesheets/style.css
@@ -186,7 +186,7 @@ img
div
{
- margin: 10px 0;
+ margin: 40px 0;
}
#search
View
7 themes/default/views/admin/index.html.haml
@@ -0,0 +1,7 @@
+%h1 Bookshare Administration
+
+%p
+ = link_to("Statistics", url_for(:controller => :admin, :action => :stats))
+
+%p
+ = link_to("User Management", url_for(:controller => :admin, :action => :users))
View
33 themes/default/views/admin/stats.html.haml
@@ -0,0 +1,33 @@
+%h1 Statistics
+
+%table
+ %tr
+ %td
+ = @users
+ %td
+ users
+
+ %tr
+ %td
+ = @books
+ %td
+ books
+
+ %tr
+ %td
+ = @watchings
+ %td
+ watched books
+
+ %tr
+ %td
+ = @current_loans
+ %td
+ current loans
+
+ %tr
+ %td
+ = @loans
+ %td
+ loans for all time, including current loans
+
View
67 themes/default/views/admin/users.html.haml
@@ -0,0 +1,67 @@
+%h1 Users
+
+#admins
+ %h2 Administrators
+
+ - if @admins.count > 0
+
+ %table
+ - for user in @admins
+ %tr
+ %td
+ = link_to(user.login, user_path(user.id))
+ %td
+ = user.status
+ %td
+ - form_for user, :method => 'post', :url => demote_user_path(:id => user.login) do |f|
+ = f.error_messages
+ = f.submit "Demote"
+ - else
+
+ %p.warning There are no administrators on this site. Something is wrong! (Like, you shouldn't be able to see this page for a start.)
+
+
+#banned
+ %h2 Banned Users
+
+ - if @banned.count > 0
+
+ %table
+ - for user in @banned
+ %tr
+ %td
+ = link_to(user.login, user_path(user.id))
+ %td
+ = user.status
+ %td
+ - form_for user, :url => unban_user_path(user.id) do |f|
+ = f.error_messages
+ = f.submit "Unban"
+
+ - else
+
+ %p No users are banned.
+
+
+#non_admins
+ %h2 Non-Administrators
+
+ - if @non_admins.count > 0
+
+ %table
+ - for user in @non_admins
+ %tr
+ %td
+ = link_to(user.login, user_path(user.id))
+ %td
+ = user.status
+ %td
+ = link_to "Ban", new_ban_path(:login => user.login)
+ %td
+ - form_for user, :method => 'post', :url => promote_user_path(:id => user.login) do |f|
+ = f.error_messages
+ = f.submit "Promote"
+
+ - else
+
+ %p There are no other users.
View
48 themes/default/views/bans/new.html.haml
@@ -0,0 +1,48 @@
+%h1
+ = link_to image_tag(@user.gravatar_image_url(75)), '/members/' + @user.login
+ Ban
+ = @user.name
+ (
+ = @user.login
+ )
+
+
+%p Banning is a temporary measure to suspend someone's account while you sort out a problem.
+
+%p Banned members can:
+
+%ul
+ %li check in books that people have lent to them
+ %li have other members check in books they've borrowed from them
+ %li login and logout
+
+%p but they can't:
+
+%ul
+ %li add or delete books
+ %li borrow or lend books
+ %li watch or unwatch books
+
+%p While a member is banned none of their books will show in the catalogue.
+
+%p Ban periods are not set in advance. Any administrator can unban a user at any time.
+
+= form_for(@ban) do |f|
+ = f.hidden_field :login, :value => @user.login
+
+ - if @ban.errors.any?
+ .error_explanation
+ %h2
+ = pluralize(@ban.errors.count, "error")
+ prohibited this ban from being saved:
+
+ %ul
+ - @ban.errors.full_messages.each do |msg|
+ %li= msg
+
+ .field
+ = f.label :reason, "Why are you banning this member?"
+ %br
+ = f.text_area :reason, :rows => 10, :cols => 50
+ .actions
+ = f.submit :value => "Ban #{@user.name} (#{@user.login})"
View
6 themes/default/views/layouts/application.html.haml
@@ -51,9 +51,9 @@
= link_to_unless_current "Borrowed (#{current_user.active_borrowings.count.to_s})", :borrowings, :accesskey => '4'
&nbsp;&nbsp;
= link_to_unless_current "Watch List (#{current_user.watched_books.count.to_s})", :watchlist, :accesskey => '5'
- -#
- &nbsp;&nbsp;
- = link_to_unless_current "My Account", :account, :accesskey => '6'
+ &nbsp;&nbsp;
+ - if is_admin?
+ = link_to_unless_current "Administration", :controller => :admin
&nbsp;&nbsp;
= link_to_unless_current "Log Out", :logout, :method => :delete, :confirm => "Are you sure you want to logout?"
- else
View
48 themes/default/views/users/show.html.haml
@@ -1,6 +1,50 @@
-%h1 My Account
+%p= link_to "<-- All users", :controller => :admin, :action => :users
+
+%h1= @user.login
= image_tag @user.gravatar_image_url(80)
%p
- = pluralize(@user.books.count, "book")
+ = link_to "Send a message to #{@user.login}", { :controller => :messages, :action => :new, :recipient => @user.login }
+
+%p
+ = link_to(pluralize(@user.books.count, "book"), "/members/#{@user.login}")
+
+%h2 Bans
+
+- unless @user.banned?
+ %p
+ = link_to "Ban #{@user.login}", new_ban_path(:login => @user.login)
+
+- if @user.bans.count > 0
+
+ %table
+
+ %tr
+ %th Banned at
+ %th Banned by
+ %th Reason
+ %th Unbanned at
+ %th Unbanned by
+ %th &nbsp;
+
+ - for ban in @user.bans
+ %tr
+ %td= nice_date ban.created_at
+ %td= link_to(ban.banner.login, "/members/#{ban.banner.login}")
+ %td= simple_format(ban.reason)
+ - if ban.unbanned_at.nil?
+ %td &nbsp;
+ %td &nbsp;
+ - else
+ %td= nice_date ban.unbanned_at
+ %td= link_to(ban.unbanner.login, "/members/#{ban.unbanner.login}")
+ - if ban.unbanned_at.nil?
+ %td
+ - form_for @user, :url => unban_user_path(@user.id) do |f|
+ = f.error_messages
+ = f.submit "Unban"
+
+- else
+
+ %p This user has never been banned.
View
3 themes/sutton/views/layouts/application.html.haml
@@ -48,9 +48,6 @@
= link_to_unless_current "Borrowed (#{current_user.active_borrowings.count.to_s})", :borrowings, :accesskey => '4'
&nbsp;&nbsp;
= link_to_unless_current "Watch List (#{current_user.watched_books.count.to_s})", :watchlist, :accesskey => '5'
- -#
- &nbsp;&nbsp;
- = link_to_unless_current "My Account", :account, :accesskey => '6'
&nbsp;&nbsp;
= link_to_unless_current "Log Out", :logout, :method => :delete, :confirm => "Are you sure you want to logout?"
- else
View
4 vendor/plugins/isbn_validation/tasks/isbn_validation_tasks.rake
@@ -1,4 +0,0 @@
-# desc "Explaining what the task does"
-# task :isbn_validation do
-# # Task goes here
-# end
View
2 vendor/plugins/isbn_validation/test/test_helper.rb
@@ -1,5 +1,5 @@
$:.unshift(File.dirname(__FILE__) + '/../lib')
-RAILS_ROOT = File.dirname(__FILE__)
+::Rails.root.to_s = File.dirname(__FILE__)
require 'rubygems'
require 'test/unit'

0 comments on commit 5daad95

Please sign in to comment.
Something went wrong with that request. Please try again.