OSDN Git Service

Anonymous users can now be allowed to create, edit, comment issues, comment news...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Tue, 20 Nov 2007 15:40:16 +0000 (15:40 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Tue, 20 Nov 2007 15:40:16 +0000 (15:40 +0000)
These permissions need to be explicitly given to the Anonymous role (Admin -> Roles & Permissions -> Anonymous).

git-svn-id: http://redmine.rubyforge.org/svn/trunk@919 e93f8b46-1217-0410-a6f0-8f06a7374b81

19 files changed:
app/controllers/application.rb
app/controllers/documents_controller.rb
app/controllers/issues_controller.rb
app/controllers/messages_controller.rb
app/controllers/my_controller.rb
app/controllers/news_controller.rb
app/controllers/projects_controller.rb
app/controllers/queries_controller.rb
app/controllers/search_controller.rb
app/controllers/timelog_controller.rb
app/controllers/welcome_controller.rb
app/controllers/wiki_controller.rb
app/models/attachment.rb
app/models/query.rb
app/models/user.rb
app/views/news/show.rhtml
db/migrate/080_add_users_type.rb [new file with mode: 0644]
lib/redmine.rb
test/unit/user_test.rb

index 991b3ff..e186455 100644 (file)
@@ -23,10 +23,6 @@ class ApplicationController < ActionController::Base
     require_dependency "repository/#{scm.underscore}"
   end
   
-  def logged_in_user
-    User.current.logged? ? User.current : nil
-  end
-  
   def current_role
     @current_role ||= User.current.role_for_project(@project)
   end
index 63ee961..94532b6 100644 (file)
@@ -49,7 +49,7 @@ class DocumentsController < ApplicationController
     @attachments = []
     params[:attachments].each { |file|
       next unless file.size > 0
-      a = Attachment.create(:container => @document, :file => file, :author => logged_in_user)
+      a = Attachment.create(:container => @document, :file => file, :author => User.current)
       @attachments << a unless a.new_record?
     } if params[:attachments] and params[:attachments].is_a? Array
     Mailer.deliver_attachments_added(@attachments) if !@attachments.empty? && Setting.notified_events.include?('document_added')
index 9244344..cca3fe6 100644 (file)
@@ -82,7 +82,7 @@ class IssuesController < ApplicationController
   def show
     @custom_values = @issue.custom_values.find(:all, :include => :custom_field, :order => "#{CustomField.table_name}.position")
     @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
-    @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
+    @status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
     respond_to do |format|
       format.html { render :template => 'issues/show.rhtml' }
       format.pdf  { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
@@ -95,7 +95,7 @@ class IssuesController < ApplicationController
       @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
     else
       begin
-        @issue.init_journal(self.logged_in_user)
+        @issue.init_journal(User.current)
         # Retrieve custom fields and values
         if params["custom_fields"]
           @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
@@ -117,7 +117,7 @@ class IssuesController < ApplicationController
     journal = @issue.init_journal(User.current, params[:notes])
     params[:attachments].each { |file|
       next unless file.size > 0
-      a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user)
+      a = Attachment.create(:container => @issue, :file => file, :author => User.current)
       journal.details << JournalDetail.new(:property => 'attachment',
                                            :prop_key => a.id,
                                            :value => a.filename) unless a.new_record?
@@ -132,17 +132,17 @@ class IssuesController < ApplicationController
   end
 
   def change_status
-    @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
+    @status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
     @new_status = IssueStatus.find(params[:new_status_id])
     if params[:confirm]
       begin
-        journal = @issue.init_journal(self.logged_in_user, params[:notes])
+        journal = @issue.init_journal(User.current, params[:notes])
         @issue.status = @new_status
         if @issue.update_attributes(params[:issue])
           # Save attachments
           params[:attachments].each { |file|
             next unless file.size > 0
-            a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user)            
+            a = Attachment.create(:container => @issue, :file => file, :author => User.current)            
             journal.details << JournalDetail.new(:property => 'attachment',
                                                  :prop_key => a.id,
                                                  :value => a.filename) unless a.new_record?
@@ -150,7 +150,7 @@ class IssuesController < ApplicationController
         
           # Log time
           if current_role.allowed_to?(:log_time)
-            @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => logged_in_user, :spent_on => Date.today)
+            @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
             @time_entry.attributes = params[:time_entry]
             @time_entry.save
           end
@@ -176,7 +176,7 @@ class IssuesController < ApplicationController
   def destroy_attachment
     a = @issue.attachments.find(params[:attachment_id])
     a.destroy
-    journal = @issue.init_journal(self.logged_in_user)
+    journal = @issue.init_journal(User.current)
     journal.details << JournalDetail.new(:property => 'attachment',
                                          :prop_key => a.id,
                                          :old_value => a.filename)
@@ -225,12 +225,11 @@ private
   def retrieve_query
     if params[:query_id]
       @query = Query.find(params[:query_id], :conditions => {:project_id => (@project ? @project.id : nil)})
-      @query.executed_by = logged_in_user
       session[:query] = @query
     else
       if params[:set_filter] or !session[:query] or session[:query].project != @project
         # Give it a name, required to be valid
-        @query = Query.new(:name => "_", :executed_by => logged_in_user)
+        @query = Query.new(:name => "_")
         @query.project = @project
         if params[:fields] and params[:fields].is_a? Array
           params[:fields].each do |field|
index 74a957d..645aadf 100644 (file)
@@ -31,12 +31,12 @@ class MessagesController < ApplicationController
   
   def new
     @message = Message.new(params[:message])
-    @message.author = logged_in_user
+    @message.author = User.current
     @message.board = @board 
     if request.post? && @message.save
       params[:attachments].each { |file|
         next unless file.size > 0
-        Attachment.create(:container => @message, :file => file, :author => logged_in_user)
+        Attachment.create(:container => @message, :file => file, :author => User.current)
       } if params[:attachments] and params[:attachments].is_a? Array    
       redirect_to :action => 'show', :id => @message
     end
@@ -44,7 +44,7 @@ class MessagesController < ApplicationController
 
   def reply
     @reply = Message.new(params[:reply])
-    @reply.author = logged_in_user
+    @reply.author = User.current
     @reply.board = @board
     @message.children << @reply
     redirect_to :action => 'show', :id => @message
index 2fa5a9d..cb326bc 100644 (file)
@@ -44,7 +44,7 @@ class MyController < ApplicationController
 
   # Show user's page
   def page
-    @user = self.logged_in_user
+    @user = User.current
     @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT
   end
 
@@ -76,7 +76,7 @@ class MyController < ApplicationController
 
   # Manage user's password
   def password
-    @user = self.logged_in_user
+    @user = User.current
     flash[:error] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id
     if request.post?
       if @user.check_password?(params[:password])
@@ -102,7 +102,7 @@ class MyController < ApplicationController
 
   # User's page layout configuration
   def page_layout
-    @user = self.logged_in_user
+    @user = User.current
     @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup
     session[:page_layout] = @blocks
     %w(top left right).each {|f| session[:page_layout][f] ||= [] }
@@ -116,7 +116,7 @@ class MyController < ApplicationController
   def add_block
     block = params[:block]
     render(:nothing => true) and return unless block && (BLOCKS.keys.include? block)
-    @user = self.logged_in_user
+    @user = User.current
     # remove if already present in a group
     %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block }
     # add it on top
@@ -151,7 +151,7 @@ class MyController < ApplicationController
   
   # Save user's page layout  
   def page_layout_save
-    @user = self.logged_in_user
+    @user = User.current
     @user.pref[:my_page_layout] = session[:page_layout] if session[:page_layout]
     @user.pref.save
     session[:page_layout] = nil
index c41c584..109afe4 100644 (file)
@@ -45,7 +45,7 @@ class NewsController < ApplicationController
   
   def add_comment
     @comment = Comment.new(params[:comment])
-    @comment.author = logged_in_user
+    @comment.author = User.current
     if @news.comments << @comment
       flash[:notice] = l(:label_comment_added)
       redirect_to :action => 'show', :id => @news
index 289b34e..0f50cd7 100644 (file)
@@ -48,7 +48,7 @@ class ProjectsController < ApplicationController
   # Lists visible projects
   def list
     projects = Project.find :all,
-                            :conditions => Project.visible_by(logged_in_user),
+                            :conditions => Project.visible_by(User.current),
                             :include => :parent
     @project_tree = projects.group_by {|p| p.parent || p}
     @project_tree.each_key {|p| @project_tree[p] -= [p]}
@@ -176,7 +176,7 @@ class ProjectsController < ApplicationController
     if request.post? and @document.save        
       # Save the attachments
       params[:attachments].each { |a|
-        Attachment.create(:container => @document, :file => a, :author => logged_in_user) unless a.size == 0
+        Attachment.create(:container => @document, :file => a, :author => User.current) unless a.size == 0
       } if params[:attachments] and params[:attachments].is_a? Array
       flash[:notice] = l(:notice_successful_create)
       Mailer.deliver_document_added(@document) if Setting.notified_events.include?('document_added')
@@ -216,7 +216,7 @@ class ProjectsController < ApplicationController
       return
     end    
     @issue.status = default_status
-    @allowed_statuses = ([default_status] + default_status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker))if logged_in_user
+    @allowed_statuses = ([default_status] + default_status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker))
     
     if request.get?
       @issue.start_date ||= Date.today
@@ -321,10 +321,9 @@ class ProjectsController < ApplicationController
 
   # Add a news to @project
   def add_news
-    @news = News.new(:project => @project)
+    @news = News.new(:project => @project, :author => User.current)
     if request.post?
       @news.attributes = params[:news]
-      @news.author_id = self.logged_in_user.id if self.logged_in_user
       if @news.save
         flash[:notice] = l(:notice_successful_create)
         Mailer.deliver_news_added(@news) if Setting.notified_events.include?('news_added')
@@ -340,7 +339,7 @@ class ProjectsController < ApplicationController
       @attachments = []
       params[:attachments].each { |file|
         next unless file.size > 0
-        a = Attachment.create(:container => @version, :file => file, :author => logged_in_user)
+        a = Attachment.create(:container => @version, :file => file, :author => User.current)
         @attachments << a unless a.new_record?
       } if params[:attachments] and params[:attachments].is_a? Array
       Mailer.deliver_attachments_added(@attachments) if !@attachments.empty? && Setting.notified_events.include?('file_added')
index 7feafd3..69bad34 100644 (file)
@@ -22,14 +22,13 @@ class QueriesController < ApplicationController
   def index
     @queries = @project.queries.find(:all, 
                                      :order => "name ASC",
-                                     :conditions => ["is_public = ? or user_id = ?", true, (logged_in_user ? logged_in_user.id : 0)])
+                                     :conditions => ["is_public = ? or user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
   end
   
   def new
     @query = Query.new(params[:query])
     @query.project = @project
-    @query.user = logged_in_user
-    @query.executed_by = logged_in_user
+    @query.user = User.current
     @query.is_public = false unless current_role.allowed_to?(:manage_public_queries)
     @query.column_names = nil if params[:default_columns]
     
@@ -71,9 +70,8 @@ private
   def find_project
     if params[:id]
       @query = Query.find(params[:id])
-      @query.executed_by = logged_in_user
       @project = @query.project
-      render_403 unless @query.editable_by?(logged_in_user)
+      render_403 unless @query.editable_by?(User.current)
     else
       @project = Project.find(params[:project_id])
     end
index 2c00b3d..7c50d4d 100644 (file)
@@ -31,7 +31,7 @@ class SearchController < ApplicationController
     begin; offset = params[:offset].to_time if params[:offset]; rescue; end
     
     # quick jump to an issue
-    if @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(logged_in_user))
+    if @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(User.current))
       redirect_to :controller => "issues", :action => "show", :id => $1
       return
     end
@@ -87,7 +87,7 @@ class SearchController < ApplicationController
         end
       else
         operator = @all_words ? ' AND ' : ' OR '
-        Project.with_scope(:find => {:conditions => Project.visible_by(logged_in_user)}) do
+        Project.with_scope(:find => {:conditions => Project.visible_by(User.current)}) do
           @results += Project.find(:all, :limit => limit, :conditions => [ (["(LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'projects'
         end
         # if only one project is found, user is redirected to its overview
index 68c0ede..1a1bace 100644 (file)
@@ -107,15 +107,15 @@ class TimelogController < ApplicationController
     @entries = (@issue ? @issue : @project).time_entries.find(:all, :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :order => sort_clause)
 
     @total_hours = @entries.inject(0) { |sum,entry| sum + entry.hours }
-    @owner_id = logged_in_user ? logged_in_user.id : 0
+    @owner_id = User.current.id
     
     send_csv and return if 'csv' == params[:export]    
     render :action => 'details', :layout => false if request.xhr?
   end
   
   def edit
-    render_404 and return if @time_entry && @time_entry.user != logged_in_user
-    @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => logged_in_user, :spent_on => Date.today)
+    render_404 and return if @time_entry && @time_entry.user != User.current
+    @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
     @time_entry.attributes = params[:time_entry]
     if request.post? and @time_entry.save
       flash[:notice] = l(:notice_successful_update)
index 2eac226..b4be7fb 100644 (file)
@@ -19,7 +19,7 @@ class WelcomeController < ApplicationController
   layout 'base'
 
   def index
-    @news = News.latest logged_in_user
-    @projects = Project.latest logged_in_user
+    @news = News.latest User.current
+    @projects = Project.latest User.current
   end
 end
index 7609323..37a36bf 100644 (file)
@@ -69,7 +69,7 @@ class WikiController < ApplicationController
       #@content.text = params[:content][:text]
       #@content.comments = params[:content][:comments]
       @content.attributes = params[:content]
-      @content.author = logged_in_user
+      @content.author = User.current
       # if page is new @page.save will also save content, but not if page isn't a new record
       if (@page.new_record? ? @page.save : @content.save)
         redirect_to :action => 'index', :id => @project, :page => @page.title
@@ -157,7 +157,7 @@ class WikiController < ApplicationController
     # Save the attachments
     params[:attachments].each { |file|
       next unless file.size > 0
-      a = Attachment.create(:container => @page, :file => file, :author => logged_in_user)
+      a = Attachment.create(:container => @page, :file => file, :author => User.current)
     } if params[:attachments] and params[:attachments].is_a? Array
     redirect_to :action => 'index', :page => @page.title
   end
index d2bcab3..7262498 100644 (file)
@@ -21,7 +21,7 @@ class Attachment < ActiveRecord::Base
   belongs_to :container, :polymorphic => true
   belongs_to :author, :class_name => "User", :foreign_key => "author_id"
   
-  validates_presence_of :container, :filename
+  validates_presence_of :container, :filename, :author
   validates_length_of :filename, :maximum => 255
   validates_length_of :disk_filename, :maximum => 255
 
@@ -82,11 +82,6 @@ class Attachment < ActiveRecord::Base
   def increment_download
     increment!(:downloads)
   end
-       
-       # returns last created projects
-       def self.most_downloaded
-               find(:all, :limit => 5, :order => "downloads DESC")     
-       end
 
   def project
     container.is_a?(Project) ? container : container.project
index 30df55b..f869f64 100644 (file)
@@ -112,11 +112,8 @@ class Query < ActiveRecord::Base
   def initialize(attributes = nil)
     super attributes
     self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
-  end
-  
-  def executed_by=(user)
-    @executed_by = user
-    set_language_if_valid(user.language) if user
+    @executed_by = User.current.logged? ? User.current : nil
+    set_language_if_valid(executed_by.language) if executed_by
   end
   
   def validate
index 2543bed..93b73dd 100644 (file)
@@ -19,6 +19,7 @@ require "digest/sha1"
 
 class User < ActiveRecord::Base
   # Account statuses
+  STATUS_ANONYMOUS  = 0
   STATUS_ACTIVE     = 1
   STATUS_REGISTERED = 2
   STATUS_LOCKED     = 3
@@ -36,15 +37,15 @@ class User < ActiveRecord::Base
   # Prevents unauthorized assignments
   attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
        
-  validates_presence_of :login, :firstname, :lastname, :mail
+  validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
   validates_uniqueness_of :login, :mail        
   # Login must contain lettres, numbers, underscores only
-  validates_format_of :login, :with => /^[a-z0-9_\-@\.]+$/i
+  validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
   validates_length_of :login, :maximum => 30
   validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i
   validates_length_of :firstname, :lastname, :maximum => 30
-  validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
-  validates_length_of :mail, :maximum => 60
+  validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
+  validates_length_of :mail, :maximum => 60, :allow_nil => true
   # Password length between 4 and 12
   validates_length_of :password, :in => 4..12, :allow_nil => true
   validates_confirmation_of :password, :allow_nil => true
@@ -216,11 +217,17 @@ class User < ActiveRecord::Base
   end
   
   def self.current
-    @current_user ||= AnonymousUser.new
+    @current_user ||= User.anonymous
   end
   
   def self.anonymous
-    AnonymousUser.new
+    return @anonymous_user if @anonymous_user
+    anonymous_user = AnonymousUser.find(:first)
+    if anonymous_user.nil?
+      anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
+      raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
+    end
+    @anonymous_user = anonymous_user
   end
   
 private
@@ -231,16 +238,17 @@ private
 end
 
 class AnonymousUser < User
-  def logged?
-    false
-  end
   
-  def time_zone
-    nil
+  def validate_on_create
+    # There should be only one AnonymousUser in the database
+    errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
   end
   
-  # Anonymous user has no RSS key
-  def rss_key
-    nil
-  end
+  # Overrides a few properties
+  def logged?; false end
+  def admin; false end
+  def name; 'Anonymous' end
+  def mail; nil end
+  def time_zone; nil end
+  def rss_key; nil end
 end
index ef5bbcd..2b51c1f 100644 (file)
@@ -26,7 +26,7 @@
 <h3 class="icon22 icon22-comment"><%= l(:label_comment_plural) %></h3>
 <% @news.comments.each do |comment| %>
     <% next if comment.new_record? %>
-    <h4><%= format_time(comment.created_on) %> - <%= comment.author.name %></h4>
+    <h4><%= authoring comment.created_on, comment.author %></h4>
     <div class="contextual">
         <%= link_to_if_authorized l(:button_delete), {:controller => 'news', :action => 'destroy_comment', :id => @news, :comment_id => comment}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
     </div>
diff --git a/db/migrate/080_add_users_type.rb b/db/migrate/080_add_users_type.rb
new file mode 100644 (file)
index 0000000..c907b47
--- /dev/null
@@ -0,0 +1,10 @@
+class AddUsersType < ActiveRecord::Migration
+  def self.up
+    add_column :users, :type, :string
+    User.update_all "type = 'User'"
+  end
+
+  def self.down
+    remove_column :users, :type
+  end
+end
index 959cfc0..8a79b26 100644 (file)
@@ -29,11 +29,11 @@ Redmine::AccessControl.map do |map|
                                   :issues => [:index, :changes, :show, :context_menu],
                                   :queries => :index,
                                   :reports => :issue_report}, :public => true                    
-    map.permission :add_issues, {:projects => :add_issue}, :require => :loggedin
+    map.permission :add_issues, {:projects => :add_issue}
     map.permission :edit_issues, {:projects => :bulk_edit_issues,
-                                  :issues => [:edit, :destroy_attachment]}, :require => :loggedin
-    map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}, :require => :loggedin
-    map.permission :add_issue_notes, {:issues => :add_note}, :require => :loggedin
+                                  :issues => [:edit, :destroy_attachment]}
+    map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
+    map.permission :add_issue_notes, {:issues => :add_note}
     map.permission :change_issue_status, {:issues => :change_status}, :require => :loggedin
     map.permission :move_issues, {:projects => :move_issues}, :require => :loggedin
     map.permission :delete_issues, {:issues => :destroy}, :require => :member
@@ -53,7 +53,7 @@ Redmine::AccessControl.map do |map|
   map.project_module :news do |map|
     map.permission :manage_news, {:projects => :add_news, :news => [:edit, :destroy, :destroy_comment]}, :require => :member
     map.permission :view_news, {:news => [:index, :show]}, :public => true
-    map.permission :comment_news, {:news => :add_comment}, :require => :loggedin
+    map.permission :comment_news, {:news => :add_comment}
   end
 
   map.project_module :documents do |map|
@@ -83,7 +83,7 @@ Redmine::AccessControl.map do |map|
   map.project_module :boards do |map|
     map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
     map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
-    map.permission :add_messages, {:messages => [:new, :reply]}, :require => :loggedin
+    map.permission :add_messages, {:messages => [:new, :reply]}
   end
 end
 
index 82cbbda..9f58d27 100644 (file)
@@ -60,7 +60,7 @@ class UserTest < Test::Unit::TestCase
   def test_validate
     @admin.login = ""
     assert !@admin.save
-    assert_equal 2, @admin.errors.count
+    assert_equal 1, @admin.errors.count
   end
   
   def test_password
@@ -87,6 +87,13 @@ class UserTest < Test::Unit::TestCase
     assert_equal nil, user  
   end
   
+  def test_create_anonymous
+    AnonymousUser.delete_all
+    anon = User.anonymous
+    assert !anon.new_record?
+    assert_kind_of AnonymousUser, anon
+  end
+  
   def test_rss_key
     assert_nil @jsmith.rss_token
     key = @jsmith.rss_key