Adding donated code https://dev.eclipse.org/ipzilla/attachment.cgi?id=351, see also https://dev.eclipse.org/ipzilla/show_bug.cgi?id=1174
diff --git a/source/.project b/source/.project
new file mode 100644
index 0000000..04b12eb
--- /dev/null
+++ b/source/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>EPF Wiki Sources</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/source/CHANGELOG b/source/CHANGELOG
new file mode 100644
index 0000000..0026dc7
--- /dev/null
+++ b/source/CHANGELOG
@@ -0,0 +1,4 @@
+== 0.9
+
+* LogicaCMG code donation (non-EPL components removed)
+
diff --git a/source/COPYRIGHT b/source/COPYRIGHT
new file mode 100644
index 0000000..d716bff
--- /dev/null
+++ b/source/COPYRIGHT
@@ -0,0 +1,11 @@
+
+Copyright (c) 2006 LogicaCMG and others
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+
+Contributors:
+* Onno van der Straaten:: initial implementation
+
diff --git a/source/EPFWiki_source_only.zip b/source/EPFWiki_source_only.zip
new file mode 100644
index 0000000..e6e0d04
--- /dev/null
+++ b/source/EPFWiki_source_only.zip
Binary files differ
diff --git a/source/Rakefile b/source/Rakefile
new file mode 100644
index 0000000..9404217
--- /dev/null
+++ b/source/Rakefile
@@ -0,0 +1,9 @@
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake.
+
+require(File.join(File.dirname(__FILE__), 'config', 'boot'))
+
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+require 'tasks/rails'
\ No newline at end of file
diff --git a/source/app/controllers/application.rb b/source/app/controllers/application.rb
new file mode 100644
index 0000000..9007f4d
--- /dev/null
+++ b/source/app/controllers/application.rb
@@ -0,0 +1,78 @@
+# Filters added to this controller will be run for all controllers in the application.
+# Likewise, all the methods added will be available for all controllers.
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class ApplicationController < ActionController::Base
+
+ protected
+
+ def log_error(exception) #:doc:
+ super(exception)
+ begin
+ # TODO R? don't send error email when action error causes an error
+ Notifier.deliver_error_report(exception, clean_backtrace(exception),
+ @session.instance_variable_get("@data"),
+ @params,
+ @request.env)
+ rescue => e
+ logger.error(e)
+ end
+ end
+
+ # all exceptions are redirected to OtherController.error
+ def rescue_action_in_public(exception) #:doc:
+ flash['error'] = exception.message
+ flash['notice'] = "An application error occurred while processing your request. This error was logged and an email was sent to notify the administrator."
+ redirect_to :controller => 'other', :action => 'error'
+ end
+
+ # instead of an error stack we want to display a nice user friendly error message
+ def local_request? #:doc:
+ false
+ end
+
+ # The #authenticate method is used as a <tt>before_hook</tt> in
+ # controllers that require the user to be authenticated. If the
+ # session does not contain a valid user, the method
+ # redirects to the LoginController.login.
+ #
+ # TODO R? to have caching of pages per user group add something like :params => params.merge( :utype=> 'admin' )
+ def authenticate #:doc:
+ unless session['user']
+ session["return_to"] = @request.request_uri
+ redirect_to :controller => "login"
+ return false
+ end
+ end
+
+ def authenticate_admin #:doc:
+ if !admin?
+ flash['notice'] = 'Administrators privileges are required to access this function'
+ flash['error'] = LoginController::FLASH_UNOT_ADMIN
+ redirect_to :controller => 'other', :action => 'error'
+ return false
+ end
+ end
+
+ def authenticate_cadmin #:doc:
+ if !cadmin?
+ flash['notice'] = 'You need to be the central administrator to access this function'
+ flash['error'] = LoginController::FLASH_UNOT_CADMIN
+ redirect_to :controller => 'other', :action => 'error'
+ return false
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/source/app/controllers/baselines_controller.rb b/source/app/controllers/baselines_controller.rb
new file mode 100644
index 0000000..2bb0871
--- /dev/null
+++ b/source/app/controllers/baselines_controller.rb
@@ -0,0 +1,58 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class BaselinesController < ApplicationController
+ before_filter :authenticate
+ before_filter :authenticate_admin, :only => [:edit]
+
+ def index
+ list
+ render :action => 'list'
+ end
+
+ def list
+ if params[:site_id]
+ @site = Site.find(params[:site_id])
+ @baselines = @site.baselines
+ else
+ @baselines = Baseline.find_all
+ end
+ end
+
+ def show
+ @baseline = Baseline.find(params[:id])
+ @version_pages, @versions = paginate :version, :per_page => 5, :order => 'created_on DESC', :conditions => ['baseline_id = ? and version <> 0', @baseline.id ]
+ end
+
+ def show_comments
+ @site = Site.find(params[:site_id]) if params[:site_id]
+ @baseline = Baseline.find(params[:id])
+ @comment_pages, @comments = paginate :comment, :per_page => 5, :order => 'created_on DESC', :conditions => ['baseline_id = ?', @baseline.id ]
+ render :action => 'show'
+ end
+
+ def edit
+ @baseline = Baseline.find(params[:id])
+ if request.post?
+ @baseline = Baseline.find(params[:id])
+ if @baseline.update_attributes(params[:baseline])
+ flash[:notice] = 'Baseline was successfully updated.'
+ redirect_to :action => 'show', :id => @baseline
+ else
+ render :action => 'edit'
+ end
+ end
+ end
+
+end
diff --git a/source/app/controllers/comments_controller.rb b/source/app/controllers/comments_controller.rb
new file mode 100644
index 0000000..fe57484
--- /dev/null
+++ b/source/app/controllers/comments_controller.rb
@@ -0,0 +1,152 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class CommentsController < ApplicationController
+
+ before_filter :authenticate
+ before_filter :authenticate_admin, :only => [:toggle_done, :review]
+
+ def new
+ list
+ @comment_new = Comment.new(:site => @site, :page => @page, :version => @version)
+ render :action => 'list'
+ end
+
+ def create
+ @comment = Comment.new(params[:comment].merge(:user => session['user'], :ip_address => ENV['CLIENTNAME'] ))
+ if @comment.save
+ logger.info("User #{session['user'].name} submitted comment #{@comment.text}")
+ # ENH R? AJAX success messages
+ users = Notification.find_all_users(@comment.site, @comment.page, 'Comment')
+ logger.info("Sending notifications to #{users.size.to_s} user(s)")
+ if users.length > 0
+ subject = "New comment submitted about #{@comment.page.presentation_name}"
+ introduction = "User #{@comment.user.name} submitted a new comment about <a href=\"http://#{request.host}/#{@comment.site.rel_path}/#{@comment.page.rel_path}\">#{@comment.page.presentation_name}</a> in site #{@comment.site.title}<br>"
+ Notifier::deliver_notification(users,subject,introduction, @comment.text, request.host)
+ end
+ else
+ logger.error("Failed to save comment of user #{session['user'].name}: #{@comment.text}")
+ Notifier::deliver_env_to(User.find_central_admin, @session.instance_variable_get("@data"), @params, @request.env)
+ # ENH R? AJAX error messages
+ end
+ render :partial => 'comment'
+ end
+
+ # Action #list for a Comment-records about Page in a specific Site
+ def list
+ @version = Version.find(params[:version_id]) if params[:version_id]
+ @site = Site.find(params[:site_id])
+ @page = Page.find(params[:page_id])
+ if @site && @page
+ @comments = Comment.find(:all, :conditions => ["page_id=? and site_id=?", @page.id, @site.id], :order => 'created_on ASC')
+ @sites_with_comments = Site.find(:all, :conditions => ['id <> ? and exists (select * from comments where comments.site_id=sites.id and comments.page_id=?)', @site.id,@page.id])
+ else
+ flash['notice'] = "Site " + params[:site_id].to_s + " or page " + params[:page_id].to_s
+ end
+ @version = Version.find_current_version(@site, @page, true)
+ #--
+ # TODO R? it is possible that a base version is not created here if the page does
+ # not exist in the site, see Version.find_current_version
+ #++
+ end
+
+ # Action #toggle_done toggles the <tt>done</tt> column.
+ def toggle_done
+ @comment = Comment.find(params[:id])
+ if @comment.done == 'Y'
+ @comment.update_attributes(:done => 'N', :user_thatmarkedtodo => session['user'])
+ else
+ @comment.update_attributes(:done => 'Y', :user_thatmarkeddone => session['user'])
+ end
+ render :inline => "<%= link_to_done_toggle(@comment) %>"
+ end
+
+ # Action #review assigns current User as the reviewer
+ def review
+ @comment = Comment.find(params[:id])
+ if @comment.reviewer == session['user']
+ logger.info("User #{@comment.reviewer.name} has unassigned himself of reviewing comment with ID #{@comment.id} with text #{@comment.text}")
+ @comment.update_attributes(:reviewer => nil)
+ elsif @comment.reviewer.nil? || cadmin?
+ logger.info("User #{session['user'].name} has made himself reviewer of comment with ID #{@comment.id} with text #{@comment.text}")
+ @comment.update_attributes(:reviewer => session['user'])
+ else
+ logger.info("User #{session['user'].name} cannot make himself reviewer of comment of user #{@comment.reviewer.name} with ID #{@comment.id} with text #{@comment.text}")
+ end
+ render :inline => "<%= link_to_reviewer(@comment) %>"
+ end
+
+ # Action #listtodo for list of Comment-records where <tt>done</tt> is equal to <tt>Y</tt>, see also #listtodo, #listdone.
+ def listtodo
+ @comment_pages, @comments = paginate :comment, :per_page => 10, :order => 'created_on DESC', :conditions => ['done=?', "N"]
+ @heading = 'Comments To Do'
+ render :action => 'listall'
+ end
+
+ # Action #listall to display all comments, see also #listtodo, #listdone.
+ def listall
+ @comment_pages, @comments = paginate :comment, :per_page => 10, :order => 'created_on DESC'
+ @heading = 'Comments'
+ end
+
+ # Action #listtodo for list of Comment-records where <tt>done</tt> is equal to <tt>N</tt>, see also #listtodo, #listdone.
+ def listdone
+ @comment_pages, @comments = paginate :comment, :per_page => 10, :order => 'created_on DESC', :conditions => ['done=?', "Y"]
+ @heading = 'Comments Done'
+ render :action => 'listall'
+ end
+
+ # Action #edit to display the edit form
+ def edit
+ @comment = Comment.find(params[:id])
+ @page = @comment.page
+ @site = @comment.site
+ @version = @comment.version
+ render :layout => false
+ end
+
+ # Action #update to update a Comment-record. You can only update your own records
+ def update
+ @comment = Comment.find(params[:id])
+ @site = @comment.site
+ @page = @comment.page
+ @version = @comment.version
+ if mine?(@comment) || cadmin?
+ if @comment.update_attributes(params[:comment])
+ # ENH R? AJAX error messages
+ render :partial => 'comment'
+ else
+ render :action => 'edit', :layout => false
+ end
+ else
+ # ENH R? AJAX error messages
+ render :action => 'edit', :layout => false
+ end
+ end
+
+ # Action #destroy to delete a Comment-record. You can only delete your own records.
+ def destroy
+ @comment = Comment.find(params[:id])
+ @site = @comment.site
+ @page = @comment.page
+ @version = @comment.version
+ if mine?(@comment) || cadmin?
+ @comment.destroy
+ flash['success'] = ::FLASH_RECORD_DELETED
+ else
+ flash['error'] = ::FLASH_NOT_OWNER
+ end
+ redirect_to :action => 'list', :site_id => @site, :page_id => @page
+ end
+end
diff --git a/source/app/controllers/difference_analyses_controller.rb b/source/app/controllers/difference_analyses_controller.rb
new file mode 100644
index 0000000..9e4d3e2
--- /dev/null
+++ b/source/app/controllers/difference_analyses_controller.rb
@@ -0,0 +1,119 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class DifferenceAnalysesController < ApplicationController
+
+ before_filter :authenticate
+ before_filter :authenticate_cadmin, :only => [:new, :analyze_now, :destroy]
+
+ verify :method => :post, :only => [ :destroy, :create, :update ],
+ :redirect_to => { :action => :list }
+
+ FLASH_SCHEDULED = 'Difference analysis scheduled to be created'
+ FLASH_PERFORMED = 'Analysis succesfully performed'
+
+ def new
+ @baseline_processes = Site.find_baseline_processes
+ if request.get?
+ params[:site_id] = Site.find(:first).id if !params[:site_id]
+ @baseline_process = Site.find(params[:site_id])
+ @difference_analysis = DifferenceAnalysis.new
+ @difference_analysis.site = @baseline_process
+ else
+ @difference_analysis = DifferenceAnalysis.new(params[:difference_analysis])
+ @baseline_process = @difference_analysis.site
+ if @difference_analysis.save
+ flash['success'] = FLASH_SCHEDULED
+ redirect_to :action => 'show', :id => @difference_analysis.id
+ else
+ render :action => 'new'
+ end
+ end
+ @baseline_processes = Site.find_baseline_processes
+ # FIXME DifferenceAnalyAsis message: uninitialized constant DifferenceAnalyAsis
+ #baseline_processes = Site.find_baseline_processes - @baseline_process.difference_analyses.collect {|aDiff| aDiff.site_from} - [@baseline_process]
+ end
+
+ # TODO R? 'IGNORED' status for pages of which differences are not relevant?
+ def show
+ @difference_analysis = DifferenceAnalysis.find(params[:id])
+ @site_from = @difference_analysis.site_from
+ @site = @difference_analysis.site
+ @baseline_from = @difference_analysis.baseline_from
+ @baseline = @difference_analysis.baseline
+ @difference_analysis_item_pages, @difference_analysis_items = paginate :difference_analysis_item, :per_page =>25, :order => 'id ASC', :conditions => ['difference_analysis_id = ?', @difference_analysis.id ]
+ flash.now['notice'] = FLASH_SCHEDULED if @difference_analysis.analyzed_on.nil?
+ end
+
+ def showchanged
+ show
+ @difference_analysis_item_pages, @difference_analysis_items = paginate :difference_analysis_item, :per_page =>25, :order => 'id ASC', :conditions => ['difference_analysis_id = ? and result=?', @difference_analysis.id, "CHANGED" ]
+ render :action => 'show'
+ end
+
+ def showhtmlchanged
+ show
+ @difference_analysis_item_pages, @difference_analysis_items = paginate :difference_analysis_item, :per_page =>25, :order => 'id ASC', :conditions => ['difference_analysis_id = ? and result=?', @difference_analysis.id, "HTMLCHANGED" ]
+ render :action => 'show'
+ end
+
+ def shownew
+ show
+ @difference_analysis_item_pages, @difference_analysis_items = paginate :difference_analysis_item, :per_page =>25, :order => 'id ASC', :conditions => ['difference_analysis_id = ? and result=?', @difference_analysis.id, "NEW" ]
+ render :action => 'show'
+ end
+
+ def showremoved
+ show
+ @difference_analysis_item_pages, @difference_analysis_items = paginate :difference_analysis_item, :per_page =>25, :order => 'id ASC', :conditions => ['difference_analysis_id = ? and result=?', @difference_analysis.id, "REMOVED" ]
+ render :action => 'show'
+ end
+
+ def show_item
+ @diff_item = DifferenceAnalysisItem.find(params[:item_id])
+ @page = @diff_item.page
+ @site = @diff_item.difference_analysis.site
+ @site_from = @diff_item.difference_analysis.site_from
+ @baseline = @diff_item.difference_analysis.baseline
+ @baseline_from = @diff_item.difference_analysis.baseline_from
+ @difference_analysis = @diff_item.difference_analysis
+ end
+
+ def update
+ @difference_analysis = DifferenceAnalysis.find(params[:id])
+ if @difference_analysis.update_attributes(params[:difference_analysis])
+ flash[:notice] = 'DifferenceAnalysis was successfully updated.'
+ redirect_to :action => 'show', :id => @difference_analysis
+ else
+ render :action => 'edit'
+ end
+ end
+
+ def destroy
+ DifferenceAnalysis.find(params[:id]).destroy
+ redirect_to :action => 'list'
+ end
+
+ def analyze_now
+ difference_analysis = DifferenceAnalysis.find(params[:id])
+ difference_analysis.perform_analysis
+ if difference_analysis.save
+ flash['success'] = FLASH_PERFORMED
+ else
+ flash['error'] = 'Errors were reported during analysis'
+ end
+ redirect_to :action => 'show', :id => difference_analysis.id
+ end
+
+end
diff --git a/source/app/controllers/login_controller.rb b/source/app/controllers/login_controller.rb
new file mode 100644
index 0000000..3470f90
--- /dev/null
+++ b/source/app/controllers/login_controller.rb
@@ -0,0 +1,276 @@
+# This controller takes care of security.
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class LoginController < ApplicationController
+
+ before_filter :authenticate, :except => [:index, :sign_up2, :sign_up, :login, :lost_password, :new_cadmin,
+ :confirm_account, :report_password_reset_attempt, :auto_complete_for_user_email, :resend]
+ before_filter :authenticate_admin, :only => [:resend]
+
+ verify :method => :post, :only => [:resend],:add_flash => {'error' => ::FLASH_USE_POST_NOT_GET}, :redirect_to => { :controller => 'other', :action => 'error' }
+
+ FLASH_CENTRAL_ADMIN_ALREADY_CREATED = 'You can only create the central admin if this user has not been created yet!'
+ FLASH_INVALID_PW = 'Invalid combination of username password!'
+ FLASH_NO_VALID_TOKEN = 'Not a valid token!'
+ FLASH_PASSWORD_ACTIVATED = 'New password activated!'
+ FLASH_LOST_PASSWORD_ABUSE = 'A notification was sent to the administrator reporting the abuse of your email address'
+ FLASH_CENTRAL_ADMIN_CREATED = 'Central admin user created!'
+ FLASH_PW_SENT = 'Password sent!'
+ FLASH_PW_CONFIRMATION_EMAIL_SENT = 'A confirmation email has been sent to your email address. Please confirm your account be clicking on the hyperlink in this email'
+ FLASH_EMAIL_NOT_FOUND = 'Email address not found!'
+ FLASH_UNOT_ADMIN = "You are not an admin user!"
+ FLASH_UNOT_CADMIN = "You are not the central administrator!"
+
+ # Is be used to create the first user, the central admin account
+ def new_cadmin
+ if User.count > 0
+ flash['error'] = FLASH_CENTRAL_ADMIN_ALREADY_CREATED
+ redirect_to :action => 'login'
+ else
+ if request.get?
+ @user = User.new
+ else
+ @user = User.new_cadmin(params[:user])
+ if @user.save
+ flash['success'] = FLASH_CENTRAL_ADMIN_CREATED
+ redirect_to :action => 'login'
+ else
+ render :action => 'new_cadmin'
+ end
+ end
+ end
+ end
+
+ # Action #sign_up creates the account or displays the form to create the account.
+ # Passwords can be generated or supplied by the user.
+ # If passwords are supplied by the user the account needs to be confirmed,
+ # see #confirm_account
+ def sign_up
+ if request.get?
+ @user = User.new
+ else
+ @user = User.new_signup(params[:user])
+ if @user.save
+ # The following code is workaround for the fact that we cannot
+ # use url_for in view files for emails. Same goes for urls variable
+ sites = Site.find_wikis
+ sites.each {|site| site.url = url_for(site.rel_path)}
+ # end of workaround code
+ if ENV['EPFWIKI_GENERATE_PASSWORDS'] == '1'
+ urls = ['http://' + request.host]
+ urls << url_for(:controller => 'users', :action => 'edit', :id => @user.id)
+ urls << url_for(:controller => 'login', :action => 'change_password')
+ Notifier::deliver_new_password(@user, sites, urls )
+ flash['success'] = FLASH_PW_SENT
+ redirect_to :action => "login"
+ else
+ urls = [url_for(:controller => 'login', :action => 'confirm_account', :id => @user.id, :tk => @user.token)]
+ urls << url_for(:controller => 'login', :action => 'report_password_reset_attempt', :id => @user.id, :tk => @user.token)
+ Notifier::deliver_confirmation_link(@user, sites, urls)
+ flash['success'] = FLASH_PW_CONFIRMATION_EMAIL_SENT
+ redirect_to :action => "login"
+ end
+ else
+ @user.email = @user.email.gsub(@user.email_extension,"") if @user.email && @user.email_extension
+ @user.password = ""
+ @user.password_confirmation = ""
+ end
+ end
+ end
+
+ # Action #confirm_account is used to confirm a new password send by email. Without confirmation anyone could reset passwords.
+ # The token used for confirmation is just the new password hashed twice. The new password is stored in the column <tt>confirmation_token</tt>.
+ # Action #resend_password is used to request a new password.
+ def confirm_account
+ @user = User.find(params[:id])
+ if @user.confirm_account(params[:tk])
+ if @user.save
+ flash['success'] = FLASH_PASSWORD_ACTIVATED
+ else
+ raise "Failed to activate account for #{@user.email}"
+ end
+ else
+ flash['error'] = FLASH_NO_VALID_TOKEN
+ end
+ redirect_to :action => 'login'
+ end
+
+ # admin users are able to send a new password to a user
+ def resend
+ @user = User.find(params[:id])
+ @user.set_new_pw
+ if @user.save
+ # the following is workaround code for the fact that we cannot use url_for
+ # views for email
+ sites = Site.find_wikis
+ sites.each {|site| site.url = url_for(site.rel_path)}
+ urls = ['http://' + request.host]
+ urls << url_for(:controller => 'users', :action => 'edit', :id => @user.id)
+ urls << url_for(:controller => 'login', :action => 'change_password')
+ # end of workaround code
+ Notifier::deliver_new_password(@user, sites, urls )
+ flash['success'] = FLASH_PW_SENT
+ else
+ logger.debug("Failed to save new password of user " + @user.email + ".")
+ flash['error'] = FLASH_FAILED_TO_RESEND_PW
+ end
+ redirect_to :controller => 'users', :action => 'list'
+ end
+
+ # Action #change_password allows a user to change the password
+ #--
+ # TODO: security enhancement: require the old password
+ # TODO: like to use flash.now here but functional tests will fail! Is a bug?
+ # TODO: add to user details?
+ #++
+ def change_password
+ @user= User.find(session['user'].id)
+ if request.get?
+ else
+ @user.errors.add(:password, "Can't be blank") if params[:user][:password].blank?
+ @user.change_password(User.new(params[:user]))
+ if @user.save
+ flash['success'] = FLASH_PW_CHANGED
+ else
+ @user= User.find(session['user'].id)
+ end
+ end
+ end
+
+ # With action #report_password_reset_attempt users can report that they received a new password that they didn't request.
+ def report_password_reset_attempt
+ @user = User.find(params[:id])
+ Notifier::deliver_env_to(User.find_central_admin,
+ @session.instance_variable_get("@data"),
+ @params,
+ @request.env)
+ flash['notice'] = ::MSG_LOST_PASSWORD_ABUSE
+ redirect_to :controller => 'users', :action => 'show'
+ end
+
+ def index
+ redirect_to :action => 'login'
+ end
+
+ # Generate a new password for a user and sends it in a email.
+ # The new password is activated after the user confirms it. The old passwords remains
+ # active, otherwise any user can disable accounts!
+ def lost_password
+ if request.get?
+ @user = User.new
+ else
+ @user = User.new(params[:user])
+ logger.info('Finding user with email: ' + @user.email.downcase)
+ @user_by_email = User.find_by_email(@user.email.downcase)
+ if @user_by_email
+ @user_by_email.set_new_pw
+ if @user_by_email.save
+ urls = [url_for(:controller => 'login', :action => 'confirm_account', :id => @user_by_email.id, :tk => @user_by_email.token)]
+ urls << url_for(:constroller => 'login', :action => 'report_password_reset_attempt', :id => @user_by_email.id, :tk => @user_by_email.token)
+ Notifier::deliver_lost_password(@user_by_email, urls)
+ Notifier::deliver_env_to(User.find_central_admin,
+ @session.instance_variable_get("@data"),
+ @params,
+ @request.env)
+ flash['success'] = FLASH_PW_SENT
+ redirect_to :action => "login"
+ else
+ logger.error(@user_by_email.errors.full_messages.join(', '))
+ end
+ else
+ @user.email = ""
+ flash['notice'] = FLASH_EMAIL_NOT_FOUND
+ end
+ end
+ end
+
+ # Action #login checks if there is a cookie. With 'posts' we try to login using User.try_to_login. If the user
+ # wants to be remembered a cookie is created. 'Gets' can login the user if the user has a good cookie.
+ def login
+ @wikis = Site.find_wikis
+ if request.get?
+ if cookies[:epfwiki_id] && User.exists?(cookies[:epfwiki_id])
+ logger.info("Found cookie and user with id " + cookies[:epfwiki_id])
+ @user = User.find(cookies[:epfwiki_id])
+ token = cookies[:epfwiki_token]
+ if @user.confirm_account(token)
+ logger.info("Token good refresh cookies and login user")
+ create_cookie(@user) # refresh van cookie
+ @user.update_attributes({:http_user_agent => request.env['HTTP_USER_AGENT'], :ip_address => request.env['REMOTE_ADDR'] , :last_logon => Time.now, :logon_count => @user.logon_count + 1, :logon_using_cookie_count => @user.logon_using_cookie_count + 1})
+ session['user'] = @user
+ redirect2page
+ else
+ expire_cookie(session['user'])
+ session['user'] = nil
+ @user = User.new
+ logger.info("get response")
+ end
+ else
+ @cadmin = User.find_central_admin
+ if @cadmin
+ session['user'] = nil
+ @user = User.new
+ else
+ redirect_to :action => 'new_cadmin'
+ end
+ end
+ else
+ @user = User.new(params[:user])
+ @logged_in_user = @user.try_to_login
+ if @logged_in_user
+ logger.info("Login succesfull")
+ session['user'] = @logged_in_user
+ if @user.remember_me == "0" # remember_me = 0, do not remember_me is 1
+ create_cookie(@logged_in_user)
+ end
+ @logged_in_user.update_attributes({:http_user_agent => request.env['HTTP_USER_AGENT'], :ip_address => request.env['REMOTE_ADDR'] , :last_logon => Time.now, :logon_count => @logged_in_user.logon_count + 1})
+ redirect2page
+ else
+ @user = User.new
+ flash['notice'] = FLASH_INVALID_PW
+ logger.info("Invalid combination of username password for #{@user.email}")
+ end
+ end
+ end
+
+ # destroy the session and cookie redirect to #login
+ def logout
+ session['user'] = nil
+ flash[:notice] = "Logged out"
+ redirect_to :action => "login"
+ expire_cookie
+ end
+
+ def redirect2page
+ if session["return_to"]
+ redirect_to_path(session["return_to"])
+ session["return_to"] = nil
+ else
+ redirect_to :controller => "users", :action => "show", :id => @logged_in_user
+ end
+ end
+
+ def auto_complete_for_user_email
+ search = params[:user][:email]
+ logger.debug("search:" + search)
+ @users = User.find(:all, :conditions => ["email like ?", search + "%"], :order => "email ASC") unless search.blank?
+ if @users.length == 1
+ render :inline => "<ul class=\"autocomplete_list\"><li class=\"autocomplete_item\"><%= @users[0].email %></li></ul>"
+ else
+ render :inline => "<ul class=\"autocomplete_list\"></ul>"
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/source/app/controllers/other_controller.rb b/source/app/controllers/other_controller.rb
new file mode 100644
index 0000000..304a7ed
--- /dev/null
+++ b/source/app/controllers/other_controller.rb
@@ -0,0 +1,154 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class OtherController < ApplicationController
+ before_filter :authenticate, :except => [:error]
+ before_filter :authenticate_cadmin, :only => [:run_indexer, :migrate, :upload_release, :online_update, :show_log]
+
+ # Action #info displays information this application
+ def info
+ # determine available releases
+ entries = (Dir.entries(ENV['EPFWIKI_RELEASE_DIR']) - [".", ".."]) if File.exists?(ENV['EPFWIKI_RELEASE_DIR'])
+ if entries
+ entries = entries.collect {|entry| entry if !entry.downcase.index(".zip")}
+ logger.info("Entries: " + entries.inspect)
+ @releases = Array.new
+ entries.compact.each do |entry|
+ parts = entry.split("_")
+ @releases << [entry, parts[1], parts[2] + "_" + parts[3], db_script_version(ENV['EPFWIKI_RELEASE_DIR'] + entry + "/db/migrate")]
+ end
+ end
+ # determine database schema script version
+ @version = db_script_version(ENV['EPFWIKI_ROOT_DIR'] + "db/migrate")
+ @database_schema = User.find_by_sql('select version from schema_info')[0]
+ if @database_schema.version.to_s == @version.to_s
+ @version = nil
+ else
+ flash.now['warning'] = "Database seems out-of-date. Available scripts are of a higher version. Available is " + @version.to_s + ", installed is " + @database_schema.version.to_s
+ end
+ if File.exists?(ENV['EPFWIKI_ROOT_DIR'] + "db/simple_search_index")
+ @index_mtime = File.mtime(ENV['EPFWIKI_ROOT_DIR'] + "db/simple_search_index")
+ end
+ end
+
+ #--
+ # TODO R? Home page with general info, recent comments, downloads, recent versions.
+ #++
+ def home
+ end
+
+ def download_logfile
+ send_file("#{ENV['EPFWIKI_ROOT_DIR']}log/#{params[:file]}" , :type => 'text/plain', :stream => false)
+ end
+
+ # Action #online_update updates the application with another release, typcially a newer release.
+ # 1) remove migrate folder, 2) copy ( and overwrite) the target release to the app root, 3) migrate database, 4) restart server
+ # In case the target release uses of previous version of the database, the procedure is a little different. In that case the database is migrated first.
+ # Note: we remove the migrate folder because otherwise it is not possible to determine if the database is up-to-date or not.
+ def online_update
+ raise "Of couse you cannot use the online update feature in development" if RAILS_ENV == "development"
+ @release_folder = params[:release]
+ raise "Release folder does not exits" if !File.exists?(ENV['EPFWIKI_RELEASE_DIR'] + @release_folder)
+ schema_version = db_script_version("#{ENV['EPFWIKI_ROOT_DIR']}db/migrate")
+ target_schema_version = db_script_version(ENV['EPFWIKI_RELEASE_DIR'] + @release_folder + "/db/migrate")
+ downgrade = (target_schema_version < schema_version)
+ if downgrade
+ logger.info("Downgrading schema definition from version #{schema_version} to version #{target_schema_version}")
+ result = db_migrate_to_version(target_schema_version)
+ end
+ logger.info("Removing files in folder \"#{ENV['EPFWIKI_ROOT_DIR']}db/migrate\" and copying \"#{ENV['EPFWIKI_RELEASE_DIR']}#{@release_folder} to #{ENV['EPFWIKI_ROOT_DIR']}")
+ (Dir.entries("#{ENV['EPFWIKI_ROOT_DIR']}db/migrate") - [".", ".."]).each { | file | File.delete("#{ENV['EPFWIKI_ROOT_DIR']}db/migrate/#{file}") }
+ # NOTE: not possible to simply copy and overwrite in Ruby?
+ # FileUtils.cp_r(ENV['EPFWIKI_RELEASE_DIR'] + @release_folder + "/.", ENV['EPFWIKI_ROOT_DIR'], :force => true)
+ #File.copy(ENV['EPFWIKI_RELEASE_DIR'] + @release_folder, ENV['EPFWIKI_ROOT_DIR'])
+ cmdParameters = Array.new
+ cmdParameters << ENV['EPFWIKI_ROOT_DIR'].split(":")[0] + ":"
+ cmdParameters << ENV['EPFWIKI_ROOT_DIR'].gsub("/","\\")
+ cmdParameters << ENV['EPFWIKI_ANT_PATH']
+ cmdParameters << ENV['EPFWIKI_RELEASE_DIR']
+ cmdParameters << @release_folder
+ cmdLine = "#{ENV['EPFWIKI_ROOT_DIR']}script/other/deploy.bat #{cmdParameters.join(' ')}"
+ logger.info("Copying release using Apache Ant, command: " + cmdLine)
+ cmd = IO.popen(cmdLine, "w+")
+ cmd.close_write
+ result_deploy = cmd.readlines.join
+ if !downgrade
+ logger.info("Migrating schema definition from version #{schema_version} to version #{target_schema_version}")
+ result = db_migrate_to_version
+ end
+ logger.info("Result of database migration: " + result)
+ logger.info("Result of deploy: " + result_deploy)
+ write_log("deploy.log", [result,result_deploy].compact.join("\n"))
+ cmd = IO.popen("restart.bat", "w+")
+ cmd.close_write
+ # ENH R? ? online_update stops here because of the restart, better to use a job to restart?
+ end
+
+ def upload_release
+ dummy = Site.new(params[:site]) # for good measure using Site class for the upload
+ @filename = dummy.file.original_filename
+ @filename = @filename.gsub(/^.*(\\|\/)/, '') # sanitize filename, how this looks depends on browser, IE or FireFox
+ @filename = @filename.gsub(/[^\w\.\-]/,'_')
+ @content_type = dummy.file.content_type
+ logger.info("Uploading release, filename #{@filename}, content_type #{@content_type}")
+ raise "Not a zip!" if !@filename.downcase.index(".zip")
+ @release_folder = @filename.upcase.gsub(".ZIP", "")
+ File.makedirs(ENV['EPFWIKI_RELEASE_DIR'])
+ File.open(ENV['EPFWIKI_RELEASE_DIR'] + @filename, "wb") { |f| f.write(dummy.file.read) }
+ cmdParameters = Array.new
+ cmdParameters << ENV['EPFWIKI_ROOT_DIR'].split(":")[0] + ":"
+ cmdParameters << (ENV['EPFWIKI_ROOT_DIR'] + 'script/other').gsub("/","\\")
+ cmdParameters << ENV['EPFWIKI_ANT_PATH']
+ cmdParameters << ENV['EPFWIKI_RELEASE_DIR']
+ cmdParameters << @filename
+ cmdParameters << @release_folder
+ cmdLine = "#{ENV['EPFWIKI_UNZIP_RELEASE_BAT_FILE']} #{cmdParameters.join(' ')}"
+ logger.debug("Unzipping release zip using Apache Ant, command: " + cmdLine)
+ cmd = IO.popen(cmdLine, "w+")
+ cmd.close_write
+ text = cmd.readlines.join
+ flash['success'] = "File #{@filename} uploaded to server and unzipped to folder #{ENV['EPFWIKI_RELEASE_DIR']}#{@release_folder}"
+ write_log("upload_release.log", text)
+ redirect_to :action => 'info'
+ end
+
+ def migrate
+ result = db_migrate_to_version
+ flash['notice'] = "Migration was called, see log file for details"
+ write_log("migrate.log", result)
+ redirect_to :action => 'info'
+ end
+
+ # TODO R? full text search
+ def run_indexer
+ indexer = IO.popen("ruby script/indexer", "w+")
+ indexer.close_write
+ output = indexer.readlines.join
+ write_log("indexer.log", output)
+ if output.index("creating index file") then
+ flash['success'] = "Index updated, see log file for details"
+ else
+ flash['warning'] = "Index was not updated succesfully, see log file for details"
+ end
+ redirect_to :action => 'info'
+ end
+
+ # Action #error is redirected to from ApplicationController.resque_action_in_public to display a userfriendly error message
+ def error
+ end
+
+ # Action #env displays environment variables
+ def env
+ end
+end
diff --git a/source/app/controllers/pages_controller.rb b/source/app/controllers/pages_controller.rb
new file mode 100644
index 0000000..c191362
--- /dev/null
+++ b/source/app/controllers/pages_controller.rb
@@ -0,0 +1,240 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class PagesController < ApplicationController
+
+ before_filter :authenticate
+ before_filter :authenticate_cadmin, :only => [:destroy]
+
+ model :page
+ model :comment
+ model :version
+ model :checkout
+ model :site
+ model :user
+
+ FLASH_CHECKIN_SUCCESS = "Check-in succesfull, please add or update the version note!"
+
+ # action #checkout to create a new checkout
+ # GET request with id, site_id, target_site_id (optional), version_id (optional)
+ # TODO source page not visible in view
+ def checkout
+ if request.get?
+ @version = Version.new
+ @page = Page.find(params[:id])
+ @wiki = Site.find(params[:site_id]) if params[:site_id]
+ @wiki = @page.wikis_4checkout[0] if @wiki.nil? && @page_wikis_4checkout[0]
+ @version.site = @wiki
+ @version.site = Site.find(params[:target_site_id]) if params[:target_site_id]
+ @checkout = session['user'].checkouts.find_by_site_id_and_page_id(@wiki.id, @page.id)
+ if @checkout
+ logger.info("File #{@page.presentation_name} already checked out by user #{session['user']}")
+ redirect_to :action => 'edithtml', :checkout_id => @checkout.id
+ else
+ if params[:version_id]
+ logger.info("Finding source version by version_id:" + params[:version_id].to_s)
+ @version.source_version = Version.find(params[:version_id])
+ else
+ logger.info("Current version of #{@page.presentation_name} in #{@wiki.title} will be the source version")
+ source_version = Version.find_current_version(@wiki, @page, true)
+ source_version.save! if source_version.version == 0 # save the base version if we created one
+ @version.source_version = source_version
+ end
+ @version.page = @page
+ # NOTE: when creating a new page @source_version.page and @page are different.
+ @versions = @version.source_version.page.versions
+ end
+ else
+ @wiki = Site.find(params[:wiki_id])
+ @version = Version.new(params[:version])
+ logger.debug('Before checkout.new')
+ @checkout = Checkout.new(:note => @version.note, :page => @version.page, :site => @version.site, :source_version => @version.source_version, :user => session['user'] )
+ if @checkout.save
+ logger.debug('Save is true')
+ redirect_to :action => 'edithtml', :checkout_id => @checkout.id
+ end
+ end
+ end
+
+ # FIXME R1 pinEdit warning: please don't use / at the beginning or end of a globalDocDir
+ # TODO R? EPF Editor support
+ # TODO R1 FireFox support
+ def edithtml
+ ENV['EPFWIKI_EDITOR'] = params[:editor] if params[:editor] # hidden feature, change editor online
+ @checkout = Checkout.find(params[:checkout_id])
+ raise 'Cannot edit a file that is checked out by another user' if !mine?(@checkout) && !cadmin?
+ render :layout => false
+ end
+
+ # Action #new to create a new Page based on a template or based on another page.
+ def new
+ if request.get?
+ @wiki = Site.find(params[:site_id])
+ @page = Page.new
+ @templates = @wiki.templates
+ @page.source_version = @templates[0].versions.last.id unless @templates.empty?
+ if params[:id]
+ @another_page = Page.find(params[:id])
+ version = Version.find_current_version(@wiki,@another_page, true)
+ version.save! if version.version == 0
+ @page.source_version = version.id
+ @templates = [@another_page.reload] + @templates # reload page so that possible new baseversion is found
+ end
+ else
+ @page = Page.new(params[:page].merge(:user=> session['user']))
+ @page.source_version = Version.find(@page.source_version) # turn id into object
+ @page.site = @page.source_version.site
+ if @page.save
+ @checkout = @page.checkout(@page.source_version.site)
+ if @checkout
+ redirect_to :action => 'edithtml', :checkout_id => @checkout.id
+ else
+ raise 'No checkout created; new page operation should have created a checkout'
+ end
+ end
+ end
+ end
+
+ # TODO R1 TinyMCE support - Save from browser (not the top link) does a checkin, not a save
+ # TODO R1 TinyMCE support - buttons for save, checkin, preview
+ def saveorcheckin
+ if (params[:save] == 'Y' || params[:save] == 'P')
+ save
+ else
+ checkin
+ end
+ end
+
+ #--
+ # TODO R? improved security - move authorisation check to Checkout.undo?
+ #++
+ def undocheckout
+ @checkout = Checkout.find(params[:checkout_id])
+ if mine?(@checkout) || cadmin?
+ @checkout.undo
+ if Checkout.exists?(@checkout.id)
+ raise "Failed to undo checkout #{@checkout.id} of page #{@checkout.page.presentation_name}"
+ else
+ redirect_to :controller => 'versions', :action => 'list', :site_id => @checkout.version.site.id, :page_id => @checkout.page
+ end
+ else
+ raise "This checkout is owned by #{@checkout.user.name}. You cannot undo a checkout that belongs to another user"
+ end
+ end
+
+
+ # #filelist is used from the HTML editor component (called from public\editor\dialogs\php\dialog.htm).
+ # NOTE: this action replaces the filelist.php from PinEdit
+ #--
+ # TODO R1 TinyMCE support
+ #++
+ def filelist
+ # this is called from public\editor\dialogs\php\dialog.htm
+ # url = url + "mode=" + mode;
+ # url = url + "&language=" + language;
+ # url = url + "&urlabs=" + urlabs;
+ # url = url + "&pathabs=" + pathabs;
+ # url = url + "&filter=" + filter;
+ # url = url + "&rnd=" + Math.random() ;
+ logger.debug("params[:pathabs]:" + params[:pathabs])
+ if params[:pathabs].index(session['user'].documents_path)
+ @files = session['user'].documents
+ else
+ @files = session['user'].images
+ end
+ render :layout => false
+ end
+
+ #++
+ # TODO R? check if file already exists and raise exception?
+ # TODO R1 TinyMCE support - works only with PinEdit
+ # TODO R? versioning for documents and images ?
+ #--
+ def upload
+ @file = params[:file]
+ @path = params[:path]
+ @insert = params[:insert]
+ File.open(params[:path]+params[:file].original_filename, "wb") { |f| f.write(params[:file].read) }
+ render :layout => false
+ end
+
+ # to #show the properties and relationships of a specific Page. Some operations on and attributes of a Page
+ # depend on the context (Site), so it is possible to call certain actions with a Site-record
+ def show
+ @page = Page.find(params[:id])
+ @site = Site.find(params[:site_id]) if params[:site_id]
+ @version_pages, @versions = paginate :version, :per_page => 5, :order => 'created_on DESC', :conditions => ['page_id = ? and site_id = ?', @page.id, @site.id ]
+ end
+
+ # action #show displays the tab for the Version-records. Action #show_comments displays the Comment-records for
+ # a specific Page-record
+ def show_comments
+ @page = Page.find(params[:id])
+ @site = Site.find(params[:site_id]) if params[:site_id]
+ @comment_pages, @comments = paginate :comment, :per_page => 5, :order => 'created_on DESC', :conditions => ['page_id = ? and site_id = ?', @page.id, @site.id ]
+ render :action => 'show'
+ end
+
+ # TODO R? Implement test
+ def destroy
+ @page = Page.find(params[:id])
+ paths = @page.sites.collect {|site|@page.path(site)}
+ #paths.each {|path| File.delete(path) if File.exists?(path)} # decided not to delete the files
+ Checkout.destroy_all(['page_id=?', @page.id])
+ Comment.destroy_all(['page_id=?', @page.id])
+ DifferenceAnalysisItem.destroy_all(['page_id=?', @page.id])
+ Notification.destroy_all(['page_id=?', @page.id])
+ Version.destroy_all(['page_id=?', @page.id])
+ @page.destroy
+ flash['success'] = "Page record and files " + paths.join(", ") + " deleted!"
+ redirect_to :controller => 'sites'
+ end
+
+ ###########
+ private
+ ###########
+
+ # #save the HTML after checking that the User is the owner. The Page remains checked-out.
+ #--
+ # TODO R? move mine? check to version.save_html?
+ #++
+ def save
+ @checkout = Checkout.find(params[:checkout_id])
+ raise LoginController::FLASH_UNOT_CADMIN if !mine?(@checkout) && !cadmin?
+ @checkout.version.html(params[:html])
+ @checkout.version.save
+ if params[:save] == 'P'
+ redirect_to_path url_for('/' + @checkout.version.rel_path_root)
+ else
+ redirect_to :action => 'edithtml', :checkout_id => @checkout.id
+ end
+ end
+
+ # #checkin to checkin a page that is checked-out
+ def checkin
+ checkout = Checkout.find(params[:checkout_id])
+ version = checkout.version
+ checkout.checkin(session['user'], params[:html])
+ raise "Failed to checkin #{checkout.id}" if Checkout.exists?(checkout.id)
+ flash['success'] = FLASH_CHECKIN_SUCCESS
+ users = Notification.find_all_users(version.site, version.page, 'Version')
+ unless users.empty?
+ subject = "New version created of #{version.page.presentation_name}"
+ introduction = "User #{version.user.name} created a version of <a href=\"http://#{request.host}/#{version.site.rel_path}/#{version.page.rel_path}\">#{version.page.presentation_name}</a> in site #{version.site.title}<br>"
+ Notifier::deliver_notification(users,subject,introduction, version.note, request.host)
+ end
+ redirect_to :controller => 'versions', :action => 'edit', :id => version.id
+ end
+
+end
\ No newline at end of file
diff --git a/source/app/controllers/search_controller.rb b/source/app/controllers/search_controller.rb
new file mode 100644
index 0000000..256b221
--- /dev/null
+++ b/source/app/controllers/search_controller.rb
@@ -0,0 +1,94 @@
+require_dependency "search_system"
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class SearchController < ApplicationController
+ layout 'application' , :except => [:rss, :description]
+
+ def index
+ search
+ end
+
+ #-----------------------------------------------------------------------
+ # search through the index, get the ActiveRecord's that match and
+ # return those to the caller
+ #-----------------------------------------------------------------------
+ def search
+ @search_config = YAML.load(File.open(File.join(RAILS_ROOT,'config','search.yml')))
+
+ if @params['search_terms'].nil? then
+ @search_terms = @search_config['default_search_terms']
+ else
+ @search_terms = @params['search_terms'].split
+ end
+
+ @count = @params['count'].to_i || -1
+
+ self.send("#{@search_config['search_backend']}_search")
+ render :action => 'index'
+ end
+
+ def simple_search
+
+ empty_contents = MockContents.new
+
+ index_filename = File.join(RAILS_ROOT,@search_config['simple_backend']['index_filename'])
+
+ if not File.exists?(index_filename) then
+ raise "content index file (#{File.expand_path(index_filename)}) does not exist. Did you run scripts/indexer ?"
+ end
+
+ simple_index = Search::Simple::Searcher.load(empty_contents,index_filename)
+
+ # what to return to the caller
+ @results = Array.new
+
+ search_results = simple_index.find_words(@search_terms)
+ if search_results.contains_matches && search_results.warnings.empty? then
+ #if search_results.contains_matches then
+ search_results.results.sort.each do |result|
+ (classname,pk_id,column) = result.name.split(".")
+ classvar = eval(classname)
+ @results << classvar.find(pk_id)
+ break if @count > 0 and @results.size >= @count
+ end
+ end
+
+ @results.uniq!
+ @pages = Array.new
+ @comments = Array.new
+ @wikis = Array.new
+ @results.each do |result|
+ if result.class.to_s == 'Page'
+ @pages << result
+ @wikis = @wikis | result.sites
+ elsif result.class.to_s == 'Comment'
+ @comments << result
+ end
+ end
+ @wikis = @wikis & Site.find_wikis
+ end
+
+
+ def description
+ @headers["Content-Type"] = "text/xml"
+ render 'opensearch/description'
+ end
+ def rss
+ @headers["Content-Type"] = "text/xml"
+ search
+ render 'opensearch/rss'
+ end
+end
diff --git a/source/app/controllers/sites_controller.rb b/source/app/controllers/sites_controller.rb
new file mode 100644
index 0000000..076a4df
--- /dev/null
+++ b/source/app/controllers/sites_controller.rb
@@ -0,0 +1,181 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class SitesController < ApplicationController
+
+ before_filter :authenticate
+ before_filter :authenticate_admin, :only => [:new, :compare, :new_wiki, :create, :update_wiki, :update, :upload]
+ before_filter :authenticate_cadmin, :only => [:wikify_now, :update_wiki_now, :scan4content]
+
+ FLASH_NEED_TO_UPLOAD = "To be able to create baseline process you will first have to upload a EPF published site to a folder in #{ENV['EPFWIKI_SITES_FOLDER']}"
+ FLASH_UPLOAD_SUCCESS = 'The file was uploaded, if the folder is not in dropdown box, please refresh'
+ FLASH_WIKI_SITE_SCHEDULED = 'The Wiki is scheduled to be created! For performance reasons this is done using a nightly build process. An email will be send after the site is created'
+ FLASH_WIKI_CREATED = 'Wiki succesfully created'
+ FLASH_WIKI_SITE_UPDATE_SCHEDULED = 'The site is scheduled to be updated. An email will be send after the site is updated'
+ FLASH_NO_BL_CANDIDATE = 'No candidate baseline processes found'
+ FLASH_WIKI_UPDATE_SUCCESS = 'Wiki succesfully updated'
+ FLASH_CHECKOUTS_NO_UPDATE = 'There are checkouts, so the Wiki cannot be updated. An email was sent requesting checkin.'
+
+ #--
+ # FIXME R1 Invalid argument in console
+ # In the console when running built-in server the message ERROR Errno::EINVAL: Invalid argument is displayed
+ #++
+ def index
+ list
+ render :action => 'list'
+ end
+
+ def list
+ @baseline_processes = Site.find_baseline_processes
+ @pending_sites = Site.find_wikis_pending
+ @wiki_sites = Site.find_wikis - @pending_sites
+ @deleted_sites = Site.find_all_by_site_type('D')
+ end
+
+ #--
+ # FIXME R1 error occured while evaluating nil.original_filename
+ # after upload of zip and submit of the new site. Workaround is to
+ # refresh the page
+ # FIXED? with redirect_to instead of render?
+ #++
+ def upload
+ @site = Site.new_upload(params[:site])
+ flash['success'] = FLASH_UPLOAD_SUCCESS if @site.errors.empty?
+ @baseline = Baseline.new
+ @folders = Site.folders_with_unused_baseline_processes
+ redirect_to :action => 'new'
+ end
+
+ # Action #new creates a baseline process. This will also define a Baseline, see Site.new_baseline_process.
+ def new
+ @baseline = Baseline.new
+ @folders = Site.folders_with_unused_baseline_processes
+ if request.get?
+ @site = Site.new
+ flash['notice'] = FLASH_NEED_TO_UPLOAD if @folders.empty?
+ else
+ @site = Site.new_baseline_process(params[:site].merge(:user => session['user']))
+ if @site.save
+ flash[:success] = ::FLASH_RECORD_CREATED
+ redirect_to :action => 'list'
+ else
+ render :action => 'new'
+ end
+ end
+ end
+
+ # FIXME ERROR Errno::EINVAL: Invalid argument
+ # appears in logging when new wiki is called
+ def new_wiki
+ @baseline_processes = Site.find_baseline_processes
+ if request.get?
+ @site = Site.new
+ else
+ @site = Site.new_wiki(params[:site].merge(:user => session['user']))
+ if @site.save
+ Notifier::deliver_wiki_scheduled(@site, session['user'])
+ flash['success'] = FLASH_WIKI_SITE_SCHEDULED
+ redirect_to :action => 'list'
+ end
+ end
+ end
+
+ # action #wikify_now wikifies the Site
+ def wikify_now
+ @wiki = Site.find(params[:id])
+ @wiki.wikify
+ if @wiki.save
+ flash.now['success'] = FLASH_WIKI_CREATED
+ Notifier::deliver_wiki_created(@wiki,@wiki.user)
+ end
+ show
+ render :action => 'show'
+ end
+
+ # action #update_wiki allows an administrator to schedule an update of a site with a Baseline.
+ # The actual update is performed typically done by generic.job_daily. See also #update_wiki_now
+ def update_wiki
+ @site = Site.find(params[:id])
+ if request.get?
+ flash.now['notice'] = FLASH_NO_BL_CANDIDATE if @site.baseline_processes_candidate.empty?
+ else
+ if @site.update_attributes(params[:site])
+ flash['success'] = FLASH_WIKI_SITE_UPDATE_SCHEDULED
+ unless @site.checkouts.empty?
+ flash['notice'] = 'The site has checkouts, an email has been sent to the owners requesting checkin. Update will be postponed untill all pages are checked in.'
+ Notifier::deliver_update_site_checkin_request(@site)
+ end
+ Notifier::deliver_wiki_scheduled4update(@site, session['user'])
+ redirect_to :action => 'show', :id => @site
+ end
+ end
+ end
+
+ # action #update_wiki_now allows the central administrator to do the update immediately, see also #update_wiki
+ def update_wiki_now
+ wiki = Site.find(params[:id])
+ if wiki.checkouts.empty?
+ wiki.update_wiki
+ if wiki.save
+ flash['success'] = FLASH_WIKI_UPDATE_SUCCESS
+ Notifier::deliver_email(([session['user'], User.find_central_admin]).uniq,
+ "[#{ENV['EPFWIKI_APP_NAME']}] Site #{wiki.title} updated!",[],
+ "The wiki site <strong>#{wiki.title}</strong> was succesfully updated to baseline #{wiki.baseline.baseline}")
+ else
+ # TODO because of the redirection use of error_messages in view will not work,
+ # so we misuse flash for displaying possibly messages. Maybe move this to 'edit'?
+ flash['error'] = wiki.errors.full_messages.join(', ')
+ end
+ else
+ flash['notice'] = FLASH_CHECKOUTS_NO_UPDATE
+ end
+ redirect_to :action => 'show', :id => wiki.id
+ end
+
+ def show
+ @site = Site.find(params[:id])
+ case params[:tab]
+ when nil
+ @version_pages, @versions = paginate :version, :per_page => 25, :order => 'created_on DESC', :conditions => ['site_id = ? and version <> 0', @site.id ]
+ when 'comments'
+ @comment_pages, @comments = paginate :comment, :per_page => 25, :order => 'created_on DESC', :conditions => ['site_id = ?', @site.id ]
+ when 'pages'
+ @page_pages, @pages = paginate :page, :per_page => 25, :order => 'created_on DESC', :conditions => ['exists (select * from pages_sites rrs where rrs.site_id = ? and rrs.page_id = pages.id)', @site.id]
+ end
+ end
+
+ def edit
+ @site = Site.find(params[:id])
+ if request.get?
+ else
+ @site = Site.find(params[:id])
+ if @site.update_attributes(params[:site])
+ flash['success'] = 'Site was successfully updated.'
+ redirect_to :action => 'show', :id => @site
+ else
+ render :action => 'edit'
+ end
+ end
+ end
+
+ def scan4content
+ show
+ @site.scan4content
+ if @site.save
+ flash['success'] ="Site was succesfully scanned for content. #{@site.pages.size.to_s} pages were scanned."
+ end
+ render :action => 'show'
+ end
+
+end
diff --git a/source/app/controllers/toolbar_controller.rb b/source/app/controllers/toolbar_controller.rb
new file mode 100644
index 0000000..a5ae15c
--- /dev/null
+++ b/source/app/controllers/toolbar_controller.rb
@@ -0,0 +1,83 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class ToolbarController < ApplicationController
+
+ def show
+ #--
+ # TODO R1 after update of a site with a new baseline process, the toolbar shouldn't show Last updated message
+ # This is now fixed with user of find_current_version?
+ #
+ # TODO R? Show some comments using with 'more...' link to comments.list
+ # TODO R1 add 'Compare with previous' link
+ #
+ # FIXME R? some filenames contain strange characters, for instance configuration_&_change_management,_wgltAP_IEdmAzesbYywanQ.html
+ # This results in the file not being found?
+ # Parameters: {"_change_management,_wgltAP_IEdmAzesbYywanQ.html"=>nil, "url"=>"http://localhost:3000/wikis/rup4project1/rup/domains/configuration_", "action"=>"toolbar", "controller"=>"rupwiki"}
+ #
+ # FIXME R1 wrong position of toolbar for pages that don't use, include treebrowser.js (pages for grouping folders)
+ #++
+ logger.debug("params[:url]:" + params[:url])
+ @document_url = params[:url]
+ url_parts = params[:url].split('/')
+ filename = url_parts[url_parts.size - 1]
+ @show_toolbar = Site::WIKI_FILE_PATTERN.match(filename).nil?
+ if @show_toolbar
+ url = params[:url]
+ s1,s2,s3,s4,s5 = params[:url].split('/')
+ @rel_path = params[:url].sub("http://#{s3}/#{s4}/#{s5}/", '').split('?')[0] # url sometimes contains a parameter!
+ logger.debug("Finding wiki by folder #{s4}")
+ @wiki = Site.find_by_folder_and_site_type(s5, 'W')
+ @page = Page.find_by_rel_path(@rel_path)
+ if @page
+ @comments = Comment.find(:all, :conditions => ['site_id=? and page_id=?', @wiki.id, @page.id], :limit => 3, :order=> 'created_on DESC') if @page.comments_count > 0
+ @checkout = @page.checkout(@wiki)
+ @version = Version.find_current_version(@wiki, @page)
+ @version = nil if @version && @version.version == 0
+ end
+ end
+ end
+
+ def expand_toggle
+ if session['toolbar_expanded']
+ session['toolbar_expanded'] = false
+ else
+ session['toolbar_expanded'] = true
+ end
+ show
+ render :action => 'show'
+ end
+
+ # Action #edit will find the Page-record (using Page.find_or_new) and then redirect to PageController.checkout for
+ # step 1 in editing a file: checking it out.
+ def edit
+ @site = Site.find(params[:id])
+ @page = Page.find_or_new(params, @site)
+ redirect_to :controller => 'pages', :action => 'checkout', :id => @page.id, :site_id => @site.id
+ end
+
+ # Action #new will find or create the Page-record and then redirect to PageController.new to start creation of a new page
+ def new
+ @site = Site.find(params[:id])
+ @page = Page.find_or_new(params, @site)
+ redirect_to :controller => 'pages', :action => 'new', :id => @page.id, :site_id => @site.id
+ end
+
+ # Action #new_comment will find or create the Page-record and then redirect to CommentsController.new to add a Comment to the Page
+ def new_comment
+ @site = Site.find(params[:id])
+ @page = Page.find_or_new(params, @site)
+ redirect_to :controller => 'comments', :action => 'new', :page_id => @page.id, :site_id => @site.id
+ end
+end
diff --git a/source/app/controllers/users_controller.rb b/source/app/controllers/users_controller.rb
new file mode 100644
index 0000000..809f728
--- /dev/null
+++ b/source/app/controllers/users_controller.rb
@@ -0,0 +1,144 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class UsersController < ApplicationController
+
+ model :user
+ model :notifier
+ before_filter :authenticate
+ before_filter :authenticate_admin, :only => [:list, :admin]
+ before_filter :authenticate_cadmin, :only => [:destroy, :cadmin]
+ require 'ftools'
+
+ verify :method => :post, :only => [:send_report, :destroy, :cadmin, :admin, :resend],
+ :add_flash => {'error' => ::FLASH_USE_POST_NOT_GET},
+ :redirect_to => { :controller => 'other', :action => 'error' }
+
+ FLASH_REPORT_SENT = "Report sent!"
+ FLASH_FAILED_TO_RESEND_PW = "New password could not be saved!"
+ FLASH_NO_LONGER_CADMIN = "You are no longer the central administrator"
+
+ def index
+ redirect_to :action => 'list'
+ end
+
+ def list
+ @admins = User.find_all_by_admin('Y')
+ @users = User.find_all_by_admin('N')
+ @cadmin = User.find_central_admin
+ end
+
+ def send_report
+ Notifier::deliver_report(params.merge(:user => session['user']))
+ flash['success'] = FLASH_REPORT_SENT
+ redirect_to :action => 'show'
+ end
+
+ def show
+ select_user
+ @version_pages, @versions = paginate :version, :per_page => 5, :order => 'created_on DESC', :conditions => ['user_id = ? and version <> 0', @user.id ]
+ end
+
+ def show_comments
+ select_user
+ @comment_pages, @comments = paginate :comment, :per_page => 5, :order => 'created_on DESC', :conditions => ['user_id = ?', @user.id ]
+ render :action => 'show'
+ end
+
+ def edit
+ @user = User.find(params[:id])
+ if request.get?
+ else
+ if mine?(@user) || cadmin?
+ if @user.update_attributes(params[:user].merge(:user => session['user']))
+ flash.now['success'] = ::FLASH_RECORD_UPDATED
+ end
+ else
+ flash.now['error'] = ::FLASH_NOT_OWNER
+ end
+ end
+ end
+
+ def destroy
+ #TODO: cannot destroy user with versions and comments, for good measure we should also do something with version and comments
+ #TODO: assign versions and comments to admin user, and do a flash notice
+ User.find(params[:id]).destroy
+ redirect_to :action => 'list'
+ end
+
+ def cadmin
+ @cadmin = User.find(session['user'].id) # about to become 'ordinary' admin
+ @user = User.find(params[:id]) # about to become cadmin
+ User.cadmin(@cadmin,@user)
+ flash['notice'] = FLASH_NO_LONGER_CADMIN
+ redirect_to :action => 'list'
+ end
+
+ def admin
+ @user = User.find(params[:id])
+ @user.update_attributes(params[:user].merge(:user => session['user']))
+ if @user.save
+ flash['success'] = ::FLASH_RECORD_UPDATED
+ end
+ redirect_to :action => 'list'
+ end
+
+ def toggle_change_report_notification
+ user = User.find(session['user'].id)
+ if mine?(user) || admin?
+ user.notify_daily = (user.notify_daily - 1).abs if params[:type] == 'D'
+ user.notify_weekly = (user.notify_weekly - 1).abs if params[:type] == 'W'
+ user.notify_monthly = (user.notify_monthly - 1).abs if params[:type] == 'M'
+ #user.notify_dialy = 1
+ user.save!
+ end
+ render :inline => "<%= link_to_change_report_notification_toggle('#{params[:type]}') %>"
+ end
+
+ # Action #notification creates or deletes (toggles) a notification of a certain type for a Page and Site
+ def notification
+ @site = Site.find(params[:site_id])
+ @page = Page.find(params[:page_id])
+ @type = params[:notification_type]
+ notification = Notification.find(:first, :conditions => ["user_id=? and site_id=? and page_id=? and notification_type=?", session['user'].id, @site.id, @page.id, @type])
+ if notification
+ notification.destroy
+ else
+ notification = Notification.create(:user => session['user'], :page => @page, :site => @site, :notification_type => @type)
+ end
+ render :inline => '<%= link_to_notification_toggle(@site, @page, @type)%>'
+ end
+
+ # Action #destroy_notification to destroy Notification.
+ # Should be called from link_to_remote using :remove
+ def destroy_notification
+ notification = Notification.find(params[:notification_id])
+ notification.destroy if mine?(notification)
+ render :inline => 'Removed'
+ end
+
+ protected
+ def select_user #:doc:
+ if params[:id]
+ @user = User.find(params[:id])
+ else
+ @user = session['user']
+ end
+ if !cadmin? && !mine?(@user)
+ @user = session['user']
+ flash['notice'] = LoginController::FLASH_UNOT_ADMIN
+ end
+ end
+
+end
diff --git a/source/app/controllers/versions_controller.rb b/source/app/controllers/versions_controller.rb
new file mode 100644
index 0000000..3d28c75
--- /dev/null
+++ b/source/app/controllers/versions_controller.rb
@@ -0,0 +1,137 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class VersionsController < ApplicationController
+
+ before_filter :authenticate
+ before_filter :authenticate_admin, :only => [:toggle_done, :review]
+
+ FLASH_FILES_IDENTICAL = "The two selected files are identical"
+
+ def show
+ @version = Version.find(params[:id])
+ @baseversion = @version.baseversion
+ @latest_version = Version.find_latest_version(@version.site, @version.page)
+ @current_version = @version.current_version
+ @source_version = @version.source_version
+ @previous_version = @version.previous_version
+ end
+
+ # Action #list to display the version history (versions of a page in a particular site)
+ def list
+ @site = Site.find(params[:site_id])
+ @page = Page.find(params[:page_id])
+ @versions = @page.versions_in_site(@site)
+ @other_versions = Version.find(:all, :conditions => ['site_id<>? and page_id=?', @site.id, @page.id], :order=> 'site_id, version ASC')
+ end
+
+ def listall
+ @version_pages, @versions = paginate :version, :per_page => 10, :order => 'created_on DESC', :conditions => ['version <> ?', 0]
+ @heading = 'Versions'
+ end
+
+ def listtodo
+ @version_pages, @versions = paginate :version, :per_page => 10, :order => 'created_on DESC', :conditions => ['done <> ? and version <> ?', "Y", 0]
+ @heading = 'Versions To Do'
+ render :action => 'listall'
+ end
+
+ def listdone
+ @version_pages, @versions = paginate :version, :per_page => 10, :order => 'created_on DESC', :conditions => ['done=? and version <> ?', "Y", 0]
+ @heading = 'Versions Done'
+ render :action => 'listall'
+ end
+
+ def listcheckouts
+ @version_pages, @versions = paginate :version, :per_page => 10, :order => 'created_on DESC', :conditions => ['exists (select * from checkouts cot where cot.version_id = versions.id)']
+ @heading = "Checkouts"
+ render :action => 'listall'
+ end
+
+ # Action #edit to update the version note
+ def edit
+ @version = Version.find(params[:id])
+ if request.get?
+ else
+ @version = Version.find(params[:id])
+ # TODO R? move to authorization to model
+ if mine?(@version) || cadmin?
+ @version.note = params[:version][:note]
+ if @version.update_attributes(params[:version])
+ flash['notice'] = ::FLASH_RECORD_UPDATED
+ redirect_to :action => 'list', :site_id => @version.site_id, :page_id => @version.page_id
+ end
+ else
+ flash.now['error'] = ::FLASH_NOT_OWNER
+ end
+ end
+ end
+
+ # Action #review assigns current User as the reviewer
+ def review
+ @version = Version.find(params[:id])
+ if @version.reviewer.nil?
+ @version.reviewer = session['user']
+ else
+ if @version.reviewer == session['user']
+ @version.reviewer = nil
+ else
+ @version.reviewer = session['user'] if cadmin?
+ end
+ end
+ @version.save!
+ render :inline => "<%= link_to_reviewer(@version) %>"
+ end
+
+ def markdown
+ @version = Version.find(params[:id])
+ end
+
+ def toggle_done
+ @version = Version.find(params[:id])
+ if @version.done == 'N'
+ @version.done = 'Y'
+ @version.user_thatmarkeddone = session['user']
+ else
+ @version.done = 'N'
+ @version.user_thatmarkedtodo = session['user']
+ end
+ @version.save!
+ render :inline => '<%= link_to_done_toggle(@version) %>'
+ end
+
+ # Action #compare is used to analyse the differences of the files of two Version-records.
+ # TODO ? check if markdown files are equal. Versio-record files can be different when markdown versions are not (although not likely)
+ # TODO ? check if version different from other_version
+ # TODO R1 html2text.py replacement, see xhtmldiff? [http://theinternetco.net/projects/ruby/xhtmldiff] instead of the Python script
+ # TODO R1 refactor to model
+ def compare
+ @version = Version.find(params[:id])
+ @versions = @version.page.versions_in_site(@version.site)
+ if request.get?
+ @source_version = @version.previous_version
+ else
+ @source_version = Version.find(params[:source_version_id])
+ if File.compare(@source_version.path, @version.path)
+ flash['notice'] = FLASH_FILES_IDENTICAL
+ else
+ @compare_results = diff(@version, @source_version) if params[:tab] == 'html'
+ @compare_results = diff_markdown(@version, @source_version) if !params[:tab]
+ end
+ end
+ end
+
+end
+
+
diff --git a/source/app/helpers/application_helper.rb b/source/app/helpers/application_helper.rb
new file mode 100644
index 0000000..5fc34c8
--- /dev/null
+++ b/source/app/helpers/application_helper.rb
@@ -0,0 +1,457 @@
+# Methods added to this helper will be available to all templates in the application.
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+#--
+# TODO formatting.. RadRails screws up formatting of this code
+#++
+module ApplicationHelper
+
+ class TabularFormBuilder < ActionView::Helpers::FormBuilder
+ (field_helpers - %w(radio_button hidden_field)).each do |selector|
+ src = <<-END_SRC
+ def #{selector}(field, options = {})
+ @template.content_tag("tr",
+ @template.content_tag("th", field.to_s.humanize, :width => 200) +
+ @template.content_tag("td", super))
+ end
+ END_SRC
+ class_eval src, __FILE__, __LINE__
+ end
+ end
+
+ def tabular_form_for(name, object = nil, options = nil, &proc)
+ if @table_heading
+ concat("<div class='sectionHeading'>#{@table_heading}</div>", proc.binding)
+ else
+ concat("<div class='sectionHeading'>#{name.to_s.humanize}</div>", proc.binding)
+ end
+ concat("<div class=\"sectionContent\"><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"sectionTable\"><tr valign=\"top\"><td class=\"sectionTableCell\"><table>",
+ proc.binding)
+ form_for(name,
+ object,
+ (options||{}).merge(:builder => TabularFormBuilder),
+ &proc)
+ concat("</table></td></tr></table></div>", proc.binding)
+ end
+
+ def url_for_site(site)
+ returning url = [] do
+ if site.baseline_process?
+ url << url_for("/#{ENV['EPFWIKI_SITES_FOLDER']}/#{site.folder}/")
+ else
+ url << url_for("/#{ENV['EPFWIKI_WIKIS_FOLDER']}/#{site.folder}/")
+ end
+ end.join("\n")
+ end
+
+ # call #tinymce in your view to render textarea's as TinyMCE textarea's
+ def tinymce(theme = 'simple')
+ @tinymce = theme
+ end
+
+ # helper #link_to_versions generates a link to the versions (version history)
+ # of the specified Page and Site.
+ def link_to_versions(site, page, text = '', popup=false)
+ if page.versions_count > 0
+ all_versions = Version.find_history_excl_baseversions1(page)
+ if all_versions.length > 0
+ versions = Version.find_history_excl_baseversions2(site, page)
+ title = "No versions exist in site \"#{site.title}\" but #{pluralize(all_versions.length, 'version')} exist in another site or baseline"
+ img = "version_zw"
+ if versions.length > 0
+ title = "#{pluralize(versions.length, 'version')} of \"#{page.presentation_name}\" exist in \"#{site.title}\""
+ img = "version"
+ end
+ return link_to(image_tag(img, :border => 0, :title => title, :align => 'middle') + ' ' + text, {:controller => 'versions', :action => 'list', :site_id => site, :page_id => page}, :popup => popup, :title => title)
+ end
+ end
+ end
+
+ # render link to Comments about a Page in a Site
+ def link_to_comments(site, page, text = '' ,popup=false)
+ returning url = [] do
+ if page.comments_count > 0
+ comments = page.comments.find_all_by_site_id_and_baseline_id( site.id, site.baseline.id)
+ title = "There are no comments for the current site but there are some for another site and/or baseline"
+ img = "comment2_zw"
+ if comments.length > 0
+ title = "#{pluralize(comments.length, 'comment')} of \"#{page.presentation_name}\" exist in \"#{site.title}\""
+ img = "comment2"
+ end
+ url << link_to(image_tag(img, :border => 0, :title => title, :align => 'middle') + ' '+ text, {:controller => "comments", :action => "list", :site_id => site, :page_id => page}, :popup => popup, :title => title)
+ end
+ end
+ end
+
+ # #link_to_difference_analysis helper for a DifferenceAnalysis-record
+ def link_to_difference_analysis_from(differenceAnalysis)
+ returning html = [] do
+ html << "From " + link_to_baseline(differenceAnalysis.baseline_from,nil)
+ html << " to " + link_to_baseline(differenceAnalysis.baseline,nil)
+ html << ", [" + link_to("View results", :controller => 'difference_analyses', :action =>'show', :id => differenceAnalysis.id) + "]"
+ end.join("\n")
+ end
+
+ # #link_to_difference_analysis_item helper for a DifferenceAnalysisItem-record
+ def link_to_difference_analysis_item(differenceAnalysisItem)
+ differenceAnalysis = differenceAnalysisItem.difference_analysis
+ site = differenceAnalysis.site
+ site_from = differenceAnalysis.site_from
+ baseline = differenceAnalysis.baseline
+ baseline_from = differenceAnalysis.baseline_from
+ page = differenceAnalysisItem.page
+ returning html = [] do
+ if differenceAnalysisItem.result == "NEW" || differenceAnalysisItem.result == "CHANGED" || differenceAnalysisItem.result == "EQUAL"
+ html << link_to_page(site, page)
+ elsif differenceAnalysisItem.result == "REMOVED"
+ html << link_to_page(site_from, page)
+ end
+ html << link_to(image_tag("compare", :border => 0, :title => "Show changes in " + @page.presentation_name, :align => 'middle'), {:controller => "difference_analyses", :action => "show_item", :item_id => differenceAnalysisItem}) if differenceAnalysisItem.result == "CHANGED"
+ html << link_to(image_tag("compare", :border => 0, :title => "Show changes in " + @page.presentation_name, :align => 'middle'), {:controller => "difference_analyses", :action => "show_item", :item_id => differenceAnalysisItem, :tab => "html"}) if differenceAnalysisItem.result == "HTMLCHANGED"
+ html << differenceAnalysisItem.result.downcase + " from baseline " + link_to_baseline(baseline_from, nil) + " to " + link_to_baseline(baseline, nil)
+ end.join("\n")
+ end
+
+ # #link_to_baseline helper for a Baseline-record
+ def link_to_baseline(baseline, site)
+ returning url = [] do
+ if site
+ url << link_to(baseline.baseline, :controller => 'baselines', :action => 'show', :id => baseline.id, :site_id => site.id)
+ else
+ url << link_to(baseline.baseline, :controller => 'baselines', :action => 'show', :id => baseline.id)
+ end
+ end.join("\n")
+ end
+
+ def link_to_notification_toggle(site, page, notification_type)
+ returning html = [] do
+ div_id = "notification_" + site.id.to_s + "_" + page.id.to_s + "_" + notification_type
+ html << "<span id=\"" + div_id + "\">"
+ notification = Notification.find(:first, :conditions => ["user_id=? and site_id=? and page_id=? and notification_type=?", session['user'].id, site.id, page.id, notification_type])
+ if notification_type == "Comment"
+ txt = "<input type=checkbox>notify me of follow-up comments"
+ txt = "<input type=checkbox checked>notify me of follow-up comments" if notification
+ elsif notification_type == "Version"
+ txt = "<input type=checkbox>notify me of new versions"
+ txt = "<input type=checkbox checked>notify me of new versions" if notification
+ end
+ html << link_to_remote(txt, :update => div_id, :url => {:controller => "users", :action => "notification", :page_id => @page.id, :site_id => site.id,:notification_type=> notification_type}, :post => true)
+ html << "</span>"
+ end.join("\n")
+ end
+
+ def link_to_change_report_notification_toggle(type = 'D')
+ returning html = [] do
+ user = User.find(session['user'].id)
+ div_id = "change_report_" + user.id.to_s + "_" + type
+ checked = ""
+ checked = "checked" if (type == 'D' && user.notify_daily == 1) || (type == 'M' && user.notify_monthly == 1) || (type == 'W' && user.notify_weekly == 1)
+ #checked = "checked" if type == 'M' && user.notify_monthly == "1"
+ #checked = "checked" if type == 'D' && user.notify_weekly == "1"
+ txt = "<input type=checkbox #{checked}> Daily" if type == 'D'
+ txt = "<input type=checkbox #{checked}> Monthly" if type == 'M'
+ txt = "<input type=checkbox #{checked}> Weekly" if type == 'W'
+ html << "<span id=\"" + div_id + "\">"
+ html << link_to_remote(txt, :update => div_id, :url => {:controller => "users", :action => "toggle_change_report_notification", :type => type}, :post => true)
+ html << "</span>"
+ end.join("\n")
+ end
+
+ def link_to_notification(notification)
+ site = notification.site
+ page = notification.page
+ txt = "follow-up comments on "
+ txt = "new versions of " if notification.notification_type == "Version"
+ returning html = [] do
+ html << "<span id=\"" + div_id(notification,"") + "\">"
+ html << txt.capitalize + link_to_page(site, page) + " in site " + link_to_site(site) + " "
+ html << link_to_remote(image_tag("delete", :border => 0, :title => "Don't notify me of " + txt + page.presentation_name), :update=>div_id(notification, ""), :url => {:controller => "users", :action => "destroy_notification", :notification_id => notification.id}, :post => true) if mine?(notification)
+ html << "</span>"
+ end.join("\n")
+ end
+
+ def link_to_done_toggle(record)
+ returning html = [] do
+ html << "<span id=\"" + div_id(record, "done_toggle") + "\">"
+ if record.done == 'Y'
+ title = 'Click to mark this record \'todo\''
+ html4checkbox = "<input type=checkbox checked>"
+ else
+ title = 'Check to mark this record \'done\''
+ html4checkbox = "<input type=checkbox>"
+ end
+ if !session["user"] || !admin?
+ html << html4checkbox
+ else
+ html << link_to_remote(html4checkbox, :update => div_id(record, 'done_toggle'), :url => { :controller => record.class.to_s.downcase.pluralize, :action => "toggle_done", :id => record}, :title => title)
+ end
+ html << "</span>"
+ end.join("\n")
+ end
+
+ # #link_to_reviewer helper for Comment and Version-record to set the "reviewer".
+ # The controller involved needs a method 'review',
+ # see for instance CommentsController.review and VersionsController.review
+ def link_to_reviewer(record)
+ returning url = [] do
+ url << "<span id=\"" + div_id(record, "reviewer") + "\">"
+ if !session["user"]
+ if record.reviewer_id != nil
+ url << link_to_user(record.reviewer)
+ end
+ else
+ if record.reviewer_id == nil
+ if admin?
+ url << link_to_remote("_______", :update => div_id(record, "reviewer"), :url => { :controller => record.class.to_s.downcase.pluralize, :action => "review", :id => record} )
+ else
+ url << "" #TODO
+ end
+ else
+ if record.reviewer_id == session["user"].id
+ url << link_to_remote(record.reviewer.name, :update => div_id(record, "reviewer"), :url => { :controller => record.class.to_s.downcase.pluralize, :action => "review", :id => record} )
+ else
+ url << link_to_user(record.reviewer)
+ end
+ end
+ url << "</span> "
+ end
+ end.join("\n")
+ end
+
+ def url_for_page(page, site)
+ return url_for_site(site) + page.rel_path
+ end
+
+ # link_to helper method for a Page-record
+ # is there another way to
+ def link_to_page(site,page, extlink_only = false)
+ img = "extlink.gif"
+ img = "extlink2.gif" if site && site.wiki?
+ returning url = [] do
+ vsns = page.versions_in_site(site) if page.versions_count > 0
+ comments= page.comments_in_site(site) if page.comments_count > 0
+ if !extlink_only
+ url << link_to(page.presentation_name,:controller => 'pages',:action => 'show',:id => page.id,:site_id => site.id)
+ end
+ url << " <a href='" + url_for_page(page, site) + "'>"
+ url << image_tag(img,:border => 0,:title => "Activate page \"#{page.presentation_name}\" in site \"#{site.title}\"")
+ url << "</a>"
+ url << link_to_versions(site, page) if vsns
+ if site && comments
+ url << link_to_comments(site, page)
+ end
+ end.join("\n")
+ end
+
+ # link_to helper method for a Version. Renders a link with a given prefix (often "version") with possibly a lot of clickable images displaying status
+ def link_to_version(version,urlprefix)
+ returning link = [] do
+ link << link_to(urlprefix + " " + version.version.to_s,:controller => 'versions',:action => 'show',:id => version.id)
+ if !version.version_id
+ else
+ source_version = version.source_version
+ if version.site_id != source_version.site_id
+ from_site = source_version.site
+ to_site = version.site
+ link << link_to(image_tag("site", :border => 0, :align => 'middle', :title => 'Based on version ' + source_version.version.to_s + " from site " + from_site.title) ,:controller => 'versions',:action => 'show',:id => source_version.id)
+ else
+ if version.baseline_id != source_version.baseline_id
+ from_baseline = source_version.baseline
+ to_baseline = version.baseline
+ link << link_to(image_tag("baseline", :border => 0, :align => 'middle', :title => 'Based on version ' + source_version.version.to_s + " from baseline " + from_baseline.baseline) ,:controller => 'versions',:action => 'show',:id => source_version.id)
+ else
+ if version.page_id != source_version.page_id
+ base_page = source_version.page
+ link << link_to(image_tag("new", :border => 0, :align => 'middle', :title => 'New page based on ' + source_version.page.presentation_name + " version " + source_version.version.to_s) ,:controller => 'versions',:action => 'show',:id => source_version.id)
+ else
+ if version.version != source_version.version + 1
+ link << " (based on "
+ link << link_to(" version " + source_version.version.to_s,:controller => 'versions',:action => 'show',:id => source_version.id)
+ link << ")"
+ else
+ end
+ end
+ end
+ end
+ end
+ checkout = version.checkout
+ if checkout
+ user = checkout.user
+ link << link_to(image_tag("checkout2", :border => 0, :align=>"middle", :title=>'Version is checked-out by ' + user.name ),:controller => 'versions',:action => 'show',:id => version.id)
+ link << " "
+ if user == session['user']
+ link << link_to(image_tag("edit.gif", :border => 0, :align=>"middle", :title=>'Version is checked-out by you. Click to continue editing.' ),:controller => 'pages',:action => 'edithtml',:checkout_id => checkout.id)
+ end
+ end
+ link << link_to(image_tag("compare", :border => 0, :align=>"middle", :title=>'Compare with previous version' ),:controller => 'versions',:action => 'compare',:id => version) if version.version != 0
+ link << link_to(image_tag("format_txt", :border => 0, :align=>"middle", :title=>'View as plain text' ), {:controller => 'versions',:action => 'markdown',:id => version})
+ end.join("\n")
+ end
+
+ # link_to helper method for a Version. Renders links to the Page as well as the Version.
+ def link_to_version2 (version)
+ if version
+ page = version.page
+ site = version.site
+ returning link = [] do
+ link << link_to_page(site,page)
+ link << " "
+ link << link_to_version(version,"version")
+ end.join("\n")
+ end
+ end
+
+ # link_to helper method for a Site
+ def link_to_site(site, page = nil)
+ img = "extlink.gif"
+ img = "extlink2.gif" if site.wiki?
+ returning link = [] do
+ link << link_to(site.title,:controller => 'sites',:action => 'show',:id => site.id) #if !admin?
+ link << link_to(image_tag(img,:border => 0,:title => "Activate site \"#{site.title}\""), "/#{site.rel_path}/", :title => "Activate site \"#{site.title}\"") if !page
+ link << link_to_page(site, page, true) if page
+ vars = [site.baseline_process, 'updated with site'] if (site.status == 'U')
+ vars = [site.baseline_process, 'created based on site'] if (site.status == 'P')
+ link << image_tag("progress.gif",:border => 0,:title => 'This site is scheduled to ' + vars[1] + ' ' + vars[0].title + '(' + vars[0].baseline.baseline + ')') if vars
+ if site.baseline_process? && cadmin?
+ link << link_to(image_tag("compare2", :border => 0, :title => "Compare this site with another site"), :controller => "difference_analyses", :action => "new", :site_id => site.id)
+ end
+ end.join("\n")
+ end
+
+ # link_to helper method for a User
+ def link_to_user(user)
+ returning link = [] do
+ link << link_to(user.name,:controller => 'users',:action => 'show',:id => user.id) if admin?
+ link << user.name if !admin?
+ link << image_tag("user" + user.admin, :border => 0, :title => "") if user.admin?
+ end.join("\n")
+ end
+
+ # link_to helper method for a Comment
+ def link_to_comment(comment)
+ page = comment.page
+ site = comment.site
+ user = comment.site
+ returning link = [] do
+ #link << link_to(comment.title,:controller => 'comments',:action => 'list',:site_id => site.id, :page_id => page.id)
+ url = url_for(:controller => 'comments', :action=> 'list', :site_id => site.id, :page_id => page.id) + "\#" + div_id(comment,"")
+ link << "<a href=\"#{url}\" title=\"More...\">" + truncate(strip_tags(comment.text)) + "</a>"
+ #link << link_to_reviewer(comment) if admin?
+ if session['user']
+ if user == session['user']
+ link << link_to(image_tag("edit.gif", :border => 0, :align=>"middle", :title=>'Edit this comment'), :controller => 'comments', :action => 'edit', :id => comment.id )
+ end
+ end
+ end.join("\n")
+ end
+
+ # returns unique div id from a record in a page
+ def div_id(record, call_id)
+ return record.class.to_s + record.id.to_s + "_" + call_id
+ end
+
+ # helper method for a displaying navigation links to first, next, previous, last pages to use when displaying records in pages.
+ # See preserving parameters [http://64.233.183.104/search?q=cache:VZkWDCGLNBIJ:wiki.rubyonrails.com/rails/show/HowtoPagination+pagination+how+to+ruby+on+rails&hl=nl&gl=nl&ct=clnk&cd=4]
+ def links_to_pages(pages)
+ if pages.length > 1
+ returning link = [] do
+ link << link_to(image_tag('first_page', :border => 0, :align=>"middle", :title => "First Page"), {:params => params.merge(:page => 1)} ) if pages.current.previous
+ link << image_tag('first_page_disabled', :border => 0, :align=>"middle", :title => "First Page") if !pages.current.previous
+ link << link_to(image_tag('previous_page', :border => 0, :align=>"middle", :title => "Previous Page"), {:params => params.merge(:page => pages.current.previous)}) if pages.current.previous
+ link << image_tag('previous_page_disabled', :border => 0, :align=>"middle", :title => "Previous Page") if !pages.current.previous
+ link << "<small>[" + pages.current.number.to_s + "/" + pages.length.to_s + "]</small>"
+ link << link_to(image_tag('next_page', :border => 0, :align=>"middle", :title => "Next Page"), {:params => params.merge(:page => pages.current.next)}) if pages.current.next
+ link << image_tag('next_page_disabled', :border => 0, :align=>"middle", :title => "Next Page") if !pages.current.next
+ link << link_to(image_tag('last_page', :border => 0, :align=>"middle", :title => "Last Page"), {:params => params.merge( :page => pages.last)}) if pages.current.next
+ link << image_tag('last_page_disabled', :border => 0, :align=>"middle", :title => "Last Page") if !pages.current.next
+ end.join("\n")
+ end
+ end
+
+ # link_to helper method for displaying tabs, example
+ # <tt><% tabs([["All", url_for(:action => 'listall'), true],["To Do", url_for(:action=> 'listtodo')], ["Done", url_for(:action=>'listdone')], 75$]) %> </tt>
+ # will display three tabs with titles 'All', 'To Do', 'Done' for actions <tt>listall</tt>, <tt>listtodo</tt>, <tt>listdone</tt>.
+ # the last parameter is the 100% minus the width of the tabs together (the remaining space after the tabs)
+ def tabs(tabs, widthPerc)
+ logger.debug('tabs')
+ #<% tabs([["All", url_for(:action => 'listall'), true],["To Do", url_for(:action=> 'listtodo')], ["Done", url_for(:action=>'listdone')]]) %>
+ returning link = [] do
+ link << "<!-- start application_helper tabs -->"
+ link << "<table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\">"
+ link << "<tr valign=\"middle\">"
+ #link << "<td class=\"tab\" width=\"10\">" + image_tag("tab/shim.gif", :height =>17, :width => 10) + "</td>"
+ i = 0
+ logger.debug('tabs: ' + tabs.inspect)
+ for tab in tabs
+ logger.debug('tab: ' + tab.inspect)
+ active = false
+ txt = tab[0]
+ url = tab[1]
+ active = tab[2] if tab[2]
+ element_class = "tab"
+ element_class = "activeTab" if active
+ if i == 0
+ logger.debug("First tab: adding shim")
+ link << "<td class=\"" + element_class + "\" width=\"10\">" + image_tag("tab/shim.gif", :height => 17, :width => 10)+ "</td>"
+ elsif i > 0 && i < tabs.length - 1
+
+ end
+ if active
+ active_index = i
+ link << "<td class=\"activeTab\">" + txt + "</td>"
+ #link << "<td width=\"21\">" + image_tag("tab/tab_middle-a_i.gif", :height => 17, :width => 21, :align => 'absmiddle') + "</td>"
+ else
+ link << "<td class=\"tab\"><a class=\"tab\" href=\"" + url + "\"><span style=\"white-space:nowrap;\">" + txt + "</span></a></td>"
+ end
+ img_tab = "tab/tab_middle-i_i.gif" # default assume we are between inactive and inactive
+ img_tab = "tab/tab_middle-a_i.gif" if active_index == i
+ img_tab = "tab/tab_middle-i_a.gif" if !active_index && tabs[i+1][2] == true #active index not determined there must be a next tab, so check if it is the active one
+ if i == (tabs.length - 1) # last tab
+ if i == active_index # last tab is active
+ link << "<td width=\"21\">" + image_tag("tab/tab_end-a.gif", :height => 17, :width => 21) + "</td><td width=\"" + widthPerc.to_s + "%\">" + image_tag("tab/shim.gif", :height => 17, :width => 10) + "</td>"
+ else
+ link << "<td width=\"21\">" + image_tag("tab/tab_end-i.gif", :height => 17, :width => 21) + "</td><td width=\"" + widthPerc.to_s + "%\">" + image_tag("tab/shim.gif", :height => 17, :width => 10) + "</td>"
+ end
+ else
+ link << "<td width=\"21\">" + image_tag(img_tab, :height => 17, :width => 21, :align => 'absmiddle') + "</td>"
+ end
+ logger.info("Adding tab " + txt + " with link " + url + ". Is active? " + active.to_s)
+ i = i + 1
+ end
+ #logger.info("last tab: adding tab-end-i")
+ #link << "<td width=\"21\">" + image_tag("tab/tab_end-i.gif", :height => 17, :width => 21) + "</td><td width=\"50%\">" + image_tag("tab/shim.gif", :height => 17, :width => 10) + "</td>"
+ link << "</tr><tr>"
+ if active_index == 0
+ link << "<td colspan=\"2\" class=\"activeTab\">" + image_tag("tab/shim.gif", :height => 2)+ "</td>"
+ link << "<td class=\"activeTab\">" + image_tag("tab/tab_space.gif", :height => 2, :width => 21) + "</td>"
+ link << "<td colspan=\"" + (tabs.length+1-3).to_s + "\">" + image_tag("tab/shim.gif", :height => 2) + "</td>"
+ else
+ link << "<td colspan=\"" + (active_index*2).to_s + "\">" + image_tag("tab/shim.gif", :height => 2)+ "</td>"
+ link << "<td>" + image_tag("tab/tab_space_middle.gif", :height => 2 , :width => 21) + "</td><td class=\"activeTab\">"
+ link << image_tag("tab/shim.gif", :height=>2, :width =>10) + "</td>"
+ link << "<td>" + image_tag("tab/tab_space.gif", :height => 2, :width => 21) + "</td>"
+ link << "<td colspan=\"" + ((tabs.length*2+2) - (active_index*2) -3).to_s + "\">" + image_tag("tab/shim.gif", :height => 2) + "</td>"
+ end
+ i = i + 1
+ link << "</tr>"
+ link << "<tr><td class=\"activeTab\" colspan=\"10\">" + image_tag("tab/shim.gif", :height => 5) + "</td>"
+ link << "</tr>"
+ link << "</table>"
+ link << "<!-- end application_helper tabs -->"
+ end.join("\n")
+ end
+
+end
+
diff --git a/source/app/helpers/users_helper.rb b/source/app/helpers/users_helper.rb
new file mode 100644
index 0000000..2ce467b
--- /dev/null
+++ b/source/app/helpers/users_helper.rb
@@ -0,0 +1,36 @@
+# View helper methods available to all users templates in the application.
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+module UsersHelper
+
+ def link_to_user_actions(theUser)
+ returning link = [] do
+ if cadmin?
+ if !mine?(theUser)
+ link << link_to(image_tag("sendpassword", :border => 0, :align=>"middle", :title=>'(re)Send password to user'), {:controller => 'users', :action => 'resend', :id => theUser.id}, :confirm => 'Are you sure! This will reset the current password of ' + theUser.name + "!", :post => true)
+ link << link_to(image_tag("up", :border => 0, :align=>"middle", :title=>'Make this user the central administrator'), {:controller => 'users', :action => 'cadmin', :id => theUser.id}, :confirm => 'Are you sure? There can only be one!' ) if theUser.admin?
+ link << link_to(image_tag("down", :border => 0, :align=>"middle", :title=>'Revoke administrator privileges'), :controller => 'users', :action => 'admin', :id => theUser.id, :admin => 'N' ) if theUser.admin?
+ link << link_to(image_tag("up" , :border => 0, :align=>"middle", :title=>'Grant administrator privileges'), :controller => 'users', :action => 'admin', :id => theUser.id, :admin => 'Y' ) if !theUser.admin?
+ link << link_to(image_tag("delete", :border => 0, :align=>"middle", :title=>'Delete this User'), {:controller => 'users', :action => 'destroy', :id => theUser.id}, :confirm => 'Not properly implemented yet! Leads to corruption if user has versions, comments. This user has ' + theUser.versions_count.to_s + " versions and " + theUser.comments_count.to_s + " comments!")
+ end
+ elsif admin?
+ if !mine?(theUser)
+ link << link_to(image_tag("up" , :border => 0, :align=>"middle", :title=>'Grant administrator privileges'), :controller => 'users', :action => 'make_admin', :id => theUser.id, :admin => 'Y' ) if !theUser.admin?
+ end
+ end
+ end.join("\n")
+ end
+
+end
\ No newline at end of file
diff --git a/source/app/models/baseline.rb b/source/app/models/baseline.rb
new file mode 100644
index 0000000..ee2e225
--- /dev/null
+++ b/source/app/models/baseline.rb
@@ -0,0 +1,66 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: baselines
+#
+# id :integer(11) not null, primary key
+# baseline :string(250) default(), not null
+# buildid :string(250) default(), not null
+# description :text
+# created_on :datetime
+# updated_on :datetime
+#
+
+# A Baseline is established when a baseline process is created, see Site.new_baseline_process.
+# Therefore: a Baseline has one baseline process from which it was created.
+#
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--
+# TODO R? remove baseline table. The idea of this table is that we could
+# remove a baseline process site and keep information about the baseline.
+# A better approach problably is to not delete baseline process sites but
+# make them obsolote or something. To save disk space we can remove content
+# of a baseline process site when it has become obsolete.
+#++
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+class Baseline < ActiveRecord::Base
+
+ has_and_belongs_to_many :pages
+ has_and_belongs_to_many :sites
+ has_many :comments
+ has_many :versions
+ has_many :checkouts
+
+ validates_presence_of :baseline
+ validates_uniqueness_of :baseline
+
+ def pages_count
+ return Page.count_by_sql("select count(*) from baselines_pages where baseline_id=" + self.id.to_s )
+ end
+
+ # method #sites_current returns collection of Site records where the Baseline is the current.
+ def sites_current
+ return Site.find(:all, :conditions => ['baseline_id = ?', self.id], :order => 'created_on DESC')
+ end
+
+ def wikis_current
+ return Site.find(:all, :conditions => ['baseline_id =? and site_type = ?', self.id, 'W'])
+ end
+
+ def baseline_process
+ return Site.find(:first, :conditions => ['baseline_id =? and site_type = ?', self.id, 'S'])
+ end
+end
diff --git a/source/app/models/checkout.rb b/source/app/models/checkout.rb
new file mode 100644
index 0000000..1e03d65
--- /dev/null
+++ b/source/app/models/checkout.rb
@@ -0,0 +1,118 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: checkouts
+#
+# id :integer(11) not null, primary key
+# user_id :integer(10) default(0), not null
+# site_id :integer(10)
+# page_id :integer(10)
+# version_id :integer(10) default(0), not null
+# baseline_id :integer(10) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+#
+
+# A Checkout is a working copy (Version) of a Page created so that
+# it can be edited
+#
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Checkout < ActiveRecord::Base
+
+ belongs_to :version
+ belongs_to :user
+ belongs_to :page
+ belongs_to :site
+ belongs_to :baseline
+
+ # Version we are checking out
+ attr_accessor :source_version
+
+ # Temporary variable used to check if a checkout already exists, a database constraint
+ # doesn't suffice because we cannot rollback file operations
+ attr_accessor :checkout
+
+ # Note supplied with checkout will be used to create Version.note
+ attr_accessor :note
+
+ validates_presence_of :user, :page, :site, :version, :baseline
+
+ #--
+ # TODO R1 Undo checkout of a new page should destroy also the new page
+ # TODO R? move authorisation check here by adding a user parameter
+ #++
+ def undo
+ logger.info('Undo checkout')
+ version.destroy
+ self.destroy
+ end
+
+ def checkin(user, html = nil)
+ raise 'Cannot checkin, checked is not owned by user' if user != self.user && !user.cadmin?
+ self.version.html(html) if !html.blank? # blank? returns true if its receiver is nil or an empty string
+ File.copy(self.version.path, self.page.path(self.site))
+ Page.enhance_file(self.page.path(self.site))
+ html = self.page.html(self.site)
+ html = html.gsub(Page::BODY_TAG_PATTERN, self.page.body_tag ) if self.page.body_tag
+ html = html.gsub(Page::TREEBROWSER_PLACEHOLDER, self.page.treebrowser_tag) if self.page.treebrowser_tag
+ html = html.gsub(Page::COPYRIGHT_PLACEHOLDER, self.page.copyright_tag) if self.page.copyright_tag
+ file = File.new(self.page.path(self.site), "w")
+ file.puts(html)
+ file.close
+ self.destroy
+ # TODO R? update page.text on checkin or maybe add and update new text column in pages_sites table
+ end
+
+ #--
+ # TODO R1 With creation of 1 checkout record, all callbacks fire twice except before_create and
+ # after_create. Maybe it is better not to use these kinds of callbacks?
+ #
+ # This causes an extra call to new_basedonversion and thus creates two version files. The second file
+ # is overwritten with next new checkout creation.
+ #
+ #++
+
+ def before_validation_on_create
+ logger.debug('before_validation_on_create')
+ self.baseline = self.site.baseline if !self.site.nil?
+ self.checkout = self.page.checkouts.find_by_site_id(site.id)
+ if self.site.wiki? && self.site.status != 'P' && self.checkout.nil?
+ self.source_version = Version.find_current_version(self.site, self.page, true) if self.source_version.nil?
+ self.version = Version.new_basedonversion(self.site, self.page, self.source_version, self.user,0)
+ self.version.note = self.note
+ #page.sites << site if !page.sites.index(site)
+ end
+ end
+
+ def validate_on_create
+ logger.debug('validate_on_create')
+ errors.add(:site, 'can\'t be a baseline process') if self.site.baseline_process?
+ errors.add(:site, 'not wikified yet') if self.site.status == 'P'
+ errors.add_to_base('Checkout already exists') if !self.checkout.nil?
+ end
+
+ # Cleanup version file and set title when creating a new page
+ def before_create
+ logger.debug('Before create')
+ if self.valid? && self.version.page.id != self.source_version.page.id
+ remove_empty_lines(self.version.path)
+ self.version.set_title(self.page.presentation_name)
+ end
+ end
+
+end
diff --git a/source/app/models/comment.rb b/source/app/models/comment.rb
new file mode 100644
index 0000000..10f3077
--- /dev/null
+++ b/source/app/models/comment.rb
@@ -0,0 +1,73 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: comments
+#
+# id :integer(11) not null, primary key
+# text :text
+# ip_address :string(500)
+# done :string(1) default(N), not null
+# user_id :integer(10) default(0), not null
+# page_id :integer(10)
+# site_id :integer(10)
+# version_id :integer(10) default(0), not null
+# baseline_id :integer(11) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+# reviewer_id :integer(11)
+# user_id_markdone :integer(11)
+# user_id_marktodo :integer(11)
+#
+
+require_dependency "search_system"
+
+# A Comment belongs Page and is created within the context of a Site by a specific User.
+# There is redundancy here as also the Version of the Page is recorded with a Comment.
+# Because the Baseline of a Site can change in time, the Comment also belongs to a Baseline.
+#
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--
+# TODO R? validate submitted html (all tags closed etc)
+#++
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Comment < ActiveRecord::Base
+
+ belongs_to :site
+ belongs_to :baseline
+ belongs_to :user
+ belongs_to :reviewer, :class_name => "User", :foreign_key => "reviewer_id"
+ belongs_to :page, :counter_cache => true
+ belongs_to :version
+ belongs_to :user_thatmarkeddone, :class_name => "User", :foreign_key => "user_id_markdone" #:doc:
+ belongs_to :user_thatmarkedtodo, :class_name => "User", :foreign_key => "user_id_marktodo" #:doc:
+
+ validates_presence_of :text, :user, :version, :page, :baseline, :site
+
+ make_searchable [:text]
+
+ def before_validation_on_create
+ if self.version.nil?
+ self.version = Version.find_current_version(self.site, self.page, true)
+ else
+ self.page = self.version.page if self.page.nil?
+ self.site = self.version.site if self.site.nil?
+ self.baseline = self.site.baseline if self.baseline.nil?
+ end
+ self.baseline = self.site.baseline if self.baseline.nil?
+ end
+
+end
diff --git a/source/app/models/difference_analysis.rb b/source/app/models/difference_analysis.rb
new file mode 100644
index 0000000..cd77fd0
--- /dev/null
+++ b/source/app/models/difference_analysis.rb
@@ -0,0 +1,132 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: difference_analyses
+#
+# id :integer(11) not null, primary key
+# site_id :integer(10)
+# site_id_from :integer(10)
+# baseline_id :integer(10) default(0), not null
+# baseline_id_from :integer(10) default(0), not null
+# difference_analysis_items_count :integer(11) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+# analyzed_on :datetime
+#
+
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class DifferenceAnalysis < ActiveRecord::Base
+
+ belongs_to :site_from, :class_name => 'Site', :foreign_key => 'site_id_from'
+ belongs_to :site
+ belongs_to :baseline_from, :class_name => 'Baseline', :foreign_key => 'baseline_id_from'
+ belongs_to :baseline
+ has_many :difference_analysis_items
+ has_many :items , :class_name => 'DifferenceAnalysisItem', :foreign_key => 'difference_analysis_id'
+ has_many :items_changed, :class_name => 'DifferenceAnalysisItem', :foreign_key => 'difference_analysis_id', :conditions => "result = 'CHANGED'"
+ has_many :items_htmlchanged, :class_name => 'DifferenceAnalysisItem', :foreign_key => 'difference_analysis_id', :conditions => "result = 'HTMLCHANGED'"
+ has_many :items_removed, :class_name => 'DifferenceAnalysisItem', :foreign_key => 'difference_analysis_id', :conditions => "result = 'REMOVED'"
+ has_many :items_new, :class_name => 'DifferenceAnalysisItem', :foreign_key => 'difference_analysis_id', :conditions => "result = 'NEW'"
+ has_many :items_equal, :class_name => 'DifferenceAnalysisItem', :foreign_key => 'difference_analysis_id', :conditions => "result = 'EQUAL'"
+
+ validates_presence_of :site_id, :site_id_from, :baseline_id, :baseline_id_from
+
+ # TODO: unclear what validates associated does,
+ # it does report errors, fails to save when items
+ # are not valid, so this remains a little bit a mistery
+ validates_associated :difference_analysis_items
+ validates_uniqueness_of :site_id, :scope => 'site_id_from', :message => 'Difference Analysis already exists'
+
+ def title
+ return "From " + self.baseline_from.baseline + " to " + self.baseline.baseline
+ end
+
+ def perform_analysis
+ # TODO R? 1 transaction. This should be 1 transaction.
+ # Errors during creation of items are not visible, not reported
+ self.site.scan4content if !site.content_scanned?
+ self.site_from.scan4content if !site_from.content_scanned?
+ self.baseline = self.site.baseline
+ self.baseline_from = self.site_from.baseline
+ pages = self.site.pages
+ pages_from = self.site_from.pages
+ pages_intersection = pages & pages_from
+ pages_new = pages - pages_from
+ pages_removed = pages_from - pages
+ pages_html_changed = Array.new
+ pages_equal = Array.new
+ pages_text_changed = Array.new # change in text means change in html
+ logger.info("Finding which files changed and which remained equal...")
+ pages_intersection.each do |page|
+ if !File.compare(page.path(self.site), page.path(self.site_from))
+ pages_html_changed << page
+ else
+ pages_equal << page
+ end
+ end
+ pages_html_changed.each do |page|
+ diff_item = DifferenceAnalysisItem.new
+ diff_item.difference_analysis = self
+
+ diff_item.page = page
+ # NOTE: we need txt extension when using CSDIFF
+ path = "#{ENV['EPFWIKI_DIFF_TMP_DIR']}/html.txt"
+ path_from = "#{ENV['EPFWIKI_DIFF_TMP_DIR']}/htmlfrom.txt"
+ path2markdown = "#{ENV['EPFWIKI_DIFF_TMP_DIR']}/markdown.txt"
+ path2markdownfrom = "#{ENV['EPFWIKI_DIFF_TMP_DIR']}/markdownfrom.txt"
+ path2diff = "#{ENV['EPFWIKI_DIFF_TMP_DIR']}/diff.txt"
+ path2diff2 = "#{ENV['EPFWIKI_DIFF_TMP_DIR']}/diff2.txt"
+
+ # generate html diff
+ File.copy(page.path(self.site), path)
+ File.copy(page.path(self.site_from), path_from)
+ diff_item.diff_html = diff_files(path, path_from, path2diff, true)
+
+ #generate text diff
+ html2markdownfile(page.path(self.site), path2markdown, true)
+ html2markdownfile(page.path(self.site_from), path2markdownfrom, true)
+ # TODO R? compare status IGNORED
+ # Some changes in some pages are not usefull and should be ignored to increase usefullness
+ # of a difference analysis
+ if File.compare(path2markdown, path2markdownfrom)
+ diff_item.result = "HTMLCHANGED"
+ else
+ diff_item.result = "CHANGED"
+ diff_item.diff = diff_files(path2markdown, path2markdownfrom, path2diff2, true )
+ end
+ self.difference_analysis_items << diff_item
+ #diff_item.result = "CHANGED" if diff_item.diff.index("HDDeleted") || diff_item.diff.index("HDAdded")
+ [path, path_from, path2markdown, path2markdownfrom, path2diff, path2diff2].each {|path| File.delete(path) if File.exists?(path) }
+ end
+ pages_new.each { | page | self.difference_analysis_items << DifferenceAnalysisItem.new(:difference_analysis => self, :result => "NEW", :page => page)}
+ pages_removed.each { | page | self.difference_analysis_items << DifferenceAnalysisItem.new(:difference_analysis => self, :result => "REMOVED", :page => page)}
+ pages_equal.each { | page | self.difference_analysis_items << DifferenceAnalysisItem.new(:difference_analysis => self, :result => "EQUAL", :page => page)}
+ self.analyzed_on = Time.now
+ end
+
+ def before_validation_on_create
+ self.baseline = self.site.baseline if self.baseline.nil? && !self.site.nil?
+ self.baseline_from = self.site_from.baseline if self.baseline_from.nil? && !self.site_from.nil?
+ end
+
+ def validate
+ errors.add(:site, "is not a baseline process") if self.site && self.site.wiki?
+ errors.add(:site_from, "is not a baseline process") if self.site_from && self.site_from.wiki?
+ errors.add(:site, "cannot compare with itself") if self.site_from && self.site && self.site_from == self.site
+ end
+end
diff --git a/source/app/models/difference_analysis_item.rb b/source/app/models/difference_analysis_item.rb
new file mode 100644
index 0000000..56a1731
--- /dev/null
+++ b/source/app/models/difference_analysis_item.rb
@@ -0,0 +1,38 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: difference_analysis_items
+#
+# id :integer(11) not null, primary key
+# difference_analysis_id :integer(10) default(0), not null
+# page_id :integer(10)
+# result :string(500) default(), not null
+# diff :text
+# diff_html :text
+#
+
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class DifferenceAnalysisItem < ActiveRecord::Base
+
+ belongs_to :difference_analysis
+ belongs_to :page
+
+ validates_presence_of :difference_analysis_id, :page_id, :result
+ validates_format_of :result, :with => /CHANGED|HTMLCHANGED|NEW|REMOVED|EQUAL/
+
+end
diff --git a/source/app/models/notification.rb b/source/app/models/notification.rb
new file mode 100644
index 0000000..254e0ec
--- /dev/null
+++ b/source/app/models/notification.rb
@@ -0,0 +1,45 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: notifications
+#
+# id :integer(11) not null, primary key
+# page_id :integer(10)
+# site_id :integer(10)
+# user_id :integer(10) default(0), not null
+# notification_type :string(50) default(), not null
+# created_on :datetime
+# updated_on :datetime
+#
+
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Notification < ActiveRecord::Base
+
+ belongs_to :user
+ belongs_to :page
+ belongs_to :site
+
+ #--
+ # TODO R? user class as third parameter?
+ #++
+ def self.find_all_users(theSite, thePage, theType)
+ return Notification.find(:all, :conditions => ["site_id=? and page_id=? and notification_type=?", theSite.id, thePage.id, theType]).collect {|aNotification|aNotification.user}
+ end
+
+end
+
diff --git a/source/app/models/notifier.rb b/source/app/models/notifier.rb
new file mode 100644
index 0000000..8d3bdd5
--- /dev/null
+++ b/source/app/models/notifier.rb
@@ -0,0 +1,192 @@
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Notifier < ActionMailer::Base
+
+ def new_password(user, sites, urls)
+ content_type "text/html"
+ @recipients = user.email
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] Welcome to " + ENV['EPFWIKI_APP_NAME']
+ @body['user'] = user
+ @body['admin'] = User.find_central_admin
+ @body['cnt'] = User.count
+ @body['sites'] = sites
+ @body['urls'] = urls
+ end
+
+ def confirmation_link(user, sites, urls)
+ content_type "text/html"
+ @recipients = user.email
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] Confirm Your New Account"
+ @body['user'] = user
+ @body['admin'] = User.find_central_admin
+ @body['cnt'] = User.count
+ @body['sites'] = sites
+ @body['urls'] = urls
+ end
+
+ def lost_password(user, urls)
+ content_type "text/html"
+ @recipients = user.email
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] New Password"
+ @body['user'] = user
+ @body['admin'] = User.find_central_admin
+ @body['cnt'] = User.count
+ @body['urls'] = urls
+ end
+
+
+ def error_report(exception, trace, session, params, env, sent_on = Time.now)
+ content_type "text/html"
+ @recipients = User.find_central_admin.email
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @subject = "[Error] exception in #{env['REQUEST_URI']}"
+ @sent_on = sent_on
+ @body["exception"] = exception
+ @body["trace"] = trace
+ @body["session"] = session
+ @body["params"] = params
+ @body["env"] = env
+ end
+
+
+ # TODO R1 send bcc instead of recipients
+ def report(params)
+ content_type "text/html"
+
+ runtime = Time.now
+ case params[:type]
+ when 'D' # daily
+ starttime = 1.day.ago
+ @recipients = email_addresses_4_report(User.find_all_by_notify_daily(1))
+ subject_text = 'Daily'
+ when 'W' # weekly
+ starttime = 1.week.ago
+ @recipients = email_addresses_4_report(User.find_all_by_notify_weekly(1))
+ subject_text = 'Weekly'
+ when 'M' # monthly
+ starttime = 1.month.ago
+ @recipients = email_addresses_4_report(User.find_all_by_notify_monthly(1))
+ subject_text = 'Monthly'
+ else
+ raise 'Report type is required'
+ end
+
+ @recipients = email_addresses_4_report(params[:user]) unless params[:user].blank?
+ @subject = "[#{ENV['EPFWIKI_APP_NAME']}] #{subject_text} Change Report - #{runtime.strftime('%B %Y')}"
+
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @sent_on = starttime
+ @body['runtime'] = @runtime
+ @body['starttime'] = @starttime
+ @body['sites'] = Site.find_wikis
+ @body['versions'] = Version.find(:all, :conditions => ['created_on > ? and version <> 0', starttime ], :order => 'created_on DESC')
+ @body['comments'] = Comment.find(:all, :conditions => ['created_on > ?', starttime ], :order => 'created_on DESC')
+ @body['users'] = User.find(:all, :conditions => ['created_on > ?', starttime ], :order => 'created_on DESC')
+ @body['checkouts'] = Checkout.find_all
+ @body['subject'] = @subject
+ @body['admin'] = User.find_central_admin
+ @body['host'] = params[:host]
+ end
+
+ def env_to(user, session, params, env, sent_on = Time.now)
+ content_type "text/html"
+ @recipients = user.email
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] " + params[:action]
+ @sent_on = sent_on
+ @body["session"] = session
+ @body["params"] = params
+ @body["env"] = env
+ end
+
+ def wiki_created(site,user)
+ content_type "text/html"
+ cadmin = User.find_central_admin
+ @recipients = [user.email, cadmin.email]
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @body['count'] = site.wikifiable_files_count
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + site.title + " created!"
+ @body['site'] = site
+ @body['user'] = user
+ @body['admin'] = cadmin
+ end
+
+ def wiki_scheduled(site,user)
+ content_type "text/html"
+ cadmin = User.find_central_admin
+ @recipients = [user.email, cadmin.email]
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @body['count'] = site.wikifiable_files_count
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + site.title + " scheduled for creation!"
+ @body['site'] = site
+ @body['user'] = user
+ @body['admin'] = cadmin
+ end
+
+ def wiki_scheduled4update(site,user)
+ content_type "text/html"
+ cadmin = User.find_central_admin
+ @recipients = [user.email, cadmin.email]
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ #@body['count'] = wikifiable_files(site.parent.path).length
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + site.title + " scheduled for update!"
+ @body['site'] = site
+ @body['user'] = user
+ @body['admin'] = cadmin
+ end
+
+ def update_site_checkin_request(wiki)
+ content_type "text/html"
+ cadmin = User.find_central_admin
+ @recipients = [cadmin.email]
+ wiki.checkouts.each do |checkout|
+ @recipients << checkout.user.email
+ end
+ logger.debug('Recipients:' + @recipients.join(', '))
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] " + wiki.title + " - Check-In Request"
+ @body['wiki'] = wiki
+ @body['cadmin'] = cadmin
+ end
+
+ def notification(theUsers, subject, introduction, text, request_host)
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ content_type "text/html"
+ @subject = "[#{ENV['EPFWIKI_APP_NAME']}] #{subject}"
+ @recipients = email_addresses_4_report(theUsers)
+ @body['link'] = "<a href=\"http://#{request_host}/users/show\">#{request_host}</a>"
+ @body['introduction'] = introduction
+ @body['text'] = text
+ @body['admin'] = User.find_central_admin
+ end
+
+ def email(theUsers, theSubject, theFilePaths, theText)
+ @from = ENV['EPFWIKI_REPLY_ADDRESS']
+ content_type "text/html"
+ @subject = "[" + ENV['EPFWIKI_APP_NAME'] + "] " + theSubject
+ @recipients = email_addresses_4_report(theUsers)
+ @body['text'] = theText
+ @body['admin'] = User.find_central_admin
+ for filePath in theFilePaths
+ attachment :content_type => "application/zip", :body => File.open(filePath, "rb") {|io| io.read}, :filename => filePath.split("/").last
+ end
+ end
+
+end
diff --git a/source/app/models/page.rb b/source/app/models/page.rb
new file mode 100644
index 0000000..723a36f
--- /dev/null
+++ b/source/app/models/page.rb
@@ -0,0 +1,295 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: pages
+#
+# id :integer(11) not null, primary key
+# rel_path :string(767) default(), not null
+# presentation_name :string(500) default(), not null
+# content_type :string(100) default(), not null
+# filename :string(250) default(), not null
+# versions_count :integer(11) default(0), not null
+# comments_count :integer(11) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+# body_tag :string(1000)
+# treebrowser_tag :string(1000)
+# copyright_tag :string(1000)
+# text :text
+#
+
+require_dependency "search_system"
+# A page is a wikifiable HTML file created using EPF.
+#
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--
+# # Info about Ruby regular expressions: the last i in a pattern is a modifier,
+# for case insensitive matches, same as the last m, for multiline matches
+# see for more info about regular expressions
+# Ruby_Syntax[http://www.ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html]
+#
+#++
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Page < ActiveRecord::Base
+
+ has_and_belongs_to_many :baselines #, :dependent => :destroy TODO: causes an error Unknown key(s)
+ has_and_belongs_to_many :sites #, :dependent => :destroy TODO: causes an error Unknown key(s)
+ has_many :versions#, :dependent => :destroy # NOTE: this will use RoR callbacks, :delete_all won't, it will just do a MySQL delete
+ has_many :checkouts#, :dependent => :destroy
+ has_many :comments#, :dependent => :destroy
+ has_many :difference_analysis_items#, :dependent => :destroy
+ has_many :notifications#, :dependent => :destroy
+
+ validates_presence_of :rel_path, :presentation_name, :content_type, :filename
+ validates_length_of :filename, :maximum => 250
+ validates_length_of :content_type, :maximum => 100
+ validates_length_of :presentation_name, :maximum => 500
+ validates_length_of :rel_path, :maximum => 250
+
+ # For creating a new page, use to specify the source version of the template or page
+ # NOTE: depending where it is used (view or model) this stores an Id or and object.
+ attr_accessor :source_version
+
+ # For creating a new page, use to specify the user
+ attr_accessor :user
+
+ # For creating a new page, use to specify the site
+ attr_accessor :site
+
+ # When creating a new page, use to supply a note for creating the version
+ attr_accessor :note
+
+ make_searchable [:presentation_name, :text]
+
+ # the following HTML fragment is added to each wikifiable HTML file
+ IFRAME_FRAGMENT = ['<!-- epfwiki iframe start -->','<script language="JavaScript">',
+ 'if (location.protocol == "http:") {',
+ 'aURL = "http://" + location.host + "/toolbar/show?url=" + document.location.href;',
+ 'document.write(" <div id=\"toolbar\">\n");',
+ 'document.write(" <iframe width=\"250\" height=\"700\" frameborder=\"0\" src=\"" + aURL + "\" frameborder=\"0\" scrolling=\"auto\" ALLOWTRANSPARENCY=\"TRUE\">\n");',
+ 'document.writeln(" </div>");','}','</script>','<!-- epfwiki iframe end -->'].join("\n")
+
+ # Used to replace treebrowser.js from HTML files because it chrashes the HTML editor
+ TREEBROWSER_PATTERN = /<script ( )*src( )*=(")?(.\/)(..\/)*scripts\/treebrowser.js.*<\/script>/i
+ # Placeholder for TREEBROWSER_PATTERN , so we can easily place it back in the file
+ TREEBROWSER_PLACEHOLDER = "<!-- treebrowser tag -->"
+ # Used to remove onload event from HTML files because it chrashed the HTML Editor
+ BODY_TAG_PATTERN = /<body.*>/i
+ # Used to add the HTML fragment that effectivly wikifies the HTML file
+ BODY_CLOSING_TAG_PATTERN = /<\/body>/i
+ # Used to remove HTML fragment that wikifies the HTML file so it can be edited.
+ IFRAME_PATTERN = /<\!-- epfwiki iframe start -->.*<\!-- epfwiki iframe end -->/im
+ # Used to fix some layout problems with the 'horizontal rule'
+ SHIM_TAG_PATTERN = /images\/shim.gif(")?( )*\/?>.?( )*?.?( )*?<\/td>/im
+ # Used to fix some layout problems with the 'horizontal rule'
+ SHIM_TAG = "images/shim.gif\"></td>"
+ # Used to replace copyright notice from the file so it can be edited.
+ COPYRIGHT_PATTERN = /<p>( )*?(.)?( )*?copyright(.)*?<\/p>/im
+ # Placeholder for copyright notice we find with COPYRIGHT_PATTERN
+ COPYRIGHT_PLACEHOLDER = "<!-- copyright statement -->"
+ TITLE_PATTERN = /<title>(.)*<\/title>/i
+ HEAD_PATTERN = /<head>(.)*<\/head>/im
+ TITLE_START = /<title>/i
+ TITLE_END = /<\/title>/i
+ TITLE2_PATTERN = /class="pageTitle">(.)*<\/td>/
+ TITLE2_START = /class="pageTitle">/i
+ TITLE2_END = /<\/td>/
+ ELEMENT_TYPE_PATTERN = /<meta(.)*element_type(.)*>/i
+
+ #--
+ # FIXME R1 filenames sometimes contain & characters, for instance configuration_&_change_management.
+ # If a file cannot be found using find_or_new we should look it for it in the directory?
+ #
+ # TODO R? new table element_type so that we can count, show pages per element_type
+ #
+ # #find_or_new can cause an errors in the console UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)
+ # This is the case if Python isn't configured correctly, see install notes
+ #++
+ def self.find_or_new(params, theSite)
+ logger.debug("Finding page with relative path #{params[:rel_path]}")
+ raise 'Version files cannot be manipulated by users' if params[:rel_path].upcase.index("_EPFWIKI_")
+ page = Page.find_by_rel_path(params[:rel_path])
+ if page
+ logger.info("Page with relative path #{params[:rel_path]} found in site #{theSite.title}")
+ else
+ page = Page.new
+ page.rel_path = params[:rel_path]
+ fileContents = page.html(theSite)
+ page.presentation_name = page.title_from_file(theSite)
+ page.content_type = Page.meta_tag_content_type(fileContents)
+ page.filename = File.basename(File.expand_path(params[:rel_path], theSite.path))
+ html = page.html(theSite)
+ page.text = html2markdown(page.path(theSite))
+ tag = html
+ tag =~ BODY_TAG_PATTERN
+ page.body_tag = $&
+ html = IO.readlines(page.path(theSite)).join
+ tag2 = html
+ tag2 =~ TREEBROWSER_PATTERN
+ page.treebrowser_tag = $&
+ page.copyright_tag = COPYRIGHT_PATTERN.match(html).to_s
+ end
+ return page
+ end
+
+ # Method #prepare_for_edit is used to prepare the file for editing in
+ # the HTML editor that runs in the browser:
+ # 1. onload event is removed from the body element
+ # 2. Javascript lib treebrowser.js that chrashes the editor is replaced by a placeholder comment tag
+ # 3. the EPF iframe element is removed
+ # 4. the copyright_tag is replaced by a placeholder tag
+ #
+ # See also #find_or_new where content that is removed here, was stored.
+ #--
+ # TODO: use tidy_file here too?
+ # TODO: move self.page attributes here?
+ #++
+ def self.prepare_html_for_editing(html)
+ html = html.gsub(BODY_TAG_PATTERN, '<body>') # 1
+ treebrowser_tag = html
+ treebrowser_tag =~ TREEBROWSER_PATTERN
+ html = html.gsub(TREEBROWSER_PATTERN, TREEBROWSER_PLACEHOLDER) # 2
+ html = html.gsub(IFRAME_PATTERN, '') # 3
+ html = html.gsub(COPYRIGHT_PATTERN, COPYRIGHT_PLACEHOLDER) # 4
+ return html
+ end
+
+ # Method #enhance_file enhances a file if it hasn't been enhanced yet.
+ # * replace body-tag with iframe
+ # * add Javascript libs and Wiki styles
+ # * change table width from 100% to 99% to get rid of the vertical scrollbar
+ def self.enhance_file(path)
+ if IO.readlines(path).join.index('epfwiki iframe end')
+ logger.info("File skipped (already enhanced): #{path}")
+ else
+ logger.info("Enhancing file: " + path)
+ html = IO.readlines(path).join #("\n")
+ html = html.gsub(BODY_CLOSING_TAG_PATTERN, IFRAME_FRAGMENT + "</body>\n")
+ html = html.gsub("width=\"100%\"", "width=\"99%\"")
+ file = File.new(path, "w")
+ file.puts(html)
+ file.close
+ end
+ end
+
+ def self.meta_tag_content_type(html)
+ return ELEMENT_TYPE_PATTERN.match(html).to_s.downcase.gsub("meta", "").gsub("name=", "").gsub("content=", "").gsub("element_type", "").gsub("\"", "").gsub("<","").gsub(">", "").strip.capitalize
+ end
+
+ # Method #sites_with_versions returns collection of sites with versions
+ def sites_with_versions
+ return self.versions.collect{|aVersion| aVersion.site}.uniq
+ end
+
+ # Method #baselines_with_versions returns collection of baselines with versions
+ def baselines_with_versions
+ return self.versions.collect{|aVersion| aVersion.baseline}.uniq
+ end
+
+ # #meta_tag_content_type extracts the meta_tag 'content type' from the HTML
+ def meta_tag_content_type(site)
+ return Page.meta_tag_content_type(self.html(site))
+ end
+
+ # what is or should be the #path to the Page in a Site. This can only be determined in context of a Site.
+ def path(site)
+ return site.path + '/' + self.rel_path
+ end
+
+ def html(site)
+ return IO.readlines(self.path(site)).join
+ end
+
+ # #title_from_file reads the value of the title element from the HTML file.
+ # This should correspond with the "presentation_name" column.
+ # Example: TaskDescriptor: Review Change Requests
+ # See also #title_2file
+ def title_from_file(site)
+ title = "N.A."
+ self.html(site) =~ TITLE_PATTERN
+ title = $&.gsub(TITLE_START,'').gsub(TITLE_END,'')
+ return title
+ end
+
+ # #title_from_file updates the title element in the HTML file based on the value of <tt>presentation_name</tt> column. These should be equal.
+ # See also #title_from_file
+ #--
+ # TODO not used, remove?
+ #++
+ def title_2file(site)
+ html = self.html(site)
+ html.gsub()
+ lines = IO.readlines(path(theSite)) #.join("\n") # this contains #{title}
+ lines.each do |aLine|
+ if aLine.index("<title>")
+ strFront, aLine = aLine.split("<title>")
+ title, strBack = aLine.split("</title>")
+ end
+ end
+ end
+
+ def versions_in_site(site)
+ return Version.find(:all, :conditions => ['site_id=? and page_id=?', site.id, id], :order=> 'created_on ASC')
+ end
+
+ def comments_in_site(site)
+ return Comment.find(:all, :conditions => ['site_id=? and page_id=?', site.id, id], :order=> 'created_on ASC')
+ end
+
+ def checkout(site)
+ return Checkout.find_by_site_id_and_page_id(site.id, self.id)
+ end
+
+ # return collection of wikis that allow new checkout of this page
+ def wikis_4checkout
+ return Site.find_wikis - self.checkouts.collect {|checkout| checkout.site}
+ end
+
+ def before_validation_on_create
+ if !self.source_version.nil?
+ logger.info('New page based on a source version (of another page or template)')
+ logger.error('Supplied filename will be overwritten') if !self.filename.blank?
+ raise "User can't be blank" if self.user.blank?
+ self.filename = self.presentation_name.downcase.delete("&+-.\"/\[]:;=,").tr(" ","_") + ".html" if !self.presentation_name.blank?
+ if self.source_version.template?
+ self.rel_path = File.expand_path(self.filename, self.site.new_files_dir).gsub(self.site.path + '/','')
+ logger.info("New page based on a template, rel_path is #{self.rel_path}")
+ else
+ self.rel_path = File.expand_path(self.filename, File.dirname(self.source_version.path)).gsub(self.site.path + '/','')
+ logger.info("New page based on another page, rel_path is #{self.rel_path}")
+ #self.source_version.page.rel_path.gsub(self.source_version.page.filename,self.filename) TODO remove
+ end
+ self.content_type = self.source_version.page.meta_tag_content_type(self.source_version.site)
+ self.body_tag = self.source_version.page.body_tag
+ self.treebrowser_tag = self.source_version.page.treebrowser_tag
+ self.copyright_tag = self.source_version.page.copyright_tag
+ #self.text = self.source_version.page.text
+ unless File.exist?(self.path(self.site)) || !Page.find_by_rel_path(self.rel_path).nil?
+ self.checkouts << Checkout.new(:user => self.user, :page => self, :site => self.site, :source_version => self.source_version, :note => self.note)
+ self.sites << site
+ end
+ end
+ end
+
+ def validate_on_create
+ logger.info('validate_on_create')
+ if !self.source_version.nil?
+ errors.add(:rel_path, "already used; can\'t create another file as a file with path #{self.path(self.site)} already exists") if File.exist?(self.path(self.site))
+ errors.add(:rel_path, "already used; can\'t create another page with relative path #{self.rel_path}") if !Page.find_by_rel_path(self.rel_path).nil?
+ end
+ end
+end
diff --git a/source/app/models/site.rb b/source/app/models/site.rb
new file mode 100644
index 0000000..f432052
--- /dev/null
+++ b/source/app/models/site.rb
@@ -0,0 +1,503 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: sites
+#
+# id :integer(11) not null, primary key
+# title :string(40) default(), not null
+# description :text
+# site_type :string(1)
+# baseline_id :integer(10)
+# site_id_baseline_process :integer(10)
+# created_on :datetime
+# updated_on :datetime
+# html_files_count :integer(11)
+# wikifiable_files_count :integer(11)
+# user_id :integer(11)
+# content_scanned_on :datetime
+# folder :string(200) default(), not null
+#
+
+# A Site can be a published website from EPF or a Wiki, which is an enhanced
+# published website from EPF. The published websites from EPF that are not
+# enhanced are also referred to as baseline processes. Baseline processes are
+# used to create or update Wiki sites.
+#
+# Creation or update of a Wiki is a two step process for performance reasons.
+# This way the second step can be performed using a job that runs at night.
+#
+# Therefore, #new_wiki is the first step of creation of a new Wiki. #wikify
+# does the actual 'wikifying'. To update a Wiki the first step is to set
+# the baseline_process attribute. The actual update is done by #update_wiki
+#
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Site < ActiveRecord::Base
+
+ has_many :comments
+ has_many :versions
+ has_many :checkouts
+ has_many :difference_analyses
+ belongs_to :baseline
+ belongs_to :user
+ has_and_belongs_to_many :pages
+ has_and_belongs_to_many :baselines
+
+ # TODO remove already defined above
+ # has_many :difference_analyses, :class_name => "DifferenceAnalysis", :foreign_key => "site_id"
+
+ has_many :used_in_difference_analyses, :class_name => 'DifferenceAnalysi', :foreign_key => 'site_id_from'
+
+ # Baseline process to create or update a Wiki
+ belongs_to :baseline_process, :class_name => "Site", :foreign_key => "site_id_baseline_process"
+
+ validates_presence_of :user_id, :title, :folder
+ validates_format_of :site_type, :with => /W|S/
+ validates_format_of :folder, :message => 'should consist of letters, digits and underscores', :with => /^([0-9A-Za-z_-])([0-9A-Za-z_-])*[0-9A-Za-z_-]$/
+
+ # Not baseline_id because id is only present after save for 'static sites'
+ # See also #validate_on_create
+ validates_presence_of :baseline
+
+ # required when using #new_baseline_process
+ attr_accessor :baseline_baseline, :baseline_description
+
+ # during creation of a new static Site this stores the zip-file that contains the content
+ attr_accessor :file
+
+ # We don't want this view logic here but because we cannot use url_for in emails,
+ # this is the workaround
+ attr_accessor :url
+
+ # this style element is added to default.css of every wiki, see #wikify and #update_wiki
+ # NOTE: the text '!important' is for cross browser support, the lines with !important are
+ # read by FireFox, the other lines are read by IE
+ TOOLBAR_STYLE = ['#toolbar {position:absolute;',
+ 'right: 110px!important;', 'right:50px', 'top: 11px;',
+ 'width: 200px;', 'height: 10px;','z-index: 100','}'].join("\n")
+
+ # CSS-file to add toolbar style too, see #enhance_files
+ DEFAULT_CSS = 'css/default.css'
+
+ # Modified treebrowser Javascript lib to use in each site, see #enhance_files
+ TREEBROWSER_JS = 'public/javascripts/treebrowser.js'
+
+ # A wikifiable file is a HTML file
+ HTML_FILE_PATTERN = /.*.htm(l)?/i
+
+ # A wikifiable is not a Wiki file (a version file created using the Wiki)
+ WIKI_FILE_PATTERN = /(.)*wiki(.)*/i
+
+ # HTML Editors remove the nowrap attribute, so we add it to the CSS-file
+ CSS_PAGETITLE_PATTERN = /.pageTitle(.)*\{(.)*\}/im
+ CSS_PAGETITLE = ['.pageTitle', '{',
+ 'background: #9999cc;',
+ 'color: #ffffff;',
+ 'font-size: 12pt;',
+ 'font-weight: bold;',
+ 'padding-bottom: 5px;',
+ 'padding-left: 10px;',
+ 'padding-right: 10px;',
+ 'padding-top: 5px;',
+ 'text-align: left;',
+ 'white-space: nowrap;','}'].join("\n")
+
+ # Method #new_upload to process a upload of content for a baseline process.
+ # This does not create a baseline process, for this #new_baseline_process is used.
+ # TODO directly after upload, create new site, causes error, very strange
+ def self.new_upload(params = nil)
+ site = Site.new(params)
+ site.errors.add(:folder, 'can\'t be blank') if site.folder.blank?
+ site.errors.add(:file, 'can\'t be blank') if site.file.original_filename.blank?
+
+ # FIXME can't convert nil to string
+ site.errors.add(:folder, 'already exists') if File.exists?(site.path) && !site.folder.blank?
+ if site.errors.empty?
+ site.folder = site.folder
+ logger.debug("Writing upload zip to #{site.path2zip}")
+ File.open(site.path2zip, "wb") { |f| f.write(site.file.read) }
+ site.unzip_upload
+ end
+ return site
+ end
+
+ # Method #new_baseline_process to create a new Site. This will also define a Baseline
+ # NOTE: the content is not scanned yet, see #scan4content
+ def self.new_baseline_process(params = nil)
+ site = Site.new(params)
+ site.site_type = 'S'
+ if !site.folder.nil? && File.exists?(site.path)
+ site.html_files_count = Site.files_html(site.path).size
+ wikifiable_files = site.files_wikifiable
+ site.wikifiable_files_count = wikifiable_files.size
+ #TODO the following causes an error when there are no files
+ site.baseline = Baseline.new(:buildid => buildid(File.ctime(wikifiable_files[0])), :baseline => site.baseline_baseline, :description => site.baseline_description )
+ end
+ return site
+ end
+
+ def self.folders_with_unused_baseline_processes
+ sites_path = "#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_SITES_FOLDER']}"
+ File.makedirs(sites_path)
+ entries = Dir.entries(sites_path) - ['.', '..', 'compare', '.svn']
+ folders = entries.collect {|entry| entry if File.ftype(File.expand_path(entry, sites_path)) == 'directory'}
+ sites = Site.find_baseline_processes
+ usedFolders = sites.collect {|aSite| aSite.path.gsub("#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_SITES_FOLDER']}/",'')}
+ return folders.compact - usedFolders
+ end
+
+ # Method #scan4content
+ # 1. scans the Site folder for pages that can be wikified and
+ # 2. and associates the Page to the Site using Page.find_or_new and
+ # 3. if the site is static, completes the definition of a Baseline by associating the Page records also it as well.
+ def scan4content
+ logger.info("Scanning content in site #{self.title}")
+ raise 'Scanning content is only supported for baseline_processes' if self.wiki?
+ files = self.files_wikifiable
+ files.each do |aFile|
+ page = Page.find_or_new({:rel_path => aFile.gsub(self.path + '/', '')}, self)
+ self.pages << page if !self.pages.include?(page)
+ end
+ self.content_scanned_on = Time.now
+ if self.baseline_process?
+ if self.baseline.pages_count == 0
+ # TODO: we have to split up this transaction
+ # because it causes MySQL to chrash when there are 6000 or something more records?
+ # Maybe this will work with InnoDB? My ISAM this problem reported
+ self.baseline.pages = self.pages
+ end
+ end
+ self.save!
+ end
+
+ def content_scanned?
+ return !self.content_scanned_on.nil?
+ end
+
+ # Method #new_wiki is first step of creation of a new Wiki based
+ # on a baseline process. Method #wikify
+ # For performance reasons this is implemented as a two step process: this creates
+ # a 'pending' Wiki site, #wikify creates the the wikified content
+ def self.new_wiki(params = nil)
+ wiki = Site.new(params)
+ logger.info("Creating wiki " + wiki.title)
+ wiki.site_type = "W"
+ if !wiki.baseline_process.nil?
+ wiki.baseline = wiki.baseline_process.baseline
+ wiki.wikifiable_files_count = wiki.baseline_process.wikifiable_files_count
+ wiki.html_files_count = wiki.baseline_process.html_files_count
+ end
+ return wiki
+ end
+
+ # Method #wikify does the actual wikifying of the content. It is the second step of the two step
+ # process, the first step was performed using #new_wiki.
+ # * copies content of the source Site (parent) into that folder
+ # * scans the content of the baseline process if this was not done yet, see #scan4content
+ # * enhances the files in that site using method #enhance_files
+ # * creates a relation between the Baseline and the Site
+ def wikify
+ logger.info("Wikifying " + self.title)
+ raise 'The site is not a pending wiki site!' if self.status != 'P'
+ #raise "A baseline process cannot be wikified" if self.status != 'P'
+ #raise "No baseline process specified for this site" if self.baseline_process.nil?
+ raise "Can only update with a baseline process (static site)" if self.baseline_process.wiki?
+ File.makedirs(self.path)
+ logger.info("Copying files from " + self.baseline_process.path + " to " + self.path )
+ FileUtils.cp_r(self.baseline_process.path + "/.", self.path) # How to copy the contents of a folder and not the folder [http://www.ruby-doc.org/core/classes/FileUtils.html#M001703]
+
+ self.baseline_process.scan4content if !self.baseline_process.content_scanned_on
+ self.pages << self.baseline_process.pages
+ # NOTE: the parent.path already has a trailing slash
+ enhance_files
+ self.baselines << self.baseline_process.baseline unless self.baselines.include?(self.baseline_process.baseline)
+ self.baseline_process = nil
+ end
+
+ # add checks that update site is static and site to update is a wiki
+ # content of the baseline process is scanned (#scan4content) if this wasn't done yet
+ def update_wiki
+ logger.info("Starting update of wiki #{title}")
+ if self.checkouts.length > 0
+ logger.error("Could not update site #{title} because of checkouts")
+ raise "Could not update #{title} due to checkouts"
+ elsif !baseline_process
+ logger.error('No baseline specified')
+ raise "No baseline specified for update of #{title}"
+ else
+ logger.info("Copy update site " + baseline_process.path + " to " + self.path)
+ self.baseline_process.copy_to(self, nil)
+ self.baseline_process.scan4content if self.baseline_process.pages.size == 0
+ baseline_process_pages = self.baseline_process.pages
+ logger.debug("Wiki has no pages") if self.pages.size == 0
+ logger.debug("Baseline process has no pages") if self.baseline_process.pages.size == 0
+ self.pages = self.baseline_process.pages | self.pages # assumes that both are not nil
+ logger.info("Enhancing site " + self.baseline_process.path + " to " + self.path)
+ enhance_files
+ self.baseline = self.baseline_process.baseline
+ self.baseline_process = nil
+ self.baselines << self.baseline unless self.baselines.include?(self.baseline)
+ end
+ end
+
+ def baseline_processes_candidate
+ returning bp_candidate = [] do
+ if self.status == 'W'
+ Site.find_baseline_processes.each do |bp|
+ bp_candidate << bp unless self.baselines.include?(bp.baseline)
+ end
+ end
+ end
+ end
+
+ def self.find_wikis_pending
+ returning wikis_pending = [] do
+ Site.find_wikis.each do |wiki|
+ wikis_pending << wiki if wiki.status == 'P'
+ end
+ end
+ end
+
+ def self.find_wikis
+ Site.find_all_by_site_type('W')
+ end
+
+ def self.find_wikis_update
+ returning wikis_update = [] do
+ Site.find_wikis.each do |wiki|
+ wikis_update << wiki if wiki.status == 'U'
+ end
+ end
+ end
+
+ def self.find_baseline_processes
+ Site.find_all_by_site_type('S')
+ end
+
+ # return collection of Site-records that need to scanned
+ def self.find_baseline_processes_2scan
+ returning bp_2scan = [] do
+ Site.find_baseline_processes.each do |bp|
+ bp_2scan << bp if bp.content_scanned_on.blank?
+ end
+ end
+ return Site.find(:all, :conditions => ['site_type="S" and content_scanned_on is null'], :order => "title ASC")
+ end
+
+ def wiki?
+ return self.site_type == 'W'
+ end
+
+ def baseline_process?
+ return self.site_type == 'S'
+ end
+
+ def path
+ return "#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_WIKIS_FOLDER']}/#{self.folder}" if self.wiki?
+ return "#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_SITES_FOLDER']}/#{self.folder}"
+ end
+
+ def rel_path
+ return path.gsub(ENV['EPFWIKI_ROOT_DIR'] + 'public/','')
+ end
+
+
+ def path2zip
+ return self.path + '.zip'
+ end
+
+ def status
+ return 'S' if self.baseline_process?
+ return 'P' if self.pages.size == 0 && !self.baseline_process.nil?
+ return 'U' if self.pages.size > 0 && !self.baseline_process.nil?
+ return 'W'
+ end
+
+ # #templates returns a collection of Page records.
+ # These Page records are templates for creating new pages.
+ # These templates are stored in #templates_dir.
+ def templates
+ somePages = Array.new
+ entries = Dir.entries(ENV['EPFWIKI_TEMPLATES_DIR']) - [".", "..", ".svn"]
+ entries.each do |entry|
+ path = self.templates_dir + '/' + entry
+ rel_path = path.gsub(self.path + '/','')
+ path_source = (ENV['EPFWIKI_TEMPLATES_DIR'] + entry)
+ if !File.exists?(path)
+ logger.info("Template " + path + " does not exist, copy from " + path_source)
+ File.makedirs(self.templates_dir)
+ File.copy(path_source, path)
+ Page.enhance_file(path)
+ end
+ page = Page.find_or_new({:rel_path => rel_path}, self)
+ version = Version.find_current_version(self, page, true)
+ page.save!
+ version.save!
+ somePages << page
+ end
+ return somePages
+ end
+
+ def difference_analyses2
+ return DifferenceAnalysis.find(:all, :conditions => ['baseline_id=? or baseline_id_from=?', self.baseline_id, self.baseline_id], :order => "created_on ASC")
+ end
+
+ # #templates_dir returns the path to the folder where the site templates are stored.
+ def templates_dir
+ return path + "/wiki/templates"
+ end
+
+ # #new_files_dir returns the path to the folder where new pages are stored.
+ def new_files_dir
+ return path + "/wiki/new"
+ end
+
+ def users
+ return User.find(:all, :conditions => ['exists (select * from versions vsn where vsn.site_id = ? and vsn.user_id = users.id) or exists (select * from comments cmt where cmt.user_id = users.id and cmt.site_id = ?)', id, id])
+ end
+
+ def versions_count_excluding_baseversions
+ return Version.find(:all, :conditions => ['site_id= ? and version <> 0', id]).length
+ end
+
+ def versions_count_since(time)
+ return Version.find(:all, :conditions => ['site_id= ? and version <> 0 and created_on > ?', id, time]).length
+ end
+
+ def comments_count_since(time)
+ return Comment.find(:all, :conditions => ['site_id= ? and created_on > ?', id, time]).length
+ end
+
+ def unzip_upload
+ raise "Folder #{self.path} exists" if File.exists?(self.path)
+ logger.debug("Unzipping uploaded file using Apache Ant, command: " + unzip_upload_cmdline)
+ cmd = IO.popen(unzip_upload_cmdline, "w+")
+ cmd.close_write
+ write_log("unzip_upload.log", cmd.readlines.compact.join("\n"))
+ end
+
+ def validate_on_create
+ logger.info("Validating creation of site: #{inspect}")
+ if baseline_process? # static site (or baseline process)
+ logger.info('New static site validation')
+ errors.add(:folder, 'doesn\'t exist') if folder.nil? || !File.exists?(self.path)
+ errors.add(:folder, 'was already used to create a baseline process (static site)') if !folder.nil? && Site.find_all_by_site_type_and_folder('S',folder).size > 0
+ baseline.errors.each {|attr, e| errors.add(attr, e)} if !baseline.nil? && !baseline.valid? # adding all baseline errors to site so these are displayed
+ elsif status == 'P' # pending! We are creating a new Wiki
+ logger.info('New wiki site validation')
+ errors.add(:folder, 'already exists') if File.exists?("#{ENV['EPFWIKI_WIKIS_PATH']}#{folder}")
+ errors.add(:baseline_process, 'not a baseline process (type is not \'S\'') if !site_id_baseline_process.nil? && baseline_process.site_type != 'S'
+ end
+ end
+
+ def validate_on_update
+ logger.info("Validating update of site: #{inspect}")
+ site = Site.find(id) # old values from db
+ errors.add(:site_type, 'can\'t be updated for a baseline process') if site.baseline_process? and wiki?
+ if wiki? and !baseline_process.nil?
+ errors.add(:baseline_process, 'is equal to current baseline') if baseline_process.baseline == baseline and site.status != 'P'
+ errors.add(:baseline_process, 'is not a baseline process') if baseline_process.wiki?
+ errors.add(:baseline_process, 'was already used to create or update this site') if site.baselines.index(baseline_process.baseline)
+ end
+ end
+
+ # array of HTML files that are candate Wikification
+ def self.files_html(path)
+ paths = Array.new
+ (Dir.entries(path) - [".", ".."]).each do |entry|
+ new_path = File.expand_path(entry, path)
+ if FileTest.directory?(new_path)
+ paths = paths + Site.files_html(new_path)
+ else
+ paths << new_path if !HTML_FILE_PATTERN.match(entry).nil? && WIKI_FILE_PATTERN.match(entry).nil?
+ end
+ end
+ return paths
+ end
+
+ def files_wikifiable
+ # return array of html-files that have a meta-tag "element type" -> rup-files
+ raise 'Path can\'t be blank' if self.path.blank?
+ returning paths = [] do
+ Site.files_html(self.path).each do |path2|
+ paths << path2 unless Page::ELEMENT_TYPE_PATTERN.match(IO.readlines(path2).join("\n")).nil?
+ end
+ end
+ end
+
+ ###########
+ private
+ ###########
+
+ # TODO R? test if default_CSS was added already
+ def enhance_files
+ #html_iframe_fragment = IO.readlines(ENV['EPFWIKI_IFRAME_FRAGMENT_FILE_PATH']).join # TODO: remove
+ File.copy(ENV['EPFWIKI_ROOT_DIR'] + TREEBROWSER_JS, self.path + "/scripts/treebrowser.js" )
+ html = IO.readlines(self.path + '/' + DEFAULT_CSS).join + "\n" + TOOLBAR_STYLE
+ html = html.gsub(CSS_PAGETITLE_PATTERN.match(html).to_s, CSS_PAGETITLE)
+ file = File.new(self.path + '/' + DEFAULT_CSS, 'w')
+ file.puts(html)
+ file.close
+ self.files_wikifiable.each do |file|
+ Page.enhance_file(file)
+ end
+ end
+
+ # action #copy_to copies the content of a site to another site (theDestSite). Files are overwritten if they exist in the destination site.
+ # NOTE: Ruby does not have a copy + overwrite command?
+ def copy_to(theDestSite, theFolderPath = nil)
+ if theFolderPath
+ (Dir.entries(theFolderPath) - [".", ".."]).each do |aEntry|
+ aPath = File.expand_path(aEntry, theFolderPath)
+ aDestPath = aPath.gsub(self.path, theDestSite.path)
+ if FileTest.directory?(aPath)
+ logger.info("Copying folder " + aPath + " to " + aDestPath)
+ File.makedirs(aDestPath)
+ copy_to(theDestSite, aPath)
+ else
+ if !FileTest.exists?(aDestPath)
+ logger.info("New file copied " + aPath + " to " + aDestPath)
+ File.copy(aPath, aDestPath)
+ else
+ if FileUtils.cmp(aPath, aDestPath)
+ logger.info("Not copied because equal: " + aPath)
+ else
+ logger.info("Overwritten: " + aPath)
+ File.delete(aDestPath)
+ File.copy(aPath, aDestPath)
+ end
+ end
+ end
+ end
+ else
+ logger.info("Copying content from site " + self.title + " to " + theDestSite.title)
+ logger.info("Source folder: " + self.path + ". Destination folder: " + theDestSite.path)
+ copy_to(theDestSite, self.path)
+ end
+ end
+
+ def unzip_upload_cmdline
+ cmdParameters = Array.new
+ cmdParameters << ENV['EPFWIKI_ROOT_DIR'].split(":")[0] + ":" #drive letter
+ cmdParameters << ENV['EPFWIKI_ROOT_DIR'].gsub("/","\\")
+ cmdParameters << ENV['EPFWIKI_ANT_PATH']
+ cmdParameters << self.path2zip
+ cmdParameters << self.path
+ return "#{ENV['EPFWIKI_ROOT_DIR']}script/other/unzip_upload.bat #{cmdParameters.join(' ')}"
+ end
+
+end
diff --git a/source/app/models/user.rb b/source/app/models/user.rb
new file mode 100644
index 0000000..5fb9ff0
--- /dev/null
+++ b/source/app/models/user.rb
@@ -0,0 +1,258 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: users
+#
+# id :integer(11) not null, primary key
+# email :string(250) default(), not null
+# name :string(50) default(), not null
+# ip_address :string(20) default(), not null
+# hashed_password :string(40)
+# hashed_password_new :string(40)
+# admin :string(1) default(N), not null
+# notify_daily :integer(1) default(0), not null
+# notify_weekly :integer(1) default(0), not null
+# notify_monthly :integer(1) default(0), not null
+# site_id :integer(10)
+# created_on :datetime
+# updated_on :datetime
+# http_user_agent :string(250)
+# logon_count :integer(5) default(0)
+# logon_using_cookie_count :integer(5) default(0)
+# last_logon :datetime
+# confirmed_on :datetime
+#
+
+require 'digest/sha1'
+
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class User < ActiveRecord::Base
+
+ DOMAIN_PATTERN = /@.*/
+
+ has_many :sites
+ has_many :checkouts
+ has_many :versions
+ has_many :comments
+ has_many :notifications
+ has_many :versions2review, :class_name => "Version", :foreign_key => "reviewer_id"
+ has_many :comments2review, :class_name => "Comment", :foreign_key => "reviewer_id"
+ belongs_to :user_thatmarkeddone, :class_name => "User", :foreign_key => "user_id_markdone"
+ belongs_to :user_thatmarkedtodo, :class_name => "User", :foreign_key => "user_id_marktodo"
+ belongs_to :site # default site of user TODO: not used
+
+ validates_confirmation_of :password
+ validates_presence_of :name, :email
+ validates_uniqueness_of :name, :email
+ validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
+ validates_format_of :admin, :with => /Y|N|C/
+
+ attr_accessor :password, :remember_me, :email_extension
+
+ # Changing account to admin or cadmin requires that
+ # you specify the user that is requesting the change
+ attr_accessor :user
+ validates_associated :user
+
+ # #new_cadmin creates the central adminstrator user
+ def self.new_cadmin(params)
+ raise 'Already create central admin' if User.count > 0
+ user = User.new(params)
+ user.hashed_password = hash_pw(user.password) if user.password
+ user.admin = "C"
+ user.confirmed_on = Time.now
+ return user
+ end
+
+ # #new_signup creates an ordinary user account
+ def self.new_signup(params)
+ user = User.new(params)
+ user.email = user.email + user.email_extension if ENV['EPFWIKI_DOMAINS'] && user.email_extension
+ if ENV['EPFWIKI_GENERATE_PASSWORDS'] == '1'
+ logger.info("Creating account with generated password for #{user.email}")
+ user.password = user.generate_new_pw
+ user.password_confirmation = user.password
+ user.confirmed_on = Time.now # account does not need to be confirmed
+ else
+ logger.info("Creating account with supplied password for #{user.email}")
+ end
+ user.hashed_password = hash_pw(user.password) if user.password
+ return user
+ end
+
+ # #login searches the user on email and hashed_password and returns it, see also #try_to_login
+ def self.login(email, password)
+ logger.info("Doing login for #{email} with password #{password}, hash_pw is #{hash_pw(password)}")
+ hashed_password = hash_pw(password)
+ user = find(:first, :conditions => ["email = ? and hashed_password = ?", email.downcase, hashed_password])
+ return nil if user && (password.nil? || user.confirmed_on.nil?)
+ return user
+ end
+
+ # #confirm_account is used to confirm new accounts or confirm new passwords in case user requested on
+ def confirm_account(token)
+ logger.debug("Confirming account with token: " + token)
+ logger.debug("Hashed password is: " + self.hashed_password)
+ logger.debug("Hashed password new is: " + (self.hashed_password_new || ''))
+ if self.hashed_password && (hash_pw(self.hashed_password) == token)
+ self.confirmed_on = Time.now
+ elsif self.hashed_password_new && (hash_pw(self.hashed_password_new) == token)
+ self.confirmed_on = Time.now
+ self.hashed_password = self.hashed_password_new
+ self.hashed_password_new = nil
+ else
+ raise "Failed to activate account for #{self.email}"
+ end
+ end
+
+ # Use #set_new_pw to set and return a new password for a user.
+ # Needs to be confirmed using #confirm_account
+ def set_new_pw
+ new_pw = generate_new_pw
+ self.password = new_pw
+ self.hashed_password_new = hash_pw(new_pw)
+ end
+
+ # Log in if the name and password (after hashing)
+ # match the database, or if the name matches
+ # an entry in the database with no password
+ def try_to_login
+ User.login(self.email.downcase, self.password)
+ end
+
+ # #change_password changes the password of a User
+ def change_password(user)
+ raise "Password can't be blank" if user.password.blank?
+ self.password = user.password
+ self.password_confirmation = user.password_confirmation
+ self.hashed_password = hash_pw(user.password)
+ self.confirmed_on = Time.now
+ end
+
+ def self.cadmin(from, to)
+ raise 'From needs to be central admin' if !from.cadmin?
+ User.transaction(from, to) do
+ to.admin = 'C'
+ to.user = from
+ from.admin = 'Y'
+ to.save
+ from.save
+ end
+ end
+
+ # Count of versions of user without counting base versions
+ def versions_count_excluding_baseversions
+ return Version.count_by_sql('select count(*) from versions where user_id = ' + self.id.to_s + ' and version <> 0 ' )
+ end
+
+ # Token that can be used to confirm a account
+ def token
+ return Digest::SHA1.hexdigest(self.hashed_password)
+ end
+
+ def user?
+ return admin == 'N'
+ end
+
+ def admin?
+ return admin == 'Y' || admin == 'C'
+ end
+
+ def cadmin?
+ return admin == 'C'
+ end
+
+ def self.find_central_admin
+ return User.find(:first, :conditions => ["admin=?", "C"] )
+ end
+
+ def documents_path
+ return "users/" + id.to_s + "/docs"
+ end
+
+ def images_path
+ return "users/" + id.to_s + "/images"
+ end
+
+ # #sites returns Site records where user created versions or comments
+ def sites
+ return Site.find(:all, :conditions => ['exists (select * from versions where user_id = ? and site_id = sites.id) or exists (select * from comments where user_id = ? and site_id = sites.id)', id, id])
+ end
+
+ # Returns list of uploaded images
+ def images
+ path = "#{ENV['EPFWIKI_ROOT_DIR']}public/#{self.images_path}"
+ logger.debug("Getting entries in directory #{path}")
+ File.makedirs(path)
+ return Dir.entries(path) - [".", "..", "Thumbs.db"] # NOTE: dir entires returns array like [".", "..", "config.h", "main.rb"]
+ end
+
+ # Returns list of uploaded documents
+ def documents
+ path = "#{ENV['EPFWIKI_ROOT_DIR']}public/#{self.documents_path}"
+ logger.debug("Getting documents in #{path}")
+ File.makedirs(path)
+ return Dir.entries(path) - [".", "..", "Thumbs.db"]
+ end
+
+ def before_validation_on_update
+ end
+
+ def validate
+ if ENV['EPFWIKI_DOMAINS']
+ valid_domain = !ENV['EPFWIKI_DOMAINS'].split(" ").index(DOMAIN_PATTERN.match(email.downcase).to_s).nil?
+ errors.add(:email, "domain not valid") if !valid_domain && !self.cadmin?
+ end
+ end
+
+ def validate_on_create
+ if ENV['EPFWIKI_GENERATE_PASSWORDS'] == '1'
+ else
+ errors.add(:password, "can't be blank") if password.blank? || hashed_password.blank?
+ errors.add(:password_confirmation, "can't be blank") if password_confirmation.blank?
+ end
+ errors.add("Central admin already exists") if User.count > 0 && admin == 'C'
+ end
+
+ def validate_on_update
+ errors.add(:hashed_password, "can't be blank") if hashed_password.blank?
+ old_admin = User.find(id).admin
+ if admin == 'C' and old_admin != 'C'
+ if user.nil? || User.find(user.id).admin != 'C'
+ errors.add(:admin, 'can only be set to C by the central admin')
+ end
+ end
+ if admin == 'Y' and old_admin == 'N'
+ errors.add(:admin, 'can only be set by an admin') if user.nil? || user.admin == 'N'
+ end
+ if admin == 'N' and !old_admin.index(/Y|C/).nil?
+ errors.add(:admin, 'can only be revoked by the central admin') if user.nil? || user.admin != 'C'
+ end
+ end
+
+ def before_save
+ self.email = self.email.downcase
+ end
+
+ def generate_new_pw
+ random = rand(10-6+1)+6 # TODO: random is not used anymore?
+ chars = ["A".."Z","a".."z","0".."9"].collect { |r| r.to_a }.join + %q(!@$%^&*)
+ (1..8).collect { chars[rand(chars.size)] }.pack("C*")
+ end
+
+end
diff --git a/source/app/models/version.rb b/source/app/models/version.rb
new file mode 100644
index 0000000..25e2cb6
--- /dev/null
+++ b/source/app/models/version.rb
@@ -0,0 +1,252 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: versions
+#
+# id :integer(11) not null, primary key
+# version :integer(3) default(0), not null
+# note :text
+# done :string(1) default(N), not null
+# user_id :integer(10) default(0), not null
+# page_id :integer(10)
+# site_id :integer(10)
+# version_id :integer(10)
+# baseline_id :integer(10) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+# reviewer_id :integer(11)
+# user_id_markdone :integer(11)
+# user_id_marktodo :integer(11)
+# rel_path :string(1000) default(), not null
+#
+
+require 'ftools'
+# A Version of a Page. A Version belongs to a Site, Page and Baseline.
+# The following types can be distinguished:
+# 1. #baseversion, the first (0) version. This version is automatically created. This version is the version created with EPF, see #baseversion
+# 2. Latest Version: the version with the highest version number, see #find_latest_version and #latest_version
+# 3. Current Version: the version with highest version number or the previous version of the latest version if the latest version is checked out, see #find_current_version and #current_version.
+# 4. Source Version: the version that was used to create a version (does not have to be the previous version)
+# 5. Previous Version: the version with version number - 1, see #previous_version
+#
+# More information:
+# * {EPF Wiki Data model}[link:files/doc/DATAMODEL.html]
+#
+#--
+# TODO R? store markdown in table instead filesystem?
+#++
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Version < ActiveRecord::Base
+
+ belongs_to :user
+ belongs_to :site
+ belongs_to :baseline
+ belongs_to :page
+ has_one :checkout
+ belongs_to :source_version, :class_name => 'Version', :foreign_key => 'version_id'
+ belongs_to :reviewer, :class_name => 'User', :foreign_key => 'reviewer_id'
+ belongs_to :user_thatmarkeddone, :class_name => 'User', :foreign_key => 'user_id_markdone'
+ belongs_to :user_thatmarkedtodo, :class_name => 'User', :foreign_key => 'user_id_marktodo'
+ has_many :child_versions, :class_name => 'Version', :foreign_key => 'version_id'
+ has_many :comments
+ belongs_to :page, :counter_cache => true
+
+ # In case #new_basedonversion leads to creation of a baseversion it is stored here.
+ # RoR will save it for us when we save the version.
+ attr_accessor :new_baseversion
+
+ # Method #find_currentversion returns the current Version of a
+ # Page in a Site.
+ #
+ # Returns latest version, unless it is checked out. Or it returns
+ # the baseversion if there are no versions, unless we don't want
+ # it created or a file was not found to create the baseversion from.
+ # NOTE: if a baseversion is returned, it hasn't been saved yet!
+ def self.find_current_version(site, page, create_baseversion_ifnotexists=false)
+ raise 'Cannot use find_current_version on a baseline process' if site.baseline_process?
+ version = Version.find(:first ,:order => "version DESC", :conditions => ["page_id=? and site_id =? and baseline_id = ?", page.id, site.id, site.baseline_id])
+ version = version.previous_version if !version.nil? && version.checkout
+ if version.nil? && create_baseversion_ifnotexists
+ if File.exists?(page.path(site))
+ version = Version.new(:user => User.find_central_admin, :page => page,
+ :site => site, :version => 0, :done => 'Y', :note => 'Base version',
+ :baseline => site.baseline, :rel_path => page.rel_path + '_EPFWIKI_v0_' + site.baseline.baseline + '.html')
+ File.copy(page.path(site), version.path)
+ version.html(Page.prepare_html_for_editing(version.html))
+ else
+ # NOTE: if the file doesn't exists there is no use in creating the baseversion
+ # we do raise exception because it is posssible that the file doesn't exist,
+ # this is the case when we create a new Page by using a template of by checking
+ # out from another site.
+ logger.info("File " + site.path + page.rel_path + " does not exist, so baseversion is not created")
+ end
+ end
+ return version
+ end
+
+ # #new_basedonversion creates a new Version based on another Version. The method uses #find_previousversion to determine the version number.
+ # TODO this could also be a checked-out version? Raise error here?
+ # TODO: we can remove version param?
+ def self.new_basedonversion(site, page, basedonversion, user, version = 0)
+ logger.debug('new_basedonversion')
+ version = Version.new(:site => site, :page => page, :user => user, :baseline => site.baseline,
+ :source_version => basedonversion)
+ currentversion = Version.find_current_version(site, page, true)
+ version.new_baseversion = currentversion if !currentversion.nil? && currentversion.version == 0
+ # setting the transient attribute new_baseversion makes it part of the transaction
+ # RoR will save it for us when we save version
+ if currentversion
+ version.version = currentversion.version + 1
+ else
+ version.version = version
+ end
+ version.version = 1 if page != basedonversion.page # don't use id, id can be null if baseversion is just created
+ version.rel_path = page.rel_path + "_EPFWIKI_v" + version.version.to_s + "_" + version.baseline.baseline + ".html"
+ File.makedirs(File.dirname(version.path))
+ logger.debug("Copying file #{basedonversion.path} to #{version.path}")
+ File.copy(basedonversion.path, version.path )
+ return version
+ end
+
+ def previous_version
+ return nil if self.version == 0
+ return Version.find(:first, :conditions => ['site_id = ? and baseline_id =? and page_id=? and version=?',
+ self.site_id, self.baseline_id, self.page_id, self.version - 1])
+ end
+
+ def baseversion
+ return Version.find(:first, :conditions => ['site_id = ? and baseline_id =? and page_id=? and version=0',
+ self.site_id, self.baseline_id, self.page_id])
+ end
+
+ def current_version
+ return Version.find_current_version(self.site, self.page)
+ end
+
+ def path
+ return self.site.path + '/' + self.rel_path
+ end
+
+ def self.find_latest_version(site, page)
+ return Version.find(:first ,:order => "version DESC", :conditions => ["page_id=? and site_id =? and baseline_id = ?", page.id, site.id, site.baseline.id])
+ end
+
+ # Returns relative path of a version in folder 'public',
+ # the column rel_path stores the relatieve path in a Site folder
+ def rel_path_root
+ return self.path.gsub("#{ENV['EPFWIKI_ROOT_DIR']}public/", '')
+ end
+
+ # use #tidy to tidy the file using HTML Tidy.
+ # This also removes any empty lines that may have been
+ # created by PinEdit.
+ def tidy
+ logger.info("Tidying file " + path)
+ tidy_file(path)
+ #remove_empty_lines(path)
+ end
+
+
+ # method #html read or writes the HTML of a version from or to the version file.
+ # When writing HTML Tidy is used to cleanup the file
+ #--
+ # TODO R? only owner or cadmin should be allowed to save
+ # FIXME multiple head tags with page any_role
+ # FIXME TinyMCE support, tincyMCE removes the image map links
+ # TODO R? PinEdit makes hrefs absolute,
+ # use Pathname (relative_path_from) to make these relative again p1 = Pathname.new(path) # Pathname:/usr/lib
+ #++
+ def html(html = nil)
+ if html
+ logger.debug("Saving HTML: " + html)
+ # TinyMCE only submits the body -> retrieve from source version
+ if self.source_version && ENV['EPFWIKI_EDITOR'] = 'tinymce'
+ logger.debug("Correcting TinyMCE stuff")
+ html = Page::HEAD_PATTERN.match(self.source_version.html).to_s + '<body>' + html + '</body>'
+ html = html.gsub(Page::TITLE_PATTERN, "<title>#{self.page.presentation_name}</title>")
+ end
+ aFile = File.new(self.path, "w")
+ aFile.puts(html)
+ aFile.close
+ # works on the file, we are using tidy lib
+ self.tidy
+ html = self.html.gsub(Page::SHIM_TAG_PATTERN, Page::SHIM_TAG)
+ aFile = File.new(self.path, "w")
+ aFile.puts(html)
+ aFile.close
+ return html
+ else
+ return IO.readlines(self.path).join
+ end
+ end
+
+ # use #set_title to set the browser window title (value title element in HTML file), see also #title
+ def set_title(title)
+ logger.info("Set title to #{title} in file #{self.path}")
+ new_html = self.html.gsub(Page::TITLE_PATTERN, "<html>#{title}</html>").gsub(Page::TITLE2_PATTERN, "<td class=\"pageTitle\">#{title}</td>")
+ self.html(new_html)
+ end
+
+ # #find_history_excl_baseversions2 returns a collection of Version records without baseversions (version <> 0) for a Page in a Site.
+ # See #find_history_excl_baseversions1. It is possible that a Page doesn't have a baseversion. This is the
+ # case when a Page was created in the Wiki.
+ def self.find_history_excl_baseversions2(theSite, thePage)
+ return Version.find(:all, :order => 'version DESC', :conditions => ["page_id=? and site_id =? and baseline_id = ? and version <> 0", thePage.id, theSite.id, theSite.baseline_id])
+ end
+
+ # #find_history_excl_baseversions1 returns a collection of Version records without baseversions for a Page.
+ def self.find_history_excl_baseversions1(thePage)
+ return Version.find(:all, :order => 'version DESC', :conditions => ["page_id=? and version <> 0", thePage.id])
+ end
+
+ def markdownpath
+ return ENV['EPFWIKI_MARKDOWN_PATH'] + markdownname
+ end
+
+ def markdownname
+ return "version" + id.to_s + ".txt"
+ end
+
+ def markdown
+ html2markdownfile(path, markdownpath)
+ return IO.readlines(self.markdownpath).join
+ end
+
+ def template?
+ return !self.path.index(self.site.templates_dir).nil?
+ end
+
+ # #version_text returns version number, site title and baseline,
+ # for example <tt>1 from OpenUP(OUP_20060721)</tt>
+ def version_text
+ return self.version.to_s + ' from ' + self.site.title + ' (' + self.site.baseline.baseline + ')'
+ end
+
+ def before_destroy
+ logger.debug("Before Destroy: deleting file #{self.path}")
+ #raise 'Cannot destroy version, child versions exist' if self.child_versions.size > 0
+ File.delete(self.path)
+ end
+
+ def diff_markdown(source_version)
+ generic.diff_markdown(self, source_version)
+ end
+
+ def diff(source_version)
+ generic.diff(self, source_version)
+ end
+
+end
diff --git a/source/app/views/baselines/edit.rhtml b/source/app/views/baselines/edit.rhtml
new file mode 100644
index 0000000..d05fef1
--- /dev/null
+++ b/source/app/views/baselines/edit.rhtml
@@ -0,0 +1,16 @@
+<% @heading = 'Edit Baseline' %>
+<% @overview = "Use this form to edit the details of baseline #{link_to_baseline(@baseline, nil)}" %>
+
+<% tinymce %>
+
+<%= error_messages_for 'baseline' %>
+
+<% tabular_form_for :baseline, @baseline do |f| %>
+ <%= f.text_field :buildid%>
+ <%= f.text_field :baseline%>
+ <%= f.text_area :description, :cols => 60, :rows => 8 %>
+ <tr><th></th><td><%= submit_tag 'Submit' %></td></tr>
+<% end %>
+
+
+
diff --git a/source/app/views/baselines/list.rhtml b/source/app/views/baselines/list.rhtml
new file mode 100644
index 0000000..0c69998
--- /dev/null
+++ b/source/app/views/baselines/list.rhtml
@@ -0,0 +1,34 @@
+<% @heading = 'Baselines' %>
+
+ <div class="sectionHeading">Baselines</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>Baseline</th>
+ <th>Build ID</th>
+ <th>Versions</th>
+ <th>Comments</th>
+ <th>Created</th>
+ </tr>
+
+ <% for baseline in @baselines %>
+ <tr><td><%= baseline.id %></td>
+ <td><%= link_to_baseline baseline, @site %></td>
+ <td><%= baseline.buildid %></td>
+ <td><%= baseline.versions_count.to_s %></td>
+ <td><%= baseline.comments_count.to_s %></td>
+ <td><%= baseline.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+
+
diff --git a/source/app/views/baselines/show.rhtml b/source/app/views/baselines/show.rhtml
new file mode 100644
index 0000000..d04ce8c
--- /dev/null
+++ b/source/app/views/baselines/show.rhtml
@@ -0,0 +1,111 @@
+<% @heading = "Baseline: #{@baseline.baseline}" %>
+
+<div id="menu">
+ <%= link_to 'edit', :action => 'edit', :id => @baseline.id %>
+ | <%= link_to 'list', :action => 'list' %>
+</div>
+
+<div class="sectionHeading">Description</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <td align="left" class="sectionTableCell"><%= @baseline.description %></td>
+ <tr>
+ </table>
+</div>
+
+<p>
+<%= tabs([["Versions", url_for(:action => 'show', :id => @baseline.id), (params[:action] == "show")],["Comments", url_for(:action=> 'show_comments', :id => @baseline.id), (params[:action] == "show_comments")]], 80) %>
+</p>
+
+<%= links_to_pages(@version_pages) if @version_pages %>
+<%= links_to_pages(@comment_pages) if @comment_pages %>
+
+<%= render(:partial => 'versions/versions_list') if @version_pages %>
+<%= render(:partial => 'comments/comments_list') if @comment_pages %>
+
+
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Established with baseline process</th>
+ <td align="left" class="sectionTableCell"><%= link_to_site @baseline.baseline_process %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Current Wikis</th>
+ <td align="left" class="sectionTableCell">
+ <ul>
+ <% for wiki in @baseline.wikis_current %>
+ <li>
+ <%= link_to_site wiki %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Previous and current Wikis</th>
+ <td align="left" class="sectionTableCell">
+ <ul>
+ <% for site in @baseline.sites %>
+ <% if site.wiki? %>
+ <li>
+ <%= link_to_site site %>
+ </li>
+ <% end %>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Checkouts</th>
+ <td align="left" class="sectionTableCell">
+ <ul>
+ <% for checkout in @baseline.checkouts %>
+ <li>
+ <%= link_to_version2 checkout.version %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+</table>
+</div>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">ID</th>
+ <td align="left" class="sectionTableCell"><%= @baseline.id.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Baseline</th>
+ <td align="left" class="sectionTableCell"><%= @baseline.baseline%></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Build ID</th>
+ <td align="left" class="sectionTableCell"><%= @baseline.buildid%></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Description</th>
+ <td align="left" class="sectionTableCell"><%= @baseline.description%></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created On</th>
+ <td align="left" class="sectionTableCell"><%= @baseline.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Updated On</th>
+ <td align="left" class="sectionTableCell"><%= @baseline.updated_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+</table>
+</div>
+
+
+
+
+
+
diff --git a/source/app/views/comments/_comment.rhtml b/source/app/views/comments/_comment.rhtml
new file mode 100644
index 0000000..b1635f3
--- /dev/null
+++ b/source/app/views/comments/_comment.rhtml
@@ -0,0 +1,18 @@
+<% if @comment.created_on %>
+<div id="<%= div_id(@comment, "") %>">
+ <% if session['user'] && (mine?(@comment) || cadmin? )%>
+ <%= link_to_remote image_tag('edit.gif', :border => 0, :title => 'Edit'), :update => div_id(@comment, ""), :url => { :action => 'edit', :id => @comment} %>
+ <%= link_to image_tag('delete', :border => 0, :title => 'Delete'), { :action => 'destroy', :id => @comment, :site_id => @comment.site.id, :page_id => @comment.page.id }, :confirm => 'Are you sure?' %>
+ <% end %>
+ <div class="comment"><a name="<%= div_id(@comment,"") %>"><%= @comment.text %></a>
+ </div>
+ <div class="commentfooter">
+ Comment created <%= time_ago_in_words(@comment.created_on) %>
+ ago by <%= link_to_user @comment.user %>
+ about <%= link_to_version @comment.version, 'version' %>
+ <br>
+ </div>
+</div>
+<% else %>
+ <%= @comment.errors.full_messages.join(', ') %>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/comments/_comments_list.rhtml b/source/app/views/comments/_comments_list.rhtml
new file mode 100644
index 0000000..29b5d0e
--- /dev/null
+++ b/source/app/views/comments/_comments_list.rhtml
@@ -0,0 +1,38 @@
+<div class="sectionHeading">Comments</div>
+<div class="sectionContent">
+ <% if @comments %>
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ToDo</th>
+ <th>ID</th>
+ <th>Title</th>
+ <th>Created</th>
+ <th>Created By</th>
+ <th>Reviewer</th>
+ <th>Page</th>
+ <th>Site</th>
+ </tr>
+
+ <% for comment in @comments %>
+ <tr>
+ <td><%= link_to_done_toggle comment %></td>
+ <td><%= comment.id %></td>
+ <td><%= link_to_comment comment %></td>
+ <td><%= comment.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ <td><%= link_to_user comment.user %></td>
+ <td><%= link_to_reviewer comment %></td>
+ <td><%= link_to_page comment.site, comment.page %></td>
+ <td><%= link_to_site comment.site %></td>
+ </tr>
+ <% end %>
+ </table>
+ <% else %>
+ No comments found!
+ <% end %>
+ </td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
diff --git a/source/app/views/comments/_form.rhtml b/source/app/views/comments/_form.rhtml
new file mode 100644
index 0000000..b08f733
--- /dev/null
+++ b/source/app/views/comments/_form.rhtml
@@ -0,0 +1,10 @@
+<%= hidden_field 'comment', 'site_id', :value => @comment.site.id %>
+<%= hidden_field 'comment', 'version_id', :value => @comment.version.id if @comment.version %>
+<%= hidden_field 'comment', 'page_id', :value => @comment.page.id %>
+<%= text_area 'comment', 'text', :cols => 65, :rows => 30 %>
+<br>
+<br><br>
+<input type="submit" value="submit" onclick="tinyMCE.triggerSave(true, true)">
+
+
+
diff --git a/source/app/views/comments/edit.rhtml b/source/app/views/comments/edit.rhtml
new file mode 100644
index 0000000..559f130
--- /dev/null
+++ b/source/app/views/comments/edit.rhtml
@@ -0,0 +1,14 @@
+<script type="text/javascript" language="JavaScript">
+ tinyMCE.execCommand("mceAddControl", true, "comment[text]")
+</script>
+<div class="comment">
+ <%= form_remote_tag(:update => div_id(@comment,''),:url => { :action => 'update', :id => @comment.id}) %>
+ <%= render :partial => 'form' %>
+ <%= end_form_tag %>
+</div>
+<div class="commentfooter">
+ Comment created <%= time_ago_in_words(@comment.created_on) %> ago by <%= link_to_user @comment.user %>
+ about <%= link_to_version @comment.version, 'version' %>
+ <br>
+</div>
+
diff --git a/source/app/views/comments/list.rhtml b/source/app/views/comments/list.rhtml
new file mode 100644
index 0000000..6cf22a1
--- /dev/null
+++ b/source/app/views/comments/list.rhtml
@@ -0,0 +1,63 @@
+<% @heading = 'Comments' %>
+<% @overview = "This page displays the comments about #{link_to_page(@site, @page)} in site #{link_to_site(@site)}" %>
+
+<% tinymce('advanced') %>
+
+<div id="menu">
+ <%= link_to 'add comment', {:action=> 'new', :site_id => @site.id, :page_id => @page.id, :anchor => 'new_comment'}, :post => true %>
+ | <%= link_to_notification_toggle(@site, @page, 'Comment') %>
+</div>
+
+<br>
+<br>
+ <div id="commentsList">
+ <% for @comment in @comments%>
+ <%= render :partial => 'comment' %>
+ <% end %>
+ <% if @comment_new %>
+ <% @comment = @comment_new %>
+ <div id="new_comment">
+ <div class="comment">
+ <%= form_remote_tag(:update => 'new_comment', :url => { :action => 'create'}) %>
+ <%= render :partial => 'form' %>
+ <%= end_form_tag %>
+ </div>
+ <div class="commentfooter">
+ Creating comment about <%= link_to_version @version, 'version' if @version %>
+ <br>
+ </div>
+ </div>
+ <% end %>
+ </div>
+
+
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0"
+class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Other Sites
+ </th>
+ <td class="sectionTableCell">
+ The following other sites have comments about this page:
+ <ul>
+ <% for site in @sites_with_comments %>
+ <li>
+ <%= link_to_site site %> <%= link_to image_tag("comment2", :border => 0, :title => 'Show comments'), :action => 'list', :page_id => @page.id, :site_id => site.id %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Content File
+ </th>
+ <td class="sectionTableCell">
+ <%= link_to_page(@site, @page) %>
+ </td>
+ </tr>
+</table>
+</div>
+
diff --git a/source/app/views/comments/listall.rhtml b/source/app/views/comments/listall.rhtml
new file mode 100644
index 0000000..c89c0f2
--- /dev/null
+++ b/source/app/views/comments/listall.rhtml
@@ -0,0 +1,9 @@
+<% @overview = "This page displays all submitted comments in all sites ordered by creation date, the most recent first.<br><br>" %>
+
+<br>
+<%= tabs([["All", url_for(:action => 'listall'), (@heading == "Comments")],["To Do", url_for(:action=> 'listtodo'), (@heading == "Comments To Do")], ["Done", url_for(:action=>'listdone'), (@heading == "Comments Done")]], 80) if admin? %>
+<br>
+<%= links_to_pages(@comment_pages) %>
+<%= render :partial => 'comments_list' %>
+
+
diff --git a/source/app/views/difference_analyses/new.rhtml b/source/app/views/difference_analyses/new.rhtml
new file mode 100644
index 0000000..f84c5b6
--- /dev/null
+++ b/source/app/views/difference_analyses/new.rhtml
@@ -0,0 +1,16 @@
+<% @heading = 'Difference Analyses' %>
+<% @overview = "Use this form to create a new Difference Analysis for #{link_to_site(@baseline_process)}" %>
+
+<%= error_messages_for 'difference_analysis' %>
+
+<% tabular_form_for :difference_analysis, @difference_analysis do |f| %>
+ <%= f.hidden_field :site_id %>
+ <tr><th width="200">From</th><td><%= f.select :site_id_from, @baseline_processes.collect {|bp| [bp.title, bp.id]} %></td>
+ </tr>
+ <tr>
+ <th>To</th>
+ <td><%= link_to_site @baseline_process %>
+ </td>
+ </tr>
+ <tr><th></th><td><%= submit_tag 'Submit' %></td></tr>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/difference_analyses/show.rhtml b/source/app/views/difference_analyses/show.rhtml
new file mode 100644
index 0000000..2ae02ea
--- /dev/null
+++ b/source/app/views/difference_analyses/show.rhtml
@@ -0,0 +1,100 @@
+<% @heading = "Difference Analysis: #{@difference_analysis.title}" %>
+<% @overview = "From #{link_to_baseline(@baseline_from, nil)} to #{link_to_baseline(@baseline, nil)}" %>
+
+<p>
+<% if cadmin? %>
+<div id="menu">
+ <%= link_to 'delete', :action => 'destroy', :id => @difference_analysis %>
+ | <%= link_to 'analyze now', :action => 'analyze_now', :id => @difference_analysis %>
+</div>
+<% end %>
+</p>
+
+<%= tabs([["All", url_for(:action => 'show', :id => @difference_analysis.id), params[:action] == "show"],
+["Changed", url_for(:action=> 'showchanged', :id => @difference_analysis.id), params[:action] == "showchanged"],
+["HTML Changed", url_for(:action=> 'showhtmlchanged', :id => @difference_analysis.id), params[:action] == "showhtmlchanged"],
+["New", url_for(:action=>'shownew', :id => @difference_analysis.id),params[:action] == "shownew"],
+["Removed", url_for(:action=>'showremoved', :id => @difference_analysis.id),params[:action] == "showremoved"]], 70) %>
+<br>
+<%= links_to_pages(@difference_analysis_item_pages) if @difference_analysis_item_pages %>
+
+<div class="sectionHeading">Item</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>From Page</th>
+ <th>To Page</th>
+ <th>Result</th>
+ <th>Action</th>
+ </tr>
+
+ <% for diff_item in @difference_analysis_items %>
+ <tr>
+ <td><%= diff_item.id %></td>
+ <td><%= link_to_page(@site_from, diff_item.page) if diff_item.result != "NEW" %></td>
+ <td><%= link_to_page(@site, diff_item.page) if diff_item.result != "REMOVED" && @site %></td>
+ <td><%= diff_item.result %></td>
+ <td><%= link_to("Show Changes", :controller => 'difference_analyses', :action => 'show_item', :item_id => diff_item.id ) if diff_item.result == "CHANGED" %>
+ <%= link_to("Show Changes", :controller => 'difference_analyses', :action => 'show_item', :item_id => diff_item.id, :tab => "html" ) if diff_item.result == "HTMLCHANGED" %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">From</th>
+ <td align="left" class="sectionTableCell"><%= link_to_site(@site_from) %> (<%= link_to_baseline(@difference_analysis.baseline_from, nil) %>)</td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">To</th>
+ <td align="left" class="sectionTableCell"><%= link_to_site(@site) %> (<%= link_to_baseline(@difference_analysis.baseline, nil) %>)</td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created</th>
+ <td align="left" class="sectionTableCell"><%= @difference_analysis.created_on.strftime("%I:%M %p %d-%b-%y")%></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">New</th>
+ <td align="left" class="sectionTableCell"><%= DifferenceAnalysisItem.count(["difference_analysis_id = ? and result=?", @difference_analysis.id, "NEW"]) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Removed</th>
+ <td align="left" class="sectionTableCell"><%= DifferenceAnalysisItem.count(["difference_analysis_id = ? and result=?", @difference_analysis.id, "REMOVED"]) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Changed</th>
+ <td align="left" class="sectionTableCell"><%= DifferenceAnalysisItem.count(["difference_analysis_id = ? and result=?", @difference_analysis.id, "CHANGED"]) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">HTML Changed</th>
+ <td align="left" class="sectionTableCell"><%= DifferenceAnalysisItem.count(["difference_analysis_id = ? and result=?", @difference_analysis.id, "HTMLCHANGED"]) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Equal</th>
+ <td align="left" class="sectionTableCell"><%= DifferenceAnalysisItem.count(["difference_analysis_id = ? and result=?", @difference_analysis.id, "EQUAL"]) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created On</th>
+ <td align="left" class="sectionTableCell"><%= @difference_analysis.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Updated On</th>
+ <td align="left" class="sectionTableCell"><%= @difference_analysis.updated_on.strftime("%I:%M %p %d-%b-%y") if @difference_analysis.updated_on %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Analyzed On</th>
+ <td align="left" class="sectionTableCell"><%= @difference_analysis.analyzed_on.strftime("%I:%M %p %d-%b-%y") if @difference_analysis.analyzed_on %></td>
+ </tr>
+ </table>
+</div>
diff --git a/source/app/views/difference_analyses/show_item.rhtml b/source/app/views/difference_analyses/show_item.rhtml
new file mode 100644
index 0000000..ed1a3e9
--- /dev/null
+++ b/source/app/views/difference_analyses/show_item.rhtml
@@ -0,0 +1,48 @@
+<% @heading = 'Page Difference Analysis' %>
+<% @overview = "This page shows changes #{link_to_page(@site || @site_from, @page)}" %>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Difference Analysis</th>
+ <td align="left" class="sectionTableCell"><%= link_to_difference_analysis_from(@difference_analysis) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">From</th>
+ <td align="left" class="sectionTableCell"><%= link_to_page(@site_from, @page) + " baseline " + link_to_baseline(@baseline_from, nil) if @diff_item.result != "NEW" %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">To</th>
+ <td align="left" class="sectionTableCell"><%= link_to_page(@site, @page) + " baseline " + link_to_baseline(@baseline, nil) if @diff_item.result != "REMOVED" %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Result</th>
+ <td align="left" class="sectionTableCell"><%= @diff_item.result %></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
+<br>
+<br>
+<%= tabs([["Text", url_for(:action => 'show_item', :item_id => @diff_item.id), !params[:tab] || params[:tab] == "text"],["HTML", url_for(:action=> 'show_item', :item_id => @diff_item.id, :tab => "html"), (params[:tab] == "html")]], 80) %>
+
+<% if @diff_item.result == "CHANGED" || @diff_item.result == "HTMLCHANGED" %>
+ <div class="sectionHeading">Changes</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <td class="sectionTableCell">
+ <%= simple_format(@diff_item.diff) if params[:tab] == 'text' || !params[:tab] %>
+ <%= simple_format(@diff_item.diff_html) if params[:tab] == 'html' %><br>
+ </td>
+ </tr>
+ </table>
+ </div>
+<% end %>
+
diff --git a/source/app/views/layouts/application.rhtml b/source/app/views/layouts/application.rhtml
new file mode 100644
index 0000000..bbfd797
--- /dev/null
+++ b/source/app/views/layouts/application.rhtml
@@ -0,0 +1,180 @@
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title><%= (ENV['EPFWIKI_APP_NAME'] + " - ") if !@site || !@site.id %><% if @site && @site.id %><%= @site.title + ' - ' %><% end %><%= @heading %></title>
+ <%= stylesheet_link_tag 'default' %>
+ <%= javascript_include_tag "prototype" %>
+ <%= javascript_include_tag "contentpage" %>
+ <%= javascript_include_tag "steps" %>
+ <script type="text/javascript" language="JavaScript">
+ backPath = './../../';
+ </script>
+ <% unless @tinymce.blank? %>
+ <%= javascript_include_tag 'tiny_mce/tiny_mce.js' %>
+ <script language="javascript" type="text/javascript">
+ tinyMCE.init({
+ mode : "textareas",
+ theme : "<%= @tinymce %>",
+ theme_advanced_statusbar_location: "bottom",
+ theme_advanced_resizing : true,
+ content_css : "../../stylesheets/default.css"
+ });
+ </script>
+ <% end %>
+ </head>
+ <body onload="createSectionLinks('div', 'sectionHeading', './../../images/'); createStepLinks('div', 'stepHeading');">
+
+<% if session['user'] && cadmin? %>
+<div id="search_form">
+ <%= start_form_tag({:controller => 'search', :action => 'search'}, {:method => 'get'}) %>
+ <% if @search_terms && @search_terms.size > 0 %>
+ <input type="text" name="search_terms" value="<%= @search_terms.join(" ") %>" class="box"/>
+ <% else %>
+ <input type="text" name="search_terms" value="" class="box"/>
+ <% end %>
+ <!-- <input type="submit" value="" style="background-image: url(http://localhost:3000/images/search.png); width: 210px; height: 112px; border: 0;" />-->
+ <input type="submit" value="" class="searchsubmit" title="Search through pages and comments" accesskey="4" />
+ <%= end_form_tag %>
+</div>
+<% end %>
+
+
+ <table width="100%" cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td valign="top">
+ <a name="Top" id="Top"></a>
+
+ <table width="100%" cellpadding="0" cellspacing="0" border="0">
+ <tr>
+ <td class="pageTitle">
+ <%= @heading %>
+ </td>
+
+ <td align="right">
+ <strong>
+ <% if session['user'] %>
+ <%= link_to image_tag("user" + session['user'].admin , :border => 0, :title => 'User Details'), :controller => 'users', :action => 'show', :id => session["user"].id %>
+ <%= link_to image_tag("version", :border => 0, :title => 'List Versions' ), :controller => 'versions', :action => "listall" %>
+ <%= link_to image_tag("comment2", :border => 0, :title => 'List Comments' ), :controller => 'comments', :action => "listall" %>
+ <%= link_to image_tag("checkout2", :border => 0, :title => 'List Checkouts' ), :controller => 'versions', :action => "listcheckouts" %>
+ <%= link_to image_tag("site", :border => 0, :title => 'List Sites' ), :controller => 'sites' %>
+ <%= link_to image_tag("info", :border => 0, :title => 'Information about ' + ENV['EPFWIKI_APP_NAME'] ), :controller => 'other', :action => 'info' %>
+ <%= link_to "logout", :controller => 'login', :action => 'logout' %>
+ <% end %>
+ </strong>
+ <%= image_tag("busy.gif", :id => "busy", :style=>"display:none;" ) %>
+ </td>
+ </tr>
+ </table>
+
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
+ <tr>
+ <td class="pageTitleSeparator">
+ <%= image_tag "shim.gif",:height => 1 %></td>
+ </tr>
+ </table>
+
+ <div class="overview">
+ <table cellpadding="0" cellspacing="0" border="0"
+ width="97%">
+ <tr>
+ <td width="50">
+ <%= image_tag("site_large") %>
+ </td>
+ <td>
+ <table cellpadding="0" cellspacing="0" border="0"
+ class="overviewTable">
+ <tr>
+ <td valign="top">
+ <%= @overview %>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <% if (flash['notice'] || flash['success'] || flash['error'] || flash['warning']) %>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table>
+ <% ['error', 'warning', 'notice', 'success'].each do |flash_type| %>
+ <% if flash[flash_type] %>
+ <tr>
+ <th valign="top" width="200"><%= image_tag(flash_type) %></th>
+ <td><%= flash[flash_type] %></td>
+ </tr>
+ <% end %>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <br>
+ <% end %>
+ <%= @content_for_layout %>
+ </td>
+ </tr>
+ </table>
+ <br>
+ <br>
+ <br>
+ <% if RAILS_ENV == "development" %>
+ <div class="sectionHeading">Debug</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Session</th>
+ <td align="left" class="sectionTableCell"><%= debug(session) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Params</th>
+ <td align="left" class="sectionTableCell"><%= debug(params) %></td>
+ </tr>
+ <!--<tr valign="top">
+ <th scope="row" class="sectionTableHeading">Response</th>
+ <td align="left" class="sectionTableCell"> debug(response) </td>
+ </tr> -->
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Request Environment</th>
+ <td align="left" class="sectionTableCell"><%= debug(request.env) %></td>
+ </tr>
+ <% if @site %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Site</th>
+ <td align="left" class="sectionTableCell"><!-- TODOdebug(@site) --></td>
+ </tr>
+ <% end %>
+ <% if @page %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Page</th>
+ <td align="left" class="sectionTableCell"><%= debug(@page) %></td>
+ </tr>
+ <% end %>
+ <% if @baseline %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Baseline</th>
+ <td align="left" class="sectionTableCell"><%= debug(@baseline) %></td>
+ </tr>
+ <% end %>
+ <% if @version %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Version</th>
+ <td align="left" class="sectionTableCell"><%= debug(@version) %></td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <% end %>
+ </body>
+</html>
+
diff --git a/source/app/views/layouts/toolbar.rhtml b/source/app/views/layouts/toolbar.rhtml
new file mode 100644
index 0000000..bc7c81a
--- /dev/null
+++ b/source/app/views/layouts/toolbar.rhtml
@@ -0,0 +1,45 @@
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <%= stylesheet_link_tag 'default' %>
+<style type="text/css">
+body {background-color: transparent; text-align: right;}
+p { font-size: xx-small }
+#toolbar_header {position:absolute;
+ right: -10px;
+ right: 500px;
+ right: 110px;
+ right: 20px;
+ width: 166px;
+ height: 10px;
+ z-index: 100;
+ top: -0;}
+#toolbar_expanded {position:absolute;
+ top: 35px!important;
+ top: 40px;
+ top: 20px;
+ width: 225px;
+ z-index: 100;
+ right: 20px;
+ background-color: #FDFFED;
+ font-size: 10pt;
+ padding-bottom: 2px;
+ padding-left: 2px;
+ padding-top: 2px;
+ padding-right: 2px;
+ text-decoration: none;
+ border-bottom: #ccc solid 1px;
+ border-left: #ccc solid 1px;
+ border-right: #ccc solid 1px;
+ border-top: #ccc solid 1px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ text-align: left;}
+</style>
+ </head>
+ <body>
+ <%= @content_for_layout %>
+ </body>
+</html>
\ No newline at end of file
diff --git a/source/app/views/login/change_password.rhtml b/source/app/views/login/change_password.rhtml
new file mode 100644
index 0000000..1ec0e28
--- /dev/null
+++ b/source/app/views/login/change_password.rhtml
@@ -0,0 +1,8 @@
+<% @heading = 'Change Password' %>
+<%= error_messages_for 'user' %>
+
+<% tabular_form_for :user do |f| %>
+ <%= f.password_field :password, :size => 42 %>
+ <%= f.password_field :password_confirmation, :size => 42 %>
+ <tr><th></th><td><%= submit_tag "Change password" %></td></tr>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/login/login.rhtml b/source/app/views/login/login.rhtml
new file mode 100644
index 0000000..2d8966f
--- /dev/null
+++ b/source/app/views/login/login.rhtml
@@ -0,0 +1,38 @@
+<%= javascript_include_tag :defaults %>
+<% @heading = 'Log in' %>
+<% @overview = "Not a user? Click #{link_to('here', :controller => 'login', :action => 'sign_up')} to create a new account!" %>
+
+<%= error_messages_for 'user' %>
+
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width=100% border=0>
+ <tr>
+ <td>
+ <h3>Welcome to <%= ENV['EPFWIKI_APP_NAME'] %></h3><br>
+ free software process descriptions that anyone can edit.<br>
+ <%= Page.count.to_s %> pages, <%= Version.count.to_s %> edits, <%= Comment.count.to_s %> comments, <%= Baseline.count.to_s %> deployed baseline processes, <%= User.count.to_s %> registered users
+ </td>
+ <td>
+ <ul>
+ <% for wiki in @wikis %>
+ <li><%= link_to(wiki.title + " " + image_tag("extlink.gif", :border => 0, :title => "Activate this site"), url_for_site(wiki)) %>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
+
+
+<% tabular_form_for :user do |f| %>
+ <tr><th>Email</th><td><%= text_field_with_auto_complete :user, :email, :size => 40 %><td></tr>
+ <tr><th>Password</th><td><%= password_field(:user, :password, :size => 42) %> (<%= link_to 'I forgot my password', :controller => 'login', :action => 'lost_password' %>)</td></tr>
+ <tr><th></th><td><%= check_box(:user, :remember_me, {}, 0, 1) %> Remember me on this computer</td></tr>
+ <tr><th></th><td><%= submit_tag 'Let me in!' %></td></tr>
+<% end %>
diff --git a/source/app/views/login/lost_password.rhtml b/source/app/views/login/lost_password.rhtml
new file mode 100644
index 0000000..73c6055
--- /dev/null
+++ b/source/app/views/login/lost_password.rhtml
@@ -0,0 +1,7 @@
+<% @heading = 'Lost Password' %>
+<%= error_messages_for 'user' %>
+
+<% tabular_form_for :user do |f| %>
+ <%= f.text_field :email, :size => 30 %>
+ <tr><th></th><td><%= submit_tag "Send new password" %></td></tr>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/login/new_cadmin.rhtml b/source/app/views/login/new_cadmin.rhtml
new file mode 100644
index 0000000..d77df9a
--- /dev/null
+++ b/source/app/views/login/new_cadmin.rhtml
@@ -0,0 +1,10 @@
+<% @heading = 'Create Central Admin User' %>
+<%= error_messages_for 'user' %>
+
+<% tabular_form_for :user do |f| %>
+ <%= f.text_field :name, :size => 30 %>
+ <%= f.text_field :email, :size => 30 %>
+ <%= f.password_field :password, :size => 42 %>
+ <%= f.password_field :password_confirmation, :size => 42 %>
+ <tr><th></th><td><%= submit_tag 'Submit' %></td></tr>
+<% end %>
diff --git a/source/app/views/login/sign_up.rhtml b/source/app/views/login/sign_up.rhtml
new file mode 100644
index 0000000..8453919
--- /dev/null
+++ b/source/app/views/login/sign_up.rhtml
@@ -0,0 +1,20 @@
+<% @heading = 'Sign up' %>
+<%= error_messages_for 'user' %>
+
+<% tabular_form_for :user do |f| %>
+ <%= f.text_field :name, :size => 30 %>
+ <tr><th>Email</th><td><%= text_field('user', 'email', :size => 41) %>
+ <% if ENV['EPFWIKI_DOMAINS'] %>
+ <select name="user[email_extension]">
+ <% for domain in ENV['EPFWIKI_DOMAINS'].split(' ') %>
+ <%= '<option>' + domain + '</option>' %>
+ <% end %>
+ </select>
+ <% end %>
+ </td></tr>
+ <% if ENV['EPFWIKI_GENERATE_PASSWORDS'] == '0' %>
+ <%= f.password_field :password, :size => 42 %>
+ <%= f.password_field :password_confirmation, :size => 42 %>
+ <% end %>
+ <tr><th></th><td><%= submit_tag 'Sign me up!' %></td></tr>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/notifier/confirmation_link.rhtml b/source/app/views/notifier/confirmation_link.rhtml
new file mode 100644
index 0000000..88daa4b
--- /dev/null
+++ b/source/app/views/notifier/confirmation_link.rhtml
@@ -0,0 +1,16 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+A request was made to create an account for your email address. <br><br>
+To complete the process and activate the new password <strong><%= @user.password %></strong>, click the link below.<br>
+<a href="<%= @urls[0] %>">Activate my new password <%= @user.password %></a><br>
+<br>
+If this request was not made by you, you can report the attempt to reset your password by clicking on the link below.<br>
+<a href="<%= @urls[1] %>">Report attempt to reset my password</a><br>
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
\ No newline at end of file
diff --git a/source/app/views/notifier/email.rhtml b/source/app/views/notifier/email.rhtml
new file mode 100644
index 0000000..2845b01
--- /dev/null
+++ b/source/app/views/notifier/email.rhtml
@@ -0,0 +1,13 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+<br>
+<%= @text %>
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
+
diff --git a/source/app/views/notifier/env_to.rhtml b/source/app/views/notifier/env_to.rhtml
new file mode 100644
index 0000000..4c01d0e
--- /dev/null
+++ b/source/app/views/notifier/env_to.rhtml
@@ -0,0 +1,55 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<h2>Lost Password Resend <%= Time.now %></h2>
+
+<table border="0">
+<tr><td>Location</td><td><%= @env['REQUEST_URI'] %></td></tr>
+<tr><td>Action</td><td><%= @params.delete('action') %></td></tr>
+<tr><td>Controller</td><td><%= @params.delete('controller') %></td></tr>
+<tr><td>Query</td><td><%= @env['QUERY_STRING'] %></td></tr>
+<tr><td>Method</td><td><%= @env['REQUEST_METHOD'] %></td></tr>
+<tr><td>SSL</td><td><%= @env['SERVER_PORT'].to_i == 443 ? "true" : "false" %></td></tr>
+<tr><td>Agent</td><td><%= @env['HTTP_USER_AGENT'] %></td></tr>
+<% if ENV['RAILS_ENV'] != "test" && session['user'] -%>
+<tr><td>User id</td><td><%= session['user'].id %></td></tr>
+<tr><td>User name</td><td><%= session['user'].name %></td></tr>
+<tr><td>User email</td><td><%= session['user'].email %></td></tr>
+<tr><td>Registered</td><td><%= session['user'].created_on %></td></tr>
+<% end -%>
+</table>
+
+<h3>Params</h3>
+<hr/>
+<% for key, val in @params -%>
+<p><b><%= key %></b></p>
+<p><%= val.to_yaml.to_a.join("</p>\n<p> ") %></p>
+<% end if @params -%>
+
+<h3>Session</h3>
+<hr/>
+<% for key, val in @session -%>
+<p><b><%= key %></b></p>
+<p><%= val.to_yaml.to_a.join("</p>\n<p> ") %></p>
+<% end if @session -%>
+
+<h3>Environment</h3>
+<hr/>
+<table border="0">
+<% for key, val in @env -%>
+<tr>
+ <td>
+ <small><b><%= key %></b></small>
+
+ </td>
+ <td>
+ <small><%= val %></small>
+ </td>
+</tr>
+<% end if @env -%>
+</table>
+
diff --git a/source/app/views/notifier/error_report.rhtml b/source/app/views/notifier/error_report.rhtml
new file mode 100644
index 0000000..db70fe7
--- /dev/null
+++ b/source/app/views/notifier/error_report.rhtml
@@ -0,0 +1,58 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<h2>Error report from <%= Time.now %></h2>
+
+<table border="0">
+<tr><td>Message</td><td><%= @exception.message %></td></tr>
+<tr><td>Location</td><td><%= @env['REQUEST_URI'] %></td></tr>
+<tr><td>Action</td><td><%= @params.delete('action') %></td></tr>
+<tr><td>Controller</td><td><%= @params.delete('controller') %></td></tr>
+<tr><td>Query</td><td><%= @env['QUERY_STRING'] %></td></tr>
+<tr><td>Method</td><td><%= @env['REQUEST_METHOD'] %></td></tr>
+<tr><td>SSL</td><td><%= @env['SERVER_PORT'].to_i == 443 ? "true" : "false" %></td></tr>
+<tr><td>Agent</td><td><%= @env['HTTP_USER_AGENT'] %></td></tr>
+<% if @session['user'] -%>
+<tr><td>User id</td><td><%= @session['user'].id %></td></tr>
+<tr><td>User name</td><td><%= @session['user'].name %></td></tr>
+<tr><td>User email</td><td><%= @session['user'].email %></td></tr>
+<tr><td>Registered</td><td><%= @session['user'].created_on %></td></tr>
+<% end -%>
+</table>
+
+<h3>Backtrace</h3>
+<div><%= @trace.to_a.join("</p>\n<p>") -%></div>
+
+<h3>Params</h3>
+<hr/>
+<% for key, val in @params -%>
+<p><b><%= key %></b></p>
+<p><%= val.to_yaml.to_a.join("</p>\n<p> ") %></p>
+<% end if @params -%>
+
+<h3>Session</h3>
+<hr/>
+<% for key, val in @session -%>
+<p><b><%= key %></b></p>
+<p><%= val.to_yaml.to_a.join("</p>\n<p> ") %></p>
+<% end if @session -%>
+
+<h3>Environment</h3>
+<hr/>
+<table border="0">
+<% for key, val in @env -%>
+<tr>
+ <td>
+ <small><b><%= key %></b></small>
+
+ </td>
+ <td>
+ <small><%= val %></small>
+ </td>
+</tr>
+<% end if @env -%>
+</table>
diff --git a/source/app/views/notifier/lost_password.rhtml b/source/app/views/notifier/lost_password.rhtml
new file mode 100644
index 0000000..1e2a40b
--- /dev/null
+++ b/source/app/views/notifier/lost_password.rhtml
@@ -0,0 +1,16 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+A request to send a lost password was received for this email address. <br><br>
+To complete the process and activate the new password <strong><%= @user.password %></strong>, click the link below.<br>
+<a href="<%= @urls[0] %>">Activate my new password <%= @user.password %></a><br>
+<br>
+If this request was not made by you, you can cancel by clicking on the link below.<br>
+<a href="<%= @urls[1] %>">Cancel this new password, the request was not made by me</a><br>
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
\ No newline at end of file
diff --git a/source/app/views/notifier/new_password.rhtml b/source/app/views/notifier/new_password.rhtml
new file mode 100644
index 0000000..e30aa0e
--- /dev/null
+++ b/source/app/views/notifier/new_password.rhtml
@@ -0,0 +1,50 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br>
+<br>
+<br>
+An account has been created for you with password <strong><%= @user.password %></strong><br>
+You are the <%= @cnt.to_s %><sup>th</sup> <%= ENV['EPFWIKI_APP_NAME'] %> user.<br>
+<br>
+Next steps you can take:<br>
+<ul>
+ <li>
+ <a href="<%= @urls[0] %>">Login to <%= ENV['EPFWIKI_APP_NAME'] %> </a>
+ </li>
+ <li>
+ <a href="<%= @urls[2] %>">Login and change your password</a>
+ </li>
+ <li>
+ <a href="<%= @urls[1] %>">Login and subscribe for a monthly, weekly or even daily report of improvements</a>
+ </li>
+</ul>
+<br>
+ You can start sharing your knowledge and experience in one of the following sites:
+ <table>
+ <tr>
+ <th>
+ Site
+ </th>
+ <th>
+ Description
+ </th>
+ </tr>
+ <% for site in @sites %>
+ <tr>
+ <td>
+ <a href="<%= site.url %>"><%= site.title %></a>
+ </td>
+ <td>
+ <%= site.description %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+<br>
+<br>
+<br>If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
\ No newline at end of file
diff --git a/source/app/views/notifier/notification.rhtml b/source/app/views/notifier/notification.rhtml
new file mode 100644
index 0000000..9053d72
--- /dev/null
+++ b/source/app/views/notifier/notification.rhtml
@@ -0,0 +1,23 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br>
+<br>
+<br>
+<%= @introduction %>
+<br></br>
+<table width=100% border=1><tr><td>
+<%= @text %>
+</td></tr></table>
+<br>
+<br>
+To unsubscribe from receiving notifications, edit your user details at <%= @link %></br>
+<br>
+<br>
+<br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
+
diff --git a/source/app/views/notifier/report.rhtml b/source/app/views/notifier/report.rhtml
new file mode 100644
index 0000000..225bced
--- /dev/null
+++ b/source/app/views/notifier/report.rhtml
@@ -0,0 +1,103 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br>
+<br>
+<br>
+<h2><%= @subject %></h2>
+
+ <h3>Wiki Sites</h3>
+
+ <table width=100% border=1>
+ <tr>
+ <th>Site</th><th>Baseline</th><th> New Versions</th><th>New Comments</th><th>Checkouts</th><th></th>
+ </tr>
+ <% for site in @sites %>
+ <tr>
+ <td><a href="http://<%= host + '/' + site.rel_path %>"><%= site.title %></a></td>
+ <td><%= site.baseline.baseline %></td>
+ <td align="middle"><%= site.versions_count_since(@starttime).to_s %> (from <%= site.versions_count_excluding_baseversions.to_s %>)</td>
+ <td align="middle"><%= site.comments_count_since(@starttime).to_s %> (from <%= site.comments_count.to_s %>)</td>
+ <td align="middle"> <%= site.checkouts.count.to_s %></td>
+ <td align="middle"><%= "<font color='red'>New!</color>" if (site.created_on > @starttime) %></td>
+ </tr>
+ <% end %>
+ </table>
+
+
+<% if @versions.length > 0 %>
+ <h3>New Versions</h3>
+ <table width=100% border=1>
+ <tr>
+ <th align="left">Page</th><th>Version</th><th>Note</th><th>Site</th><th>Created</th>
+ </tr>
+ <% for version in @versions %>
+ <tr>
+ <% site = version.site %>
+ <% page = version.page %>
+ <td><a href="http://<%= host + '/' + site.rel_path + page.rel_path %>"><%= version.page.presentation_name %></a></td>
+ <td>Version <%= version.version.to_s %></a></td>
+ <td><%= version.note %></td>
+ <td><%= site.title %></td>
+ <td><%= ago_txt(version.created_on) %> ago by <%= version.user.name %></td>
+ </tr>
+ <% end %>
+ </table>
+<% end %>
+
+<% if @comments.length > 0 %>
+ <h3>New Comments</h3>
+ <table width=100% border=1>
+ <tr>
+ <th align="left">Comment</th><th>Page</th><th>Site</th><th>Created</th>
+ </tr>
+ <% for comment in @comments %>
+ <tr>
+ <% site = comment.site %>
+ <% page = comment.page %>
+ <td><%= truncate(strip_tags(comment.text)) %></td>
+ <td><a href="<%= host + '/' + site.rooturl + page.rel_path %>"><%= page.presentation_name %></a></td>
+ <td><%= site.title %></td>
+ <td><%= ago_txt(comment.created_on) %> ago by <%= comment.user.name %></td>
+ </tr>
+ <% end %>
+ </table>
+<% end %>
+
+<% if @users.length > 0 %>
+ <h3>New Users</h3>
+ <p>
+ <%= (@users.collect {|user| user.name}).join(", ") %>
+ </p>
+ </ul>
+<% end %>
+
+<% if @checkouts.length > 0 %>
+ <h3>Checkouts</h3>
+ <table width=100% border=1>
+ <tr>
+ <th align="left">Page</th><th>Version</th><th>Site</th><th>Created</th>
+ </tr>
+ <% for checkout in @checkouts %>
+ <tr>
+ <% site = checkout.site %>
+ <% page = checkout.page %>
+ <td><a href="<%= host + '/' + site.rooturl + page.rel_path %>"><%= page.presentation_name %></a></td>
+ <td>Version <%= checkout.version.version.to_s %></td>
+ <td><%= site.title %></td>
+ <td><%= ago_txt(checkout.created_on) %> ago by <%= checkout.user.name %></td>
+ </tr>
+ <% end %>
+ </table>
+<% end %>
+<br>
+<br>
+<p>Generated on: <strong><%= @runtime.to_s %></strong><br>
+Showing changes since: <strong><%= @starttime.to_s %></strong></p>
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
+
diff --git a/source/app/views/notifier/update_site_checkin_request.rhtml b/source/app/views/notifier/update_site_checkin_request.rhtml
new file mode 100644
index 0000000..9442f72
--- /dev/null
+++ b/source/app/views/notifier/update_site_checkin_request.rhtml
@@ -0,0 +1,48 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+<br>
+An update of site <strong><%= @wiki.title %></strong> is pending: the site will be updated from release
+<%= @wiki.baseline.baseline %> to <%= @wiki.baseline_process.baseline.baseline %><br>
+<br>
+The update will be postponed however as long as there are checkouts. Currently the site has the following checkouts:<br>
+<br>
+ <table width="100%">
+ <tr>
+ <th>
+ Page
+ </th>
+ <th>
+ Note
+ </th>
+ <th>
+ User
+ </th>
+ </tr>
+<% @wiki.checkouts.each do |checkout| %>
+<% page = checkout.page %>
+<% user = checkout.user %>
+<% version = checkout.version %>
+ <tr>
+ <td>
+ <%= page.presentation_name %>, version <%= version.version %>
+ </td>
+ <td>
+ <%= version.note %>
+ </td>
+ <td>
+ <%= user.name %> (<%= user.email %>)
+ </td>
+ </tr>
+ <% end %>
+ </table>
+<br>
+Please check-in your files at the end of the day.
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @cadmin.email %>"><%= @cadmin.name %></a>
+
diff --git a/source/app/views/notifier/wiki_created.rhtml b/source/app/views/notifier/wiki_created.rhtml
new file mode 100644
index 0000000..a4872aa
--- /dev/null
+++ b/source/app/views/notifier/wiki_created.rhtml
@@ -0,0 +1,15 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+<br>
+The wiki site <strong><%= @site.title %></strong> is online!<br>
+<br>
+This site was created in the following location <%= @site.path %>. <br>
+In all <%= @count.to_s %> files were wikified.
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
\ No newline at end of file
diff --git a/source/app/views/notifier/wiki_scheduled.rhtml b/source/app/views/notifier/wiki_scheduled.rhtml
new file mode 100644
index 0000000..d22e9d6
--- /dev/null
+++ b/source/app/views/notifier/wiki_scheduled.rhtml
@@ -0,0 +1,15 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+<br>
+The wiki site <strong><%= @site.title %></strong> is scheduled for creation!<br>
+<br>
+This site will be created in the following location <%= @site.path %>. <br>
+In all <%= @count.to_s %> files will be wikified.
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
\ No newline at end of file
diff --git a/source/app/views/notifier/wiki_scheduled4update.rhtml b/source/app/views/notifier/wiki_scheduled4update.rhtml
new file mode 100644
index 0000000..88a647d
--- /dev/null
+++ b/source/app/views/notifier/wiki_scheduled4update.rhtml
@@ -0,0 +1,14 @@
+<style>
+<!--
+
+* { font-size: 9pt; font-family: verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
+p { margin: 0 }
+-->
+</style>
+<%= ::MSG_EMAIL_SERVER_GENERATED %><br><br>
+<br>
+The wiki site <strong><%= @site.title %></strong> is scheduled to be updated.<br>
+<br>
+This site will be updated from release <%= @site.baseline.baseline %> to <%= @site.baseline_process.baseline.baseline %>.
+<br><br><br>
+If you have questions regarding <%= ENV['EPFWIKI_APP_NAME'] %> or this e-mail, please contact <a href="mailto:<%= @admin.email %>"><%= @admin.name %></a>
\ No newline at end of file
diff --git a/source/app/views/other/_changelog.rhtml b/source/app/views/other/_changelog.rhtml
new file mode 100644
index 0000000..0026dc7
--- /dev/null
+++ b/source/app/views/other/_changelog.rhtml
@@ -0,0 +1,4 @@
+== 0.9
+
+* LogicaCMG code donation (non-EPL components removed)
+
diff --git a/source/app/views/other/_logfiles.rhtml b/source/app/views/other/_logfiles.rhtml
new file mode 100644
index 0000000..c82ab54
--- /dev/null
+++ b/source/app/views/other/_logfiles.rhtml
@@ -0,0 +1,21 @@
+ <div class="sectionHeading">Log Files</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>File</th>
+ <th>Date</th>
+ </tr>
+ <% for file in Dir.entries(ENV['EPFWIKI_ROOT_DIR'] + "log") - [".", ".."] %>
+ <tr>
+ <td><%= link_to(file, :action=> 'download_logfile', :file => file) %></td>
+ <td><%= File.mtime(ENV['EPFWIKI_ROOT_DIR'] + "log/" + file).strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
\ No newline at end of file
diff --git a/source/app/views/other/_properties.rhtml b/source/app/views/other/_properties.rhtml
new file mode 100644
index 0000000..3a1a430
--- /dev/null
+++ b/source/app/views/other/_properties.rhtml
@@ -0,0 +1,55 @@
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Application Name</th>
+ <td align="left" class="sectionTableCell">ENV['EPFWIKI_APP_NAME']</td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Version</th>
+ <td align="left" class="sectionTableCell">$VERSION$</td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Buildid</th>
+ <td align="left" class="sectionTableCell">$BUILDID$</td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Rails Version</th>
+ <td align="left" class="sectionTableCell"><%= Rails::VERSION::STRING %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Database Schema Version</th>
+ <td align="left" class="sectionTableCell"><%= @database_schema.version %>
+ <% if @version %>
+ <%= image_tag("warning", :border => 0, :title => "", :align => 'middle' ) %>
+ <% if cadmin? %>
+ <%= start_form_tag :action => 'migrate' %><input type="submit" value="Migrate to version <%= @version %>"><%= end_form_tag %>
+ <% end %>
+ <% end %>
+ </td>
+ </tr>
+
+ <% if admin? %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Database Name</th>
+ <td align="left" class="sectionTableCell"><%= ActiveRecord::Base.configurations[RAILS_ENV]['database'] %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Database User</th>
+ <td align="left" class="sectionTableCell"><%= ActiveRecord::Base.configurations[RAILS_ENV]['username'] %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Environment</th>
+ <td align="left" class="sectionTableCell"><%= RAILS_ENV %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Search index updated on</th>
+ <td align="left" class="sectionTableCell"><%= @index_mtime.strftime("%I:%M %p %d-%b-%y") if @index_mtime %>
+ <% if cadmin? %>
+ <%= start_form_tag :action => 'run_indexer' %><input type="submit" value="Run indexer now!"><%= end_form_tag %>
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+</table>
+</div>
diff --git a/source/app/views/other/_stats.rhtml b/source/app/views/other/_stats.rhtml
new file mode 100644
index 0000000..3480b68
--- /dev/null
+++ b/source/app/views/other/_stats.rhtml
@@ -0,0 +1,18 @@
+(in U:/ROR/epfwiki_donation)
++----------------------+-------+-------+---------+---------+-----+-------+
+| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |
++----------------------+-------+-------+---------+---------+-----+-------+
+| Helpers | 493 | 398 | 1 | 24 | 24 | 14 |
+| Controllers | 1716 | 1220 | 12 | 104 | 8 | 9 |
+| APIs | 0 | 0 | 0 | 0 | 0 | 0 |
+| Components | 0 | 0 | 0 | 0 | 0 | 0 |
+| Functional tests | 2305 | 1624 | 20 | 85 | 4 | 17 |
+| Models | 1972 | 1154 | 11 | 125 | 11 | 7 |
+| Unit tests | 1147 | 813 | 6 | 37 | 6 | 19 |
+| Libraries | 382 | 280 | 2 | 31 | 15 | 7 |
+| Integration tests | 197 | 131 | 2 | 2 | 1 | 63 |
++----------------------+-------+-------+---------+---------+-----+-------+
+| Total | 8212 | 5620 | 54 | 408 | 7 | 11 |
++----------------------+-------+-------+---------+---------+-----+-------+
+ Code LOC: 3052 Test LOC: 2568 Code to Test Ratio: 1:0.8
+
diff --git a/source/app/views/other/env.rhtml b/source/app/views/other/env.rhtml
new file mode 100644
index 0000000..97a28ca
--- /dev/null
+++ b/source/app/views/other/env.rhtml
@@ -0,0 +1,40 @@
+<% @heading = 'Environment Variables' %>
+<% @overview = 'This page display the environment variables' %>
+
+<div class="sectionHeading"><%= ENV['EPFWIKI_APP_NAME'] %> Environment Variables</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table>
+ <% ENV.keys.sort.each do |key| %>
+ <% if key.index("EPFWIKI") %>
+ <tr>
+ <th><%=key%></th><td><%=ENV[key]%></td>
+ </tr>
+ <% end %>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div class="sectionHeading">Other Environment Variables</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table>
+ <% ENV.keys.sort.each do |key| %>
+ <% if !key.index("EPFWIKI") %>
+ <tr>
+ <th><%=key%></th><td><%=ENV[key]%></td>
+ </tr>
+ <% end %>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
diff --git a/source/app/views/other/error.rhtml b/source/app/views/other/error.rhtml
new file mode 100644
index 0000000..7d5b09b
--- /dev/null
+++ b/source/app/views/other/error.rhtml
@@ -0,0 +1,3 @@
+<% @heading = "Application Error" %>
+<% @overview = "An application error occurred while processing your request. " %>
+
diff --git a/source/app/views/other/info.rhtml b/source/app/views/other/info.rhtml
new file mode 100644
index 0000000..e68d7d2
--- /dev/null
+++ b/source/app/views/other/info.rhtml
@@ -0,0 +1,96 @@
+<% @heading = "About" %>
+<% @overview = "<strong>#{ENV['EPFWIKI_APP_NAME']} $VERSION$</strong> ($BUILDID$)<br>Designed to be used together with Eclipse Process Framework (EPF) <br>Copyright (c) 2006 LogicaCMG Result Centre" %>
+
+<div class="sectionHeading"><%= "About " + ENV['EPFWIKI_APP_NAME'] %></div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <td scope="row" class="sectionTableCell">
+ <p>EPF Wiki is Wiki technology designed to be used together with Eclipse Process Framework (EPF). This offers the best of two distinct worlds: the worlds of Wikis and powerfull process frameworks. It combines a modular method construction approach and the flexibility and ease of use that is the defining characteristic of a wiki.
+ </p>
+ <p>EPF Wiki is an innovation that adds wiki functions to the hypertext process descriptions created with EPF.
+ </p>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+<%= render_partial 'properties' %>
+
+<% if cadmin? %>
+ <div class="sectionHeading">Releases</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>Release</th>
+ <th>BuildID</th>
+ <th>Database Schema</th>
+ <th>Action</th>
+ </tr>
+ <% if @releases %>
+ <% for release in @releases %>
+ <tr>
+ <td><%= release[1] %></td>
+ <td><%= release[2] %></td>
+ <td><%= release[3] %></td>
+ <td>
+ <%= start_form_tag :action => 'online_update' %><input type="submit" value="Deploy" <%= "disabled" if RAILS_ENV == "development" %>><input name="release" type="hidden" value="<%= release[0] %>"/><%= end_form_tag %>
+ </td>
+ </tr>
+ <% end %>
+ <% end %>
+ </table>
+
+
+<%= start_form_tag({:action => 'upload_release'}, :multipart => true) %>
+<table>
+ <tr>
+ <th align="right"><label for="file">Release ZIP</label>
+ </th>
+ <td><%= file_field 'site', 'file' %>
+ </td>
+ </tr>
+ <tr>
+ <th align="right" valign="top">
+ </th>
+ <td> <%= submit_tag "upload" %>
+ </td>
+ </tr>
+</table>
+<%= end_form_tag %>
+
+ </td>
+ </tr>
+ </table>
+ </div>
+
+
+<%= render_partial "logfiles" %>
+
+<div class="sectionHeading">Statistics</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <td scope="row" class="sectionTableCell">
+<pre>
+<%= render_partial "stats" %>
+</pre>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+<div class="sectionHeading">Change Log</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <td scope="row" class="sectionTableCell">
+<%= simple_format(IO.readlines(ENV['EPFWIKI_ROOT_DIR'] + "CHANGELOG").join) %>
+</td>
+ </tr>
+ </table>
+ </div>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/pages/_list.rhtml b/source/app/views/pages/_list.rhtml
new file mode 100644
index 0000000..734e492
--- /dev/null
+++ b/source/app/views/pages/_list.rhtml
@@ -0,0 +1,33 @@
+ <div class="sectionHeading">Pages</div>
+ <div class="sectionContent">
+ <% unless @pages.empty? %>
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>Presentation Name</th>
+ <th>Filename</th>
+ <th>Type</th>
+ <th>Created</th>
+ </tr>
+
+ <% for page in @pages %>
+ <td><%= page.id %></td>
+ <td>
+ <%= link_to_page @site, page %>
+ </td>
+ <td><%= page.filename %></td>
+ <td><%= page.content_type %></td>
+ <td><%= page.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <% end %>
+ </table>
+ <% else %>
+ No pages found!
+ <% end %>
+ </td>
+ </tr>
+ </table>
+ </div>
\ No newline at end of file
diff --git a/source/app/views/pages/_pinedit.rhtml b/source/app/views/pages/_pinedit.rhtml
new file mode 100644
index 0000000..9dcf83d
--- /dev/null
+++ b/source/app/views/pages/_pinedit.rhtml
@@ -0,0 +1,112 @@
+<% src = url_for("/editor/pinEdit.html?url=/#{url_for(@checkout.version.rel_path_root)}") %>
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title><%= @checkout.site.title + ' - Edit ' + @checkout.page.presentation_name %></title>
+ <%= stylesheet_link_tag 'default' %>
+ </head>
+<script>
+var editor;
+
+// this function is called if editor is loaded
+function editOnEditorLoaded(objEditor)
+{
+ // save editor object for later use (save)
+ editor = objEditor;
+
+ // read the HTML content from hidden text area
+ //var html = document.getElementById("__editData").value;
+ // write content to editor
+ //editor.editWrite(html);
+
+ // get document object
+ //var doc = editor.editGetDocument();
+
+}
+// load the HTML content from the editor in the hidden field "html"
+function editOnBeforeSave(object, sContent)
+{
+ //alert(sContent);
+ document.forms[0].html.value = sContent;
+ document.forms[0].submit();
+ return true;
+}
+function transfer()
+{
+ // get the html content from the editor
+ var html = editor.editGetHtml();
+ // add the content to the hidden field
+ document.forms[0].html.value = html;
+ // submit the formular
+ document.forms[0].submit();
+}
+function save()
+{
+ document.forms[0].save.value = 'Y'
+ transfer();
+}
+function checkin()
+{
+ if (confirm("Save and check-in the current document?") )
+ {
+ transfer();
+ }
+}
+function preview()
+{
+ if (confirm("Save changes and preview the page?") )
+ { document.forms[0].save.value = 'P'
+ transfer();
+ }
+}
+</script>
+
+<body style="margin-left:0px;margin-bottom:0px;margin-right:0px;overflow:hidden;">
+ <table width="100%" cellpadding="0" cellspacing="0" border="0">
+ <tr>
+ <td class="pageTitle">
+ <%= "Edit " + @checkout.page.presentation_name %>
+ </td>
+ <td align="right">
+ <strong>
+ <a href="javascript: preview();">preview</a> |
+ <a href="javascript: checkin();">checkin</a> |
+ <%= link_to 'undo check out', {:controller => 'pages', :action => 'undocheckout', :checkout_id => @checkout.id}, :confirm => "Are you sure to want to undo the checkout? Any changes made to this version will be lost." %> |
+ <a href="javascript: save()">save</a>
+ </strong>
+ </td>
+ </tr>
+ </table>
+
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
+ <tr>
+ <td class="pageTitleSeparator">
+ <img alt="Shim" height="1" src="/images/shim.gif" /></td>
+ </tr>
+ </table>
+<%= start_form_tag :action => 'saveorcheckin' %>
+ <input type="hidden" name="html" value="" id="html">
+ <input type="hidden" name="checkout_id" value="<%= @checkout.id.to_s %>">
+ <input type="hidden" name="save">
+</form>
+<!------------------------------------>
+<!-- include this code in your page -->
+<!-- this hidden field is used to post the content -->
+
+
+<!-- the content is loaded here -->
+<div style="position:absolute;visibility:hidden;top:1;height:1;">
+<TEXTAREA style='visibility:hidden' id="__editData" NAME="__editData"></TEXTAREA>
+</div>
+
+<!-- include this code in your page -->
+<!------------------------------------>
+
+
+<!---------------------------------------------->
+<!-- set the correct path to the pinEdit.html -->
+<!---------------------------------------------->
+<IFRAME id="editorFrame" style="WIDTH: 100%; HEIGHT: 92%" src=<%= "\""+ src + '&Id=' + session['user'].images_path + '&dd=' + session['user'].documents_path + '&hm=2&hb=1"' %> frameborder=0>
+</IFRAME>
+ </body>
+</html>
diff --git a/source/app/views/pages/_relationships.rhtml b/source/app/views/pages/_relationships.rhtml
new file mode 100644
index 0000000..ffe783b
--- /dev/null
+++ b/source/app/views/pages/_relationships.rhtml
@@ -0,0 +1,80 @@
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Sites
+ </th>
+ <td class="sectionTableCell">
+ <p>This page was modified in the following Wiki sites: </p>
+ <ul>
+ <% for site in @page.sites_with_versions %>
+ <li>
+ <%= link_to_site(site, @page) %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ <td class="sectionTableCell">
+ <p>This page is part of the following sites: </p>
+ <ul>
+ <% for site in @page.sites %>
+ <li>
+ <%= link_to_site(site, @page) %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Baselines
+ </th>
+ <td class="sectionTableCell">
+ <p>This page modified the following baselines: </p>
+ <ul>
+ <% for baseline in @page.baselines_with_versions %>
+ <li>
+ <%= link_to_baseline baseline, nil %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ <td class="sectionTableCell">
+ <p>This page is part of the following baselines: </p>
+ <ul>
+ <% for baseline in @page.baselines %>
+ <li>
+ <%= link_to_baseline baseline, nil %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Baseline Updates
+ </th>
+ <td class="sectionTableCell" colspan=2>
+ <p>Changes of this page between successive baselines </p>
+ <ul>
+ <% for item in @page.difference_analysis_items %>
+ <li>
+ <%= link_to_difference_analysis_item(item) %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Checkouts
+ </th>
+ <td class="sectionTableCell" colspan=2>
+ <ul>
+ <% for checkout in @page.checkouts %>
+ <li>
+ <%= link_to_version2 checkout.version %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
diff --git a/source/app/views/pages/_tinymce.rhtml b/source/app/views/pages/_tinymce.rhtml
new file mode 100644
index 0000000..1b3ccda
--- /dev/null
+++ b/source/app/views/pages/_tinymce.rhtml
@@ -0,0 +1,108 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title><%= @checkout.site.title + ' - Edit ' + @checkout.page.presentation_name %></title>
+ <%= javascript_include_tag "tiny_mce/tiny_mce" %>
+ <%= stylesheet_link_tag 'default' %>
+<!-- TinyMCE -->
+<script language="javascript" type="text/javascript">
+ tinyMCE.init({
+ mode : "textareas",
+ theme : "advanced",
+ plugins : "devkit,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras",
+ theme_advanced_buttons1_add_before : "save,newdocument,separator",
+ theme_advanced_buttons1_add : "fontselect,fontsizeselect",
+ theme_advanced_buttons2_add : "separator,insertdate,inserttime,preview,separator,forecolor,backcolor,advsearchreplace",
+ theme_advanced_buttons2_add_before: "cut,copy,paste,pastetext,pasteword,separator,search,replace,separator",
+ theme_advanced_buttons3_add_before : "tablecontrols,separator",
+ theme_advanced_buttons3_add : "emotions,iespell,media,advhr,separator,print,separator,ltr,rtl,separator,fullscreen",
+ theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,|,visualchars,nonbreaking",
+ theme_advanced_toolbar_location : "top",
+ theme_advanced_toolbar_align : "left",
+ theme_advanced_path_location : "bottom",
+ content_css : "../../stylesheets/default.css",
+ plugin_insertdate_dateFormat : "%Y-%m-%d",
+ plugin_insertdate_timeFormat : "%H:%M:%S",
+ extended_valid_elements : "hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
+ external_link_list_url : "example_link_list.js",
+ external_image_list_url : "example_image_list.js",
+ flash_external_list_url : "example_flash_list.js",
+ media_external_list_url : "example_media_list.js",
+ file_browser_callback : "fileBrowserCallBack",
+ theme_advanced_resize_horizontal : false,
+ theme_advanced_resizing : true,
+ nonbreaking_force_tab : true,
+ apply_source_formatting : true,
+ document_base_url : "/<%= @checkout.version.rel_path_root %>"
+ });
+ function fileBrowserCallBack(field_name, url, type, win) {
+ // This is where you insert your custom filebrowser logic
+ alert("Example of filebrowser callback: field_name: " + field_name + ", url: " + url + ", type: " + type);
+
+ // Insert new URL, this would normaly be done in a popup
+ win.document.forms[0].elements[field_name].value = "someurl.htm";
+ }
+ function transfer()
+{
+ // get the html content from the editor
+ //var html = editor.editGetHtml();
+ // add the content to the hidden field
+ document.forms[0].html.value = html;
+ // submit the formular
+ document.forms[0].submit();
+}
+function save()
+{
+ document.forms[0].save.value = 'Y'
+ document.forms[0].submit();
+}
+function checkin()
+{
+ if (confirm("Save and check-in the current document?") )
+ {
+ document.forms[0].submit();
+ }
+}
+function preview()
+{
+ if (confirm("Save changes and preview the page?") )
+ { document.forms[0].save.value = 'P'
+ document.forms[0].submit();
+ }
+}
+</script>
+<!-- /TinyMCE -->
+</head>
+<body style="margin-left:0px;margin-bottom:0px;margin-right:0px;overflow:hidden;">
+ <table width="100%" cellpadding="0" cellspacing="0" border="0">
+ <tr>
+ <td class="pageTitle">
+ <%= "Edit " + @checkout.page.presentation_name %>
+ </td>
+ <td align="right">
+ <strong>
+ <a href="javascript: preview();">preview</a> |
+ <a href="javascript: checkin();">checkin</a> |
+ <%= link_to 'undo check out', {:controller => 'pages', :action => 'undocheckout', :checkout_id => @checkout.id}, :confirm => "Are you sure to want to undo the checkout? Any changes made to this version will be lost." %> |
+ <a href="javascript: save()">save</a>
+ </strong>
+ </td>
+ </tr>
+ </table>
+
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
+ <tr>
+ <td class="pageTitleSeparator">
+ <img alt="Shim" height="1" src="/images/shim.gif" /></td>
+ </tr>
+ </table>
+
+<%= start_form_tag :action => 'saveorcheckin' %>
+ <input type="hidden" name="checkout_id" value="<%= @checkout.id.to_s %>">
+ <input type="hidden" name="save">
+ <textarea id="html" name="html" rows="15" cols="80" style="width: 100%">
+ <%= @checkout.version.html %>
+ </textarea>
+</form>
+</body>
+</html>
diff --git a/source/app/views/pages/checkout.rhtml b/source/app/views/pages/checkout.rhtml
new file mode 100644
index 0000000..0161b81
--- /dev/null
+++ b/source/app/views/pages/checkout.rhtml
@@ -0,0 +1,35 @@
+<% @heading = 'Checking Out' %>
+<% @overview = "You are about to check-out the page " + link_to_page(@wiki, @page) + ". <p>To be able to edit this page a reserved working copy will be created. <br>The page will be locked untill you check-in or undo the check-out. The changes will be visible to other users only after you check-in.</p><p>It is recommended to add a check-out note, you can modify this note when you check-in the file.</p>" %>
+
+<% tinymce %>
+
+<%= error_messages_for 'checkout' %>
+
+<% tabular_form_for :version, @version do |f| %>
+ <%= f.hidden_field :page_id %>
+ <input type="hidden" name="wiki_id" value="<%= @wiki.id %>">
+ <tr>
+ <th></th>
+ <td><%= f.text_area :note, :cols => 60, :rows => 8 %></td>
+ <tr>
+ <th valign="top" >Destination Page</th>
+ <td><%= link_to_page(@wiki, @page) %></td>
+ </tr>
+ <tr>
+ <th valign="top" >Source Page</th>
+ <td><%= link_to_page(@source_version.site, @source_version.page) if @source_version %></td>
+ </tr>
+ <tr>
+ <th>Source Version</th>
+ <td><%= f.select :version_id, @versions.collect {|version| [version.version_text, version.id]} %></td></tr>
+ </tr>
+ <tr>
+ <th>Target Site</th>
+ <td><%= f.select :site_id, @page.wikis_4checkout.collect {|wiki| [wiki.title, wiki.id]} %></td>
+ </tr>
+ <tr><th></th><td><%= submit_tag "Continue" %></td></tr>
+<% end %>
+
+
+
+
diff --git a/source/app/views/pages/edithtml.rhtml b/source/app/views/pages/edithtml.rhtml
new file mode 100644
index 0000000..52ce31c
--- /dev/null
+++ b/source/app/views/pages/edithtml.rhtml
@@ -0,0 +1 @@
+<%= render_partial ENV['EPFWIKI_EDITOR'] %>
\ No newline at end of file
diff --git a/source/app/views/pages/filelist.rhtml b/source/app/views/pages/filelist.rhtml
new file mode 100644
index 0000000..ac062aa
--- /dev/null
+++ b/source/app/views/pages/filelist.rhtml
@@ -0,0 +1,36 @@
+<html>
+ <head>
+ <script>
+ </script>
+ </head>
+ <body style="margin: 2px">
+ <table style="cursor: Hand;padding-left: 2px; padding-right: 2px;font-family: arial; font-size:11px; font-weight:normal"
+ border="0" cellspacing="0" cellpadding="1" width="100%">
+ <form name="frmSelect" id="frmSelect" method="POST" action="filelist.php?pathabs=<%= @rootPath %>&urlabs=<%= @rootUrl%>&language=<%= @language %>&filter=<%= @filters %>">
+ <input type="hidden" id="path" name="path" value="<%= @path %>">
+ </form>
+ <td colspan="2" align="left" bgcolor="#ECE9D8">Name</td>
+ <td align="right" bgcolor="#ECE9D8">Size</td>
+ <td align="left" bgcolor="#ECE9D8">Type</td>
+ <td align="left" bgcolor="#ECE9D8">Changed</td>
+<% @j=0 %>
+
+<% for file in @files %>
+ <% @subFilePath = session['user'].documents_path + "/" + file;
+ @subFileName = file;
+ #@subFolderDate = date("m/d/Y H:i:s", filemtime($subFolderPath));
+ %>
+ <tr onclick="clickRow(this,<%= @j%>,'FILE');" ondblclick="dblClick(<%= @j %>,'FILE')" onmouseover="this.style.background='buttonface'" onmouseout="this.style.background='white'">
+ <input type="hidden" id="hidRow<%= @j%>" value="<%= ENV['EPFWIKI_USERDATA_URL'] + @subFilePath%>">
+ <td width="1px"><%= image_tag("html.gif", :border=> 0) %></td>
+ <td align="left"><%= @subFileName%></td>
+ <td align="right"><%= file.size %></td>
+ <td align="left">File</td>
+ <td nowrap width="1%" align="left"><%= file.size %> </td>
+ </tr>
+ <% @j=@j+1 %>
+<% end %>
+</td></tr>
+</table>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/app/views/pages/new.rhtml b/source/app/views/pages/new.rhtml
new file mode 100644
index 0000000..0dd5590
--- /dev/null
+++ b/source/app/views/pages/new.rhtml
@@ -0,0 +1,43 @@
+<% @heading = 'New Page' %>
+<% @overview = "Use this form to create a new page in site #{link_to_site(@wiki)}" %>
+
+<% tinymce %>
+
+<%= error_messages_for 'page' %>
+
+<% unless @templates.empty? %>
+ <% tabular_form_for :page, @page do |f| %>
+ <%= f.text_field :presentation_name %>
+ <%= f.text_area :note, :cols => 60, :rows => 8 %>
+ <tr>
+ <th align="right">Template (or Page)</th>
+ <td>
+ <br>
+ <br>
+ <table width="100%" border=1>
+ <tr>
+ <th width="40%">Template</th>
+ <th>Versions</th>
+ </tr>
+ <% for template in @templates %>
+ <tr>
+ <td><%= link_to_page @wiki, template %></td>
+ <td>
+ <% for version in template.versions %>
+ <% if version.site_id == @wiki.id %>
+ <%= radio_button(:page, :source_version, version.id) %> <%= link_to_version version, 'Version' %>
+ <% end %>
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ <tr><th></th><td><%= submit_tag "Submit" %></td></tr>
+ <% end %>
+<% end %>
+
+
+
+
diff --git a/source/app/views/pages/show.rhtml b/source/app/views/pages/show.rhtml
new file mode 100644
index 0000000..1d20d02
--- /dev/null
+++ b/source/app/views/pages/show.rhtml
@@ -0,0 +1,82 @@
+<% @heading = @page.presentation_name %>
+<% @overview = "This page shows the details of #{link_to_page(@site, @page)} in site #{link_to_site(@site)}" %>
+
+<% if @site.wiki? %>
+<div id="menu">
+ <%= link_to 'edit', :action => 'checkout', :id => @page.id %>
+ | <%= link_to 'new page', :action => 'new', :id => @page, :site_id => @site %>
+ <% if cadmin? %>
+ | <%= link_to 'destroy', :action => 'destroy', :id => @page %>
+ <% end %>
+ <%= link_to_notification_toggle(@site, @page, 'Comment') %>
+ <%= link_to_notification_toggle(@site, @page, 'Version') %>
+</div>
+
+<p>
+<%= tabs([["Versions", url_for(:action => 'show', :id => @page.id, :site_id => @site), (params[:action] == "show")],
+["Comments", url_for(:action=> 'show_comments', :id => @page.id, :site_id => @site.id), (params[:action] == "show_comments")]], 80) %>
+</p>
+
+<%= links_to_pages(@version_pages) if @version_pages %>
+<%= links_to_pages(@comment_pages) if @comment_pages %>
+
+<%= render(:partial => 'versions/versions_list') if @version_pages %>
+<%= render(:partial => 'comments/comments_list') if @comment_pages %>
+
+<% end %>
+<div class="sectionHeading"> Relationships</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <%= render_partial("relationships") %>
+ </table>
+</div>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">ID</th>
+ <td align="left" class="sectionTableCell"><%= @page.id.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Presentation Name</th>
+ <td align="left" class="sectionTableCell"><%= @page.presentation_name %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Content Type</th>
+ <td align="left" class="sectionTableCell"><%= @page.content_type %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">File Name</th>
+ <td align="left" class="sectionTableCell"><%= @page.filename %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Relative Path</th>
+ <td align="left" class="sectionTableCell"><%= @page.rel_path %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Updated On</th>
+ <td align="left" class="sectionTableCell"><%= @page.updated_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Updated On</th>
+ <td align="left" class="sectionTableCell"><%= @page.updated_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <% if cadmin? %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">body_tag</th>
+ <td align="left" class="sectionTableCell"><%=h @page.body_tag %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">treebrowser_tag</th>
+ <td align="left" class="sectionTableCell"><%=h @page.treebrowser_tag %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">copyright_tag</th>
+ <td align="left" class="sectionTableCell"><%=h @page.copyright_tag %></td>
+ </tr>
+ <% end %>
+</table>
+</div>
+
+
diff --git a/source/app/views/pages/upload.rhtml b/source/app/views/pages/upload.rhtml
new file mode 100644
index 0000000..310b514
--- /dev/null
+++ b/source/app/views/pages/upload.rhtml
@@ -0,0 +1,9 @@
+<% if @insert == "1" %>
+ <body onload="window.opener.callback_editUpload('<%= @file.original_filename %>');window.close()">
+</body>
+<% else %>
+ <body onload="alert('File <%= @path + @file.original_filename %> uploaded successfully !');window.close()">
+</body>
+<% end %>
+
+
diff --git a/source/app/views/search/_generic.rhtml b/source/app/views/search/_generic.rhtml
new file mode 100644
index 0000000..9a5b505
--- /dev/null
+++ b/source/app/views/search/_generic.rhtml
@@ -0,0 +1,7 @@
+<div class="record">
+ <table>
+ <% generic.class.searchable_fields.each do |field| %>
+ <tr> <th><%= field.to_s %></th> <td><%= generic.send(field) %></td> </tr>
+ <% end %>
+ </table>
+</div>
diff --git a/source/app/views/search/index.rhtml b/source/app/views/search/index.rhtml
new file mode 100644
index 0000000..8c7098c
--- /dev/null
+++ b/source/app/views/search/index.rhtml
@@ -0,0 +1,32 @@
+<% @heading = "Search Results" %>
+
+<% if @pages.size > 0 %>
+<div class="sectionHeading">Pages</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ID</th>
+ <% for wiki in @wikis %>
+ <th><%= link_to_site(wiki) %></th>
+ <% end %>
+ </tr>
+
+ <% for page in @pages %>
+ <tr>
+ <td><%= page.id %></td>
+ <% for wiki in @wikis %>
+ <td><%= link_to_page(wiki, page, wiki != @wikis[0]) if page.sites.include?(wiki) %></td>
+ <% end %>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
+<% end %>
+
+<%= render :partial => 'comments/comments_list' %>
\ No newline at end of file
diff --git a/source/app/views/sites/_list.rhtml b/source/app/views/sites/_list.rhtml
new file mode 100644
index 0000000..d6c62f2
--- /dev/null
+++ b/source/app/views/sites/_list.rhtml
@@ -0,0 +1,19 @@
+<table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>Name</th>
+ <th>Pages</th>
+ <th>Created By</th>
+ <th>Created</th>
+ <th>Baseline</th>
+ </tr>
+ <% list.each do |site| %>
+ <tr><td><%= site.id %></td>
+ <td><%= link_to_site site %></td>
+ <td><%= site.pages_count %></td>
+ <td><%= link_to_user site.user %></td>
+ <td><%= site.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ <td><%= link_to_baseline site.baseline, site %></td>
+ </tr>
+ <% end %>
+</table>
diff --git a/source/app/views/sites/_list_wiki.rhtml b/source/app/views/sites/_list_wiki.rhtml
new file mode 100644
index 0000000..db73167
--- /dev/null
+++ b/source/app/views/sites/_list_wiki.rhtml
@@ -0,0 +1,25 @@
+<table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>Name</th>
+ <th>Pages</th>
+ <th>Versions</th>
+ <th>Comments</th>
+ <th>Created By</th>
+ <th>Created</th>
+ <th>Baseline</th>
+ </tr>
+ <% for site in list_wiki %>
+ <tr>
+ <td><%= site.id %></td>
+ <td><%= link_to_site site %></td>
+ <td><%= site.pages_count %></td>
+ <td><%= site.versions_count_excluding_baseversions %></td>
+ <td><%= site.comments_count.to_s %></td>
+ <td><%= link_to_user site.user %></td>
+ <td><%= site.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ <td><%= link_to_baseline site.baseline, site %></td>
+ </tr>
+ <% end %>
+</table>
+
diff --git a/source/app/views/sites/edit.rhtml b/source/app/views/sites/edit.rhtml
new file mode 100644
index 0000000..f6af747
--- /dev/null
+++ b/source/app/views/sites/edit.rhtml
@@ -0,0 +1,13 @@
+<% @heading = "Edit Baseline Process: #{@site.title}" if @site.baseline_process? %>
+<% @heading = "Edit Wiki: #{@site.title}" if @site.wiki? %>
+<% @overview = "Use the form below to update properties of #{link_to_site(@site)}" %>
+
+<%= error_messages_for 'site' %>
+<% tinymce %>
+
+<% tabular_form_for :site do |f| %>
+ <%= f.text_field :title %>
+ <%= f.text_field :folder %>
+ <%= f.text_area :description, :cols => 60, :rows => 8 %>
+ <tr><th></th><td><%= submit_tag "Submit" %></td></tr>
+<% end %>
diff --git a/source/app/views/sites/list.rhtml b/source/app/views/sites/list.rhtml
new file mode 100644
index 0000000..c4c73aa
--- /dev/null
+++ b/source/app/views/sites/list.rhtml
@@ -0,0 +1,42 @@
+<% @heading = 'Sites' %>
+
+<% if admin? %>
+<div id="menu">
+ <%= link_to 'new site', :action => 'new' %>
+ | <%= link_to 'new wiki', :action => 'new wiki' %>
+</div>
+<% end %>
+
+<div class="sectionHeading">Wikis</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <%= render_partial 'list_wiki', @wiki_sites unless @wiki_sites.nil? %>
+ </td>
+ </tr>
+ </table>
+</div>
+
+<% if admin? %>
+<div class="sectionHeading">Pending Wikis</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <%= render_partial 'list', @pending_sites unless @pending_sites.nil? %>
+ </td>
+ </tr>
+ </table>
+</div>
+<div class="sectionHeading">Baseline Processes</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <%= render_partial 'list', @baseline_processes unless @baseline_processes.nil? %>
+ </td>
+ </tr>
+ </table>
+</div>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/sites/new.rhtml b/source/app/views/sites/new.rhtml
new file mode 100644
index 0000000..fae806a
--- /dev/null
+++ b/source/app/views/sites/new.rhtml
@@ -0,0 +1,41 @@
+<% @heading = 'New Baseline Process' %>
+<% tinymce %>
+
+<%= error_messages_for 'site' %>
+
+<% unless @folders.empty? %>
+ <% tabular_form_for :site do |f| %>
+ <tr><th>Server Folder</th><td><%= f.select :folder, @folders.collect {|folder| [folder,folder]} %></td></tr>
+ <%= f.text_field :baseline_baseline %>
+ <%= f.text_field :title %>
+ <%= f.text_area :description, :cols => 60, :rows => 8 %>
+ <tr><th></th><td><%= submit_tag 'Submit' %></td></tr>
+ <% end %>
+<% end %>
+
+<!-- form_for cannot be used with multipart so we are not using tabular_form_for the next form -->
+<% @site = Site.new %>
+<div class="sectionHeading">Upload Zip File</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <%= start_form_tag({:action => 'upload'}, :multipart => true) %>
+ <table>
+ <tr><th align="right"><label for="file">File</label></th>
+ <td><%= file_field :site, :file %></td>
+ </tr>
+ <tr>
+ <th align="right" valign="top" width="200"><label for="site_folder">Server Folder Name</label></th>
+ <td><%= text_field 'site', 'folder' %></td>
+ </tr>
+ <tr>
+ <th align="right" valign="top"></th>
+ <td> <%= submit_tag 'Upload' %></td>
+ </tr>
+ </table>
+ <%= end_form_tag %>
+ </td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
diff --git a/source/app/views/sites/new_wiki.rhtml b/source/app/views/sites/new_wiki.rhtml
new file mode 100644
index 0000000..7b9ddf3
--- /dev/null
+++ b/source/app/views/sites/new_wiki.rhtml
@@ -0,0 +1,18 @@
+<% @heading = 'New Wiki' %>
+<% @overview = 'Use this form to create a new Wiki. A wiki is started from a baseline process which you can select from the listbox.' %>
+<% tinymce %>
+
+<%= error_messages_for 'site' %>
+
+<% unless @baseline_processes.empty? %>
+ <% tabular_form_for :site do |f| %>
+ <tr><th>Baseline Process</th><td><%= f.select :site_id_baseline_process, @baseline_processes.collect {|bl| [bl.title, bl.id]} %></td></tr>
+ <%= f.text_field :title %>
+ <%= f.text_field :folder %>
+ <%= f.text_area :description, :cols => 60, :rows => 8 %>
+ <tr><th></th><td><%= submit_tag 'Submit' %></td></tr>
+ <% end %>
+<% end %>
+
+
+
diff --git a/source/app/views/sites/show.rhtml b/source/app/views/sites/show.rhtml
new file mode 100644
index 0000000..f8c1a7a
--- /dev/null
+++ b/source/app/views/sites/show.rhtml
@@ -0,0 +1,210 @@
+<% @heading = "Baseline Process: #{@site.title}" if @site.baseline_process? %>
+<% @heading = "Wiki: #{@site.title}" if @site.wiki? %>
+<% @overview = "This page display details of site " + link_to_site(@site) %>
+
+<div id="menu">
+ <%= link_to 'new page', {:controller => 'page', :action => 'new', :site_id => @site}, :title => 'Create a new page based on a template' %>
+ | <%= link_to 'list', :action => 'list' %>
+ <% if admin? %>
+ | <%= link_to 'edit', :action => 'edit', :id => @site %>
+ <% end %>
+ <% if cadmin? && @site.baseline_process? %>
+ | <%= link_to 'new difference analysis', {:controller => 'difference_analyses', :action => 'new', :site_id => @site.id}, :title => "Create a new difference analysis: what is new, changed, removed, equal in baseline process" %>
+ <% end %>
+</div>
+
+<div class="sectionHeading">Description</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <%= @site.description %>
+ </td>
+ </tr>
+ </table>
+</div>
+
+<% if @site.wiki? %>
+<br>
+<br>
+<p>
+<%= tabs([["Versions", url_for(:id => @site.id), (['show',nil].include?(params[:tab]))],
+["Comments", url_for(:id => @site.id, :tab => 'comments'), (params[:tab] == "comments")],
+["Files", url_for(:id => @site.id, :tab => 'pages'), (params[:tab] == "pages")]], 80) %>
+</p>
+
+<%= links_to_pages(@version_pages) if @version_pages %>
+<%= links_to_pages(@comment_pages) if @comment_pages %>
+<%= links_to_pages(@page_pages) if @page_pages %>
+
+<%= render(:partial => 'versions/versions_list') if @version_pages %>
+<%= render(:partial => 'comments/comments_list') if @comment_pages %>
+<%= render(:partial => 'pages/list') if @page_pages %>
+<br>
+<br>
+<% end %>
+
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <th scope="row" class="sectionTableHeading">Current Baseline </th>
+ <td align="left" class="sectionTableCell"><%= link_to_baseline @site.baseline, nil %>
+ <% if @site.wiki? && admin? %>
+ <%= start_form_tag({:action => 'update_wiki', :id => @site}, {:method => 'get'}) %>
+ <input type="submit" value="Update Wiki">
+ <%= end_form_tag %>
+ <% end %>
+ </td>
+ </tr>
+ <%if @site.status == 'U' %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Target Baseline</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_baseline @site.baseline_process.baseline, nil %>
+ <% if cadmin? %>
+ <%= start_form_tag :action => 'update_wiki_now', :id => @site %>
+ <input type="submit" value="Update Wiki now!">
+ <%= end_form_tag %>
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Baselines </th>
+ <td align="left" class="sectionTableCell" >
+ Current and previous baselines:
+ <ul>
+ <% for baseline in @site.baselines %>
+ <li>
+ <%= link_to_baseline baseline, @site %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <% unless @site.checkouts.empty? %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Checkouts</th>
+ <td align="left" class="sectionTableCell" >
+ <ul>
+ <% for checkout in @site.checkouts %>
+ <li>
+ <%= link_to_version2 checkout.version %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <% end %>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Users</th>
+ <td align="left" class="sectionTableCell" >
+ The following users created new versions or submitted comments:
+ <ul>
+ <% for user in @site.users %>
+ <li>
+ <%= link_to_user(user) %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Difference Analyses</th>
+ <td align="left" class="sectionTableCell">
+ <ul>
+ <% for difference_analysis in @site.difference_analyses2 %>
+ <li>
+ <%= link_to_difference_analysis_from(difference_analysis) %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">ID</th>
+ <td align="left" class="sectionTableCell"><%= @site.id %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Title</th>
+ <td align="left" class="sectionTableCell"><%= @site.title %> <%= @site.site_type %> <%= @site.id.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Wiki</th>
+ <td align="left" class="sectionTableCell">
+ <% if @site.status == 'P' %>
+ Pending
+ <% if cadmin? %>
+ <%= form_tag :action => "wikify_now", :id => @site.id %>
+ <input type="submit" value="Wikify now!">
+ <%= end_form_tag %>
+ <% end %>
+ <% else %>
+ <%= @site.site_type %>
+ <% end %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Root Path</th>
+ <td align="left" class="sectionTableCell"><%= @site.path %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">URL</th>
+ <td align="left" class="sectionTableCell"><%= url_for(@site.rel_path) %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Versions</th>
+ <td align="left" class="sectionTableCell"><%= @site.versions_count.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Comments</th>
+ <td align="left" class="sectionTableCell"><%= @site.comments_count.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">HTML Files</th>
+ <td align="left" class="sectionTableCell"><%= @site.html_files_count.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Scanned Pages</th>
+ <td align="left" class="sectionTableCell"><%= @site.pages_count %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Wiki Files</th>
+ <td align="left" class="sectionTableCell"><%= @site.wikifiable_files_count.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created On</th>
+ <td align="left" class="sectionTableCell"><%= @site.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Updated On</th>
+ <td align="left" class="sectionTableCell"><%= @site.updated_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Content Scanned On</th>
+ <td align="left" class="sectionTableCell"><%= @site.content_scanned_on.strftime("%I:%M %p %d-%b-%y") if @site.content_scanned_on %>
+ <% if cadmin? %>
+ <%= form_tag :action => "scan4content", :id => @site.id %>
+ <input type="submit" value="Scan now!">
+ <%= end_form_tag %>
+ <% end %>
+ </td>
+ </tr>
+</table>
+</div>
+
+
+
+
+
+
+
+
+
diff --git a/source/app/views/sites/update_wiki.rhtml b/source/app/views/sites/update_wiki.rhtml
new file mode 100644
index 0000000..a5a35a6
--- /dev/null
+++ b/source/app/views/sites/update_wiki.rhtml
@@ -0,0 +1,12 @@
+<% @heading = "Update Wiki" %>
+<% @overview = "Use this form to update the wiki site #{link_to_site(@site)} with a new baseline. The current baseline is #{link_to_baseline(@site.baseline, @site)}" %>
+
+<%= error_messages_for 'site' %>
+
+<% unless @site.baseline_processes_candidate.empty? %>
+ <% tabular_form_for :site do |f| %>
+ <tr><th>Baseline Process</th><td><%= f.select :baseline_process, @site.baseline_processes_candidate.collect {|bl| [bl.title, bl.id]} %></td></tr>
+ <tr><th></th><td><%= submit_tag "Update Wiki!" %></td></tr>
+ <% end %>
+<% end %>
+
diff --git a/source/app/views/toolbar/show.rhtml b/source/app/views/toolbar/show.rhtml
new file mode 100644
index 0000000..5f4835a
--- /dev/null
+++ b/source/app/views/toolbar/show.rhtml
@@ -0,0 +1,59 @@
+<% if @show_toolbar %>
+ <% image = 'expand.gif' %>
+ <% image = 'collapse.gif' if session['toolbar_expanded'] %>
+ <div id="toolbar_header">
+ <% unless session['toolbar_expanded'] %>
+ <% if @page %>
+ <%= link_to_versions(@wiki, @page, '', true) if @page.versions_count > 0 %>
+ <%= link_to_comments(@wiki, @page, '', true) if @page.comments_count > 0 %>
+ <% end %>
+ <% unless @checkout.nil? %>
+ <%= image_tag('checkout2',:border => 0,:align => 'middle', :title => "#{@checkout.user.name} checked-out this page with the following note: \"#{strip_tags(@checkout.version.note || '')}\"") %>
+ <%= link_to(image_tag("edit.gif",:border => 0,:title => 'Continue Edit', :align => 'middle'), {:controller => 'pages', :action => 'edithtml', :checkout_id => @checkout}, :popup => 'popup' ) %>
+ <% end %>
+ <% end %>
+ <%= link_to(image_tag(image,:border => 0, :align => 'middle') + ' Edit/Info', {:action => 'expand_toggle', :url => @document_url}, :title => '', :class => 'expandCollapseLink') %>
+ </div>
+ <% if session['toolbar_expanded'] %>
+ <div id="toolbar_expanded">
+ <% if @version %>
+ Last updated <%= time_ago_in_words(@version.created_on) %> ago<br>by <%= @version.user.name %><br>
+ <br>
+ Version <%= @version.version.to_s %><br>
+ <% end %>
+ <%= link_to @wiki.baseline.baseline, {:controller => 'baselines', :action => 'show', :id => @wiki.baseline.id}, :popup => true, :title => "Show details of baseline process #{@wiki.baseline.baseline}" %>
+ <br>
+ <hr>
+ <% if @checkout %>
+ <%= image_tag('checkout2') %>
+ <% unless @checkout.version.note.blank? %>
+ <i>"<%= truncate strip_tags(@checkout.version.note) %>"</i><br>
+ <% end %>
+ <%= "Version #{@checkout.version.version.to_s} checked out <br>#{time_ago_in_words(@checkout.created_on)} ago by #{@checkout.user.name} <hr>" unless @checkout.nil? %>
+ <% end %>
+ <% if !@checkout || !session['user'] || mine?(@checkout) %>
+ <%= link_to image_tag('edit.gif', :border => 0, :align => 'middle', :title => 'Edit this page') + ' Edit this page', {:action => 'edit', :id => @wiki, :rel_path => @rel_path}, :popup => true %><br>
+ <% end %>
+ <%= link_to image_tag('edit.gif', :border => 0, :align => 'middle', :title => 'New page based on the current page or a template') + ' New page', {:action => 'new', :id => @wiki, :rel_path => @rel_path}, :popup => true, :title => 'New page based on the current page or a template' %><br>
+ <% if @page.comments_count > 0 %>
+ <%= link_to image_tag('comment2', :border => 0, :align => 'middle', :title => "Show comments (#{@page.comments_count.to_s}) ") + " Show comments (#{@page.comments_count.to_s}) ", {:controller => 'comments', :action => 'list', :site_id => @wiki.id, :page_id => @page.id}, :popup => true %><br>
+ <% end %>
+ <%= link_to image_tag('comment2', :border => 0, :align => 'middle', :title => 'Add comment') + ' Add comment', {:action => "new_comment", :id => @wiki, :rel_path => @rel_path}, :popup => true %><br>
+ <% if @page.versions_count > 0 %>
+ <%= link_to_versions(@wiki, @page, "Show versions (#{@page.versions_count.to_s})", true) %><br>
+ <% end %>
+ <%= link_to(image_tag('site',:border => 0,:title => 'Other Wiki functions', :align => 'middle') + ' Other', {:controller => 'sites', :action => 'list'}, :popup => 'popup', :title => 'Other Wiki functions' ) %>
+ <% if @comments %>
+ <hr>
+ <% for comment in @comments %>
+ <i>"<%= truncate(strip_tags(comment.text),50)%>"</i>
+ <%= link_to 'More...', {:controller => 'comments', :action => 'list', :site_id => @wiki.id, :page_id => @page.id }, :achor => div_id(comment,''), :popup => true %><br>
+ Posted <%= time_ago_in_words(comment.created_on) %> ago by <%= comment.user.name %>
+ <br>
+ <br>
+ <% end %>
+ <% end %>
+ </div>
+ <% end %>
+<% end %>
+
diff --git a/source/app/views/users/_list.rhtml b/source/app/views/users/_list.rhtml
new file mode 100644
index 0000000..2f342e6
--- /dev/null
+++ b/source/app/views/users/_list.rhtml
@@ -0,0 +1,36 @@
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>Name</th>
+ <th>Email</th>
+ <th>IP Address</th>
+ <th>Versions</th>
+ <th>Comments</th>
+ <th>Logon</th>
+ <th>Created On</th>
+ <th>Last Logon On</th>
+ <th>Actions</th>
+ </tr>
+ <% for user in list %>
+ <tr>
+ <td><%= user.id %></td>
+ <td><%= link_to_user user %></td>
+ <td><%= user.email %></td>
+ <td><%= user.ip_address %></td>
+ <td><%= user.versions_count_excluding_baseversions %></td>
+ <td><%= user.comments_count.to_s %></td>
+ <td><%= user.logon_count.to_s %></td>
+ <td><%= user.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ <td><%= user.last_logon.strftime("%I:%M %p %d-%b-%y") if user.last_logon %></td>
+ <td><%= link_to_user_actions user %></td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
\ No newline at end of file
diff --git a/source/app/views/users/edit.rhtml b/source/app/views/users/edit.rhtml
new file mode 100644
index 0000000..597f3c7
--- /dev/null
+++ b/source/app/views/users/edit.rhtml
@@ -0,0 +1,13 @@
+<% @heading = 'Edit User Details' %>
+<% @overview = "Use the form below to edit details of user #{link_to_user(@user)}" %>
+
+<%= error_messages_for 'user' %>
+
+<% tabular_form_for :user do |f| %>
+ <%= f.text_field :name, :size => 30 %>
+ <tr>
+ <th align="right">Notifications</th>
+ <td><%= check_box("user", "notify_daily") %> Daily <%= check_box("user", "notify_weekly") %> Weekly <%= check_box("user", "notify_monthly") %> Monthly</td>
+ </tr>
+ <tr><th></th><td><%= submit_tag "Submit" %></td></tr>
+<% end %>
\ No newline at end of file
diff --git a/source/app/views/users/list.rhtml b/source/app/views/users/list.rhtml
new file mode 100644
index 0000000..c7d6e7d
--- /dev/null
+++ b/source/app/views/users/list.rhtml
@@ -0,0 +1,7 @@
+<% @heading = 'Users' %>
+
+<div class="sectionHeading">Administrators</div>
+<%= render_partial 'list', @admins %>
+
+<div class="sectionHeading">Users</div>
+<%= render_partial 'list', @users %>
\ No newline at end of file
diff --git a/source/app/views/users/show.rhtml b/source/app/views/users/show.rhtml
new file mode 100644
index 0000000..52e8d04
--- /dev/null
+++ b/source/app/views/users/show.rhtml
@@ -0,0 +1,129 @@
+<% @heading = "User: #{@user.name}" %>
+<% @overview = "User details of user #{@user.name}" %>
+
+
+<% if mine?(@user) || cadmin? %>
+<div id="menu">
+ <%= link_to('edit', :action => 'edit', :id => @user.id) %>
+ <% if cadmin? %>
+ | <%= link_to 'list', :action => 'list' %>
+ | <%= link_to 'resend password', :action => 'resend', :id => @user.id %>
+ <% else %>
+ | <%= link_to 'change password', :controller => 'login', :action => 'change_password' %>
+ <% end %>
+</div>
+<% end %>
+
+<p>
+<%= tabs([["Versions", url_for(:action => 'show', :id => @user.id), (params[:action] == "show")],["Comments", url_for(:action=> 'show_comments', :id => @user.id), (params[:action] == "show_comments")]], 80) %>
+</p>
+
+<%= links_to_pages(@version_pages) if @version_pages %>
+<%= links_to_pages(@comment_pages) if @comment_pages %>
+
+<%= render(:partial => 'versions/versions_list') if @version_pages %>
+<%= render(:partial => 'comments/comments_list') if @comment_pages %>
+
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Uploads</th>
+ <td class="sectionTableCell">Images:
+ <ul><% for file in @user.images %>
+ <li><a href="../../<%= @user.images_path + '/' + file %>"><%= file %></a></li>
+ <% end %></ul>
+ </td>
+
+ <td class="sectionTableCell">Documents
+ <ul><% for file in @user.documents %>
+ <li><a href="../../<%= @user.documents_path + '/' + file %>"><%= file %></a></li>
+ <% end %></ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Sites</th>
+ <td class="sectionTableCell" colspan="2">This account was used in the following sites:
+ <ul><% for site in @user.sites %>
+ <li><%= link_to_site site %></li>
+ <% end %></ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Notifications</th>
+ <td class="sectionTableCell" colspan="2">
+ <ul><% for notification in @user.notifications %>
+ <li><%= link_to_notification(notification) %></li>
+ <% end %></ul>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+</div>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">ID</th>
+ <td align="left" class="sectionTableCell"><%= @user.id.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Name</th>
+ <td align="left" class="sectionTableCell"><%= @user.name %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Admin</th>
+ <td align="left" class="sectionTableCell"><%= @user.admin %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Email</th>
+ <td align="left" class="sectionTableCell"><%= @user.email %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Change Report</th>
+ <td align="left" class="sectionTableCell">
+ <p>Receive a change report via email:</p>
+ <%= link_to_change_report_notification_toggle('D') %> <%= link_to_change_report_notification_toggle('W') %> <%= link_to_change_report_notification_toggle('M') %>
+ <p>Send me a change report now:</p>
+ <%= link_to(image_tag("report", :border => 0, :title => 'Send now to me via email!') + " Changes of the last day", {:action => 'send_report', :type => 'D'}, :post => true) if mine?(@user) %>
+ <%= link_to(image_tag("report", :border => 0, :title => 'Send now to me via email!') + " Changes of the last week", { :action => 'send_report', :type => 'W'}, :post => true) if mine?(@user) %>
+ <%= link_to(image_tag("report", :border => 0, :title => 'Send now to me via email!') + " Changes of the last month", {:action => 'send_report', :type => 'M'}, :post => true) if mine?(@user) %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">IP Address</th>
+ <td align="left" class="sectionTableCell"><%= @user.ip_address %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Versions Created</th>
+ <td align="left" class="sectionTableCell"><%= @user.versions_count_excluding_baseversions %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Comments Created</th>
+ <td align="left" class="sectionTableCell"><%= @user.comments_count.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Logon Count</th>
+ <td align="left" class="sectionTableCell"><%= @user.logon_count.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created On</th>
+ <td align="left" class="sectionTableCell"><%= @user.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Last Logon On</th>
+ <td align="left" class="sectionTableCell"><%= @user.last_logon.strftime("%I:%M %p %d-%b-%y") if @user.last_logon %></td>
+ </tr>
+ </table>
+</div>
+
+
+
+
+
diff --git a/source/app/views/versions/_versions_list.rhtml b/source/app/views/versions/_versions_list.rhtml
new file mode 100644
index 0000000..6891c6b
--- /dev/null
+++ b/source/app/views/versions/_versions_list.rhtml
@@ -0,0 +1,35 @@
+ <div class="sectionHeading">Versions</div>
+ <div class="sectionContent">
+ <% if @versions %>
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ToDo</th>
+ <th>ID</th>
+ <th>Version</th>
+ <th>Created</th>
+ <th>Created By</th>
+ <th>Reviewer</th>
+ <th>Site</th>
+ </tr>
+ <% for version in @versions %>
+ <tr>
+ <td><%= link_to_done_toggle(version) %></td>
+ <td><%= version.id %></td>
+ <td><%= link_to_version2 version %></td>
+ <td><%= version.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ <td><%= link_to_user version.user %></td>
+ <td><%= link_to_reviewer version %></td>
+ <td><%= link_to_site version.site %></td>
+ </tr>
+ <% end %>
+ </table>
+ <% else %>
+ No versions found!
+ <% end %>
+ </td>
+ </tr>
+ </table>
+ </div>
\ No newline at end of file
diff --git a/source/app/views/versions/compare.rhtml b/source/app/views/versions/compare.rhtml
new file mode 100644
index 0000000..c16cd48
--- /dev/null
+++ b/source/app/views/versions/compare.rhtml
@@ -0,0 +1,117 @@
+<% @heading = 'Compare Versions' %>
+<% @overview = "This page shows changes between versions of #{link_to_page(@version.site, @version.page)}" %>
+
+<%= start_form_tag %>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <td class="sectionTableCell">
+ <table>
+ <tr valign="top">
+ <th width="200">Source Version</th>
+ <td>
+ <select id="source_version_id" name="source_version_id">
+ <%= options_from_collection_for_select @versions, 'id', 'version_text', @source_version.id %>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th>Target Version</th>
+ <td>
+ <select id="id" name="id">
+ <%= options_from_collection_for_select @versions, 'id', 'version_text', @version.id %>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <th></th>
+ <td><input type="submit" value="compare"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+<br>
+<%= end_form_tag %>
+
+<%= tabs([['Text', url_for(:action => 'compare', :new_version_id => @version.id, :source_version_id => @source_version.id), !params[:tab]],['HTML', url_for(:action=> 'compare', :new_version_id => @version.id, :source_version_id => @source_version.id, :tab => 'html'), (params[:tab] == 'html')]], 80) %>
+
+<% if @compare_results %>
+ <div class="sectionHeading">Differences Analysis</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0"
+ class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Old Version
+ </th>
+ <td class="sectionTableCell">
+ <%= link_to_version2 @source_version %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ New Version
+ </th>
+ <td class="sectionTableCell">
+ <%= link_to_version2 @version %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Differences
+ </th>
+ <td class="sectionTableCell">
+ <%= simple_format(@compare_results) %><br>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <div class="sectionHeading">Relationships</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0"
+ class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Page
+ </th>
+ <td class="sectionTableCell">
+ <%= link_to_page(@version.site, @version.page) %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Sites
+ </th>
+ <td class="sectionTableCell">
+ The page was changed in the following sites
+ <ul>
+ <% for site in @version.page.sites %>
+ <li>
+ <%= link_to_site site %> <%= link_to_versions site, @version.page %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Baselines
+ </th>
+ <td class="sectionTableCell">
+ The page was changed in the following baselines
+ <ul>
+ <% for baseline in @version.page.baselines %>
+ <li>
+ <%= link_to_baseline baseline, nil %>
+ </li>
+ <% end %>
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </div>
+<% end %>
+
+
diff --git a/source/app/views/versions/edit.rhtml b/source/app/views/versions/edit.rhtml
new file mode 100644
index 0000000..f5c0503
--- /dev/null
+++ b/source/app/views/versions/edit.rhtml
@@ -0,0 +1,8 @@
+<% @heading = "Version Note of #{@version.version_text}" %>
+<% @overview = "Use this form to edit the version note of #{link_to_version2(@version)}" %>
+<% tinymce %>
+
+<% tabular_form_for :version, @version do |f| %>
+ <%= f.text_area :note, :cols => 60, :rows => 8 %>
+ <tr><th></th><td><%= submit_tag 'Submit' %></td></tr>
+<% end %>
diff --git a/source/app/views/versions/list.rhtml b/source/app/views/versions/list.rhtml
new file mode 100644
index 0000000..2b7c999
--- /dev/null
+++ b/source/app/views/versions/list.rhtml
@@ -0,0 +1,56 @@
+<% @heading = "Version History of \"#{@page.presentation_name}\" in #{@site.title}" %>
+<% @overview = "This page displays the history of changes of #{link_to_page(@site, @page)} in site #{link_to_site(@site)}" %>
+
+<div id="menu">
+ <%= link_to('edit', {:controller => 'pages', :action=> 'checkout', :id=> @page.id, :site_id => @site.id} %>
+ | <%= link_to_notification_toggle(@site, @page, 'Version') %>
+</div>
+
+<div class="sectionHeading">Versions</div>
+<div class="sectionContent">
+ <% if @versions %>
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <table width="100%">
+ <tr>
+ <th>ID</th>
+ <th>Version</th>
+ <th>Note</th>
+ <th>Created</th>
+ <th>Created By</th>
+ <th>Baseline</th>
+ </tr>
+
+ <% for version in @versions %>
+ <tr><td><%= version.id %></td>
+ <td><%= link_to_version version, "Version" %></td>
+ <td><%= version.note %></td>
+ <td><%= version.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ <td><%= link_to_user version.user %></td>
+ <td><%= link_to_baseline version.baseline, @site %></td>
+ </tr>
+ <% end %>
+ </table>
+ <% else %>
+ No versions found!
+ <% end %>
+ </td>
+ </tr>
+ </table>
+</div>
+ <div class="sectionHeading">Relationships</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0"
+ class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">
+ Page
+ </th>
+ <td class="sectionTableCell" colspan=2>
+ <%= link_to_page(@site, @page) %>
+ </td>
+ </tr>
+ <%= render_partial("pages/relationships") %>
+ </table>
+ </div>
diff --git a/source/app/views/versions/listall.rhtml b/source/app/views/versions/listall.rhtml
new file mode 100644
index 0000000..4886ff4
--- /dev/null
+++ b/source/app/views/versions/listall.rhtml
@@ -0,0 +1,11 @@
+<% @overview = "This page displays the history of changes of all pages in all sites ordered by creation date, the most recent first.<br><br>" %>
+
+<br>
+<%= tabs([["All", url_for(:action => 'listall'), (@heading == "Versions")],["To Do", url_for(:action=> 'listtodo'), (@heading == "Versions To Do")], ["Done", url_for(:action=>'listdone'), (@heading == "Versions Done")],["Checkouts", url_for(:action=>'listcheckouts'), (@heading == "Checkouts")]], 70) if admin? %>
+<br>
+ <%= links_to_pages @version_pages %>
+<%= render :partial => 'versions_list' %>
+
+
+
+
diff --git a/source/app/views/versions/markdown.rhtml b/source/app/views/versions/markdown.rhtml
new file mode 100644
index 0000000..642f83a
--- /dev/null
+++ b/source/app/views/versions/markdown.rhtml
@@ -0,0 +1,15 @@
+<% @heading = 'Page as Plain Text' %>
+<% @overview = "This page show the page #{link_to_version2(@version)} in plain text format " %>
+
+<div class="sectionHeading">Text</div>
+
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+ <td class="sectionTableCell">
+ <%= simple_format(@version.markdown) %><br>
+ </td>
+</tr>
+</table>
+</div>
+
diff --git a/source/app/views/versions/show.rhtml b/source/app/views/versions/show.rhtml
new file mode 100644
index 0000000..5021960
--- /dev/null
+++ b/source/app/views/versions/show.rhtml
@@ -0,0 +1,150 @@
+<% @heading = "Version: #{@version.version_text}" %>
+<% @overview = "This page show the details of version #{link_to_version(@version, 'version')} of page #{link_to_page(@version.site, @version.page)}" %>
+
+<%= error_messages_for 'version' %>
+
+<div class="sectionHeading">Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+ <td class="sectionTableCell">
+ <%= @version.note %><br>
+ <% if mine?(@version) || cadmin? %>
+ [<%= link_to 'edit', :action => 'edit', :id => @version.id %>]
+ <% end %>
+ </td>
+</tr>
+</table>
+</div>
+
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Base Version</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_version @baseversion , 'version' if @baseversion %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Latest Version</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_version @latest_version, 'version' if @latest_version %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Current Version</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_version @current_version, 'version' if @current_version %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Source Version</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_version @source_version, 'version' if @source_version %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Previous Version</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_version @previous_version, 'version' if @previous_version %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Page</th>
+ <td align="left" class="sectionTableCell"><%= link_to_page @version.site, @version.page %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">User</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_user(@version.user) %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Reviewer</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_reviewer(@version) %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Done</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_done_toggle(@version) %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Marked "Done" By</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_user(@version.user_thatmarkeddone) if @version.user_thatmarkeddone %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Marked "ToDo" By</th>
+ <td align="left" class="sectionTableCell">
+ <%= link_to_user(@version.user_thatmarkedtodo) if @version.user_thatmarkedtodo %>
+ </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Site</th>
+ <td align="left" class="sectionTableCell"><%= link_to_site @version.site %> </td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Baseline</th>
+ <td align="left" class="sectionTableCell"><%= link_to_baseline(@version.baseline, nil) %> </td>
+ </tr>
+</table>
+</div>
+
+<div class="sectionHeading">Properties</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">ID</th>
+ <td align="left" class="sectionTableCell"><%= @version.id.to_s %></td>
+ </tr>
+ <tr valign="top">
+
+ <th scope="row" class="sectionTableHeading">Version</th>
+ <td align="left" class="sectionTableCell"><%= @version.version %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Path</th>
+ <td align="left" class="sectionTableCell"><%= @version.path %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">URL</th>
+ <td align="left" class="sectionTableCell"><%= link_to "http://#{request.host}/#{@version.rel_path_root}", "/#{@version.rel_path_root}" %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created On</th>
+ <td align="left" class="sectionTableCell"><%= @version.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Updated On</th>
+ <td align="left" class="sectionTableCell"><%= @version.updated_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+</table>
+</div>
+
+<% if @checkout %>
+<div class="sectionHeading">Checkout Properties</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">ID</th>
+ <td align="left" class="sectionTableCell"><%= @checkout.id.to_s %></td>
+ </tr>
+ <tr valign="top">
+ <th scope="row" class="sectionTableHeading">Created On</th>
+ <td align="left" class="sectionTableCell"><%= @checkout.created_on.strftime("%I:%M %p %d-%b-%y") %></td>
+ </tr>
+</table>
+</div>
+<% end %>
+
+
+
+
+
+
+
diff --git a/source/config/database.yml b/source/config/database.yml
new file mode 100644
index 0000000..ae3d3c8
--- /dev/null
+++ b/source/config/database.yml
@@ -0,0 +1,20 @@
+development:
+ adapter: mysql
+ database: epfwiki_dev
+ host: localhost
+ username: epfwiki
+ password: ikiwpur
+
+test:
+ adapter: mysql
+ database: epfwiki_test
+ host: localhost
+ username: epfwiki
+ password: ikiwpur
+
+production:
+ adapter: mysql
+ database: epfwiki
+ host: localhost
+ username: epfwiki
+ password: ikiwpur
\ No newline at end of file
diff --git a/source/config/environments/development.rb b/source/config/environments/development.rb
new file mode 100644
index 0000000..f38289b
--- /dev/null
+++ b/source/config/environments/development.rb
@@ -0,0 +1,49 @@
+# In the development environment your application's code is reloaded on
+# every request. This slows down response time but is perfect for development
+# since you don't have to restart the webserver when you make code changes.
+config.cache_classes = false
+
+# Log error messages when you accidentally call methods on nil.
+config.whiny_nils = true
+
+# Enable the breakpoint server that script/breakpointer connects to
+config.breakpoint_server = true
+
+# Show full error reports and disable caching
+#config.action_controller.consider_all_requests_local = true
+config.action_controller.consider_all_requests_local = false
+config.action_controller.perform_caching = true
+
+# Don't care if the mailer can't send
+config.action_mailer.raise_delivery_errors = false
+
+ENV['EPFWIKI_APP_NAME'] = "EPF Wiki - Development Environment"
+ENV['EPFWIKI_EDITOR'] = 'tinymce' # 'pinedit' or 'tinymce'
+ENV['EPFWIKI_ROOT_DIR'] = File.expand_path(RAILS_ROOT) + '/'
+ENV['EPFWIKI_HOST'] = "localhost:3000" # used for jobs, when there is no host variable in the environment
+ENV['EPFWIKI_SITES_FOLDER'] = 'development_sites'
+ENV['EPFWIKI_WIKIS_FOLDER'] = 'development_wikis'
+ENV['EPFWIKI_MARKDOWN_PATH'] = "#{ENV['EPFWIKI_ROOT_DIR']}/public/markdown/"
+ENV['EPFWIKI_DIFFS_PATH'] = "#{ENV['EPFWIKI_ROOT_DIR']}/public/diffs/"
+ENV['EPFWIKI_DIFF_TMP_DIR'] = 'C:/WINDOWS/Temp'
+ENV['EPFWIKI_DOMAINS'] = "@epf.org @openup.org" # specify to restrict valid emails to these domains. Uncomment to allow all.
+ENV['EPFWIKI_GENERATE_PASSWORDS'] = '0' # 0 to generate passwords or 1 to allow user to specify the password
+ENV['EPFWIKI_REPLY_ADDRESS'] = "no-reply@epfwiki.org"
+ENV['EPFWIKI_MARKDOWN_BAT_FILE'] = ENV['EPFWIKI_ROOT_DIR'] + "script/other/html2text.bat"
+ENV['EPFWIKI_TEMPLATES_DIR'] = "#{ENV['EPFWIKI_ROOT_DIR']}public/templates/"
+ENV['EPFWIKI_TIDY_PATH'] = ENV['EPFWIKI_ROOT_DIR'] + "lib/tidy/bin/tidy.dll"
+ENV['EPFWIKI_ANT_PATH'] = "C:/apache-ant-1.6.2/bin/ant"
+ENV['EPFWIKI_BACKUP_BAT_PATH'] = ENV['EPFWIKI_ROOT_DIR'] + "script/other/backup.bat"
+ENV['EPFWIKI_BACKUP_DIR'] = "C:/epfwiki_backup/"
+ENV['EPFWIKI_MYSQLDUMP_PATH'] = "U:/xampp150/xampp/mysql/bin/MYSQLDUMP"
+ENV['EPFWIKI_RELEASE_DIR'] = "C:/epfwiki_releases_uploaded/"
+ENV['EPFWIKI_UNZIP_RELEASE_BAT_FILE'] = ENV['EPFWIKI_ROOT_DIR'] + "script/other/unzip_release.bat"
+
+ActionMailer::Base.server_settings = {
+ :address => 'epfwiki.org',
+ :port => 25,
+ #:domain => ,
+ #:user_name => ,
+ #:password => ,
+ #:authentication => :login
+}
diff --git a/source/config/search.yml b/source/config/search.yml
new file mode 100644
index 0000000..479573e
--- /dev/null
+++ b/source/config/search.yml
@@ -0,0 +1,10 @@
+---
+search_backend: "simple"
+
+simple_backend:
+ index_filename: db/simple_search_index
+
+default_search_terms:
+ - search pages and comments
+
+
diff --git a/source/db/migrate/001_initial.rb b/source/db/migrate/001_initial.rb
new file mode 100644
index 0000000..198bce1
--- /dev/null
+++ b/source/db/migrate/001_initial.rb
@@ -0,0 +1,235 @@
+#--
+# ENH R1 database sessions (ActiveRecordStore instead of sessions stored in a flat file
+#++
+#
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# EPF_Wiki_Copyright[link:files/COPYRIGHT.html]
+
+class Initial < ActiveRecord::Migration
+ def self.up
+ create_table "baselines", :force => true do |t|
+ t.column "baseline", :string, :limit => 250, :default => "", :null => false
+ t.column "buildid", :string, :limit => 250, :default => "", :null => false
+ t.column "description", :text
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ end
+
+ add_index "baselines", ["baseline"], :name => "baseline", :unique => true
+
+ create_table "baselines_pages", :id => false, :force => true do |t|
+ t.column "baseline_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "page_id", :integer, :limit => 10
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ end
+
+ add_index "baselines_pages", ["baseline_id", "page_id"], :name => "baselines_pages_baseline_id_index", :unique => true
+
+ create_table "baselines_sites", :id => false, :force => true do |t|
+ t.column "site_id", :integer, :limit => 10
+ t.column "baseline_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ end
+
+ add_index "baselines_sites", ["site_id", "baseline_id"], :name => "baselines_sites_site_id_index", :unique => true
+
+ create_table "checkouts", :force => true do |t|
+ t.column "user_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "site_id", :integer, :limit => 10
+ t.column "page_id", :integer, :limit => 10
+ t.column "version_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "baseline_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ end
+
+ add_index "checkouts", ["user_id"], :name => "checkouts_user_id_index"
+ add_index "checkouts", ["page_id"], :name => "checkouts_page_id_index"
+ add_index "checkouts", ["version_id"], :name => "checkouts_version_id_index"
+ add_index "checkouts", ["baseline_id"], :name => "checkouts_baseline_id_index"
+ add_index "checkouts", ["site_id"], :name => "checkouts_site_id_index"
+
+ create_table "comments", :force => true do |t|
+ t.column "text", :text
+ t.column "ip_address", :string, :limit => 500
+ t.column "done", :string, :limit => 1, :default => "N", :null => false
+ t.column "user_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "page_id", :integer, :limit => 10
+ t.column "site_id", :integer, :limit => 10
+ t.column "version_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "baseline_id", :integer, :default => 0, :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ t.column "reviewer_id", :integer
+ t.column "user_id_markdone", :integer
+ t.column "user_id_marktodo", :integer
+ end
+
+ add_index "comments", ["page_id"], :name => "comments_page_id_index"
+ add_index "comments", ["site_id"], :name => "comments_site_id_index"
+ add_index "comments", ["user_id"], :name => "comments_user_id_index"
+ add_index "comments", ["version_id"], :name => "comments_version_id_index"
+ add_index "comments", ["baseline_id"], :name => "comments_baseline_id_index"
+
+ create_table "difference_analyses", :force => true do |t|
+ t.column "site_id", :integer, :limit => 10
+ t.column "site_id_from", :integer, :limit => 10
+ t.column "baseline_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "baseline_id_from", :integer, :limit => 10, :default => 0, :null => false
+ t.column "difference_analysis_items_count", :integer, :default => 0, :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ t.column "analyzed_on", :datetime
+ end
+
+ add_index "difference_analyses", ["site_id"], :name => "difference_analyses_site_id_index"
+ add_index "difference_analyses", ["site_id_from"], :name => "difference_analyses_site_id_from_index"
+ add_index "difference_analyses", ["baseline_id_from"], :name => "difference_analyses_baseline_id_from_index"
+ add_index "difference_analyses", ["baseline_id"], :name => "difference_analyses_baseline_id_index"
+
+ create_table "difference_analysis_items", :force => true do |t|
+ t.column "difference_analysis_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "page_id", :integer, :limit => 10
+ t.column "result", :string, :limit => 500, :default => "", :null => false
+ t.column "diff", :text
+ t.column "diff_html", :text
+ end
+
+ add_index "difference_analysis_items", ["page_id"], :name => "difference_analysis_items_page_id_index"
+ add_index "difference_analysis_items", ["difference_analysis_id"], :name => "difference_analysis_items_difference_analysis_id_index"
+
+ create_table "notifications", :force => true do |t|
+ t.column "page_id", :integer, :limit => 10
+ t.column "site_id", :integer, :limit => 10
+ t.column "user_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "notification_type", :string, :limit => 50, :default => "", :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ end
+
+ add_index "notifications", ["page_id"], :name => "notifications_page_id_index"
+ add_index "notifications", ["site_id"], :name => "notifications_site_id_index"
+ add_index "notifications", ["user_id"], :name => "notifications_user_id_index"
+
+ create_table "pages", :force => true do |t|
+ t.column "rel_path", :string, :limit => 767, :default => "", :null => false
+ t.column "presentation_name", :string, :limit => 500, :default => "", :null => false
+ t.column "content_type", :string, :limit => 100, :default => "", :null => false
+ t.column "filename", :string, :limit => 250, :default => "", :null => false
+ t.column "versions_count", :integer, :default => 0, :null => false
+ t.column "comments_count", :integer, :default => 0, :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ t.column "body_tag", :string, :limit => 1000
+ t.column "treebrowser_tag", :string, :limit => 1000
+ t.column "copyright_tag", :string, :limit => 1000
+ t.column "text", :text
+ end
+
+ add_index "pages", ["rel_path"], :name => "pages_rel_path_index", :unique => true
+
+ create_table "pages_sites", :id => false, :force => true do |t|
+ t.column "site_id", :integer, :limit => 10
+ t.column "page_id", :integer, :limit => 10
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ end
+
+ add_index "pages_sites", ["site_id", "page_id"], :name => "pages_sites_site_id_index", :unique => true
+
+ create_table "sites", :force => true do |t|
+ t.column "title", :string, :limit => 40, :default => "", :null => false
+ t.column "description", :text
+ t.column "site_type", :string, :limit => 1
+ t.column "baseline_id", :integer, :limit => 10
+ t.column "site_id_baseline_process", :integer, :limit => 10
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ t.column "html_files_count", :integer
+ t.column "wikifiable_files_count", :integer
+ t.column "user_id", :integer
+ t.column "content_scanned_on", :datetime
+ t.column "folder", :string, :limit => 200, :default => "", :null => false
+ end
+
+ add_index "sites", ["baseline_id"], :name => "sites_baseline_id_index"
+ add_index "sites", ["site_id_baseline_process"], :name => "sites_site_id_baseline_process_index"
+ add_index "sites", ["user_id"], :name => "sites_user_id_index"
+
+ create_table "users", :force => true do |t|
+ t.column "email", :string, :limit => 250, :default => "", :null => false
+ t.column "name", :string, :limit => 50, :default => "", :null => false
+ t.column "ip_address", :string, :limit => 20, :default => "", :null => false
+ t.column "hashed_password", :string, :limit => 40
+ t.column "hashed_password_new", :string, :limit => 40
+ t.column "admin", :string, :limit => 1, :default => "N", :null => false
+ t.column "notify_daily", :integer, :limit => 1, :default => 0, :null => false
+ t.column "notify_weekly", :integer, :limit => 1, :default => 0, :null => false
+ t.column "notify_monthly", :integer, :limit => 1, :default => 0, :null => false
+ t.column "site_id", :integer, :limit => 10
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ t.column "http_user_agent", :string, :limit => 250
+ t.column "logon_count", :integer, :limit => 5, :default => 0
+ t.column "logon_using_cookie_count", :integer, :limit => 5, :default => 0
+ t.column "last_logon", :datetime
+ t.column "confirmed_on", :datetime
+ end
+
+ add_index "users", ["email"], :name => "users_email_index", :unique => true
+ add_index "users", ["site_id"], :name => "users_site_id_index"
+
+ create_table "versions", :force => true do |t|
+ t.column "version", :integer, :limit => 3, :default => 0, :null => false
+ t.column "note", :text
+ t.column "done", :string, :limit => 1, :default => "N", :null => false
+ t.column "user_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "page_id", :integer, :limit => 10
+ t.column "site_id", :integer, :limit => 10
+ t.column "version_id", :integer, :limit => 10
+ t.column "baseline_id", :integer, :limit => 10, :default => 0, :null => false
+ t.column "created_on", :datetime
+ t.column "updated_on", :datetime
+ t.column "reviewer_id", :integer
+ t.column "user_id_markdone", :integer
+ t.column "user_id_marktodo", :integer
+ t.column "rel_path", :string, :limit => 1000, :default => "", :null => false
+ end
+
+ add_index "versions", ["version", "site_id", "page_id", "baseline_id"], :name => "versions_version_index", :unique => true
+ add_index "versions", ["user_id"], :name => "versions_user_id_index"
+ add_index "versions", ["page_id"], :name => "versions_page_id_index"
+ add_index "versions", ["site_id"], :name => "versions_site_id_index"
+ add_index "versions", ["version_id"], :name => "versions_version_id_index"
+ add_index "versions", ["baseline_id"], :name => "versions_baseline_id_index"
+ add_index "versions", ["reviewer_id"], :name => "versions_reviewer_id_index"
+ end
+
+ def self.down
+ drop_table "baselines_pages"
+ drop_table "baselines_sites"
+ drop_table "checkouts"
+ drop_table "comments"
+ drop_table "difference_analyses"
+ drop_table "difference_analysis_items"
+ drop_table "notifications"
+ drop_table "pages"
+ drop_table "pages_sites"
+ drop_table "sites"
+ drop_table "users"
+ drop_table "versions"
+ end
+end
diff --git a/source/doc.bat b/source/doc.bat
new file mode 100644
index 0000000..cecc23c
--- /dev/null
+++ b/source/doc.bat
@@ -0,0 +1,3 @@
+call rake stats > doc/stats.txt
+call rdoc -o doc/app --line-numbers --inline-source --title "EPF Wiki Application Documentation" doc/README_FOR_APP app CHANGELOG COPYRIGHT doc/DATAMODEL doc/INFRASTRUCTURE
+
diff --git a/source/doc/DATAMODEL b/source/doc/DATAMODEL
new file mode 100644
index 0000000..b1a6ecb
--- /dev/null
+++ b/source/doc/DATAMODEL
@@ -0,0 +1 @@
+link:../datamodel.png
\ No newline at end of file
diff --git a/source/doc/FEATURES b/source/doc/FEATURES
new file mode 100644
index 0000000..913860c
--- /dev/null
+++ b/source/doc/FEATURES
@@ -0,0 +1,175 @@
+= Features
+* <b>Browser Based HTML Editing</b>: edit existing pages or create new pages using a browser
+* <b>Edit/Info link</b>: to edit a page, simply click on the 'Edit/Info' link at the top of each page
+* <b>Linking pages</b>: links to pages can be created or edited using dialog boxes
+* <b>WYSIWYG or HTML editing</b>: choice of two HTML editors: 1) TinyMCE (open-source) or 2) PinEdit (commercial) and TinyMCE
+* <b>Wikis</b>: support for multiple Wikis with the possibility of sharing content between Wikis
+* <b>Revision Control</b>: all changes to pages are tracked, revisions can be retrieved, differences analyzed, who change what and when
+* <b>Access Control</b>: simple authorization mechanism based on two groups: administrators and users
+* <b>File attachments</b>: upload files (for instance templates, examples)
+* <b>Search</b>: full text search
+* <b>Managing users:</b> web based user registration and change of password
+* <b>Difference Analysis</b>: compare successive baseline processes (created with EPF): what is new, removed, changed, equal.
+
+== Browser Based HTML Editing
+
+Users can edit pages by checking out a page. This creates a working copy (version) of the page. Changes can be saved and are only visible to other users after checkin.
+* Implementation: Checkout
+* Testing: CheckoutTest, VersionTest, PagesControllerTest.test01_checkout
+
+Users can checkout to another Wiki.
+* Implementation: PagesController.checkout, Version.new_basedonversion
+* Testing: VersionTest.test03_checkout_to_other_wiki, PagesControllerTest.test10_checkout_to_another_site
+
+Users can create new pages based using predefined templates or any other page
+* Implementation: PagesController.new, Page, Checkout, Version.new_basedonversion
+* Testing: PagesControllerTest.test03_new_page_using_template, PagesControllerTest.test04_new_page_using_page
+
+From the editor users have the option of can save, checkin, preview or undo checkout
+* Implementation: PagesController.saveorcheckin, PagesController.undocheckout
+* Testing: PagesControllerTest.test05_save, PagesControllerTest.test06_checkin, PagesControllerTest.test07_checkin_new_pages, PagesControllerTest.test08_undocheckout
+
+User can rollback changes with a checkout and checkin of a previous version
+* Implementation: PagesController.checkout, PagesControlller.saveorcheckin
+* Testing: PagesControllerTest.test09_rollback
+
+The central admin can delete a page with its associated records
+* Implementation: PagesController.destroy
+
+
+== Edit/Info link
+Wikis (enhanced EPF sites) display an Edit/Info link. The Edit/Info link can be expanded. The collapsed link uses icons links to draw attention to important information.
+* Implementation: ToolbarController.expand_toggle
+* Testing: ToolbarControllerTest
+
+== Linking pages
+Users can link pages by copy past URL in a dialog box
+* Implementation: feature of HTML editor (TinyMCE or PinEdit)
+* Testing: tbd
+
+Users can link pages by selecting pages from a list
+* Implementation: PagesController.filelist (TODO)
+* Testing:
+
+== WYSIWYG or HTML editing
+Choice of two 1) TinyMCE or 2 PinEdit (commercial) and TinyMCE is controlled by environment variable ENV['EPFWIKI_EDITOR']
+* Implementation: PagesController.edithtml, Version.html
+* Testing: PagesControllerTest.test02_edithtml
+
+== Wikis
+
+Administrators can upload a zip file containing a published website created with EPF (or RMC)
+* Implementation: Site.unzip_upload, SitesController.upload
+* Testing: SiteTest.test01_unzip_upload,
+
+Administrators can define a baseline process with a EPF published site
+* Implementation: Site.new_site, Site.scan4content, SitesController.new, SitesController.scan4content,
+* Testing: SiteTest.test02_new_baseline_process, SitesControllerTest.test03_new
+
+Administrators can create a Wiki based on a baseline process (published site from EPF)
+* Implementation: Site.new_wiki, Site.wikify, SitesController.new_wiki,
+* Testing: SiteTest.test04_new_wiki, SiteTest.test04_wikify, SitesControllerTest.test04_new_wiki, SitesControllerTest.test05_new_wiki_post,
+
+Administrators can update a Wiki with a baseline process (published site from EPF)
+* Implementation: Site.validate_on_create, Site.update_wiki
+* Testing: SiteTest.test05_update_wiki, SitesControllerTest.test08_update_wiki
+
+For performance reasons there is an option of using scheduled jobs to perform actual wikifying.
+* Implementation: SitesController.update_wiki_now, SitesController.wikify_now
+* Testing: SitesControllerTest.test06_wikify_now, SitesControllerTest.test07_new_wiki_job_daily,
+
+It is possible to share content between difference Wikis
+* Implementation: PagesController.checkout
+* Testing: PagesControllerTest.test10_checkout_to_another_site
+
+== Revision Control
+
+Users can access version information of a version and add/update a version note
+* Implementation: VersionsController.show, VersionsController.edit
+* Testing: VersionsControllerTest.test01_show, VersionsControllerTest.test02_edit
+
+Admins (process engineers) can assign reviewer, mark versions reviewed ('done')
+* Implementation: VersionsController.review, VersionsController.toggle_done, ApplicationHelper.link_to_reviewer, ApplicationHelper.link_to_done_toggle
+* Testing: VersionsControllerTest.test03_review, VersionsControllerTest.test05_toggle_done
+
+Users can compare versions of a page
+* Implementation: VersionsController.compare, Version.markdown
+* Testing: VersionsControllerTest.test07_compare
+
+== Access Control
+
+After installation the first unauthenticated (!) user can create the central admin account
+* Implementation: User, Application.authenticate, LoginController.login, LoginController.new_cadmin
+* Testing: LoginControllerSetupTest.test01_signup_central_admin, LoginControllerTest.test01_signup_central_admin
+
+The central admin account can grant and revoke admin privileges
+* Implementation: UsersController.admin
+* Testing:
+
+The central admin can assign someone else as central admin
+* Implementation: UsersController.cadmin, User.cadmin
+* Testing:
+
+Admins can grant admin privileges
+* Implementation: UsersController.admin
+* Testing:
+
+== File attachments
+Users can upload documents and images to a user document or user images directory
+* Implementation: PagesController.upload
+* Testing: tbd
+
+== Search (TODO)
+Users can do a full text search for pages and comments
+Implementation: SearchController
+
+Admins can index content
+* Implementation: OtherController.run_indexer
+* Testing:
+
+Content can be indexed using a scheduled job
+* Implementation: feature of search_generator plugin
+
+== Managing users
+
+Users can sign up with a valid email account and by providing and confirming a password (accounts need to be confirmed via a link sent via email)
+* Implementation:
+* Testing: LoginControllerTest.test02_sign_up_with_pw, LoginControllerTest.test03_sign_up_without_pw, LoginControllerTest.test04_lost_password, SetupAndSignInTest.test02_sign_up
+
+User can sign up with a valid email account, a password is generated and sent via email
+* Implementation: User.validate_on_create, LoginController, UsersController
+* Testing: UserTest, SetupAndSignInTest.test02_sign_up
+
+Valid email accounts can be restriced to certain domains
+* Implementation: User.validate, LoginController.sign_up, ENV['EPFWIKI_DOMAINS']
+* Testing: SetupAndSignInTest.test02_sign_up
+
+== Difference Analysis
+
+The administrator can generate difference analysis data of changes in successive baseline processes
+* Implementation: DifferenceAnalysis, DifferenceAnalysisItem, DifferenceAnalysesController
+* Testing: DifferenceAnalysisTest
+
+Page information shows changes of the page between successive baseline processes (DifferenceAnalyisItem)
+* Implementation:
+* Testing:
+
+== Other
+
+'Central admin' can download log files
+* Implementation: OtherController.download_logfile
+* Testing:
+
+'Central admin' can migrate database if scripts are newer than the installed database
+* Implementation: OtherController.migrate
+* Testing:
+
+'Central admin' can do an online update of the application (update or rollback)
+* Implementation: OtherController.online_update
+* Testing:
+
+'Central admin' can upload a new application version
+* Implementation: OtherController.upload_release
+* Testing:
+
+
diff --git a/source/doc/INFRASTRUCTURE b/source/doc/INFRASTRUCTURE
new file mode 100644
index 0000000..50bc8f7
--- /dev/null
+++ b/source/doc/INFRASTRUCTURE
@@ -0,0 +1 @@
+link:../infrastructure.jpg
\ No newline at end of file
diff --git a/source/doc/README_FOR_APP b/source/doc/README_FOR_APP
new file mode 100644
index 0000000..a317339
--- /dev/null
+++ b/source/doc/README_FOR_APP
@@ -0,0 +1,140 @@
+= About EPF Wiki
+EPF Wiki is Wiki technology designed to be used together with Eclipse Process Framework (EPF). This offers the best of two distinct worlds: the worlds powerful process frameworks and Wikis. It offers an process engineering infrastructure that combines a modular method construction approach and the flexibility and ease of use that is the defining characteristic of a Wiki.
+
+EPF Wiki is an innovation that adds wiki functions to the hypertext process descriptions created with EPF.
+
+More information:
+* {Data model}[link:files/doc/DATAMODEL.html]
+* {EPF Wiki Infrastructure}[link:files/doc/INFRASTRUCTURE.html]
+* {Code Statistics}[link:../stats.txt]
+* {Change Log}[link:files/CHANGELOG.html]
+
+= Version
+* Application version: $VERSION$
+* Buildid: $BUILDID$
+
+= Features
+* <b>Browser Based HTML Editing</b>: edit existing pages or create new pages using a browser
+* <b>Edit/Info link</b>: to edit a page, simply click on the 'Edit/Info' link at the top of each page
+* <b>Linking pages</b>: links to pages can be created or edited using dialog boxes
+* <b>WYSIWYG or HTML editing</b>: choice of two HTML editors: 1) TinyMCE (open-source) or 2) PinEdit (commercial) and TinyMCE
+* <b>Wikis</b>: support for multiple Wikis with the possibility of sharing content between Wikis
+* <b>Revision Control</b>: all changes to pages are tracked, revisions can be retrieved, differences analyzed, who change what and when
+* <b>Access Control</b>: simple authorization mechanism based on two groups: administrators and users
+* <b>File attachments</b>: upload files (for instance templates, examples)
+* <b>Search</b>: full text search
+* <b>Managing users:</b> web based user registration and change of password
+* <b>Difference Analysis</b>: compare successive baseline processes (created with EPF): what is new, removed, changed, equal.
+
+= Requirements
+* Ruby 1.8.4
+* Ruby Gems 0.9.0
+* Rails 1.1.6
+* A database that is supported by Rails migrations
+* Ruby drivers for your database.
+* For best performance, you should have a web server running either Apache or Lighttpd along with FastCGI, you can use the built-in web server for low-volume testing
+* TinyMCE[http://tinymce.moxiecode.com] or PinEdit[http://pinedit.pintexx.com/] and TinyMCE
+* Python and the Python script <tt>html2text.py</tt>
+* CSDiff.exe
+* 1) PinEdit and TinyMCE or 2) TinyMCE
+* Apache Ant
+* Windows
+* acces to an SMTP server as users register using email
+
+
+= Installation
+
+Server installation consists of the following steps:
+
+1. Install Ruby and Ruby Gems
+2. Install Ruby On Rails
+3. Install Ruby Gems
+4. Generate RoR skeleton and extract downloaded epfwiki_R$VERSION$_$BUILDID$.zip
+5. Install Python & script html2text.py
+6. Edit config files: add database information and SMTP server
+7. Install EPF Wiki database schema
+8. Install HTML editor: PinEdit and/or TinyMCE
+9. Install diff tool: CSDiff
+10. path in dispatch.rb
+11. test the configuration
+
+<b>1. Install Ruby and Ruby Gems</b>
+
+Download and install Ruby from http://www2.ruby-lang.org/en/. Download and install Ruby Gems from http://www.rubygems.org/
+
+<b>2. Install Ruby On Rails</b>
+
+Open a command prompt, navigate to Ruby Gems directory (for instance C:\rubygems-0.9.0) and type <tt>gem install rails</tt>. If you are behind a proxy you can type for example <tt>gem install rails -p yourproxy</tt>
+
+For more information about gem install type <tt>gem help install</tt>
+
+<b>3. Install Ruby Gems</b>
+
+The following Ruby Gems are used:
+
+1. Tidy (tidy-1.1.2.gem[http://rubyforge.vm.bytemark.co.uk/gems/tidy-1.1.2.gem])
+2. MySQL (mysql-2.7.1-mswin32.gem[http://rubyforge.vm.bytemark.co.uk/gems/mysql-2.7.1-mswin32.gem])
+3. Search Generator (search_generator-0.5.1.gem[http://rubyforge.vm.bytemark.co.uk/gems/search_generator-0.5.1.gem])
+
+These can be installed with the following commands:
+- gem install tidy
+- gem install mysql
+- gem install search_generator
+
+Note: Ruby Gems can be installed using command <tt>gem install</tt> or can be installed manually by downloading the gems from http://gems.rubyforge.org/. Your proxy server can be specified using p switch, for more information type <tt>gem help install</tt>
+
+Note: the Tidy Gem is just a wrapper, the dll needs is a separate download. Download from http://tidy.sf.net and unzip to U:\ROR\epfwiki2\lib\tidy. The tidy folder should now contain three folders bin, include, lib. This location is specified by the environment variable EPFWIK_TIDY_PATH.
+
+<b>4. Generate RoR skeleton and extract downloaded epfwiki_R$VERSION$_$BUILDID$.zip</b>
+
+Generate a RoR skeleton using command <tt>rails epfwiki</tt>. Extra the contents of the zip file to the generate folder 'epfwiki', overwrite existing files.
+
+<b>5. Install Python & script html2text.py</b>
+
+Install Python 2.4 and html2text.py. html2text.py can be downloaded from http://www.aaronsw.com/2002/html2text/. Place this script in the directory script\other next to the file html2text.bat. To avoid Unicode encoding errors find the file <tt>site.py</tt> in the Python directory and set the encoding var to <tt>utf_8</tt> (look for 'encoding = ' in the file)
+
+So this version uses a Python script <tt>html2text.py</tt> to turn HTML into markdown text. This is used for difference analyses. The script is not part of this distribution and will in time be replaced by a Ruby alternative.
+
+<b>6. Edit config files: add database information and SMTP server</b>
+Create one or more databases (depending on the environments you want to setup: test, development and/or production). Edit the database configuration file (database.yml) and add the details of your database(s).
+
+For each environment (production, test, development) you want to use, edit the corresponding configuration file (in the config/environments folder). At a minimum you should specify the details of your SMTP server (address, port, domain)
+
+<b>7. Install EPF Wiki database schema</b>
+
+After creating the databases run the command <tt>rake migrate</tt> from your application root.
+
+<b>8. Install HTML editor: PinEdit and/or TinyMCE</b>
+
+_TinyMCE_
+1. Download TinyMCE from tinymce.moxiecode.com[http://tinymce.moxiecode.com/download.php]
+2. Extract the contents and copy the folder tinymce\jscripts\tiny_mce to [application install dir]\public\javascripts. The folder javascripts\tinymce should now contain Javascript library <tt>tiny_mce.js</tt>
+3. config.php
+For more information see http://www.busyashell.com/blog/articles/2006/06/23/using-tinymce-in-rails
+
+_PinEdit_
+1. Edit PinEdit config file (<tt>editor/config/config.js</tt>): at a minimum specify <tt>globalRootUrl</tt> and <tt>globalRootPath</tt>
+2. Edit <tt>public\editor\dialogs\php\upload.html</tt>, in <tt>beforeSubmit</tt> method set the action, for instance <tt>document.frmUpload.action = "../../../pages/upload?path=" + pathabs + "&insert=" + insert;</tt>
+
+<b>9. Install diff tool: CSDiff</b>
+
+Download CSDiff from http://www.componentsoftware.com/Products/CSDiff/download.htm. Note: this is only free software for single users. Extract the software to <tt>[RAILS_APP_ROOT]\script\other\CSDiff</tt>, for instance <tt>c:/epfwiki/script/other/CSDiff<tt>. Add the path to the 'path' environment variable.
+
+<b>10. path in dispatch.rb</b>
+
+Change the 'require' in <tt>dispatch.rb</tt> ('public' folder) to match the location of the application.
+
+<b>11. test the configuration</b>
+
+At this point it is possible to test the configuration by starting the built-in web server by running the command <tt>ruby script/server -b localhost -e development -p 3000</tt> and navigating to the location http://localhost:3000. This should now bring up the form for creating the first account (the central admininstrators account)
+
+= Copyright
+Copyright (c) 2006 LogicaCMG and others
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v10.html
+
+Contributors:
+* Onno van der Straaten:: initial implementation
\ No newline at end of file
diff --git a/source/doc/TODO b/source/doc/TODO
new file mode 100644
index 0000000..5bafb10
--- /dev/null
+++ b/source/doc/TODO
@@ -0,0 +1,33 @@
+= TODO
+
+<b>Browser Based HTML Editing</b>: edit existing pages or create new pages using a browser
+* Maybe offer more than two templates (Tool Mentor, Checklist) currently available?
+
+<b>Edit/Info link</b>: to edit a page, simply click on the ‘Edit/Info’ link at the top of each page
+* Floating toolbar is replaced with 'Edit/Info' link
+
+<b>Linking pages</b>: links to pages can be created or edited using dialog boxes
+* currently linking pages requires you to copy paste an URL in de dialog box.
+* Maybe this should be replaced for something more advanced, for instance select a page in the Wiki from a list.
+
+<b>WYSIWYG or HTML editing</b>: choice of two HTML editors: TinyMCE (open-source) and/or PinEdit (commercial)
+* TinyMCE support is present, but some extra work will be required to completely integrate TinyMCE, for instance to be able to upload documents from within TinyMCE. Also support for EPF editor should be added.
+
+<b>Wikis</b>: support for multiple Wikis with the possibility of sharing content between Wikis
+
+<b>Revision Control</b>: all changes to pages are tracked, revisions can be retrieved, differences
+* Current version uses non-EPL open source components CSDIFF and HTML2TEXT-script. The donated documentation has information on how to download and integrate these components. We have to find EPL alternatives for these components or code ourselves?
+
+<b>Access Control</b>: two groups: administrators and users
+* The access control is basic but suffices for now I think; maybe we need to provide something more advanced.
+
+<b>File attachments</b>: upload files (for instance templates, examples) using your browser
+* Uploads are supported from PinEdit but not from TinyMCE. There is no version control on uploads, I think it suffices for a first release.
+
+<b>Search</b>: full text search
+* Full text search is a beta feature we introduced; it basically works but still requires some work. The engine is a bit basic, maybe we can offer something more advanced.
+
+<b>Managing users</b>: web based user registration and change of password
+
+<b>Difference Analysis</b>: compare successive baseline processes (created with EPF): what is new, removed, changed, equal.
+* Basically works but maybe needs some more thought. Some changes should be ignored I think.
diff --git a/source/doc/datamodel.png b/source/doc/datamodel.png
new file mode 100644
index 0000000..3c2f85a
--- /dev/null
+++ b/source/doc/datamodel.png
Binary files differ
diff --git a/source/doc/infrastructure.jpg b/source/doc/infrastructure.jpg
new file mode 100644
index 0000000..a0faee1
--- /dev/null
+++ b/source/doc/infrastructure.jpg
Binary files differ
diff --git a/source/doc_feat.bat b/source/doc_feat.bat
new file mode 100644
index 0000000..ebab3a4
--- /dev/null
+++ b/source/doc_feat.bat
@@ -0,0 +1 @@
+rdoc -o doc/req --line-numbers --inline-source --title "EPF Wiki Features" doc/FEATURES doc/TODO test app COPYRIGHT
\ No newline at end of file
diff --git a/source/lib/generic.rb b/source/lib/generic.rb
new file mode 100644
index 0000000..aa504a3
--- /dev/null
+++ b/source/lib/generic.rb
@@ -0,0 +1,334 @@
+require 'digest/sha1'
+require 'logger'
+require 'ftools'
+require 'cgi'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+EPFWIKI_CSDIFF_PATH = "\"" + File.expand_path(RAILS_ROOT) + "/script/other/CSDiff/CSDiff.exe\""
+FLASH_RECORD_UPDATED = "Record updated!"
+FLASH_RECORD_CREATED = "Record created!"
+FLASH_RECORD_DELETED = "Record deleted!"
+FLASH_USE_POST_NOT_GET = 'The action does not allow a GET request, a POST request should be used'
+FLASH_NOT_OWNER = "This record was created by someone else, it can only be modified by the user that created it."
+
+MSG_EMAIL_SERVER_GENERATED = "**This message was generated by a server. Don't reply to this address.**"
+
+def create_cookie(theUser)
+ cookies[:epfwiki_id] = {:value => theUser.id.to_s, :expires => Time.now+31536000}
+ cookies[:epfwiki_token] = {:value => hash_pw(theUser.hashed_password),:expires => Time.now+31536000}
+end
+def expire_cookie
+ cookies.delete :epfwiki_id
+ cookies.delete :epfwiki_token
+end
+
+def notify_cadmin
+ Notifier::deliver_env_to(User.find_central_admin, session.instance_variable_get("@data"), params, request.env, nil)
+end
+
+def job_backup
+ buildid = buildid(Time.now)
+ #File.delete(ENV['EPFWIKI_BACKUP_DIR']) if File.exists?(ENV['EPFWIKI_BACKUP_DIR'])
+ File.makedirs(ENV['EPFWIKI_BACKUP_DIR'] + buildid )
+ params = Array.new
+ params << ENV['EPFWIKI_BACKUP_BAT_PATH'] #0: path to backup bat
+ params << buildid + ".zip" #1: zipname
+ params << ENV['EPFWIKI_BACKUP_BAT_PATH'].split(":")[0] #2: drive
+ params << ENV['EPFWIKI_BACKUP_DIR'] + buildid + "/" #3: backup dir
+ params << ENV['EPFWIKI_ANT_PATH'] #4: path to ant
+ params << ENV['EPFWIKI_ROOT_DIR'] #5: root dir of app
+ params << ENV['EPFWIKI_MYSQLDUMP_PATH'] #6: path to mysql
+ params << ActiveRecord::Base.configurations[RAILS_ENV]['database'] #7: database to backup
+ params << ActiveRecord::Base.configurations[RAILS_ENV]['username'] #8: username
+ params << ActiveRecord::Base.configurations[RAILS_ENV]['password'] #9: password
+ params << ENV['EPFWIKI_ROOT_DIR'].gsub("/","\\") #10: root dir of app
+ cmdline = params.join(" ")
+ path = ENV['EPFWIKI_BACKUP_DIR'] + buildid + "/" + buildid + ".zip"
+ #$stdout.print("Commandline: " + cmdline)
+ cmd = IO.popen(cmdline, "w+")
+ cmd.close_write
+ text = cmd.readlines.join.gsub(ActiveRecord::Base.configurations[RAILS_ENV]['password'], "********")
+ write_log("backup.log", text)
+ cmd.close_read
+ while !File.exists?(path)
+ sleep(3)
+ end
+ Notifier::deliver_email(User.find_central_admin, "Backup " + buildid + ".zip", [path], "<pre>" + text + "</pre>")
+end
+
+def job_monthly_report
+ Notifier::deliver_report(:type => 'M', :host => ENV['EPFWIKI_HOST'])
+end
+
+def job_weekly_report
+ Notifier::deliver_report(:type => 'W', :host => ENV['EPFWIKI_HOST'])
+end
+
+def job_daily_report
+ Notifier::deliver_report(:type => 'D', :host => ENV['EPFWIKI_HOST'])
+end
+
+def buildid(time)
+ return time.strftime("%Y%m%d_%H%M")
+end
+
+def email_addresses_4_report(users)
+ if users.class.to_s == "User"
+ return users.email
+ else
+ recipients = Array.new
+ for user in users
+ recipients = user.email if !recipients
+ recipients << user.email
+ end
+ return recipients
+ end
+end
+
+def diff_files(path, path2fromfile, path2diff, force = false)
+ force = !File.exists?(path2diff)
+ if !force
+ force = (File.mtime(path) > File.mtime(path2diff) || File.mtime(path2fromfile) > File.mtime(path))
+ end
+ if force
+ if File.compare(path2fromfile, path)
+ File.copy(path, path2diff)
+ else
+ logger.info("Generating diff file " + path2diff)
+ File.makedirs(ENV['EPFWIKI_DIFFS_PATH'])
+ # /Ohc:\HtmlOutput.htm /sC /t=4 U:\rupwiki\public\rupastxt\page_8.txt U:\rupwiki\public\rupastxt\page_5.txt BaseFile RevisedFile
+ cmd = EPFWIKI_CSDIFF_PATH + " /Oh" + path2diff + " /bD /sC /t=4 /q " + path2fromfile + " " + path + " BaseFile RevisedFile"
+ logger.info("Processing command: " + cmd )
+ File.delete(path2diff) if File.exists?(path2diff)
+ csdiffcommand = IO.popen(cmd, "w+")
+ csdiffcommand.close_write
+ logger.info("File generated by CSDiff, changing output!")
+ # TODO after sleeping some time log error and continue
+ while !File.exists?(path2diff)
+ sleep(3)
+ end
+ # we need to change the file a little bit, only interested in the html
+ lines = IO.readlines(path2diff)
+ aOutputFile = File.new(path2diff, "w")
+ doOut = false
+ lines.each do |aLine|
+ doOut = false if aLine.index("</pre>")
+ aOutputFile.puts(aLine) if doOut
+ doOut = true if aLine.index("<pre>") # new
+ end
+ aOutputFile.close
+ end
+ end
+ return IO.readlines(path2diff).join
+end
+
+def diff_markdown(aRecord, aFromRecord, force = false)
+ path2markdowndiff = path2markdowndiff(aRecord, aFromRecord)
+ html2markdownfile(aRecord.path, path2markdown(aRecord), force)
+ html2markdownfile(aFromRecord.path, path2markdown(aFromRecord), force)
+ diff_files(path2markdown(aRecord), path2markdown(aFromRecord), path2markdowndiff, force)
+ return IO.readlines(path2markdowndiff).join
+end
+
+#--
+# NOTE: CSDIFF has a thing about generating diffs for files with extension .html,
+# therefore we copy rename the file
+#++
+def diff(aRecord, aFromRecord, force = false)
+ logger.info("Diff of " + aRecord.path )
+ path2diff = path2diff(aRecord, aFromRecord)
+ File.copy(aRecord.path, aRecord.path + ".txt") if !File.exists?(aRecord.path + ".txt") || File.mtime(aRecord.path + ".txt") < File.mtime(aRecord.path) || force
+ File.copy(aFromRecord.path, aFromRecord.path + ".txt") if !File.exists?(aFromRecord.path + ".txt") || File.mtime(aFromRecord.path + ".txt") < File.mtime(aFromRecord.path) || force
+ diff_files(aRecord.path + ".txt", aFromRecord.path + ".txt", path2diff, force)
+ return IO.readlines(path2diff).join
+end
+
+def path2diff(aRecord, aFromRecord)
+ return ENV['EPFWIKI_DIFFS_PATH'] + aFromRecord.class.to_s.downcase + aFromRecord.id.to_s + "_to_" + aRecord.class.to_s.downcase + aRecord.id.to_s + ".html"
+end
+
+def path2markdowndiff(aRecord, aFromRecord = nil)
+ return ENV['EPFWIKI_DIFFS_PATH'] + aFromRecord.class.to_s.downcase + aFromRecord.id.to_s + "_to_" + aRecord.class.to_s.downcase + aRecord.id.to_s + "_markdown.html" if aFromRecord
+ return ENV['EPFWIKI_DIFFS_PATH'] + aRecord.class.to_s.downcase + aRecord.id.to_s + "_markdown.html"
+end
+
+def path2markdown(aRecord)
+ return ENV['EPFWIKI_MARKDOWN_PATH'] + aRecord.class.to_s.downcase + aRecord.id.to_s + ".txt"
+end
+
+#--
+# for #html2markdown the Python encoding setting is very important.
+# In site.py in c:\Python24\Lib set the encoding to utf_8. encoding = "utf_8".
+# The html content is utf-8
+#++
+def html2markdown(path2html)
+ cmd = ENV['EPFWIKI_MARKDOWN_BAT_FILE'] + " \"" + path2html+ "\" " + ENV['EPFWIKI_ROOT_DIR'].split(":")[0] + ": " + ENV['EPFWIKI_ROOT_DIR']
+ #logger.info("Generating markdown with command: " + cmd)
+ html2markdownCmd = IO.popen(cmd, "w+")
+ html2markdownCmd.close_write
+ line = html2markdownCmd.gets
+ markdown = Array.new
+ cnt = 1
+ while line
+ markdown << line if cnt > 4
+ line = html2markdownCmd.gets
+ cnt = cnt + 1
+ end
+ return markdown.join
+rescue
+ logger.info("Resque in html2markdown, notifying administrator")
+ notify_cadmin
+ return "N.A"
+ensure
+ html2markdownCmd.close if html2markdownCmd && !html2markdownCmd.closed?
+end
+
+def html2markdownfile(path2html, path2markdown, force = false)
+ # generate markdown if file does not exist or if markdown file is older than version file
+ if !File.exists?(path2markdown) || File.mtime(path2markdown) < File.mtime(path2html) || force
+ File.makedirs(ENV['EPFWIKI_MARKDOWN_PATH'])
+ # TODO a better solution than this bat file
+ markdown = html2markdown(path2html)
+ aOutputFile = File.new(path2markdown, "w")
+ aOutputFile.puts(markdown)
+ aOutputFile.close
+ end
+ return IO.readlines(path2markdown).join
+end
+
+def mine?(theRecord)
+ return (theRecord.id == session['user'].id) if (theRecord.class.to_s == "User")
+ return (theRecord.user_id == session['user'].id)
+end
+
+def admin?
+ return session['user'].admin? if session['user']
+ return false
+end
+
+def user?
+ return !session['user'].nil?
+end
+
+def cadmin?
+ return (session['user'].admin == "C") if session['user']
+ return false
+end
+
+# #remove_empty_lines all lines in a file, lines with only <tt># \r\n</tt>
+# created because PINEdit adds empty lines on each save?
+def remove_empty_lines(path)
+ someLines = IO.readlines(path)
+ outFile = File.new(path, "w")
+ someLines.each do |aLine|
+ outFile.puts(aLine) if !(aLine.gsub(" ","").chomp.length == 0)
+ end
+ outFile.close
+end
+
+def tidy_file(path)
+ require 'tidy'
+ Tidy.path = ENV['EPFWIKI_TIDY_PATH']
+ html = IO.readlines(path).join("\n")
+ xml = Tidy.open(:show_warnings=>true) do |tidy|
+ tidy.options.indent = 'auto' # auto won't indent title, li elements
+ tidy.options.quote_ampersand = false
+ tidy.options.output_encoding = 'utf8'
+ tidy.options.input_encoding = 'utf8'
+ tidy.options.char_encoding = 'utf8'
+ tidy.options.wrap = 0
+ tidy.options.quote_nbsp = 1
+ tidy.options.tidy_mark = 0
+ xml = tidy.clean(html)
+ xml
+ outFile = File.new(path, "w")
+ outFile.puts(xml)
+ outFile.close
+ end
+end
+
+def db_script_version(path2migratefolder)
+ files = Dir.entries(path2migratefolder) - [".", ".."]
+ version = 0
+ files.each { |file| version = file.split("_")[0].to_i if file.split("_")[0].to_i > version }
+ return version
+end
+
+def db_migrate_to_version(version = nil)
+ cmdline = "migrate.bat"
+ cmdline = "migrate.bat version=#{version}" if version
+ cmd = IO.popen(cmdline, "w+")
+ cmd.close_write
+ return cmd.readlines.join
+end
+
+def write_log(logfilename, content)
+ aOutputFile = File.new("#{ENV['EPFWIKI_ROOT_DIR']}log/#{logfilename}", "w")
+ aOutputFile.puts(content)
+ aOutputFile.close
+end
+
+def hash_pw(pw)
+ return Digest::SHA1.hexdigest(pw || '')
+end
+
+# ENV['EPFWIKI_HOST'] env variable is needed, because in a job we don't know the host
+def job_daily
+ @sites2update = Site.find_wikis_update
+ @cadmin = User.find_central_admin
+
+ Site.find_baseline_processes_2scan.each do |bp|
+ bp.scan4content
+ end
+
+ Site.find_wikis_pending.each do |wiki|
+ wiki.wikify
+ if wiki.save
+ Notifier::deliver_wiki_created(wiki,wiki.user)
+ else
+ raise 'wiki.wikify: ' + wiki.errors.full_messages.join(', ')
+ end
+ end
+
+ Site.find_wikis_update.each do |wiki|
+ if !wiki.checkouts.empty?
+ Notifier::deliver_update_site_checkin_request(wiki)
+ else
+ wiki.update_wiki
+ if wiki.save
+ Notifier::deliver_email([User.find_cental_admin],
+ "[#{ENV['EPFWIKI_APP_NAME']}] Site #{wiki.title} updated!",[],
+ "The wiki site <strong>#{wiki.title}</strong> was succesfully updated to baseline #{wiki.baseline.baseline}")
+ else
+ raise 'wiki.update_wiki ' + wiki.errors.full_messages.join(', ')
+ end
+ end
+ end
+
+ DifferenceAnalysis.find(:all, :conditions => 'analyzed_on is null').each do |difference_analysis|
+ difference_analysis.perform_analysis
+ if difference_analysis.save
+ Notifier::deliver_email(User.find_central_admin,
+ "Difference Analysis #{self.title} created", [],
+ "NEW: #{pages_new.size.to_s}, REMOVED: #{pages_removed.size.to_s}, EQUAL: #{pages_equal.size.to_s}" )
+ else
+ raise 'difference_analysis.perform_analysis' + difference_analysis.error.full_messages.join(', ')
+ end
+ end
+
+rescue => e
+ Notifier::deliver_email(User.find_central_admin, 'Error running job_daily', [], e.message + "\n" + e.backtrace.join("\n"))
+end
diff --git a/source/lib/search_system.rb b/source/lib/search_system.rb
new file mode 100644
index 0000000..b149d61
--- /dev/null
+++ b/source/lib/search_system.rb
@@ -0,0 +1,34 @@
+require_gem "SimpleSearch"
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class ActiveRecord::Base
+
+ def self.make_searchable(list_of_field_symbols)
+ @searchable_fields = list_of_field_symbols
+ end
+
+ def self.searchable_fields
+ @searchable_fields
+ end
+
+end
+
+class MockContents
+ def latest_mtime
+ Time.at(0)
+ end
+end
+
diff --git a/source/lib/validations.rb b/source/lib/validations.rb
new file mode 100644
index 0000000..730cf3c
--- /dev/null
+++ b/source/lib/validations.rb
@@ -0,0 +1,14 @@
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
diff --git a/source/public/404.html b/source/public/404.html
new file mode 100644
index 0000000..0e18456
--- /dev/null
+++ b/source/public/404.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body>
+ <h1>File not found</h1>
+ <p>Change this error message for pages not found in public/404.html</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/public/500.html b/source/public/500.html
new file mode 100644
index 0000000..a1001a0
--- /dev/null
+++ b/source/public/500.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<body>
+ <h1>Application error (Apache)</h1>
+ <p>Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/source/public/dispatch.fcgi b/source/public/dispatch.fcgi
new file mode 100644
index 0000000..5d9b8ec
--- /dev/null
+++ b/source/public/dispatch.fcgi
@@ -0,0 +1,24 @@
+#!c:/ruby/bin/ruby
+#
+# You may specify the path to the FastCGI crash log (a log of unhandled
+# exceptions which forced the FastCGI instance to exit, great for debugging)
+# and the number of requests to process before running garbage collection.
+#
+# By default, the FastCGI crash log is RAILS_ROOT/log/fastcgi.crash.log
+# and the GC period is nil (turned off). A reasonable number of requests
+# could range from 10-100 depending on the memory footprint of your app.
+#
+# Example:
+# # Default log path, normal GC behavior.
+# RailsFCGIHandler.process!
+#
+# # Default log path, 50 requests between GC.
+# RailsFCGIHandler.process! nil, 50
+#
+# # Custom log path, normal GC behavior.
+# RailsFCGIHandler.process! '/var/log/myapp_fcgi_crash.log'
+#
+require File.dirname(__FILE__) + "/../config/environment"
+require 'fcgi_handler'
+
+RailsFCGIHandler.process!
diff --git a/source/public/dispatch.rb b/source/public/dispatch.rb
new file mode 100644
index 0000000..4b89b01
--- /dev/null
+++ b/source/public/dispatch.rb
@@ -0,0 +1,11 @@
+#!c:/ruby/bin/ruby
+
+require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT)
+
+# If you're using RubyGems and mod_ruby, this require should be changed to an absolute path one, like:
+# "/usr/local/lib/ruby/gems/1.8/gems/rails-0.8.0/lib/dispatcher" -- otherwise performance is severely impaired
+# require "dispatcher"
+require "C:\ruby\lib\ruby\gems\1.8\gems\rails-0.14.2\lib\dispatcher"
+
+ADDITIONAL_LOAD_PATHS.reverse.each { |dir| $:.unshift(dir) if File.directory?(dir) } if defined?(Apache::RubyRun)
+Dispatcher.dispatch
\ No newline at end of file
diff --git a/source/public/favicon.ico b/source/public/favicon.ico
new file mode 100644
index 0000000..d8201cc
--- /dev/null
+++ b/source/public/favicon.ico
Binary files differ
diff --git a/source/public/images/arrow2.gif b/source/public/images/arrow2.gif
new file mode 100644
index 0000000..641c65a
--- /dev/null
+++ b/source/public/images/arrow2.gif
Binary files differ
diff --git a/source/public/images/back_to_top.gif b/source/public/images/back_to_top.gif
new file mode 100644
index 0000000..8fcd5a3
--- /dev/null
+++ b/source/public/images/back_to_top.gif
Binary files differ
diff --git a/source/public/images/baseline.png b/source/public/images/baseline.png
new file mode 100644
index 0000000..b0c761d
--- /dev/null
+++ b/source/public/images/baseline.png
Binary files differ
diff --git a/source/public/images/busy.gif b/source/public/images/busy.gif
new file mode 100644
index 0000000..1c5bc76
--- /dev/null
+++ b/source/public/images/busy.gif
Binary files differ
diff --git a/source/public/images/collapse.gif b/source/public/images/collapse.gif
new file mode 100644
index 0000000..3f6541f
--- /dev/null
+++ b/source/public/images/collapse.gif
Binary files differ
diff --git a/source/public/images/collapse_all.gif b/source/public/images/collapse_all.gif
new file mode 100644
index 0000000..38f7019
--- /dev/null
+++ b/source/public/images/collapse_all.gif
Binary files differ
diff --git a/source/public/images/comment2.png b/source/public/images/comment2.png
new file mode 100644
index 0000000..fc616b4
--- /dev/null
+++ b/source/public/images/comment2.png
Binary files differ
diff --git a/source/public/images/comment2_zw.png b/source/public/images/comment2_zw.png
new file mode 100644
index 0000000..19aea76
--- /dev/null
+++ b/source/public/images/comment2_zw.png
Binary files differ
diff --git a/source/public/images/compare.PNG b/source/public/images/compare.PNG
new file mode 100644
index 0000000..01e5e8d
--- /dev/null
+++ b/source/public/images/compare.PNG
Binary files differ
diff --git a/source/public/images/delete.png b/source/public/images/delete.png
new file mode 100644
index 0000000..225bb77
--- /dev/null
+++ b/source/public/images/delete.png
Binary files differ
diff --git a/source/public/images/down.png b/source/public/images/down.png
new file mode 100644
index 0000000..5e9ba7f
--- /dev/null
+++ b/source/public/images/down.png
Binary files differ
diff --git a/source/public/images/edit.gif b/source/public/images/edit.gif
new file mode 100644
index 0000000..d154c91
--- /dev/null
+++ b/source/public/images/edit.gif
Binary files differ
diff --git a/source/public/images/error.png b/source/public/images/error.png
new file mode 100644
index 0000000..b4fe06e
--- /dev/null
+++ b/source/public/images/error.png
Binary files differ
diff --git a/source/public/images/expand.gif b/source/public/images/expand.gif
new file mode 100644
index 0000000..2c0fe8f
--- /dev/null
+++ b/source/public/images/expand.gif
Binary files differ
diff --git a/source/public/images/expand_all.gif b/source/public/images/expand_all.gif
new file mode 100644
index 0000000..8a18a39
--- /dev/null
+++ b/source/public/images/expand_all.gif
Binary files differ
diff --git a/source/public/images/extlink.gif b/source/public/images/extlink.gif
new file mode 100644
index 0000000..bbc8b4e
--- /dev/null
+++ b/source/public/images/extlink.gif
Binary files differ
diff --git a/source/public/images/extlink2.gif b/source/public/images/extlink2.gif
new file mode 100644
index 0000000..e1a0eed
--- /dev/null
+++ b/source/public/images/extlink2.gif
Binary files differ
diff --git a/source/public/images/first_page.png b/source/public/images/first_page.png
new file mode 100644
index 0000000..6bd805a
--- /dev/null
+++ b/source/public/images/first_page.png
Binary files differ
diff --git a/source/public/images/first_page_disabled.png b/source/public/images/first_page_disabled.png
new file mode 100644
index 0000000..7de1a0e
--- /dev/null
+++ b/source/public/images/first_page_disabled.png
Binary files differ
diff --git a/source/public/images/format_txt.png b/source/public/images/format_txt.png
new file mode 100644
index 0000000..bf0de68
--- /dev/null
+++ b/source/public/images/format_txt.png
Binary files differ
diff --git a/source/public/images/info.png b/source/public/images/info.png
new file mode 100644
index 0000000..60bbc43
--- /dev/null
+++ b/source/public/images/info.png
Binary files differ
diff --git a/source/public/images/last_page.png b/source/public/images/last_page.png
new file mode 100644
index 0000000..a5f0452
--- /dev/null
+++ b/source/public/images/last_page.png
Binary files differ
diff --git a/source/public/images/last_page_disabled.png b/source/public/images/last_page_disabled.png
new file mode 100644
index 0000000..70187f8
--- /dev/null
+++ b/source/public/images/last_page_disabled.png
Binary files differ
diff --git a/source/public/images/new.png b/source/public/images/new.png
new file mode 100644
index 0000000..c661bbc
--- /dev/null
+++ b/source/public/images/new.png
Binary files differ
diff --git a/source/public/images/next_page.png b/source/public/images/next_page.png
new file mode 100644
index 0000000..f1122d4
--- /dev/null
+++ b/source/public/images/next_page.png
Binary files differ
diff --git a/source/public/images/next_page_disabled.png b/source/public/images/next_page_disabled.png
new file mode 100644
index 0000000..dbb8348
--- /dev/null
+++ b/source/public/images/next_page_disabled.png
Binary files differ
diff --git a/source/public/images/notice.png b/source/public/images/notice.png
new file mode 100644
index 0000000..2e53447
--- /dev/null
+++ b/source/public/images/notice.png
Binary files differ
diff --git a/source/public/images/previous_page.png b/source/public/images/previous_page.png
new file mode 100644
index 0000000..895de55
--- /dev/null
+++ b/source/public/images/previous_page.png
Binary files differ
diff --git a/source/public/images/previous_page_disabled.png b/source/public/images/previous_page_disabled.png
new file mode 100644
index 0000000..7b355df
--- /dev/null
+++ b/source/public/images/previous_page_disabled.png
Binary files differ
diff --git a/source/public/images/progress.gif b/source/public/images/progress.gif
new file mode 100644
index 0000000..f3b5688
--- /dev/null
+++ b/source/public/images/progress.gif
Binary files differ
diff --git a/source/public/images/report.png b/source/public/images/report.png
new file mode 100644
index 0000000..9c31fef
--- /dev/null
+++ b/source/public/images/report.png
Binary files differ
diff --git a/source/public/images/sendpassword.png b/source/public/images/sendpassword.png
new file mode 100644
index 0000000..686555c
--- /dev/null
+++ b/source/public/images/sendpassword.png
Binary files differ
diff --git a/source/public/images/shim.gif b/source/public/images/shim.gif
new file mode 100644
index 0000000..0aba790
--- /dev/null
+++ b/source/public/images/shim.gif
Binary files differ
diff --git a/source/public/images/site.png b/source/public/images/site.png
new file mode 100644
index 0000000..8f41c91
--- /dev/null
+++ b/source/public/images/site.png
Binary files differ
diff --git a/source/public/images/site_large.png b/source/public/images/site_large.png
new file mode 100644
index 0000000..745b9ed
--- /dev/null
+++ b/source/public/images/site_large.png
Binary files differ
diff --git a/source/public/images/success.png b/source/public/images/success.png
new file mode 100644
index 0000000..96fcfea
--- /dev/null
+++ b/source/public/images/success.png
Binary files differ
diff --git a/source/public/images/tab/shim.gif b/source/public/images/tab/shim.gif
new file mode 100644
index 0000000..0aba790
--- /dev/null
+++ b/source/public/images/tab/shim.gif
Binary files differ
diff --git a/source/public/images/tab/tab_end-a.gif b/source/public/images/tab/tab_end-a.gif
new file mode 100644
index 0000000..08cc5e6
--- /dev/null
+++ b/source/public/images/tab/tab_end-a.gif
Binary files differ
diff --git a/source/public/images/tab/tab_end-i.gif b/source/public/images/tab/tab_end-i.gif
new file mode 100644
index 0000000..375447f
--- /dev/null
+++ b/source/public/images/tab/tab_end-i.gif
Binary files differ
diff --git a/source/public/images/tab/tab_middle-a_i.gif b/source/public/images/tab/tab_middle-a_i.gif
new file mode 100644
index 0000000..4079557
--- /dev/null
+++ b/source/public/images/tab/tab_middle-a_i.gif
Binary files differ
diff --git a/source/public/images/tab/tab_middle-i_a.gif b/source/public/images/tab/tab_middle-i_a.gif
new file mode 100644
index 0000000..b49867f
--- /dev/null
+++ b/source/public/images/tab/tab_middle-i_a.gif
Binary files differ
diff --git a/source/public/images/tab/tab_middle-i_i.gif b/source/public/images/tab/tab_middle-i_i.gif
new file mode 100644
index 0000000..de87b0d
--- /dev/null
+++ b/source/public/images/tab/tab_middle-i_i.gif
Binary files differ
diff --git a/source/public/images/tab/tab_space.gif b/source/public/images/tab/tab_space.gif
new file mode 100644
index 0000000..84a98db
--- /dev/null
+++ b/source/public/images/tab/tab_space.gif
Binary files differ
diff --git a/source/public/images/tab/tab_space_middle.gif b/source/public/images/tab/tab_space_middle.gif
new file mode 100644
index 0000000..9ba9ba9
--- /dev/null
+++ b/source/public/images/tab/tab_space_middle.gif
Binary files differ
diff --git a/source/public/images/up.png b/source/public/images/up.png
new file mode 100644
index 0000000..277f496
--- /dev/null
+++ b/source/public/images/up.png
Binary files differ
diff --git a/source/public/images/userC.gif b/source/public/images/userC.gif
new file mode 100644
index 0000000..5fd935e
--- /dev/null
+++ b/source/public/images/userC.gif
Binary files differ
diff --git a/source/public/images/userC.png b/source/public/images/userC.png
new file mode 100644
index 0000000..8ed7283
--- /dev/null
+++ b/source/public/images/userC.png
Binary files differ
diff --git a/source/public/images/userN.gif b/source/public/images/userN.gif
new file mode 100644
index 0000000..5037f65
--- /dev/null
+++ b/source/public/images/userN.gif
Binary files differ
diff --git a/source/public/images/userN.png b/source/public/images/userN.png
new file mode 100644
index 0000000..fc43d37
--- /dev/null
+++ b/source/public/images/userN.png
Binary files differ
diff --git a/source/public/images/userY.gif b/source/public/images/userY.gif
new file mode 100644
index 0000000..87c10f6
--- /dev/null
+++ b/source/public/images/userY.gif
Binary files differ
diff --git a/source/public/images/userY.png b/source/public/images/userY.png
new file mode 100644
index 0000000..2299f1d
--- /dev/null
+++ b/source/public/images/userY.png
Binary files differ
diff --git a/source/public/images/version.png b/source/public/images/version.png
new file mode 100644
index 0000000..91f3ddc
--- /dev/null
+++ b/source/public/images/version.png
Binary files differ
diff --git a/source/public/images/version_zw.png b/source/public/images/version_zw.png
new file mode 100644
index 0000000..90eb9d1
--- /dev/null
+++ b/source/public/images/version_zw.png
Binary files differ
diff --git a/source/public/images/warning.png b/source/public/images/warning.png
new file mode 100644
index 0000000..b81b2ce
--- /dev/null
+++ b/source/public/images/warning.png
Binary files differ
diff --git a/source/public/javascripts/contentpage.js b/source/public/javascripts/contentpage.js
new file mode 100644
index 0000000..3828aff
--- /dev/null
+++ b/source/public/javascripts/contentpage.js
@@ -0,0 +1,242 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2005, 2006 IBM Corporation and others.
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Contributors:
+// IBM Corporation - initial implementation
+//------------------------------------------------------------------------------
+
+var collapseSectionsByDefault = false;
+var firstSection;
+var expandImage;
+var collapseImage;
+var expandAllImage;
+var collapseAllImage;
+var backToTopImage;
+var shimImage;
+var expandMessage = "Expand All Sections";
+var collapseMessage = "Collapse All Sections";
+var backMessage = "Back to top";
+
+// Creates the collapsible section links.
+function createSectionLinks(tagName, classSelector, imgPath) {
+ expandImage = imgPath + 'expand.gif';
+ collapseImage = imgPath + 'collapse.gif';
+ expandAllImage = imgPath + 'expand_all.gif';
+ collapseAllImage = imgPath + 'collapse_all.gif';
+ backToTopImage = imgPath + 'back_to_top.gif';
+ shimImage = imgPath + 'shim.gif';
+
+ if (document.getElementsByTagName) {
+ var elements = document.getElementsByTagName(tagName);
+ var sectionElements = new Array(elements.length);
+ var totalLinks = 0;
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ if (element.className == classSelector) {
+ sectionElements[totalLinks++] = element;
+ }
+ }
+ sectionElements.length = totalLinks;
+ sectionCollapseDivs = new Array(totalLinks);
+ sectionCollapseLinks = new Array(totalLinks);
+ firstSection = sectionElements[0];
+ for (var i = 0; i < sectionElements.length; i++) {
+ var element = sectionElements[i];
+ var siblingContainer;
+ if (document.createElement && (siblingContainer = document.createElement('div')) && siblingContainer.style) {
+ var nextSibling = element.nextSibling;
+ element.parentNode.insertBefore(siblingContainer, nextSibling);
+ var nextElement = sectionElements[i + 1];
+ while (nextSibling != nextElement && nextSibling != null && nextSibling.className != 'copyright') {
+ var toMove = nextSibling;
+ nextSibling = nextSibling.nextSibling;
+ siblingContainer.appendChild(toMove);
+ }
+ if (collapseSectionsByDefault) {
+ siblingContainer.style.display = 'none';
+ }
+ sectionCollapseDivs[i] = siblingContainer;
+ createCollapsibleSection(element, siblingContainer, i);
+ }
+ else {
+ return;
+ }
+ }
+ createExpandCollapseAllSectionsLinks(sectionElements[0]);
+ }
+}
+
+// Creates a collapsible section.
+function createCollapsibleSection(element, siblingContainer, index) {
+ if (document.createElement) {
+ // Add a spacing between the sections.
+ var sectionSeparator = document.createElement('img');
+ sectionSeparator.src = shimImage;
+ sectionSeparator.height = '3';
+ sectionSeparator.border = '0';
+ sectionSeparator.align = 'absmiddle';
+ element.parentNode.insertBefore(sectionSeparator, element);
+
+ // Add a expand/collapse link to the section heading.
+ var span = document.createElement('span');
+ var link = document.createElement('a');
+ link.collapseDiv = siblingContainer;
+ link.href = '#';
+ var image = document.createElement('img');
+ if (collapseSectionsByDefault) {
+ image.src = expandImage;
+ }
+ else {
+ image.src = collapseImage;
+ }
+ image.width = '17';
+ image.height = '15';
+ image.border = '0';
+ image.align = 'absmiddle';
+ link.appendChild(image);
+ link.onclick = expandCollapseSection;
+ sectionCollapseLinks[index] = link;
+ span.appendChild(link);
+ element.insertBefore(span, element.firstChild);
+ element.appendChild(document.createTextNode(String.fromCharCode(160)));
+ element.appendChild(document.createTextNode(String.fromCharCode(160)));
+
+ // Add a Back To Top link in the section heading.
+ createBackToTopLink(siblingContainer);
+ }
+}
+
+// Creates a Back to top link.
+function createBackToTopLink(element) {
+ var div;
+
+ if (document.createElement && (div = document.createElement('div'))) {
+ div.className = 'backToTopLink';
+ div.align = 'right';
+ var image = document.createElement('img');
+ image.src = backToTopImage;
+ image.width = '16';
+ image.height = '16';
+ image.border = '0';
+ image.align = 'absmiddle';
+ var link = document.createElement('a');
+ link.className = 'backToTopLink';
+ link.href = '#';
+ link.appendChild(image);
+ var span = document.createElement('span');
+ span.className = 'backToTopLink';
+ span.appendChild(document.createTextNode(backMessage));
+ link.appendChild(span);
+ div.appendChild(link);
+ element.appendChild(div);
+ }
+}
+
+// Expands or collapses a section based on the received event.
+function expandCollapseSection(evt) {
+ if (this.collapseDiv.style.display == '') {
+ this.parentNode.parentNode.nextSibling.style.display = 'none';
+ this.firstChild.src = expandImage;
+ }
+ else {
+ this.parentNode.parentNode.nextSibling.style.display = '';
+ this.firstChild.src = collapseImage;
+ }
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+}
+
+// Creates the Expand All and Collapse All Sections links.
+function createExpandCollapseAllSectionsLinks(firstElement) {
+ var div;
+
+ if (document.createElement && (div = document.createElement('div'))) {
+ div.className = 'expandCollapseLink';
+ div.align = 'right';
+ var image = document.createElement('img');
+ image.src = expandAllImage;
+ image.width = '16';
+ image.height = '16';
+ image.border = '0';
+ image.align = 'absmiddle';
+ var link = document.createElement('a');
+ link.className = 'expandCollapseLink';
+ link.href = '#';
+ link.appendChild(image);
+ link.onclick = expandAll;
+ var span = document.createElement('span');
+ span.className = 'expandCollapseText';
+ span.appendChild(document.createTextNode(expandMessage));
+ link.appendChild(span);
+ div.appendChild(link);
+ div.appendChild(document.createTextNode(String.fromCharCode(160)));
+ div.appendChild(document.createTextNode(String.fromCharCode(160)));
+ div.appendChild(document.createTextNode(String.fromCharCode(160)));
+ div.appendChild(document.createTextNode(String.fromCharCode(160)));
+
+ image = document.createElement('img');
+ image.src = collapseAllImage;
+ image.width = '16';
+ image.height = '16';
+ image.border = '0';
+ image.align = 'absmiddle';
+ link = document.createElement('a');
+ link.className = 'expandCollapseLink';
+ link.href = '#';
+ link.appendChild(image);
+ link.onclick = collapseAll;
+ span = document.createElement('span');
+ span.className = 'expandCollapseText';
+ span.appendChild(document.createTextNode(collapseMessage));
+ link.appendChild(span);
+ div.appendChild(link);
+
+ /*
+ var overviewSeparator = document.getElementById("overviewSeparator");
+ overviewSeparator.parentNode.insertBefore(div, overviewSeparator);
+ */
+ if (firstSection != null) {
+ firstSection.parentNode.insertBefore(div, firstSection);
+ }
+ }
+}
+
+// Expands all sections.
+function expandAll(evt) {
+ for (var i = 0; i < sectionCollapseDivs.length; i++) {
+ sectionCollapseDivs[i].style.display = '';
+ sectionCollapseLinks[i].firstChild.src = collapseImage;
+ }
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+}
+
+// Collapses all sections.
+function collapseAll(evt) {
+ for (var i = 0; i < sectionCollapseDivs.length; i++) {
+ sectionCollapseDivs[i].style.display = 'none';
+ sectionCollapseLinks[i].firstChild.src = expandImage;
+ }
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+}
+
+// This temporary function helps to resolve Javascript errors in the migrated RUP
+// content pages. It will be removed once the corresponding .js files are being
+// migrated along with the HTML content pages.
+function ReferenceHelpTopic (topicName, book , fileName) {
+ document.write("<i>"+ topicName + "<\/i>");
+}
+
+
+
diff --git a/source/public/javascripts/steps.js b/source/public/javascripts/steps.js
new file mode 100644
index 0000000..128083d
--- /dev/null
+++ b/source/public/javascripts/steps.js
@@ -0,0 +1,176 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2005, 2006 IBM Corporation and others.
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Contributors:
+// IBM Corporation - initial implementation
+//------------------------------------------------------------------------------
+
+var collapseStepsByDefault = true;
+var stepImgBackPath = '../../';
+var expandAllText = "Expand All Steps";
+var collapseAllText = "Collapse All Steps";
+var firstStepSection;
+
+// Creates the collapsible step section links.
+function createStepLinks(tagName, classSelector) {
+ if (document.getElementsByTagName) {
+ var elements = document.getElementsByTagName(tagName);
+ if (elements.length == 0) return;
+ var stepElements = new Array(elements.length);
+ var totalLinks = 0;
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ if (element.className == classSelector) {
+ stepElements[totalLinks++] = element;
+ }
+ }
+ if (totalLinks == 0) return;
+ stepElements.length = totalLinks;
+ stepCollapseDivs = new Array(totalLinks);
+ stepCollapseLinks = new Array(totalLinks);
+ firstStepSection = stepElements[0];
+ for (var i = 0; i < stepElements.length; i++) {
+ var element = stepElements[i];
+ var siblingContainer;
+ if (document.createElement && (siblingContainer = document.createElement('div')) && siblingContainer.style) {
+ var nextSibling = element.nextSibling;
+ element.parentNode.insertBefore(siblingContainer, nextSibling);
+ var nextElement = stepElements[i + 1];
+ while (nextSibling != nextElement && nextSibling != null) {
+ var toMove = nextSibling;
+ nextSibling = nextSibling.nextSibling;
+ siblingContainer.appendChild(toMove);
+ }
+ if (collapseStepsByDefault) {
+ siblingContainer.style.display = 'none';
+ }
+ siblingContainer.style.display = 'none';
+ stepCollapseDivs[i] = siblingContainer;
+ createCollapsibleStepSection(element, siblingContainer, i);
+ }
+ else {
+ return;
+ }
+ }
+ createExpandCollapseAllStepsLinks(stepElements[0]);
+ }
+}
+
+// Creates a collapsible step section.
+function createCollapsibleStepSection(element, siblingContainer, index) {
+ if (document.createElement) {
+ var span = document.createElement('span');
+ var link = document.createElement('a');
+ link.collapseDiv = siblingContainer;
+ link.href = '#';
+ var image = document.createElement('img');
+ if (collapseStepsByDefault) {
+ image.src = expandImage;
+ }
+ else {
+ image.src = collapseImage;
+ }
+ image.width = '17';
+ image.height = '15';
+ image.border = '0';
+ image.align = 'absmiddle';
+ link.appendChild(image);
+ link.onclick = expandCollapseStepSection;
+ stepCollapseLinks[index] = link;
+ span.appendChild(link);
+ element.insertBefore(span, element.firstChild);
+ element.appendChild(document.createTextNode(String.fromCharCode(160)));
+ element.appendChild(document.createTextNode(String.fromCharCode(160)));
+ }
+}
+
+// Expands or collapses a step section based on the received event.
+function expandCollapseStepSection(evt) {
+ if (this.collapseDiv.style.display == '') {
+ this.parentNode.parentNode.nextSibling.style.display = 'none';
+ this.firstChild.src = expandImage;
+ }
+ else {
+ this.parentNode.parentNode.nextSibling.style.display = '';
+ this.firstChild.src = collapseImage;
+ }
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+}
+
+// Creates the Expand All and Collapse All Steps links.
+function createExpandCollapseAllStepsLinks(firstElement) {
+ var div;
+ if (document.createElement && (div = document.createElement('div'))) {
+ div.className = 'expandCollapseLink';
+ div.align = 'right';
+ var image = document.createElement('img');
+ image.src = expandAllImage;
+ image.width = '16';
+ image.height = '16';
+ image.border = '0';
+ image.align = 'absmiddle';
+ var link = document.createElement('a');
+ link.className = 'expandCollapseLink';
+ link.href = '#';
+ link.appendChild(image);
+ link.onclick = expandAllSteps;
+ var span = document.createElement('span');
+ span.className = 'expandCollapseText';
+ span.appendChild(document.createTextNode(expandAllText));
+ link.appendChild(span);
+ div.appendChild(link);
+ div.appendChild(document.createTextNode(String.fromCharCode(160)));
+
+ image = document.createElement('img');
+ image.src = collapseAllImage;
+ image.width = '16';
+ image.height = '16';
+ image.border = '0';
+ image.align = 'absmiddle';
+ link = document.createElement('a');
+ link.className = 'expandCollapseLink';
+ link.href = '#';
+ link.appendChild(image);
+ link.onclick = collapseAllSteps;
+ span = document.createElement('span');
+ span.className = 'expandCollapseText';
+ span.appendChild(document.createTextNode(collapseAllText));
+ link.appendChild(span);
+ div.appendChild(link);
+
+ if (firstStepSection) {
+ firstStepSection.parentNode.insertBefore(div, firstStepSection);
+ }
+ }
+}
+
+// Expands all steps.
+function expandAllSteps(evt) {
+ for (var i = 0; i < stepCollapseDivs.length; i++) {
+ stepCollapseDivs[i].style.display = '';
+ stepCollapseLinks[i].firstChild.src = collapseImage;
+ }
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+}
+
+// Collapses all steps.
+function collapseAllSteps(evt) {
+ for (var i = 0; i < stepCollapseDivs.length; i++) {
+ stepCollapseDivs[i].style.display = 'none';
+ stepCollapseLinks[i].firstChild.src = expandImage;
+ }
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+}
diff --git a/source/public/javascripts/treebrowser.js b/source/public/javascripts/treebrowser.js
new file mode 100644
index 0000000..bf5e25f
--- /dev/null
+++ b/source/public/javascripts/treebrowser.js
@@ -0,0 +1,107 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2005, 2006 IBM Corporation and others.
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// which accompanies this distribution, and is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// Contributors:
+// IBM Corporation - initial implementation
+// Onno van der Straaten - changes for use with EPF Wiki
+//------------------------------------------------------------------------------
+
+// Here defines all the I18N specific messages used in the javascripts
+var treebrowser_js_MESSAGE1 = "The configuration is already displayed using views";
+var treebrowser_js_MESSAGE2 = "Display views";
+var treebrowser_js_MESSAGE3 = "Home";
+var treebrowser_js_MESSAGE4 = "Hide Treebrowser";
+
+function loadTop()
+{
+ if(parent.frames.length!=0 && (parent.frames[1].name=="ory_toc" || parent.frames[1].name=="ory_toc_frame") )
+ {
+ alert(treebrowser_js_MESSAGE1);
+ }
+ else
+ {
+ var expires = new Date();
+ expires.setTime (expires.getTime() + (1000 * 20));
+ document.cookie = "rup_ory_doc=" + escape (document.URL) +
+ "; expires=" + expires.toUTCString() + "; path=/";
+
+ var new_ory_doc_loc = null;
+
+ for(i=document.links.length-1;i>=0;i--)
+ {
+ if(document.links[i].href.indexOf("index.htm")!=-1)
+ {
+ new_ory_doc_loc = document.links[i].href;
+ break;
+ }
+ }
+
+ if(new_ory_doc_loc!=null)
+ {
+ if( self.name == "ory_doc" )
+ {
+ window.close();
+ window.open( new_ory_doc_loc );
+ }
+ else
+ {
+ top.location = new_ory_doc_loc;
+ }
+ }
+ }
+}
+
+
+ function getImageUrl(image)
+ {
+ var new_ory_doc_loc=null;
+ for(i=document.links.length-1;i>=0;i--)
+ {
+ if(document.links[i].href.indexOf("index.htm")!=-1)
+ {
+ new_ory_doc_loc = document.links[i].href.substring(0,document.links[i].href.lastIndexOf("/"));
+ new_ory_doc_loc = new_ory_doc_loc + "" + image;
+ return new_ory_doc_loc;
+ }
+ }
+ return null;
+ }
+
+MSFPhover =
+(((navigator.appName == "Netscape") &&
+ (parseInt(navigator.appVersion) >= 3 )) ||
+ ((navigator.appName == "Microsoft Internet Explorer") &&
+ (parseInt(navigator.appVersion) >= 4 )));
+
+ function MSFPpreload(img)
+ {
+ var a=new Image();
+ a.src=img;
+ return a;
+ }
+
+ if(MSFPhover)
+ {
+ RupGray=MSFPpreload(getImageUrl('/images/display_views.gif'));
+ RupBlue=MSFPpreload(getImageUrl('/images/display_views_a.gif'));
+ }
+
+
+//new code to display the load button or not
+var ory_toc_exist = typeof parent.ory_toc;
+if (ory_toc_exist == "undefined") {
+ ory_toc_exist = typeof parent.ory_toc_frame;
+}
+
+if (ory_toc_exist == "undefined") {
+ document.write("<a class=\"expandCollapseLink\" href=\"JavaScript:loadTop();\" onmouseover=\"if(MSFPhover) document['Home'].src=RupBlue.src; self.status=treebrowser_js_MESSAGE2; return true\" onmouseout=\"if(MSFPhover) document['Home'].src=RupGray.src; self.status= ' ';return true\"> <br> <img src=\"" + backPath + "images/rup1.gif");
+ document.write("\" border=\"0\" align=\"absmiddle\" alt=\"" + treebrowser_js_MESSAGE2 + "\" name=\"" + treebrowser_js_MESSAGE3 + "\" width=\"16\" height=\"16\">" + treebrowser_js_MESSAGE2 + "<\/a>");
+}
+else {
+ document.write("<a class=\"expandCollapseLink\" href=\"JavaScript:looseTop();\" onmouseover=\"if(MSFPhover) document['Home'].src=RupBlue.src; self.status=treebrowser_js_MESSAGE4; return true\" onmouseout=\"if(MSFPhover) document['Home'].src=RupGray.src; self.status= ' ';return true\"> <br> <img src=\"" + backPath + "images/rup1.gif");
+ document.write("\" border=\"0\" align=\"absmiddle\" alt=\"" + treebrowser_js_MESSAGE4 + "\" name=\"" + treebrowser_js_MESSAGE3 + "\" width=\"16\" height=\"16\">" + treebrowser_js_MESSAGE4 + "<\/a>");
+}
diff --git a/source/public/robots.txt b/source/public/robots.txt
new file mode 100644
index 0000000..4ab9e89
--- /dev/null
+++ b/source/public/robots.txt
@@ -0,0 +1 @@
+# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
\ No newline at end of file
diff --git a/source/public/stylesheets/default.css b/source/public/stylesheets/default.css
new file mode 100644
index 0000000..ed7c5c5
--- /dev/null
+++ b/source/public/stylesheets/default.css
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2005, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ * Onno van der Straaten - changes for use with EPF Wiki
+ */
+
+.HDNormal { }
+.HDDeleted { color: #00ff00;background: #ffffff;text-decoration:line-through ; font-family: Courier New ; font-size: 10pt;}
+.HDAdded { color: #000000;background: #ffff00;text-decoration:none ; font-family: Courier New ; font-size: 10pt;}
+
+#errorExplanation
+{
+ border:1px solid #CCC;
+ padding-bottom:10px;
+ background: transparent url(../images/error.png) no-repeat 15 15;
+}
+
+#errorExplanation h2
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ font-weight: normal;
+ margin-left: 220px;
+}
+
+#errorExplanation p
+{
+ margin-left: 220px;
+}
+
+#errorExplanation ul
+{
+ margin-left: 240px;
+}
+
+#search_form{
+ position:absolute;
+ top: 17px;
+ right: 250px;
+ width:200px;
+ text-align: right;
+}
+
+#search_form input.box{
+ font:1em Verdana,Helvetica,Arial,sans-serif;
+ height:1.35em;width:8.4em;float:right;
+ border:1px solid #CCC;margin:0 6px 0 10px
+ }
+
+#search_form input.searchsubmit {
+ border:0px;
+ float:left;
+ cursor:pointer;
+ font:1em arial,sans-serif;width:2em;height:22px;
+ background:url(images/search.png) top center no-repeat;
+ overflow:hidden;
+ text-indent:-999px;
+ margin:0 0 0 0
+}
+
+#commentsList {
+padding-left: 100px
+}
+
+.comment{
+background-color: #ececec;
+width: 700px;
+padding: 10px;
+}
+
+.commentfooter{
+background: url(images/arrow.gif) 20px 0 no-repeat;
+padding-left: 58px;
+padding-top: 1px;
+margin-bottom: 2em;
+font-size: 90%;
+color: #4A4A4A;
+}
+
+#menu{
+background: url(images/menu.png) 0px no-repeat;
+padding-top: 5px;
+padding-left: 10px;
+font-weight: bold;
+}
+
+body
+{
+ background-image: none;
+ background-color: #ffffff;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+}
+
+p
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+}
+
+h1
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: large;
+}
+
+h2
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 150%;
+}
+
+h3
+{
+ font-family: arial, helvetica, sans-serif;
+}
+
+h4, h5, h6
+{
+ font-family: arial, helvetica, sans-serif;
+}
+
+a:link
+{
+ color: #003399;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-decoration: none;
+}
+
+a:active
+{
+ color: #003399;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-decoration: underline;
+}
+
+a:visited
+{
+ color: #003399;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-decoration: none;
+}
+
+a[href]:hover
+{
+ color: #ff0000;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-decoration: underline;
+}
+
+ol
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ list-style-type: decimal;
+ margin-left: 30px;
+}
+
+ol li
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-align: left;
+}
+
+ul
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ list-style-type: disc;
+ margin-left: 30px;
+ margin-top: 5px;
+ padding-left: 0px;
+}
+
+ul li
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-align: left;
+}
+
+table
+{
+ background-image: none;
+ background: #ffffff;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+}
+
+tbody
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ valign: baseline;
+}
+
+th
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-align: left;
+}
+
+td
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+}
+
+td ul
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ margin-bottom: 0px;
+ margin-left: 30px;
+}
+
+.pageTitle
+{
+ background: #9999cc;
+ color: #ffffff;
+ font-size: 12pt;
+ font-weight: bold;
+ padding-bottom: 5px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 5px;
+ text-align: left;
+}
+
+.pageTitleSeparator
+{
+ background-color: #000000;
+ padding: 0px;
+}
+
+.tab
+{
+ background-color: #5c81a7;
+ color: #ffffff;
+ font-family: verdana, arial, sans-serif;
+ font-size: 11px;
+ font-weight: bold;
+}
+
+.activeTab
+{
+ background-color: #c8d7e3;
+ color: #293d6b;
+ font-family: verdana, arial, sans-serif;
+ font-size: 11px;
+ font-weight: bold;
+}
+
+a.tab:link, a.tab:active, a.tab:visited
+{
+ color: #ffffff;
+ font-family: verdana, arial, sans-serif;
+ font-size: 11px;
+ font-weight: bold;
+}
+
+a.tab:hover
+{
+ text-decoration: underline;
+}
+
+.overview
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ font-weight: normal;
+ padding-bottom: 10px;
+ padding-left: 20px;
+ padding-right: 0px;
+ padding-top: 10px;
+}
+
+.overviewTable
+{
+ background: #ffffff;
+ width: 100%;
+}
+
+.overviewTable td
+{
+ padding-bottom: 5px;
+ padding-left: 5px;
+ padding-right: 5px;
+ padding-top: 5px;
+}
+
+.overviewSeparator
+{
+ background-color: #000000;
+ padding: 0px;
+}
+
+.expandCollapseText
+{
+ font-family: verdana, arial, sans-serif;
+ font-size: 8pt;
+ padding-left: 5px;
+ padding-right: 5px;
+}
+
+.expandCollapseLink
+{
+ color: #333333;
+ padding-bottom: 5px;
+ text-decoration: none;
+}
+
+.expandCollapseLink:hover
+{
+ color: #0000ff;
+ text-decoration: underline;
+}
+
+.expandCollapseLink:visited
+{
+ color: #333333;
+}
+
+.sectionHeading
+{
+ background-color: #98b1c4;
+ color: #ffffff;
+ cursor: hand;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ font-weight: bold;
+ padding-bottom: 2px;
+ padding-left: 2px;
+ padding-top: 2px;
+ text-decoration: none;
+}
+
+.sectionContent
+{
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 0px;
+ text-align: right;
+}
+
+.sectionTable
+{
+ border-bottom: #ccc solid 0px;
+ border-left: #ccc solid 1px;
+ border-right: #ccc solid 0px;
+ border-top: #ccc solid 1px;
+ border-top-color: #ccc;
+ width: 100%;
+}
+
+.sectionTableHeading
+{
+ background: #eee;
+ border-bottom: #ccc solid 1px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 1px;
+ border-top: #ccc solid 0px;
+ color: #333333;
+ height: 20;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ text-align: left;
+ width: 20%;
+}
+
+.sectionTableCell
+{
+ border-bottom: #ccc solid 1px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 1px;
+ border-top: #ccc solid 0px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+}
+
+.breakdownTable
+{
+ border-bottom: #ccc solid 0px;
+ border-left: #ccc solid 1px;
+ border-right: #ccc solid 0px;
+ border-top: #ccc solid 1px;
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 0px;
+ width: 100%;
+}
+
+.breakdownTable th
+{
+ background: #eee;
+ border-bottom: #ccc solid 1px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 1px;
+ border-top: #ccc solid 0px;
+ color: #333333;
+ height: 20;
+ text-align: left;
+}
+
+.breakdownTable td
+{
+ border-bottom: #ccc solid 1px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 1px;
+ border-top: #ccc solid 0px;
+}
+
+.defaultTable
+{
+ border-bottom: #ccc solid 0px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 0px;
+ border-top: #ccc solid 0px;
+ padding-bottom: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 0px;
+ width: 100%;
+}
+
+.defaultTable td
+{
+ border-bottom: #ccc solid 0px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 0px;
+ border-top: #ccc solid 0px;
+ text-align: left;
+}
+
+.subSectionHeading
+{
+ color: #333333;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ font-weight: bold;
+ text-decoration: none;
+}
+
+.subSectionContent
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ text-decoration: none;
+}
+
+.stepHeading
+{
+ background-color: #ffffff;
+ color: #293d6b;
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ font-weight: bold;
+ padding-bottom: 2px;
+ padding-left: 2px;
+ padding-top: 2px;
+ text-decoration: none;
+}
+
+.stepContent
+{
+ border-bottom: #ccc solid 0px;
+ border-left: #ccc solid 0px;
+ border-right: #ccc solid 0px;
+ border-top: #ccc solid 0px;
+ padding-bottom: 5px;
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-top: 0px;
+ text-align: right;
+}
+
+.stepTable
+{
+ border-bottom: #999999 solid 1px;
+ border-left: #999999 solid 0px;
+ border-right: #999999 solid 0px;
+ border-top: #999999 solid 0px;
+ padding-bottom: 20px;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 10px;
+ width: 100%;
+}
+
+.stepTable td
+{
+ border: #ccc solid 0px;
+}
+
+.stepSeparator
+{
+ background-color: #cccccc;
+ padding: 0px;
+}
+
+.backToTopLink
+{
+ color: #fffff;
+ font-family: verdana, arial, sans-serif;
+ font-size: 8pt;
+ font-weight: normal;
+ margin: 0px;
+ padding-bottom: 10px;
+ text-align: middle;
+ text-decoration: none;
+}
+
+.backToTopLink:hover
+{
+ color: #969;
+ text-decoration: underline;
+}
+
+.backToTopLink:visited
+{
+ color: #5c81a7;
+ text-decoration: none;
+}
+
+.copyright
+{
+ color: #7080b0;
+ font-family: verdana, arial, sans-serif;
+ font-size: 8pt;
+ font-weight: normal;
+ padding-left: 0px;
+ padding-right: 10px;
+ padding-top: 25px;
+ text-align: left;
+ width: 100%;
+}
+
+.versionInfo
+{
+ color: #7080b0;
+ font-family: verdana, arial, sans-serif;
+ font-size: 8pt;
+ font-weight: normal;
+ padding-left: 10px;
+ padding-right: 0px;
+ padding-top: 25px;
+ text-align: right;
+}
+
+.quote
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ font-style: italic;
+}
+
+.codeSample
+{
+ font-family: courier;
+ font-size: 10pt;
+}
+
+.elementLink
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ color: #0000ff;
+}
+
+.elementLinkWithType
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ color: #0000ff;
+}
+
+.elementLinkWithUserText
+{
+ font-family: arial, helvetica, sans-serif;
+ font-size: 10pt;
+ color: #0000ff;
+}
+
diff --git a/source/public/stylesheets/images/arrow.gif b/source/public/stylesheets/images/arrow.gif
new file mode 100644
index 0000000..24e7d60
--- /dev/null
+++ b/source/public/stylesheets/images/arrow.gif
Binary files differ
diff --git a/source/public/stylesheets/images/bullet1.gif b/source/public/stylesheets/images/bullet1.gif
new file mode 100644
index 0000000..1c38c24
--- /dev/null
+++ b/source/public/stylesheets/images/bullet1.gif
Binary files differ
diff --git a/source/public/stylesheets/images/bullet2.gif b/source/public/stylesheets/images/bullet2.gif
new file mode 100644
index 0000000..cc18e2d
--- /dev/null
+++ b/source/public/stylesheets/images/bullet2.gif
Binary files differ
diff --git a/source/public/stylesheets/images/bullet3.gif b/source/public/stylesheets/images/bullet3.gif
new file mode 100644
index 0000000..5e79a77
--- /dev/null
+++ b/source/public/stylesheets/images/bullet3.gif
Binary files differ
diff --git a/source/public/stylesheets/images/menu.png b/source/public/stylesheets/images/menu.png
new file mode 100644
index 0000000..d7b2ee2
--- /dev/null
+++ b/source/public/stylesheets/images/menu.png
Binary files differ
diff --git a/source/public/stylesheets/images/search.png b/source/public/stylesheets/images/search.png
new file mode 100644
index 0000000..ba9eaa8
--- /dev/null
+++ b/source/public/stylesheets/images/search.png
Binary files differ
diff --git a/source/public/templates/Checklist Template.html b/source/public/templates/Checklist Template.html
new file mode 100644
index 0000000..f3c9b85
--- /dev/null
+++ b/source/public/templates/Checklist Template.html
@@ -0,0 +1,108 @@
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Template</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Checklist" name="uma.type">
+<meta content="analysis_class" name="uma.name">
+<meta content="Analysis Class" name="uma.presentationName">
+<meta content="Checklist" name="element_type">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../css/default.css" rel="StyleSheet">
+<script src="./../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../images/'); createStepLinks('div', 'stepHeading');">
+<table width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top"><a name="Top"></a>
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Checklist: ..</td><td align="right" class="expandCollapseLink" width="100%"><a href="./../../index.htm"></a><script src="./../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="100%">
+<tr>
+<td class="pageTitleSeparator"><img height="1" alt="" src="./../../images/shim.gif"></td>
+</tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../images/checklist.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">This checklist helps make sure that ...</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Related Elements</th><td class="sectionTableCell">
+<ul>
+<li>
+..
+</li>
+<li>
+..</li>
+</ul>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Main Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell"><a name="XE_analysis_class__checkpoints_for"></a><a name="XE_checkpoints__for_analysis_class"></a> <br />...
+<br /></td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Check Items</div>
+ <div class="sectionContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+ <tr>
+ <td class="sectionTableCell">
+ <div class="stepHeading">Step 1</div>
+ <div class="stepContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+ <tr valign="top">
+ <td>..</td>
+ </tr>
+ </table>
+ </div>
+
+ <div class="stepHeading">Step 2</div>
+ <div class="stepContent">
+ <table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+ <tr valign="top">
+ <td>..</td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ © Copyright .... YYYY, YYYY. All Rights Reserved.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/source/public/templates/Tool Mentor Template.html b/source/public/templates/Tool Mentor Template.html
new file mode 100644
index 0000000..3d5cdcb
--- /dev/null
+++ b/source/public/templates/Tool Mentor Template.html
@@ -0,0 +1,108 @@
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Tool Mentor: Template</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="ToolMentor" name="uma.type">
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="ToolMentor" name="element_type">
+<meta content="description" name="filetype">
+<link type="text/css" href="./../../css/default.css" rel="StyleSheet">
+<script src="./../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../';
+ </script>
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../images/');">
+<table width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top"><a name="Top"></a>
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Tool Mentor: </td><td align="right" class="expandCollapseLink" width="100%"><a href="./../../index.htm"></a><script src="./../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="100%">
+<tr>
+<td class="pageTitleSeparator"><img height="1" alt="" src="./../../images/shim.gif"></td>
+</tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../images/toolmentor.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">This tool mentor describes how to </td>
+</tr>
+<tr>
+<td>Tool:</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Related Elements</th><td class="sectionTableCell">
+<ul>
+<li>
+</li>
+<li>
+</li>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Main Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell"><h3>
+ Overview
+</h3>
+<p>
+</p>
+<p>
+</p>
+<p>
+</p>
+<h3>
+ Tool Steps
+</h3>
+<p>
+This tool mentor consists of the following steps:
+</p>
+<ol>
+ <li>1. Step 1
+ </li>
+ <li>2. Step 2
+ </li>
+</ol>
+<h4>
+1. Step 1</h4>
+<p>
+</p>
+<h4>
+ 2. Step 2
+</h4>
+<p>
+</p>
+</td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ © Copyright .. YYYY, YYYY. All Rights Reserved.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/source/script/other/backup.bat b/source/script/other/backup.bat
new file mode 100644
index 0000000..1d06669
--- /dev/null
+++ b/source/script/other/backup.bat
@@ -0,0 +1,8 @@
+set BACKUPDIR=%3
+set ZIPNAME=%1
+set RUPWIKI_ROOT_DIR=%5
+"%6" --tab=%3 --opt %7 --user=%8 --password=%9
+%2:
+shift
+cd %9script/other
+%3 backup
\ No newline at end of file
diff --git a/source/script/other/build.properties b/source/script/other/build.properties
new file mode 100644
index 0000000..b4ca96f
--- /dev/null
+++ b/source/script/other/build.properties
@@ -0,0 +1,3 @@
+version = 0.9
+abbr = EPFWiki
+
diff --git a/source/script/other/build.xml b/source/script/other/build.xml
new file mode 100644
index 0000000..7ecc7c5
--- /dev/null
+++ b/source/script/other/build.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<project name="build-delegate" default="save_sources" basedir=".">
+ <property environment="env" />
+ <property file="build.properties" />
+<!--
+ init
+ generate buildid and base name
+ remove and create the view to use for building (not very efficient way of removing deploy code)
+
+-->
+ <target name="init">
+ <tstamp />
+ <property name="buildid" value="${DSTAMP}_${TSTAMP}" />
+ <property name="baseline" value="${abbr}_R${version}_${buildid}"/>
+ <property name="baseline_ext" value="${abbr}_R${version}"/>
+ </target>
+ <target name="save_sources" depends="init">
+ <property file="${properties.tmp.file}" />
+ <copy todir="c:/epfwiki_releases/${baseline}" overwrite="true" failonerror="true">
+ <fileset dir="../../" excludes="scgi** db/simple_search_index public/editor/config/config.js stats** log/** tmp/** public/rupsites/** public/wikis/** public/markdown/** public/rupastxt/** public/rupdiffs/** public/users/** config/scgi.yaml" />
+ </copy>
+ <copy file="../../app/views/other/info.rhtml" tofile="c:/epfwiki_releases/${baseline}/app/views/other/info.rhtml" overwrite="true">
+ <!-- search for $VERSION$ and $BUILDID$ $BASELINE$ -->
+ <filterset begintoken="$" endtoken="$">
+ <filter token="VERSION" value="${version}"/>
+ <filter token="BUILDID" value="${buildid}"/>
+ </filterset>
+ </copy>
+ <copy file="../../doc/app/files/doc/README_FOR_APP.html" tofile="c:/epfwiki_releases/${baseline}/doc/app/files/doc/README_FOR_APP.html" overwrite="true">
+ <!-- search for $VERSION$ and $BUILDID$ $BASELINE$ -->
+ <filterset begintoken="$" endtoken="$">
+ <filter token="VERSION" value="${version}"/>
+ <filter token="BUILDID" value="${buildid}"/>
+ </filterset>
+ </copy>
+ <zip basedir="c:/epfwiki_releases/${baseline}" destfile="c:/epfwiki_releases/${baseline}.zip" />
+ </target>
+ <target name="unzip_upload">
+ <unzip src="${env.ROOTZIP}" dest="${env.ROOTPATH}" />
+ </target>
+ <target name="backup">
+ <copy todir="${env.BACKUPDIR}/public" overwrite="true" failonerror="true">
+ <fileset dir="${env.RUPWIKI_ROOT_DIR}/public" includes="**/*RUPWIKI*" />
+ </copy>
+ <zip basedir="${env.BACKUPDIR}" destfile="${env.BACKUPDIR}${env.ZIPNAME}" />
+ </target>
+ <target name="unzip_release">
+ <unzip src="${env.RELEASEDIR}${env.RELEASEZIP}" dest="${env.RELEASEDIR}${env.RELEASEFOLDER}" />
+ </target>
+ <target name="deploy">
+ <copy todir="${env.RUPWIKIROOTDIR}" overwrite="true" failonerror="true">
+ <fileset dir="${env.RELEASEDIR}${env.RELEASEFOLDER}" />
+ </copy>
+ </target>
+ <target name="full_backup">
+ <zip basedir="u:/rupwiki" destfile="c:/test.zip" />
+ </target>
+</project>
+
diff --git a/source/script/other/build_release.bat b/source/script/other/build_release.bat
new file mode 100644
index 0000000..05983aa
--- /dev/null
+++ b/source/script/other/build_release.bat
@@ -0,0 +1,7 @@
+cd ..\..\
+call rake stats > app\views\other\_stats.rhtml
+call doc.bat
+call doc_feat.bat
+copy CHANGELOG app\views\other\_changelog.rhtml
+cd script/other
+c:\apache-ant-1.6.2\bin\ant
\ No newline at end of file
diff --git a/source/script/other/deploy.bat b/source/script/other/deploy.bat
new file mode 100644
index 0000000..ea2f0f4
--- /dev/null
+++ b/source/script/other/deploy.bat
@@ -0,0 +1,6 @@
+set RELEASEDIR=%4
+set RELEASEFOLDER=%5
+set RUPWIKIROOTDIR=%2
+%1
+cd %2script\other
+%3 deploy
\ No newline at end of file
diff --git a/source/script/other/html2text.bat b/source/script/other/html2text.bat
new file mode 100644
index 0000000..1fd6dde
--- /dev/null
+++ b/source/script/other/html2text.bat
@@ -0,0 +1,2 @@
+%2
+%3script\other\html2text.py %1
\ No newline at end of file
diff --git a/source/script/other/unzip_release.bat b/source/script/other/unzip_release.bat
new file mode 100644
index 0000000..d21530d
--- /dev/null
+++ b/source/script/other/unzip_release.bat
@@ -0,0 +1,6 @@
+set RELEASEDIR=%4
+set RELEASEZIP=%5
+set RELEASEFOLDER=%6
+%1
+cd %2
+%3 unzip_release
\ No newline at end of file
diff --git a/source/script/other/unzip_upload.bat b/source/script/other/unzip_upload.bat
new file mode 100644
index 0000000..b11951f
--- /dev/null
+++ b/source/script/other/unzip_upload.bat
@@ -0,0 +1,5 @@
+%1%
+cd %2%\script\other
+SET ROOTZIP=%4
+SET ROOTPATH=%5
+call %3 -verbose unzip_upload
\ No newline at end of file
diff --git a/source/test/cleanup.bat b/source/test/cleanup.bat
new file mode 100644
index 0000000..c0300c5
--- /dev/null
+++ b/source/test/cleanup.bat
@@ -0,0 +1,6 @@
+IF EXIST c:\epfwiki_releases_uploaded (del /Q c:\epfwiki_releases_uploaded)
+IF EXIST ..\public\markdown (del /Q ..\public\markdown)
+IF EXIST ..\public\diffs (del /Q ..\public\diffs)
+rmdir /Q /S ..\public\test_sites
+rmdir /Q /S ..\public\test_wikis
+call rake log:clear
diff --git a/source/test/fixtures/checkouts.yml b/source/test/fixtures/checkouts.yml
new file mode 100644
index 0000000..5446edc
--- /dev/null
+++ b/source/test/fixtures/checkouts.yml
@@ -0,0 +1,29 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: checkouts
+#
+# id :integer(11) not null, primary key
+# user_id :integer(10) default(0), not null
+# site_id :integer(10)
+# page_id :integer(10)
+# version_id :integer(10) default(0), not null
+# baseline_id :integer(10) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+#
+
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+#first_checkout:
+# id: 1
+#another_checkout:
+ # id: 2
+#cr2:
+# id: 2
+# user_id: 5
+# site_id: 8
+# page_id: 7
+# version_id: 14
+# baseline_id: 1
+# created_on: "2006-03-29 20:55:52"
+# created_on: "2006-03-29 20:55:52"
diff --git a/source/test/fixtures/users.yml b/source/test/fixtures/users.yml
new file mode 100644
index 0000000..53909b0
--- /dev/null
+++ b/source/test/fixtures/users.yml
@@ -0,0 +1,76 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: users
+#
+# id :integer(11) not null, primary key
+# email :string(250) default(), not null
+# name :string(50) default(), not null
+# ip_address :string(20) default(), not null
+# hashed_password :string(40)
+# hashed_password_new :string(40)
+# admin :string(1) default(N), not null
+# notify_daily :integer(1) default(0), not null
+# notify_weekly :integer(1) default(0), not null
+# notify_monthly :integer(1) default(0), not null
+# site_id :integer(10)
+# created_on :datetime
+# updated_on :datetime
+# http_user_agent :string(250)
+# logon_count :integer(5) default(0)
+# logon_using_cookie_count :integer(5) default(0)
+# last_logon :datetime
+# confirmed_on :datetime
+#
+
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+Onno:
+ id: 1
+ email: "onno.van.der.straaten@epf.org"
+ name: "Onno"
+ ip_address: "localhost"
+ hashed_password: "<%= hash_pw("Onno") %> "
+ admin: "Y"
+ created_on: "2006-01-01 00:00:00"
+ updated_on: "2006-01-02 00:00:00"
+ confirmed_on: "<%= Time.now %>"
+User2:
+ id: 2
+ email: "user2@epf.org"
+ name: "User2"
+ ip_address: "localhost"
+ hashed_password: "<%= hash_pw("user2") %> "
+ admin: "Y"
+ created_on: "2006-01-01 00:00:00"
+ updated_on: "2006-01-02 00:00:00"
+ confirmed_on: "<%= Time.now %>"
+User3:
+ id: 3
+ email: "user3@epf.org"
+ name: "User3"
+ ip_address: "localhost"
+ hashed_password: "<%= hash_pw("user3") %> "
+ admin: "N"
+ created_on: "2006-01-01 00:00:00"
+ updated_on: "2006-01-02 00:00:00"
+ confirmed_on: "<%= Time.now %>"
+User4:
+ id: 4
+ email: "user4@epf.org"
+ name: "User4"
+ ip_address: "localhost"
+ hashed_password: "<%= hash_pw("user4") %> "
+ admin: "N"
+ created_on: "2006-01-01 00:00:00"
+ updated_on: "2006-01-02 00:00:00"
+ confirmed_on: "<%= Time.now %>"
+OnnoAdmin:
+ id: 5
+ email: "cadmin@openup.org"
+ name: "cadmin"
+ ip_address: "localhost"
+ hashed_password: "<%= hash_pw("onno") %> "
+ admin: "C"
+ created_on: "2006-01-01 00:00:00"
+ updated_on: "2006-01-02 00:00:00"
+ confirmed_on: "<%= Time.now %>"
diff --git a/source/test/fixtures/versions.yml b/source/test/fixtures/versions.yml
new file mode 100644
index 0000000..8bdfa9c
--- /dev/null
+++ b/source/test/fixtures/versions.yml
@@ -0,0 +1,27 @@
+# == Schema Information
+# Schema version: 1
+#
+# Table name: versions
+#
+# id :integer(11) not null, primary key
+# version :integer(3) default(0), not null
+# note :text
+# done :string(1) default(N), not null
+# user_id :integer(10) default(0), not null
+# page_id :integer(10)
+# site_id :integer(10)
+# version_id :integer(10)
+# baseline_id :integer(10) default(0), not null
+# created_on :datetime
+# updated_on :datetime
+# reviewer_id :integer(11)
+# user_id_markdone :integer(11)
+# user_id_marktodo :integer(11)
+# rel_path :string(1000) default(), not null
+#
+
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+#first_version:
+# id: 1
+#another_version:
+# id: 2
diff --git a/source/test/functional.bat b/source/test/functional.bat
new file mode 100644
index 0000000..aec1415
--- /dev/null
+++ b/source/test/functional.bat
@@ -0,0 +1,13 @@
+call rake db:test:prepare
+ruby functional/login_controller_test.rb
+ruby functional/users_controller_test.rb
+ruby functional/sites_controller_test.rb
+ruby functional/pages_controller_test.rb
+ruby functional/comments_controller_test.rb
+ruby functional/baselines_controller_test.rb
+ruby functional/difference_analyses_controller_test.rb
+ruby functional/other_controller_test.rb
+REM TODO ruby functional/search_controller_test.rb
+ruby functional/versions_controller_test.rb
+ruby functional/toolbar_controller_test.rb
+
diff --git a/source/test/functional/baselines_controller_test.rb b/source/test/functional/baselines_controller_test.rb
new file mode 100644
index 0000000..10c66e2
--- /dev/null
+++ b/source/test/functional/baselines_controller_test.rb
@@ -0,0 +1,68 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'baselines_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class BaselinesController; def rescue_action(e) raise e end; end
+
+class BaselinesControllerTest < Test::Unit::TestCase
+
+ def setup
+ @controller = BaselinesController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @admin = User.find_by_admin('Y')
+ @cadmin = User.find_central_admin
+ @user = User.find_by_admin('N')
+ end
+
+ # Shows:
+ # 1. only admin can edit baseline
+ def test01_edit
+ baseline = Baseline.find_first
+ get :list
+ session['user'] = @user
+ get :edit, :id => baseline.id
+ assert_unot_admin_message
+ session['user'] = @admin
+ get :edit, :id => baseline.id
+ assert_response :success
+ end
+
+ def test02_list
+ get :list
+ [@admin, @user].each do |user|
+ session['user'] = user
+ get :list
+ assert_response :success
+ end
+ end
+
+ def test03_show
+ get :list
+ [@admin, @user].each do |user|
+ Baseline.find_all.each do |baseline|
+ session['user'] = user
+ get :show, :id => baseline.id
+ assert_response :success
+ get :show_comments, :id => baseline.id
+ assert_response :success
+ end
+ end
+ end
+
+end
diff --git a/source/test/functional/comments_controller_test.rb b/source/test/functional/comments_controller_test.rb
new file mode 100644
index 0000000..92680fc
--- /dev/null
+++ b/source/test/functional/comments_controller_test.rb
@@ -0,0 +1,257 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'comments_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class CommentsController; def rescue_action(e) raise e end; end
+
+class CommentsControllerTest < Test::Unit::TestCase
+
+ def setup
+ @controller = CommentsController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @openup0721 = Site.find_by_title('openup0721')
+ @admin = User.find_by_admin('Y')
+ @cadmin = User.find_central_admin
+ @user = User.find_by_admin('N')
+ @emails = ActionMailer::Base::deliveries
+ @emails.clear
+ end
+
+ # Shows:
+ # 1. Request form for creating a new comment on page without versions
+ # 2. Comment submitted by specifying page and site (creates the baseversion)
+ # 3. Comment submitted by specifying the version
+ def test01_new_and_create
+ # 1
+ page = Page.find_by_filename('about_base_concepts,_uvje4D_fEdqDFvujd6NHiA.html')
+ assert_equal 0, page.versions.size
+ assert_equal 0, page.comments.size
+ get :new, :page_id => page.id, :site_id => @openupwiki.id
+ assert_redirected_to :controller => 'login'
+ session['user'] = @user
+ get :new, :page_id => page.id, :site_id => @openupwiki.id
+ assert_not_nil assigns(:comment_new)
+ assert_not_nil assigns(:comments)
+ assert_not_nil assigns(:version)
+ assert_equal 0, assigns(:version).version
+ assert_equal nil, assigns(:version).id
+ page.reload
+ assert_equal 0, page.versions.size # base version is created but not saved
+ # 2
+ post :create, :comment => {:text => 'comment 1 submitted in test01_new',:page_id => page.id, :site_id => @openupwiki.id}
+ assert_not_nil assigns(:comment)
+ assert_no_errors
+ page.reload
+ assert_equal 1, page.versions.size
+ assert_equal 1, page.comments.size
+ post :list, :page_id => page.id, :site_id => @openupwiki.id
+ assert_response :success
+ assert_match 'comment 1 submitted in test01_new', @response.body
+ # 3
+ page = Page.find_by_filename('tester,_0ZM4MclgEdmt3adZL5Dmdw.html')
+ version = page.versions.last
+ assert_not_nil version
+ post :create, :comment => {:text => 'comment 2 submitted in test01_new', :version_id => version.id}
+ assert_response :success
+ assert_match 'comment 2 submitted in test01_new', @response.body
+ end
+
+ # Shows:
+ # 1. user cannot mark 'todo', 'done'
+ # 2. admin can, admin is recorded as the user that marked 'done'
+ # 3. cadmin can, cadmin is recorded as the user that marked 'todo'
+ def test02_toggle_done
+ page = Page.find_by_filename('about_base_concepts,_uvje4D_fEdqDFvujd6NHiA.html')
+ get :new
+ # 1
+ session['user'] = @user
+ comment = page.comments.last
+ assert_not_nil comment
+ assert_equal 'N', comment.done
+ get :toggle_done, :id => comment.id
+ assert_response 302
+ assert_template nil
+ comment.reload
+ assert_equal 'N', comment.done
+ # 2
+ session['user'] = @admin
+ get :toggle_done, :id => comment.id
+ assert_response :success
+ comment.reload
+ assert_equal 'Y', comment.done
+ assert_equal @admin, comment.user_thatmarkeddone
+ # 3
+ session['user'] = @cadmin
+ get :toggle_done, :id => comment.id
+ assert_response :success
+ comment.reload
+ assert_equal 'N', comment.done
+ assert_equal @cadmin, comment.user_thatmarkedtodo
+ end
+
+ # Shows:
+ # 1. user cannot assign self as reviewer
+ # 2. admin can assign
+ # 3. cadmin can assign himself as reviewer if already assigned
+ # 4. admin cannot
+ # 5. owner (cadmin) can unassign
+ def test03_review
+ get :new
+ comment = Comment.find_first
+ assert_equal nil, comment.reviewer
+ # 1
+ session['user'] = @user
+ get :review, :id => comment.id
+ assert_unot_admin_message
+ assert_equal nil, comment.reviewer
+ # 2
+ session['user'] = @admin
+ get :review, :id => comment.id
+ assert_response :success
+ assert_template nil
+ comment.reload
+ assert_equal @admin, comment.reviewer
+ # 3
+ session['user'] = @cadmin
+ get :review, :id => comment.id
+ comment.reload
+ assert_response :success
+ assert_template nil # inline
+ assert_equal @cadmin, comment.reviewer # same, not cadmin
+ # 4
+ session['user'] = @admin
+ get :review, :id => comment.id
+ comment.reload
+ assert_template nil
+ assert_equal @cadmin, comment.reviewer
+ # 5
+ session['user'] = @cadmin
+ get :review, :id => comment.id
+ comment.reload
+ assert_template nil
+ assert_equal nil, comment.reviewer
+ end
+
+ # Shows:
+ # 1. other user than owner cannot edit
+ # 2. owner can edit comment
+ def test04_edit
+ get :new
+ comment = Comment.find_first
+ assert comment.user != @admin
+ # 1
+ session['user'] = @admin
+ get :edit, :id => comment.id
+ assert_response :success
+ post :edit, :id => comment.id, :comment => {:text => 'other user cannot update'}
+ assert_response :success
+ comment.reload
+ assert comment.text != 'other user cannot update'
+ # 2
+ session['user'] = comment.user
+ post :update, :id => comment.id, :comment => {:text => 'owner can update'}
+ assert_response :success
+ comment.reload
+ assert_equal 'owner can update', comment.text
+ end
+
+ def test05_list
+ get :new
+ comment = Comment.find_first
+ for i in 1..100
+ comment_new = comment.clone
+ comment_new.version = comment.version
+ assert comment_new.save
+ end
+ [@user, @admin].each do |user|
+ session['user'] = user
+ ['Y', 'N'].each do |done|
+ Comment.update_all("done = '#{done}'")
+ get :listtodo
+ get :listdone
+ get :listall
+ end
+ end
+ end
+
+ # Shows:
+ # 1. owner can destroy
+ # 2. other user cannot destroy
+ # 3. central admin can destroy any comment
+ def test06_destroy
+ get :new
+ comment = Comment.find_first
+ assert @admin != comment.user
+ session['user'] = @admin
+ get :destroy, :id => comment.id
+ assert_response 302
+ assert Comment.exists?(comment.id)
+ session['user'] = @user
+ get :destroy, :id => comment.id
+ assert_response 302
+ assert !Comment.exists?(comment.id)
+ end
+
+ # Shows:
+ # 1. no users subscribed -> no notifications
+ # 2. @user subscribed -> email to @user
+ # 3. @user and @admin subscribed
+ def test07_notifications
+ page = Page.find_by_filename('requirements,_allMQMWfEdqiT9CqkRksWQ.html')
+ assert_not_nil page
+ get :new
+ version = page.versions_in_site(@openupwiki).last
+ comments_count = Comment.count
+ assert_not_nil version
+ session['user'] = @user
+ assert_equal 0, Notification.find_all_users(@openupwiki, page, Comment.class.to_s).size
+ # 1
+ post :create, :comment => {:text => 'first comment created in test07_notifications', :version_id => version.id}
+ assert_response :success
+ assert_equal 1 + comments_count, Comment.count # first comment created
+ assert_equal(0, @emails.size)
+ # 2
+ @emails.clear
+ notification = Notification.new(:page => page, :site => @openupwiki, :user => @user, :notification_type => 'Comment')
+ assert notification.save
+ post :create, :comment => {:text => 'second comment created in test07_notifications', :version_id => version.id}
+ assert_response :success
+ assert_equal 2 + comments_count, Comment.count # second comment created
+ assert_equal(1, @emails.size) # 1 email
+ assert @emails.first.to.include?(@user.email)
+ # 3
+ @emails.clear
+ notification = Notification.new(:page => page, :site => @openupwiki, :user => @admin, :notification_type => 'Comment')
+ assert notification.save
+ post :create, :comment => {:text => 'third comment created in test07_notifications', :version_id => version.id}
+ assert_response :success
+ assert_equal 3 + comments_count, Comment.count # third comment created
+ assert_equal(1, @emails.size) # 1 email
+ assert @emails.first.to.include?(@user.email)
+ assert @emails.first.to.include?(@admin.email)
+ assert_equal @emails.first.subject, "[#{ENV['EPFWIKI_APP_NAME']}] New comment submitted about #{page.presentation_name}"
+ #assert_match "User #{@admin.name} submitted a new comment about <a href=\"http://#{@request.host}/test_wikis/openup/requirements,_allMQMWfEdqiT9CqkRksWQ.html\">#{page.presentation_name}</a> in site #{@openupwiki.title}<br>", @emails.first.body
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_match "<a href=\"http://#{@request.host}/test_wikis/openup/requirements,_allMQMWfEdqiT9CqkRksWQ.html\">#{page.presentation_name}</a>", @emails.first.body
+ else
+ assert_match "<a href=\"http://#{@request.host}/test_wikis/openup/openup_basic/domains/requirements,_allMQMWfEdqiT9CqkRksWQ.html\">#{page.presentation_name}</a>", @emails.first.body
+ end
+ end
+
+end
diff --git a/source/test/functional/difference_analyses_controller_test.rb b/source/test/functional/difference_analyses_controller_test.rb
new file mode 100644
index 0000000..56df89e
--- /dev/null
+++ b/source/test/functional/difference_analyses_controller_test.rb
@@ -0,0 +1,148 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'difference_analyses_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class DifferenceAnalysesController; def rescue_action(e) raise e end; end
+
+class DifferenceAnalysesControllerTest < Test::Unit::TestCase
+
+ def setup
+ @controller = DifferenceAnalysesController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @admin = User.find_by_admin('Y')
+ @cadmin = User.find_central_admin
+ @user = User.find_by_admin('N')
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @openup0721 = Site.find_by_title('openup0721')
+ @openup0728 = Site.find_by_title('openup0728')
+ end
+
+ # Shows:
+ # 1. need to be cadmin
+ # 2.
+ # 3.
+ # 4. Schedule analysis
+ # 5. Cannot do analysis twice (site_id, and site_id_from need to be unique)
+ def test01_new
+ assert_not_nil @openup0721
+ assert_not_nil @openup0728
+ assert 0, DifferenceAnalysis.count
+ get :list
+ session['user'] = @user
+ get :new
+ assert_unot_cadmin_message
+ # 2
+ session['user'] = @cadmin
+ get :new, :site_id => @openup0728.id
+ assert_not_nil assigns(:baseline_process)
+# assert_not_nil assigns(:difference_analyses)
+ assert_not_nil assigns(:difference_analysis)
+ assert_not_nil assigns(:baseline_processes)
+ # 3
+ post :new, :difference_analysis => {:site_id => @openup0721.id}
+ assert 'Site cannot compare with itself', assigns(:difference_analysis).errors.full_messages.join(', ')
+ assert_errors(assigns(:difference_analysis))
+ # 4
+ post :new, :difference_analysis => {:site_id => @openup0728.id, :site_id_from => @openup0721.id}
+ assert_no_errors
+ assert_redirected_to :action => 'show', :id => assigns(:difference_analysis).id
+ assert 1, DifferenceAnalysis.count
+ # 5
+ post :new, :difference_analysis => {:site_id => @openup0728.id, :site_id_from => @openup0721.id}
+ assert_errors(assigns(:difference_analysis))
+ assert 'Difference Analysis already exists', assigns(:difference_analysis).errors.full_messages.join(', ')
+ assert_response :success
+ assert 1, DifferenceAnalysis.count
+ end
+
+ # Shows:
+ # 1. only cadmin can performs analyses
+ # 2. cadmin performs analyses
+ # 3. cadmin destroys analyses
+ # 4. cadmin performs analyses using job_daily
+ def test02_analyze_now
+ get :list
+ assert_equal 1, DifferenceAnalysis.count
+ assert_equal 0, DifferenceAnalysisItem.count
+ difference_analysis = DifferenceAnalysis.find_first
+ assert difference_analysis.analyzed_on.nil?
+ # 1
+ session['user'] = @admin
+ get :analyze_now, :id => difference_analysis.id
+ assert_unot_cadmin_message
+ # 2
+ session['user'] = @cadmin
+ get :analyze_now, :id => difference_analysis.id
+ assert_redirected_to :action => 'show', :id => difference_analysis.id
+ assert DifferenceAnalysisItem.count > 0
+ assert_equal DifferenceAnalysesController::FLASH_PERFORMED, flash['success']
+ difference_analysis.reload
+ assert !difference_analysis.analyzed_on.nil?
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 10, difference_analysis.items.size
+ assert difference_analysis.save
+ assert_equal 10, difference_analysis.items.size
+ assert_equal 0, difference_analysis.items_removed.size
+ assert_equal 8, difference_analysis.items_equal.size
+ assert_equal 0, difference_analysis.items_changed.size
+ assert_equal 0, difference_analysis.items_htmlchanged.size
+ assert_equal 2, difference_analysis.items_new.size
+ else
+ assert_equal 617, DifferenceAnalysisItem.count #? not saved yet????
+ assert difference_analysis.save
+ assert_equal 617, DifferenceAnalysisItem.count
+ assert_equal 0, difference_analysis.items_removed.size
+ assert_equal 464, difference_analysis.items_equal.size
+ assert_equal 9, difference_analysis.items_changed.size
+ assert_equal 144, difference_analysis.items_htmlchanged.size
+ assert_equal 0, difference_analysis.items_new.size
+ end
+ # 3
+ #post :destroy, :id => difference_analysis.id
+ #assert_redirect_to :action => 'list'
+ #assert_equal 0, DifferenceAnalysis.count
+ #assert_equal 0, DifferenceAnalysisItem.count
+ # 4
+ #post :new, :difference_analysis => {:site_id => @openup0728.id, :site_id_from => @openup0721.id}
+ #assert_no_errors
+ #assert_redirected_to :action => 'show', :id => assigns(:difference_analysis).id
+ #assert 1, DifferenceAnalysis.count
+ # assert 0, DifferenceAnalysisItem.count
+ #job_daily
+# get :analyze_now, :id => assigns(:difference_analysis).id
+ # assert_redirect_to :action => 'show', :id => assigns(:difference_analysis).id
+ # assert_equal DifferenceAnalysisItem.count > 0
+ end
+
+ def tst03_showitem
+ logonAdmin
+ ana_count = DifferenceAnalysis.count
+ item_count = DifferenceAnalysisItem.count
+ post :create, :difference_analysis => {:site_id => 12, :site_id_from => 11}
+ assert_equal ana_count + 1, DifferenceAnalysis.count
+ assert_equal item_count + 8, DifferenceAnalysisItem.count
+ logonUser
+ diff_item = DifferenceAnalysisItem.find(:first, :conditions => ['diff is not null and result = ?', "CHANGED"])
+ post :show_item, :item_id => diff_item.id
+ assert_not_nil assigns(:site)
+ assert_not_nil assigns(:site_from)
+ assert_not_nil assigns(:baseline)
+ assert_not_nil assigns(:baseline_from)
+ assert_not_nil assigns(:diff_item)
+ assert_not_nil assigns(:diff_item).diff
+ end
+end
diff --git a/source/test/functional/login_controller_test.rb b/source/test/functional/login_controller_test.rb
new file mode 100644
index 0000000..dbc731d
--- /dev/null
+++ b/source/test/functional/login_controller_test.rb
@@ -0,0 +1,185 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'login_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class LoginController; def rescue_action(e) raise e end; end
+
+class LoginControllerTest < Test::Unit::TestCase
+ #fixtures :baselines
+ #fixtures :baselines_pages
+ #fixtures :baselines_sites
+ #fixtures :checkouts
+ #fixtures :comments
+ #fixtures :pages
+ #fixtures :pages_sites
+ #fixtures :sites
+ #fixtures :users
+ #fixtures :versions
+ #fixtures :notifications
+
+ def setup
+ @controller = LoginController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @emails = ActionMailer::Base::deliveries
+ @emails.clear
+ end
+
+ # Can create the central admin
+ def test01_signup_central_admin
+ assert User.count == 0
+ get :index
+ assert_redirected_to :action => 'login'
+ get :login
+ assert_redirected_to :action => 'new_cadmin'
+ get :new_cadmin
+ assert_field 'user_name'
+ assert_field 'user_email'
+ assert_field 'user_password'
+ assert_field 'user_password_confirmation'
+ assert_tag :tag => 'input', :attributes => {:type => 'submit'}
+ assert_tag :tag => 'form', :attributes => {:action => '/login/new_cadmin'}
+ post :new_cadmin, :user => {:name => 'Onno', :email=> 'onno.van.der.straaten@logicacmg.com', :password => 'pass2', :password_confirmation => 'pass2'}
+ assert_equal LoginController::FLASH_CENTRAL_ADMIN_CREATED, flash['success']
+ assert_redirected_to :action => 'login'
+ end
+
+ # A user can sign up by supplying name, email, password and password confirmation
+ def test02_sign_up_with_pw
+ get :sign_up
+ assert_response :success
+ assert_field 'user_name'
+ assert_field 'user_email'
+ assert_equal '0', ENV['EPFWIKI_GENERATE_PASSWORDS']
+ assert_field 'user_password'
+ assert_field 'user_password_confirmation'
+ assert !ENV['EPFWIKI_DOMAINS'].blank?
+ assert_tag :tag => 'select', :attributes => {:name => 'user[email_extension]'}
+ post :sign_up, :user => {:name => "user1", :email=>"user1", :email_extension => "@somedomain.com"}
+ assert_errors
+ assert_not_nil assigns(:user)
+ assert_equal 'Password confirmation can\'t be blank, Password can\'t be blank, Email domain not valid', assigns(:user).errors.full_messages.join(', ')
+ post :sign_up, :user => {:name => "user1", :email=>"user1", :email_extension => "@epf.org", :password => 'user1', :password_confirmation => 'user1'}
+ assert_equal 'test.host', @request.host
+ assert_redirected_to :action => 'login'
+ assert_equal LoginController::FLASH_PW_CONFIRMATION_EMAIL_SENT, flash['success']
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert_equal("[#{ENV['EPFWIKI_APP_NAME']}] Confirm Your New Account", email.subject)
+ assert_equal("user1@epf.org", email.to[0])
+ assert_equal([ENV['EPFWIKI_REPLY_ADDRESS']], email.from)
+ assert_redirected_to :action => 'login'
+ end
+
+ # A user can sign up with name and email, a password is generated and sent to the user
+ def test03_sign_up_without_pw
+ ENV['EPFWIKI_GENERATE_PASSWORDS'] = '1'
+ ENV['EPFWIKI_DOMAINS'] = ''
+ get :sign_up
+ assert_response :success
+ assert_field 'user_name'
+ assert_field 'user_email'
+ assert_no_field 'user_password'
+ assert_no_field 'user_password_confirmation'
+ assert ENV['EPFWIKI_DOMAINS'].blank?
+ assert_no_tag :tag => 'select'
+ post :sign_up, :user => {:name => "user2", :email=>"user2"}
+ assert_errors
+ assert_not_nil assigns(:user)
+ assert_equal 'Email is invalid', assigns(:user).errors.full_messages.join(', ')
+ post :sign_up, :user => {:name => "user2", :email=>"user2@somedomain.com"}
+ @password = assigns(:user).password
+ assert !@password.blank?
+ assert_equal LoginController::FLASH_PW_SENT, flash['success']
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert_equal("[#{ENV['EPFWIKI_APP_NAME']}] Welcome to #{ENV['EPFWIKI_APP_NAME']}", email.subject)
+ assert_equal("user2@somedomain.com", email.to[0])
+ assert_equal([ENV['EPFWIKI_REPLY_ADDRESS']], email.from)
+ assert_redirected_to :action => 'login'
+ end
+
+ # Shows:
+ # 1. Lost password form
+ # 2. Error on wrong email addresses
+ # 3. New password set, email sent with password and token
+ # 4. Cannot logon with 'new' password (not activated yet)
+ def test04_lost_password
+ # 1
+ get :lost_password
+ assert_response :success
+ assert_field 'user_email'
+ assert_tag :tag => 'form', :attributes => {:action => '/login/lost_password'}
+ # 2
+ post :lost_password, :user => {:email => 'noneexisting email'}
+ assert_response :success
+ assert_equal LoginController::FLASH_EMAIL_NOT_FOUND, flash['notice']
+ # 3
+ post :lost_password, :user => {:email => 'user2@somedomain.com'}
+ user_by_email = assigns(:user_by_email)
+ assert_not_nil user_by_email
+ assert_equal LoginController::FLASH_PW_SENT, flash['success']
+ assert_equal(2, @emails.size)
+ email = @emails.first
+ assert_equal("[#{ENV['EPFWIKI_APP_NAME']}] New Password", email.subject)
+ assert_equal("user2@somedomain.com", email.to[0])
+ assert_equal([ENV['EPFWIKI_REPLY_ADDRESS']], email.from)
+ assert_match(assigns(:user_by_email).password, email.body)
+ assert_match(assigns(:user_by_email).token, email.body)
+ assert_redirected_to :action => 'login'
+ @emails.clear
+ # 4
+ post :login, :user => {:email => user_by_email.email, :password => user_by_email.password}
+ assert_equal LoginController::FLASH_INVALID_PW, flash['notice']
+ end
+
+ # Shows:
+ # 1. get is not allowed
+ # 2. user cannot resend password of a user
+ # 3. admin can resend password of a user
+ def test05_resend
+ get :index
+ users = User.find_all_by_admin('N')
+ user1 = users[0]
+ user2 = users[1]
+ session['user'] = user1
+ # 1
+ get :resend, :id => user2.id
+ assert_illegal_get
+ post :resend, :id => user2.id
+ assert_unot_admin_message
+ # 2
+ @emails.clear
+ session['user'] = User.find_central_admin
+ assert_not_nil session['user']
+ post :resend, :id => user2.id
+ assert assigns(:user)
+ assert_not_nil assigns(:user)
+ assert_equal '', assigns(:user).errors.full_messages.join(', ')
+ assert_equal LoginController::FLASH_PW_SENT, flash['success']
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert_equal("[#{ENV['EPFWIKI_APP_NAME']}] Welcome to #{ENV['EPFWIKI_APP_NAME']}", email.subject)
+ assert_equal("user2@somedomain.com", email.to[0])
+ assert_equal([ENV['EPFWIKI_REPLY_ADDRESS']], email.from)
+ assert_match(assigns(:user).password, email.body)
+ assert !assigns(:user).confirmed_on.nil?
+ #assert_match(assigns(:user).token, email.body)
+ @emails.clear
+ assert_redirected_to :controller => 'users', :action => 'list'
+ end
+end
diff --git a/source/test/functional/other_controller_test.rb b/source/test/functional/other_controller_test.rb
new file mode 100644
index 0000000..cd7f37b
--- /dev/null
+++ b/source/test/functional/other_controller_test.rb
@@ -0,0 +1,51 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'other_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class OtherController; def rescue_action(e) raise e end; end
+
+class OtherControllerTest < Test::Unit::TestCase
+ def setup
+ @controller = OtherController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @admin = User.find_by_admin('Y')
+ @cadmin = User.find_central_admin
+ @user = User.find_by_admin('N')
+ end
+
+ # Shows:
+ # 1. authentication required to access info about application
+ # 2. authenticated user can access info, demos, not releases etc
+ # 3. cadmin can access info about releases, statistics and change log
+ def test01_info
+ # 1
+ get :info
+ assert_redirected_to :controller => 'login'
+ # 2
+ session['user'] = @user
+ get :info
+ assert_tag :tag => 'div', :content => 'Properties', :attributes => {:class => 'sectionHeading'}
+ #TODO #assert_tag :tag => 'div', :content => 'Demo\'s', :attributes => {:class => 'sectionHeading'}
+ assert_response :success
+ session['user'] = @admin
+ get :info
+ # 3
+ # TODO R? implement functional test
+ end
+end
diff --git a/source/test/functional/pages_controller_test.rb b/source/test/functional/pages_controller_test.rb
new file mode 100644
index 0000000..252013c
--- /dev/null
+++ b/source/test/functional/pages_controller_test.rb
@@ -0,0 +1,546 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'pages_controller'
+require 'ftools'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class PagesController; def rescue_action(e) raise e end; end
+
+class PagesControllerTest < Test::Unit::TestCase
+
+ def setup
+ @controller = PagesController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @openup0721 = Site.find_by_title('openup0721')
+ @admin = User.find_by_admin('Y')
+ @cadmin = User.find_central_admin
+ @user = User.find_by_admin('N')
+ @emails = ActionMailer::Base::deliveries
+ end
+
+ # Shows:
+ # 1. authenticated users can checkout
+ # 2. we can request form to checkout a page by id and id of the wiki, this will create a base version if there are no versions
+ # 3. we cannot checkout in a baseline process site
+ # 4. checkout of a baseversion of a page
+ # 5. cannot checkout the same page again
+ # 6. also other user cannot check out twice
+ def test01_checkout
+ page = Page.find_by_filename('any_role,_3TCEoeB5EdqnKu908IEluw.html')
+ assert_not_nil page
+ assert page.versions.empty?
+ # 1
+ get :checkout, :id => page.id, :site_id => @openupwiki.id
+ assert_redirected_to :controller => 'login'
+ session['user'] = @user
+ # 2
+ get :checkout, :id => page.id, :site_id => @openupwiki.id
+ assert_response :success
+ assert_not_nil assigns(:page)
+ assert_not_nil assigns(:wiki)
+ assert_not_nil assigns(:version)
+ assert_not_nil assigns(:version).source_version
+ assert_not_nil assigns(:version).site
+ assert_not_nil assigns(:versions)
+ assert_equal nil,assigns(:checkout)
+ assert_equal @openupwiki, assigns(:version).site
+
+ # TODO this changed at some point from 1 to 0
+ # assert_equal 1, assigns(:versions).size
+ # and yes, you are right we are not interested in knowing why this suddenly changed
+ # from 1 to 0.
+
+ assert_equal 0, assigns(:version).source_version.version
+ assert 1, page.versions.size
+ # 3
+ get :checkout, :id => page.id, :site_id => @openupwiki.id
+ assert_response :success
+ assert_equal @openupwiki, assigns(:version).site
+ # another checkout request doesn't create a new version, the baseversion already exists
+ assert_equal 1, assigns(:versions).size
+ assert_equal 0, assigns(:version).source_version.version
+ assert 1, page.versions.size
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openup0721.id, :version_id => assigns(:version).source_version.id, :note => 'test01_checkout', :page_id => page.id}
+ assigns(:checkout)
+ assert !assigns(:checkout).valid?
+ assert_errors(assigns(:checkout))
+ assert_equal 'Version can\'t be blank, Site can\'t be a baseline process', assigns(:checkout).errors.full_messages.join(", ")
+ # 4
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :version_id => assigns(:version).source_version.id, :note => 'test01_checkout', :page_id => page.id}
+ assert_equal '', assigns(:checkout).errors.full_messages.join(", ")
+ assert assigns(:checkout).valid?
+ assert_no_errors
+ assert 1, page.checkouts.size
+ assert_redirected_to :action => 'edithtml', :checkout_id => assigns(:checkout).id
+ # 5
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :version_id => assigns(:version).source_version.id, :note => 'test01_checkout', :page_id => page.id}
+ assert_equal 'Version can\'t be blank, Checkout already exists', assigns(:checkout).errors.full_messages.join(", ")
+ assert !assigns(:checkout).valid?
+ assert_errors(assigns(:checkout))
+ # 6
+ session['user'] = @admin
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :version_id => assigns(:version).source_version.id, :note => 'test01_checkout', :page_id => page.id}
+ assert_equal 'Version can\'t be blank, Checkout already exists', assigns(:checkout).errors.full_messages.join(", ")
+ assert !assigns(:checkout).valid?
+ assert_errors(assigns(:checkout))
+ end
+
+ # Shows:
+ # 1. can open page with PinEdit if PinEdit is installed in public/editor
+ # 2. can open page with TinyMCE if TinyMCE is installed in public/javascripts/tiny_mce
+ # 3. other user cannot open, except for cadmin
+ def test02_edithtml
+ # 1
+ assert_equal 'pinedit', ENV['EPFWIKI_EDITOR']
+ assert File.exists?("#{ENV['EPFWIKI_ROOT_DIR']}public/editor/pinEdit.html")
+ assert_equal 1, Checkout.count
+ checkout = Checkout.find_first
+ get :edithtml, :checkout_id => checkout.id
+ assert_redirected_to :controller => 'login'
+ session['user'] = checkout.user
+ get :edithtml, :checkout_id => checkout.id
+ assert_response :success
+ assert_not_nil assigns(:checkout)
+ assert_match "/editor/pinEdit.html?url=/#{assigns(:checkout).version.rel_path_root}&Id=users/3/images&dd=users/3/docs&hm=2&hb=1", @response.body
+ # NOTE: using assert_match and not assert_tag because assert_tag consistently fails,
+ # reporting that the tag cannot be matched, I cannot detect any difference
+ # however in the src attribute that is causing the assert to fail.
+ #assert_tag :tag => 'IFRAME', :attributes => {#:id => 'editorFrame',
+ #:style => 'WIDTH: 100%; HEIGHT: 92%',
+ #:src => "/editor/pinEdit.html?url=/#{assigns(:checkout).version.rel_path_root}&Id=/users/3/images&dd=/users/3/docs&hm=2&hb=1"}
+
+ # 2
+ ENV['EPFWIKI_EDITOR'] = 'tinymce'
+ assert File.exists?("#{ENV['EPFWIKI_ROOT_DIR']}public/javascripts/tiny_mce/tiny_mce.js")
+ #assert_tag :tag => 'textarea', :attributes => {:id => 'elm1',
+ #:style => 'WIDTH: 100%; HEIGHT: 92%',
+ # :src => "http://#{@request.host}/editor/pinEdit.html?url=http://#{@request.host}/#{assigns(:checkout).version.rel_path_root}"}
+ get :edithtml, :checkout_id => checkout.id
+ assert_response :success
+ # 3
+ session['user'] = @admin
+ assert_raise(RuntimeError) {get :edithtml, :checkout_id => checkout.id}
+ #assert_redirected_to :controller => 'other', :action => 'error'
+ session['user'] = @cadmin
+ get :edithtml, :checkout_id => checkout.id
+ assert_response :success
+ assert_not_nil assigns(:checkout)
+ end
+
+ # Shows:
+ # 1. authentication to request form
+ # 2. user request for form to create page based on a template
+ # 3. form has field 'presentation_name', textarea 'note' and radio button for selecting a version, last version of first template is default
+ # 4. new page '' based on 'Tool Mentor Template.html', create a checkout
+ # 5. page does not exist untill checkin
+ # 6. undo checkout deletes new page
+ #
+ # TODO R? undo checkout should delete a new page
+ def test03_new_page_using_template
+ # 1
+ get :new, :site_id => @openupwiki.id
+ assert_tologin
+ session['user'] = @user
+ get :new, :site_id => @openupwiki.id
+ assert_not_nil assigns(:wiki)
+ assert_not_nil assigns(:page)
+ assert_not_nil assigns(:page).source_version
+ assert_not_nil assigns(:templates)
+ assert_equal 2, assigns(:templates).size
+ assert_equal assigns(:templates)[0].versions.last.id, assigns(:page).source_version
+ assert_tag :tag => 'input', :attributes => {:type => 'radio', :name => 'page[source_version]', :value => assigns(:page).source_version, :checked => 'checked'}
+ # 3
+ assert_field('page_presentation_name')
+ assert_tag :tag => 'textarea', :attributes => {:id => 'page_note', :name => 'page[note]'}
+ assigns(:templates).each do |template|
+ template.versions.each do |version|
+ assert_tag :tag => 'input', :attributes => {:type => 'radio', :id => "page_source_version_#{version.id.to_s}", :name => 'page[source_version]', :value => version.id}
+ end
+ end
+ # 4
+ template = Page.find_by_filename('Tool Mentor Template.html')
+ template_version = template.versions.last
+ assert_not_nil template
+ post :new, :page => {:presentation_name => 'A strange name&2//++-09976', :source_version => template_version.id, :note => 'test03_new_page_using_template'}
+ assert_not_nil assigns(:page)
+ assert_not_nil assigns(:checkout)
+ assert_redirected_to :action => 'edithtml', :checkout_id => assigns(:checkout).id
+ assert_equal template_version, assigns(:checkout).version.source_version
+ assert_version_file(assigns(:checkout).version.path)
+ assert_equal 'a_strange_name209976.html', assigns(:page).filename
+ assert assigns(:checkout).version.source_version.html.index('Tool Mentor: Template')
+ assert !assigns(:checkout).version.html.index('Tool Mentor: Template')
+ assert assigns(:checkout).version.html.index('A strange name&2//++-09976')
+ assert_equal 'A strange name&2//++-09976', Page::TITLE_PATTERN.match(assigns(:checkout).version.html).to_s.gsub(Page::TITLE_START, '').gsub(Page::TITLE_END, '')
+ assert_equal 'A strange name&2//++-09976', Page::TITLE2_PATTERN.match(assigns(:checkout).version.html).to_s.gsub(Page::TITLE2_START, '').gsub(Page::TITLE2_END, '')
+ #assert_equal nil, assigns(:checkout).version.html.scan(Page::TITLE_PATTERN)
+ #assert_equal 'A strange name&2//++-09976', assigns(:page).title_from_file(@openupwiki)
+ # 5
+ assert !File.exists?(assigns(:page).path(@openupwiki)) #
+ assert File.exists?(assigns(:checkout).version.path)
+ # 6
+ end
+
+ # Shows:
+ # 1. user request for from to create page based on a page (or a template), last version of the page is default
+ # 2. user creates page using last version of page
+ # 3. page file does not exist, version file does
+ # 4. cannot create another page with the same filename
+ def test04_new_page_using_page
+ page = Page.find_by_filename('tester,_0ZM4MclgEdmt3adZL5Dmdw.html')
+ assert_not_nil page
+ # 1
+ get :new # workaround otherwise next line gives message can't convert String into Integer
+ session['user'] = @user
+ get :new, :site_id => @openupwiki.id, :id => page.id
+ assert_equal 3, assigns(:templates).size
+ assert_equal page, assigns(:templates).first # supplied page is the first in the list
+ assert_equal page.versions.last.id, assigns(:page).source_version
+ assert_tag :tag => 'input', :attributes => {:type => 'radio', :name => 'page[source_version]', :value => assigns(:page).source_version, :checked => 'checked'}
+ assigns(:templates).each do |template|
+ template.versions.each do |version|
+ assert_tag :tag => 'input', :attributes => {:type => 'radio', :id => "page_source_version_#{version.id.to_s}", :name => 'page[source_version]', :value => version.id}
+ end
+ end
+ # 2
+ page_version = page.versions.last
+ assert_not_nil page_version
+ post :new, :page => {:presentation_name => "New page based on #{page.presentation_name}", :source_version => page_version.id, :note => 'test04_new_page_using_page'}
+ assert_not_nil assigns(:page)
+ assert_not_nil assigns(:checkout)
+ assert_redirected_to :action => 'edithtml', :checkout_id => assigns(:checkout).id
+ assert_equal page_version, assigns(:checkout).version.source_version
+ assert_equal 'new_page_based_on_role_tester.html', assigns(:page).filename
+ assert_version_file(assigns(:checkout).version.path)
+ # 3
+ assert !File.exists?(assigns(:page).path(@openupwiki)) #
+ assert File.exists?(assigns(:checkout).version.path)
+ # 4
+ post :new, :page => {:presentation_name => "New page based on #{page.presentation_name}", :source_version => page_version.id, :note => 'test04_new_page_using_page'}
+ assert_not_nil assigns(:page)
+
+ #--
+ # TODO assert below does not work as expected, a checkout object is assigned
+ # although page.save is false maybe this is the checkout of the previous post???
+ # assert_equal nil, assigns(:checkout)
+ #++
+
+ assert !assigns(:page).valid?
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 'Rel path already used; can\'t create another page with relative path new_page_based_on_role_tester.html', assigns(:page).errors.full_messages.join(", ")
+ else
+ assert_equal 'Rel path already used; can\'t create another page with relative path openup_basic/roles/new_page_based_on_role_tester.html', assigns(:page).errors.full_messages.join(", ")
+ end
+ assert_errors(assigns(:page))
+ end
+
+ # Shows
+ # 1. other user can't save HTML
+ # 2. owner can save HTML
+ # 3. cadmin can save HTML of other user
+ def test05_save
+ get :new
+ page = Page.find_by_filename('any_role,_3TCEoeB5EdqnKu908IEluw.html')
+ assert_not_nil page.checkouts
+ assert_equal 1, page.checkouts.size
+ checkout = page.checkouts[0]
+ assert_not_nil checkout
+ assert_equal checkout.version.source_version.page, checkout.page # ordinary checkout, not a new page
+ html = checkout.version.html.gsub('perform general tasks','perform general tasks CHANGE IN test05_save')
+ session['user'] = @admin
+ # 1
+ assert_raise(RuntimeError) {post :saveorcheckin, :save => 'Y', :html => html, :checkout_id => checkout.id}
+ # 2
+ session['user'] = checkout.user
+ post :saveorcheckin, :save => 'Y', :html => html, :checkout_id => checkout.id
+ assert_redirected_to :action => 'edithtml', :checkout_id => checkout.id
+ assert_match 'CHANGE IN test05_save', checkout.version.html
+ # 3
+ session['user'] = @cadmin
+ post :saveorcheckin, :save => 'Y', :checkout_id => checkout.id, :html => checkout.version.html.gsub('CHANGE IN test05_save', 'CHANGE IN test05_save + change by cadmin')
+ assert_redirected_to :action => 'edithtml', :checkout_id => checkout.id
+ assert_equal 1, checkout.version.version
+ assert_match 'CHANGE IN test05_save + change by cadmin', checkout.version.html
+ end
+
+ # Shows:
+ # 1. other user cannot checkin
+ # 2. can checkin without submit of HTML
+ # 3. checkout of version 1 of page
+ # 4. can checkin with submit of HTML
+ #
+ # Anomalistic behaviour: changes matched in previous tests are gone here!!!
+ # Some sort of rollback occured strange enough
+ def test06_checkin
+ RAILS_DEFAULT_LOGGER.debug 'test05_checkin'
+ get :new
+ page = Page.find_by_filename('any_role,_3TCEoeB5EdqnKu908IEluw.html')
+ assert_not_nil page.checkouts
+ assert_equal 1, page.checkouts.size
+ checkout = page.checkouts[0]
+ # 1
+ session['user'] = @admin
+ assert @admin != checkout.user
+ assert_raise(RuntimeError) {post :saveorcheckin, :checkout_id => checkout.id, :html => checkout.version.html }
+ # 2
+ session['user'] = checkout.user
+ post :saveorcheckin, :checkout_id => checkout.id
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_match 'CHANGE IN test05_save + change by cadmin', page.html(@openupwiki)
+ assert_enhanced_file(page.path(@openupwiki))
+ assert_version_file(checkout.version.path)
+ # 3
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :version_id => page.versions.last.id, :note => 'test05_checkin', :page_id => page.id}
+ assert_equal '', assigns(:checkout).errors.full_messages.join(", ")
+ assert assigns(:checkout).valid?
+ assert_no_errors
+ assert 1, page.checkouts.size
+ assert_redirected_to :action => 'edithtml', :checkout_id => assigns(:checkout).id
+ checkout = assigns(:checkout)
+ # 4
+ post :saveorcheckin, :checkout_id => checkout.id, :html => checkout.version.html.gsub('CHANGE IN test05_save + change by cadmin', 'CHANGE IN test05_save + change by cadmin + change in test05_checkin')
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_match 'CHANGE IN test05_save + change by cadmin + change in test05_checkin', page.html(@openupwiki)
+ assert_enhanced_file(page.path(@openupwiki))
+ assert_version_file(checkout.version.path)
+ end
+
+ # Shows:
+ # 1. we can edit, preview, save and checkin a new page created based on a template
+ # 2. we can edit, preview, save and checkin a new page created based on a another page
+ def test07_checkin_new_pages
+ get :new
+ # 1
+ page = Page.find_by_presentation_name('A strange name&2//++-09976')
+ assert_equal 1, page.checkouts.size
+ checkout = page.checkouts.first
+ session['user'] = checkout.user
+ get :edithtml, :checkout_id => checkout.id # we can edit
+ post :saveorcheckin, :save => 'P', :html => checkout.version.html.gsub('This tool mentor describes how to', 'This tool mentor describes how to do something'), :checkout_id => checkout.id
+ assert_redirected_to '/' + checkout.version.rel_path_root
+ assert_match 'This tool mentor describes how to do something', checkout.version.html
+ post :saveorcheckin, :save => 'Y', :html => checkout.version.html.gsub('This tool mentor describes how to do something', 'This tool mentor describes how to do something else'), :checkout_id => checkout.id
+ assert_match 'This tool mentor describes how to do something else', checkout.version.html
+ post :saveorcheckin, :checkout_id => checkout.id
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_match 'This tool mentor describes how to do something else', page.html(@openupwiki)
+ assert_enhanced_file(page.path(@openupwiki))
+ assert_version_file(checkout.version.path)
+ # 2
+ page = Page.find_by_filename('new_page_based_on_role_tester.html')
+ assert_equal 1, page.checkouts.size
+ checkout = page.checkouts.first
+ session['user'] = checkout.user
+ get :edithtml, :checkout_id => checkout.id # we can edit
+ post :saveorcheckin, :save => 'P', :html => checkout.version.html.gsub('core activities', 'core activities + change 1 in test06_checkin_new_pages'), :checkout_id => checkout.id
+ assert_redirected_to '/' + checkout.version.rel_path_root # TODO remove passes test ? RuntimeError: The number of parameters does not match the number of substitutions.
+ assert_match 'change 1 in test06_checkin_new_pages', checkout.version.html
+ post :saveorcheckin, :save => 'Y', :html => checkout.version.html.gsub('change 1', 'change 1 + change 2'), :checkout_id => checkout.id
+ assert_match 'change 1 + change 2', checkout.version.html
+ post :saveorcheckin, :checkout_id => checkout.id
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_match 'change 1 + change 2 in test06_checkin_new_pages', page.html(@openupwiki)
+ assert_enhanced_file(page.path(@openupwiki))
+ assert_version_file(checkout.version.path)
+ end
+
+ # Shows:
+ # 1. user can undo
+ # 2. other user can't undo
+ # 3. cadmin can undo any checkout
+ def test08_undocheckout
+ get :checkout
+ session['user'] = @user
+ page = Page.find_by_filename('new_page_based_on_role_tester.html')
+ assert_equal 0, page.checkouts.size
+ # 1
+ #version = page.versions.last
+ version = Version.find_current_version(@openupwiki, page)
+ assert_equal 1, version.version
+ checkout = Checkout.new(:page => page, :site => @openupwiki, :source_version => version, :user => session['user'] )
+ assert_save checkout
+ page.reload
+ assert_equal 1, page.checkouts.size
+ version = checkout.version # TODO see below, this does not seem to work as expected
+ assert_equal 1, Checkout.count
+
+ # assert_equal 2, version.version
+ # TODO anomaly...version.version turns out to be 3, when I continue on console
+ # it turns out to be 2. That is a little more than I can understand
+ assert_equal 2, page.checkouts[0].version.version
+
+ get :undocheckout, :checkout_id => checkout.id
+ assert !Checkout.exists?(checkout.id)
+ assert !Version.exists?(version.id)
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal "#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_WIKIS_FOLDER']}/openup/new_page_based_on_role_tester.html_EPFWIKI_v2_OUP_20060721.html", page.checkouts[0].version.path
+ else
+ assert_equal "#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_WIKIS_FOLDER']}/openup/openup_basic/roles/new_page_based_on_role_tester.html_EPFWIKI_v2_OUP_20060721.html", page.checkouts[0].version.path
+ end
+ assert !File.exists?(page.checkouts[0].version.path)
+ # 2
+ checkout = Checkout.new(:page => page, :site => @openupwiki, :source_version => version, :user => session['user'] )
+ version = checkout.version
+ assert_equal '', checkout.errors.full_messages.join(", ")
+ assert checkout.save
+ session['user'] = @admin
+ assert_raise(RuntimeError) {get :undocheckout, :checkout_id => checkout.id}
+ # 3
+ session['user'] = @cadmin
+ get :undocheckout, :checkout_id => checkout.id
+ assert_redirected_to :controller => 'versions', :action => 'list', :site_id => checkout.site.id, :page_id => page.id
+ assert !Checkout.exists?(checkout.id)
+ assert !Version.exists?(checkout.version.id)
+ #assert !File.exists?(checkout.version.path) TODO anomaly: says that the file does exist
+ end
+
+ # Shows:
+ # 1. checkout with specifying a version
+ # 2. checkin van CHANGE 1
+ # 3. checkout, checkin van base version is rollback of CHANGE 1
+ def test09_rollback
+ get :new
+ session['user'] = @user
+ page = Page.find_by_filename('requirements,_allMQMWfEdqiT9CqkRksWQ.html')
+ assert_equal 0, page.versions.size
+ # 1
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :note => 'test09_rollback', :page_id => page.id}
+ assert_equal '', assigns(:checkout).errors.full_messages.join(", ")
+ assert assigns(:checkout).valid?
+ checkout = assigns(:checkout)
+ assert_no_errors
+ assert 1, page.checkouts.size
+ assert_redirected_to :action => 'edithtml', :checkout_id => checkout.id
+ # 2
+ post :saveorcheckin, :checkout_id => checkout.id, :html => checkout.version.html.gsub('requirements domain', 'requirements domain CHANGE 1')
+ assert !Checkout.exists?(checkout.id)
+ page.reload
+ assert_match 'CHANGE 1', page.versions.last.html # TODO anomaly: says that versions.last is nil
+ assert_match 'CHANGE 1', page.html(@openupwiki)
+ # 3
+ baseversion = checkout.version.baseversion
+ assert_equal 0, baseversion.version
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :note => 'test09_rollback', :page_id => page.id, :version_id => baseversion.id}
+ page.reload
+ assert 1, page.checkouts.size
+ assert_equal 2, page.versions.last.version
+ assert !page.versions.last.html.index('CHANGE 1')
+ assert page.html(@openupwiki).index('CHANGE 1')
+ post :saveorcheckin, :checkout_id => assigns(:checkout).id
+ assert 0, page.checkouts.size
+ assert !page.html(@openupwiki).index('CHANGE 1')
+ end
+
+ # file with versions
+ # fiel without versions
+ def test10_checkout_to_another_site
+ get :new
+ session['user'] = @user
+ page = Page.find_by_filename('requirements,_allMQMWfEdqiT9CqkRksWQ.html')
+ assert_equal 3, page.versions.size
+ assert_equal 0, page.checkouts.size
+ cv = Version.find_current_version(@openupwiki, page)
+ assert_not_nil cv
+ assert_equal 2, cv.version
+ openupwiki2 = Site.find_by_title('OpenUP Wiki2')
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => openupwiki2.id, :note => 'test10_checkout_to_another_site', :page_id => page.id, :version_id => cv.id}
+ page.reload
+ assert_equal 1, page.checkouts.size
+ checkout = page.checkouts.first
+ assert_equal openupwiki2, checkout.site
+ assert_equal cv, checkout.version.source_version
+ end
+
+ def test11_show
+ get :new
+ filenames = [ 'requirements,_allMQMWfEdqiT9CqkRksWQ.html',
+ 'any_role,_3TCEoeB5EdqnKu908IEluw.html',
+ 'Tool Mentor Template.html',
+ 'tester,_0ZM4MclgEdmt3adZL5Dmdw.html',
+ 'new_page_based_on_role_tester.html']
+ filenames.each do |filename|
+ page = Page.find_by_filename(filename)
+ Site.find_wikis.each do |wiki|
+ [@user, @admin, @cadmin].each do |user|
+ session['user'] = user
+ get :show, :id => page.id, :site_id => wiki.id
+ end
+ end
+ end
+ end
+
+ # Shows:
+ # 1. no users subscribed -> no notifications
+ # 2. @user subscribed -> email to @user
+ # 3. @user and @admin subscribed
+ def test12_notifications
+ @emails.clear
+ page = Page.find_by_filename('tester,_0ZM4MclgEdmt3adZL5Dmdw.html')
+ get :index
+ session['user'] = @user
+ assert_equal nil, page.checkout(@openupwiki)
+ version = page.versions.last
+ assert_not_nil version
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :note => 'test12_notifications', :page_id => page.id}
+ page.reload
+ checkout = page.checkout(@openupwiki)
+ assert_not_nil checkout
+ version = checkout.version
+ assert_equal 'test12_notifications', version.note
+ # 1
+ post :saveorcheckin, :checkout_id => checkout.id
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_equal 0, @emails.size
+ @emails.clear
+ session['user'] = @user
+ # 2
+ notification = Notification.new(:page => page, :site => @openupwiki, :user => @user, :notification_type => 'Version')
+ assert notification.save
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :note => 'test12_notifications', :page_id => page.id}
+ page.reload
+ checkout = page.checkout(@openupwiki)
+ assert_not_nil checkout
+ post :saveorcheckin, :checkout_id => checkout.id
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_equal 1, @emails.size
+ assert_equal "[#{ENV['EPFWIKI_APP_NAME']}] New version created of #{page.presentation_name}", @emails.first.subject
+ @emails.clear
+ # 3
+ notification = Notification.new(:page => page, :site => @openupwiki, :user => @admin, :notification_type => 'Version')
+ assert notification.save
+ post :checkout, :wiki_id => @openupwiki.id, :version => {:site_id => @openupwiki.id, :note => 'test12_notifications', :page_id => page.id}
+ page.reload
+ checkout = page.checkout(@openupwiki)
+ version = checkout.version
+ assert_not_nil checkout
+ post :saveorcheckin, :checkout_id => checkout.id
+ assert_equal version, page.versions.last
+ assert_raise(ActiveRecord::RecordNotFound) {Checkout.find(checkout.id)}
+ assert_equal 1, @emails.size
+ assert_equal "[#{ENV['EPFWIKI_APP_NAME']}] New version created of #{page.presentation_name}", @emails.first.subject
+ assert @emails.first.to.include?(@user.email)
+ assert @emails.first.to.include?(@admin.email)
+ assert_match "User #{version.user.name} created a version of <a href=\"http://#{@request.host}/#{version.site.rel_path}/#{version.page.rel_path}\">#{version.page.presentation_name}</a> in site #{version.site.title}<br>", @emails.first.body
+ end
+
+ # TODO R? implement functional test
+ def test02_filelist
+ end
+
+ end
+
diff --git a/source/test/functional/sites_controller_test.rb b/source/test/functional/sites_controller_test.rb
new file mode 100644
index 0000000..d911da7
--- /dev/null
+++ b/source/test/functional/sites_controller_test.rb
@@ -0,0 +1,429 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sites_controller'
+require 'generic'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class SitesController; def rescue_action(e) raise e end; end
+
+class SitesControllerTest < Test::Unit::TestCase
+ #fixtures :users
+
+ def setup
+ @controller = SitesController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @cadmin = User.find_central_admin
+ @admin = User.find_all_by_admin('Y')[0]
+ @user = User.find_all_by_admin('N')[0]
+ @emails = ActionMailer::Base::deliveries
+ @emails.clear
+ get :list
+ end
+
+ def test01_index
+ get :index
+ assert_redirected_to :controller => 'login'
+ session['user'] = User.find(2)
+ assert_not_nil(session['user'])
+ end
+
+ def test02_list
+ get :list
+ assert_redirected_to :controller => 'login'
+ session['user'] = User.find(2)
+ get :list
+ assert_response :success
+ assert_template 'list'
+ assert_not_nil assigns(:baseline_processes)
+ assert_not_nil assigns(:wiki_sites)
+ end
+
+ # Shows:
+ # 1. need to be an admin to create a baseline process
+ # 2. admin get link to create baseline process
+ # 3. admin can upload baseline process (TODO)
+ # 4. link to start baseline process available at list for admin, not for user
+ # 5. test baseline needs to be unique
+ # FIXME ignoring attempt to close
+ def test03_new
+ admin = User.find_by_admin('Y')
+ user = User.find_by_admin('N')
+ assert_not_nil admin
+ assert_not_nil user
+ # 1
+ session['user'] = user
+ get :new
+ assert_unot_admin_message
+ # 2
+ session['user'] = admin
+ get :list
+ assert_response :success
+ assert_tag :tag => 'a', :attributes => {:href => "/sites/new"}
+ # 3
+ get :new
+ assert_response :success
+ assert assigns(:site)
+ assert assigns(:baseline)
+ assert assigns(:folders)
+ assert assigns(:folders).empty?
+ assert SitesController::FLASH_NEED_TO_UPLOAD, flash['notice']
+ assert_response :success
+ #post :upload, :site => nil TODO how to test this here
+ #assert_not_nil assigns(:site)
+ #assert_errors
+ #assert_equal "Folder can't be blank, File can't be blank", assigns(:site).errors.full_messages.join(", ")
+ # unzipping, we are not testing upload
+ Site.new(:folder => openup0721_folder, :site_type => 'S').unzip_upload
+ Site.new(:folder => openup0728_folder, :site_type => 'S').unzip_upload
+ Site.new(:folder => openup0825_folder, :site_type => 'S').unzip_upload
+ get :new
+ assert_equal ["OpenUP-Basic_published_20060721#{ENV['EPFWIKI_TESTDATA']}",
+ "OpenUP-Basic_published_20060728#{ENV['EPFWIKI_TESTDATA']}",
+ "OpenUP-Basic_published_20060825#{ENV['EPFWIKI_TESTDATA']}"], assigns(:folders)
+ assigns(:folders).each do |folder|
+ assert_tag :tag => 'option', :content => folder
+ end
+ # post :new, :site => {:title => '', :file => StringIO.new('')} # how to test this?
+ # assert_equal "Title can't be blank, Folder can't be blank, Baseline can't be blank, User can't be blank", assigns(:site).errors.full_messages.join(", ")
+ # assert_errors
+ # assigns(:site).errors.full_messages.each do |message|
+ # assert_tag :tag => 'test'
+ # end
+ post :new, :site => {:title => 'openup0721', :baseline_baseline => 'OUP_20060721', :folder => assigns(:folders)[0], :description => 'test03_new'}
+ site = assigns(:site)
+ assert_not_nil site
+ assert site.valid?
+ assert_redirected_to :action => 'list'
+ assert_equal ::FLASH_RECORD_CREATED, flash[:success]
+ # 4
+ get :list
+ assert_response :success
+ assert_tag :tag => 'a', :attributes => {:href=> '/' + assigns(:site).rel_path + '/', :title => "Activate site "openup0721""}
+ # 5
+ post :new, :site => {:title => 'openup0725', :baseline_baseline => 'OUP_20060721', :folder => assigns(:folders)[1], :description => 'test03_new'}
+ assert_errors
+ assert_response :success
+ assert_equal 'Baseline has already been taken', assigns(:site).errors.full_messages.join(', ')
+ assert_errors(assigns(:site))
+ end
+
+ # Shows:
+ # 1. only admins can create wikis
+ # 2. admin can request form to create a new wiki
+ def test04_new_wiki
+ # 1
+ logonUser
+ get :new_wiki
+ assert_unot_admin_message
+ # 2
+ admin = User.find_by_admin('Y')
+ assert_not_nil admin
+ session['user'] = admin
+ get :new_wiki
+ assert_not_nil assigns(:site)
+ assert_not_nil assigns(:baseline_processes)
+ assert_field 'site_folder'
+ assert_tag :tag => 'textarea', :attributes => {:id => 'site_description', :name => 'site[description]'}
+ assert_field 'site_title'
+ assert_tag :tag => 'select', :attributes => {:id => 'site_site_id_baseline_process', :name => 'site[site_id_baseline_process]'}
+ Site.find_baseline_processes.each do |bl|
+ assert_tag :tag => 'option', :attributes => {:value => bl.id}, :content => bl.title
+ end
+ end
+
+ # Shows:
+ # 1. admin can request creation of Wiki (actual wikifying is performed directly for performance reasons)
+ # 2. a notification is sent to the central admin and the admin requesting the creation
+ def test05_new_wiki_post
+ @emails.clear
+ # 1
+ get :new_wiki
+ session['user'] = User.find_all_by_admin('Y')[0]
+ baseline_process = Site.find_by_title('openup0721')
+ assert_not_nil baseline_process
+ post :new_wiki, :site => {:folder => 'openup', :title => 'OpenUP Wiki', :description => 'Wiki for OpenUP created in test05_new_wiki_post', :baseline_process => baseline_process}
+ assert_redirected_to :action => 'list'
+ assert SitesController::FLASH_WIKI_SITE_SCHEDULED, flash['success']
+ site = assigns(:site)
+ assert_not_nil site
+ # 2
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert_equal("[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + site.title + " scheduled for creation!" , email.subject)
+ assert_equal [session['user'].email, User.find_central_admin.email], email.to
+ assert_equal site.site_type, 'W'
+ assert_equal 'P', site.status # pending
+ assert_equal session['user'], site.user
+ assert_equal baseline_process, site.baseline_process
+ end
+
+ # Shows
+ # 1. central admin can wikify content directly
+ def test06_wikify_now
+ @emails.clear
+ get 'list'
+ session['user'] = User.find_all_by_admin('Y')[0]
+ openupwiki = Site.find_by_title('OpenUP Wiki')
+ assert_not_nil openupwiki
+ baseline_process = openupwiki.baseline_process
+ assert_equal 0, openupwiki.pages.size
+ assert_equal 0, baseline_process.pages.size
+ assert_equal 'P', openupwiki.status
+ get :wikify_now, :id => openupwiki
+ assert_unot_cadmin_message
+ session['user'] = User.find_central_admin
+ get :wikify_now, :id => openupwiki.id # TODO
+ assert_not_nil assigns(:wiki)
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ #assert_equal [session['user']], email.recipients.uniq
+ assert_equal "[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + assigns(:wiki).title + " created!" , email.subject
+ assert_equal '', assigns(:wiki).errors.full_messages.join(', ')
+ openupwiki.reload
+ baseline_process = Site.find(baseline_process.id)
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 8, openupwiki.pages.size
+ assert_equal 8, baseline_process.pages.size
+ else
+ assert_equal 617, openupwiki.pages.size
+ assert_equal 617, baseline_process.pages.size
+ end
+ assert_equal 'W', openupwiki.status
+ end
+
+ # Shows
+ # 1. admin requests creation of Wiki
+ # 2. Content is wikified using job_daily (an email is sent if the job fails)
+ def test07_new_wiki_job_daily
+ # 1
+ get :new_wiki
+ session['user'] = User.find_all_by_admin('Y')[0]
+ baseline_process = Site.find_by_title('openup0721')
+ assert_not_nil baseline_process
+ post :new_wiki, :site => {:folder => 'openup2', :title => 'OpenUP Wiki2', :description => 'Wiki for OpenUP created in tst06_new_wiki2', :baseline_process => baseline_process}
+ openupwiki2 = Site.find_by_folder('openup2')
+ assert_not_nil openupwiki2
+ assert_equal 'P', openupwiki2.status
+ # 2 email sent because job fails
+ session['user'] = nil
+ folder = baseline_process.folder
+ baseline_process.folder = 'doesnotexist'
+ assert baseline_process.save
+ assert_equal 1, Site.find_wikis_pending.size
+ @emails.clear
+ job_daily
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ #assert_equal '', email.body
+ assert email.body.include?('unknown file type') && email.body.include?('doesnotexist')
+ assert_equal 1, Site.find_wikis_pending.size
+ # 2 success
+ openupwiki2.reload
+ baseline_process = openupwiki2.baseline_process
+ baseline_process.folder = folder
+ assert baseline_process.save
+ @emails.clear
+ job_daily
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert_equal "[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + openupwiki2.title + " created!" , email.subject
+ assert_equal 0, Site.find_wikis_pending.size
+ openupwiki2.reload
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 8, openupwiki2.pages.size
+ else
+ assert_equal 617, openupwiki2.pages.size
+ end
+ assert_equal 'W', openupwiki2.status
+ end
+
+ # Shows
+ # 1. users cannot request a form to update a Wiki
+ # 2. a message is displayed if there are no candidate baseline processes
+ # 3. admin can select a candite baseline process
+ # 4. user cannot post the form
+ # 5. update is postponed if there are checkouts (checkin request email)
+ # 6. update job fails, notification sent
+ # 7. cannot do update_wiki_now
+ # 8. cadmin request immediate update of wiki
+ # 9. update wiki via job_daily
+ def test08_update_wiki
+ # 1
+ openupwiki2 = Site.find_by_folder('openup2')
+ assert_not_nil openupwiki2
+ get :update_wiki, :id => openupwiki2.id
+ assert_redirected_to :controller => 'login'
+ session['user'] = @user
+ assert_not_nil session['user']
+ get :update_wiki, :id => openupwiki2.id
+ assert_unot_admin_message
+ # 2
+ session['user'] = @admin
+ get :update_wiki, :id => openupwiki2.id
+ assert_response :success
+ assert_equal 0, openupwiki2.baseline_processes_candidate.size
+ assert_tag :content => SitesController::FLASH_NO_BL_CANDIDATE
+ assert_no_tag :tag => 'select', :attributes => {:id => 'site_baseline_process', :name => 'site[baseline_process]'}
+ assert_no_tag :tag => 'form'
+ # 3
+ post :new, :site => {:title => 'openup0728', :baseline_baseline => 'OUP_20060728', :folder => "OpenUP-Basic_published_20060728#{ENV['EPFWIKI_TESTDATA']}", :description => 'test08_update_wiki'}
+ openupwiki2.reload
+ assert_equal 1, openupwiki2.baseline_processes_candidate.size
+ get :update_wiki, :id => openupwiki2.id
+ assert_tag :tag => 'form'
+ assert_tag :tag => 'select', :attributes => {:id => 'site_baseline_process', :name => 'site[baseline_process]'}
+ openupwiki2.baseline_processes_candidate.each do |bl|
+ assert_tag :tag => 'option', :attributes => {:value => bl.id}, :content => bl.title
+ end
+ post :new, :site => {:title => 'openup0825', :baseline_baseline => 'OUP_20060825', :folder => "OpenUP-Basic_published_20060825#{ENV['EPFWIKI_TESTDATA']}", :description => 'test08_update_wiki'}
+ openupwiki2.reload
+ assert_equal 2, openupwiki2.baseline_processes_candidate.size
+ get :update_wiki, :id => openupwiki2.id
+ assert_tag :tag => 'form'
+ assert_tag :tag => 'select', :attributes => {:id => 'site_baseline_process', :name => 'site[baseline_process]'}
+ openupwiki2.baseline_processes_candidate.each do |bl|
+ assert_tag :tag => 'option', :attributes => {:value => bl.id}, :content => bl.title
+ end
+ # creating a checkout
+ page = Page.find_by_filename('artifact,_fdRfkBUJEdqrUt4zetC1gg.html')
+ assert_not_nil page
+ checkout = Checkout.new(:user => @user, :page => page, :site => openupwiki2, :note => 'test08_update_wiki')
+ assert checkout.save
+ checkout.reload
+ # 4
+ session['user'] = @user
+ post :update_wiki, :id => openupwiki2.id, :site => {:baseline_process => openupwiki2.baseline_processes_candidate[0]}
+ assert_unot_admin_message
+ # 5
+ session['user'] = @admin
+ @emails.clear
+ post :update_wiki, :id => openupwiki2.id, :site => {:baseline_process => openupwiki2.baseline_processes_candidate[0]}
+ assert_redirected_to :action => 'show', :id => openupwiki2.id
+ assert_equal SitesController::FLASH_WIKI_SITE_UPDATE_SCHEDULED, flash['success']
+ assert_equal(2, @emails.size)
+ email = @emails.first
+ assert email.to.include?(@user.email)
+ assert email.to.include?(@cadmin.email)
+ assert_equal "[" + ENV['EPFWIKI_APP_NAME'] + "] " + openupwiki2.title + " - Check-In Request", email.subject
+ email = @emails[1]
+ assert_equal "[" + ENV['EPFWIKI_APP_NAME'] + "] Site " + openupwiki2.title + " scheduled for update!", email.subject
+ #assert_equal '', email.inspect
+ assert email.to.include?(@admin.email)
+ assert email.to.include?(@cadmin.email)
+ # 6
+ @emails.clear
+ job_daily
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert email.to.include?(@user.email)
+ assert email.to.include?(@cadmin.email)
+ assert_equal "[" + ENV['EPFWIKI_APP_NAME'] + "] " + openupwiki2.title + " - Check-In Request", email.subject
+ # extra checkout
+ page = Page.find_by_filename('determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html')
+ checkout = Checkout.new(:user => @admin, :page => page, :site => openupwiki2, :note => 'test08_update_wiki')
+ assert checkout.save
+ checkout.reload
+ @emails.clear
+ job_daily
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert email.to.include?(@admin.email)
+ assert email.to.include?(@cadmin.email)
+ assert email.to.include?(@user.email)
+ assert_equal 3, email.to.size
+ assert_equal "[" + ENV['EPFWIKI_APP_NAME'] + "] " + openupwiki2.title + " - Check-In Request" , email.subject
+ # 7
+ session['user'] = @admin
+ post :update_wiki_now, :id => openupwiki2.id
+ assert_unot_cadmin_message
+ session['user'] = @cadmin
+ post :update_wiki_now, :id => openupwiki2.id
+ assert_equal SitesController::FLASH_CHECKOUTS_NO_UPDATE, flash['notice']
+ # checkin the two checkouts
+ Checkout.find_all[0].checkin(@user)
+ Checkout.find_all[0].checkin(@admin)
+ openupwiki2.reload
+ assert openupwiki2.checkouts.empty?
+ # 8
+ @emails.clear
+ assert_equal 1, Site.find_wikis_update.size
+ post :update_wiki_now, :id => openupwiki2.id
+ assert_equal SitesController::FLASH_WIKI_UPDATE_SUCCESS, flash['success']
+ assert_equal 0, Site.find_wikis_update.size
+ assert_equal(1, @emails.size)
+ assert email.to.include?(@user.email)
+ assert email.to.include?(@admin.email)
+ assert email.to.include?(@admin.email)
+ assert "[#{ENV['EPFWIKI_APP_NAME']}] Site #{openupwiki2.title} updated!", email.subject
+ # 9 update via job daily
+ openupwiki2.reload
+ assert_equal 1, openupwiki2.baseline_processes_candidate.size
+ openup0825 = openupwiki2.baseline_processes_candidate[0]
+ post :update_wiki, :id => openupwiki2.id, :site => {:baseline_process => openup0825}
+ assert_equal 1, Site.find_wikis_update.size
+ openupwiki2.reload
+ assert_equal 'U', openupwiki2.status
+ openupwiki2.reload
+ assert_equal openupwiki2.baseline_process, openup0825
+ @emails.clear
+ assert !openupwiki2.baselines.include?(openup0825.baseline)
+ job_daily # update wiki
+ assert_equal 0, Site.find_wikis_update.size
+ openupwiki2.reload
+ assert openupwiki2.baselines.include?(openup0825.baseline)
+ assert_equal 'W', openupwiki2.status
+ assert_equal 1, @emails.size
+ email = @emails.first
+ assert "[#{ENV['EPFWIKI_APP_NAME']}] Site #{openupwiki2.title} updated!", email.subject
+ # additional tests
+ openupwiki2.reload
+ pages = []
+ openupwiki2.baselines.each do |baseline|
+ baseline.pages.each do |page|
+ assert openupwiki2.pages.include?(page)
+ end
+ end
+ end
+
+ # Shows:
+ # 1. cadmin users are presented with a link to create a new difference analysis
+ #
+ def test09_show
+ [@admin, @cadmin, @user].each do |user|
+ session['user'] = user
+ Site.find_all.each do |site|
+ get :show, :id => site.id
+ assert_response :success
+ if cadmin? && site.site_type == 'S'
+ # TODO R? implement functional test. For some reason we cannot detect this link using assert_tag?
+ # assert_tag :tag => 'a', :attributes => {:href => '/difference_analyes/new'}
+ end
+ get :show, :id => site.id, :tab => 'comments'
+ assert_response :success
+ get :show, :id => site.id, :tab => 'pages'
+ assert_response :success
+ end
+ end
+ end
+
+ def test10_list
+ [@admin, @cadmin, @user].each do |user|
+ session['user'] = user
+ get :list
+ end
+ end
+end
diff --git a/source/test/functional/toolbar_controller_test.rb b/source/test/functional/toolbar_controller_test.rb
new file mode 100644
index 0000000..25515b4
--- /dev/null
+++ b/source/test/functional/toolbar_controller_test.rb
@@ -0,0 +1,75 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'toolbar_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class ToolbarController; def rescue_action(e) raise e end; end
+
+class ToolbarControllerTest < Test::Unit::TestCase
+ def setup
+ @controller = ToolbarController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ end
+
+ def test01_show
+ @openupwiki.pages.each do |page|
+ get :show, :url => "http://#{@request.host}/#{@openupwiki.rel_path}/#{page.rel_path}"
+ assert_not_nil assigns(:rel_path)
+ assert_equal page.rel_path, assigns(:rel_path)
+ assert_equal @openupwiki, assigns(:wiki)
+ #assert_equal @openupwiki.baseline, assigns(:baseline)
+ assert_equal page, assigns(:page)
+ assert_template 'show'
+ #assert_layout 'toolbar'
+ end
+ end
+
+ def test02_edit
+ @openupwiki.pages.each do |page|
+ get :edit, :id => @openupwiki.id, :rel_path => page.rel_path
+ assert_redirected_to :controller => 'pages', :action => 'checkout', :id => page.id, :site_id => @openupwiki.id
+ end
+ end
+
+ def test03_new
+ @openupwiki.pages.each do |page|
+ get :new, :id => @openupwiki.id, :rel_path => page.rel_path
+ assert_redirected_to :controller => 'pages', :action => 'new', :id => page.id, :site_id => @openupwiki.id
+ end
+ end
+
+ def test04_new_comment
+ @openupwiki.pages.each do |page|
+ get :new_comment, :id => @openupwiki.id, :rel_path => page.rel_path
+ assert_redirected_to :controller => 'comments', :action => 'new', :page_id => page.id, :site_id => @openupwiki.id
+ end
+ end
+
+ def test05_expand_toggle
+ page = @openupwiki.pages[4]
+ get :expand_toggle, :url => "http://#{@host}/ENV['EPFWIKI_WIKIS_FOLDER']/#{@openupwiki.folder}/#{page.rel_path}"
+ assert_not_nil assigns(:wiki)
+ assert_not_nil assigns(:rel_path)
+ assert_equal @openupwiki, assigns(:wiki)
+ assert_equal true, session['toolbar_expanded']
+ get :expand_toggle, :url => "http://#{@host}/ENV['EPFWIKI_WIKIS_FOLDER']/#{@openupwiki.folder}/#{page.rel_path}"
+ assert_equal false, session['toolbar_expanded']
+ get :expand_toggle, :url => "http://#{@host}/ENV['EPFWIKI_WIKIS_FOLDER']/#{@openupwiki.folder}/#{page.rel_path}"
+ assert_equal true, session['toolbar_expanded']
+ end
+end
diff --git a/source/test/functional/users_controller_test.rb b/source/test/functional/users_controller_test.rb
new file mode 100644
index 0000000..a42c364
--- /dev/null
+++ b/source/test/functional/users_controller_test.rb
@@ -0,0 +1,272 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'users_controller'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class UsersController; def rescue_action(e) raise e end; end
+
+class UsersControllerTest < Test::Unit::TestCase
+ fixtures :users
+
+ def setup
+ @controller = UsersController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @emails = ActionMailer::Base::deliveries
+ @emails.clear
+ end
+
+ def test01_index
+ get :index
+ assert_tologin
+ end
+
+ def test02_list
+ get :list
+ assert_tologin
+ end
+
+ def test03_list_cadmin
+ # get the central admin
+ get :list
+ logonCentralAdmin
+ get :list
+ assert_not_nil assigns(:users)
+ assert_not_nil assigns(:admins)
+ assert_not_nil assigns(:cadmin)
+ end
+
+ def test04_list_admin
+ # get the admin
+ get :list
+ logonAdmin
+ get :list
+ assert_not_nil assigns(:users)
+ assert_not_nil assigns(:admins)
+ assert_not_nil assigns(:cadmin)
+ end
+
+ def test05_list_normaluser
+ # normal user
+ get :list
+ session['user'] = User.find(3)
+ get :list
+ assert_unot_admin_message
+ # normal user tries to look at details of admin user
+ post :show, :id => 1
+ assert_equal session['user'], assigns(:user)
+ assert_equal LoginController::FLASH_UNOT_ADMIN, flash['notice']
+ end
+
+ # Shows:
+ # 1. user can edit his details
+ # 2. user cannot edit another users details
+ # 3. admin cannot edit another users details
+ # 4. cadmin can edit another users details
+ def test06_edit
+ # 1
+ get :index
+ users = User.find_all_by_admin('N')
+ assert users.size > 1
+ session['user'] = users[0]
+ saved_name = users[0].name
+ post :edit, :id => users[0].id, :user => {:name => 'test06_edit'}
+ assert_response :success
+ users[0].reload
+ assert_equal 'test06_edit', users[0].name
+ users[0].name = saved_name
+ users[0].save!
+ # 2
+ session['user'] = users[1]
+ post :edit, :id => users[0].id, :user => {:name => 'test06_edit'}
+ assert_response :success
+ users[0].reload
+ assert_equal saved_name, users[0].name # unchanged
+ # 3
+ session['user'] = User.find_by_admin('Y')
+ post :edit, :id => users[0].id, :user => {:name => 'test06_edit'}
+ assert_response :success
+ users[0].reload
+ assert_equal saved_name, users[0].name # unchanged
+ # 4
+ session['user'] = User.find_by_admin('C')
+ post :edit, :id => users[0].id, :user => {:name => 'test06_edit'}
+ assert_response :success
+ users[0].reload
+ assert_equal 'test06_edit', users[0].name # changed
+ users[0].name = saved_name
+ users[0].save!
+ end
+
+ def test08_resend
+ #moved to logincontroller
+ end
+
+ def test09_send_report
+ logonUser3
+ post :send_report, :type => 'M'
+ assert_equal UsersController::FLASH_REPORT_SENT, flash['success']
+ assert_redirected_to :action => 'show'
+ assert_equal(1, @emails.size)
+ email = @emails.first
+ assert email.subject.index('Monthly')
+ assert_equal("user3@epf.org", email.to[0])
+ assert_equal([ENV['EPFWIKI_REPLY_ADDRESS']], email.from)
+ post :send_report, :type => 'D'
+ assert_equal UsersController::FLASH_REPORT_SENT, flash['success']
+ post :send_report, :type => 'W'
+ assert_equal UsersController::FLASH_REPORT_SENT, flash['success']
+ end
+
+ # Show:
+ # 1. user can access details
+ # 2. user has links to 'edit', 'change password'
+ # 3. other users cannot see details of other users
+ # 4. admins can't also
+ # 5. cadmin is shown links 'edit', 'list', 'resend password'
+ def test12_show
+ users = User.find_all_by_admin('N')
+ assert users.size > 1
+ get :index
+ # 1
+ session['user'] = users[0]
+ get :show, :id => users[0].id
+ assert_response :success
+ assert_template 'show'
+ assert_not_nil assigns(:user)
+ assert_not_nil assigns(:version_pages)
+ assert_not_nil assigns(:versions)
+ assert_equal users[0].id, assigns(:user).id
+ # 2
+ assert_tag :tag => 'a', :attributes => {:href => "/users/edit/#{users[0].id.to_s}"}
+ assert_tag :tag => 'a', :attributes => {:href => '/login/change_password'}
+ # 3
+ session['user'] = users[1]
+ get :show, :id => users[0].id
+ assert_equal users[1].id, assigns(:user).id # user sees his own details
+ # 4
+ session['user'] = User.find_by_admin('Y')
+ get :show, :id => users[0].id
+ assert_equal session['user'].id, assigns(:user).id # admin sees his own details
+ # 5
+ session['user'] = User.find_by_admin('C')
+ get :show, :id => users[0].id
+ assert_equal users[0].id, assigns(:user).id # cadmin sees details of user
+ assert_tag :tag => 'a', :attributes => {:href => "/users/edit/#{users[0].id.to_s}"}
+ assert_tag :tag => 'a', :attributes => {:href => '/users/list'}
+ assert_tag :tag => 'a', :attributes => {:href => "/users/resend/#{users[0].id.to_s}"}
+ end
+
+ def test13_show_comments
+ get :list
+ session['user'] = User.find(1)
+ get :show_comments, :id => 1
+ assert_response :success
+ assert_template 'show'
+ assert_not_nil assigns(:user)
+ assert_not_nil assigns(:comment_pages)
+ assert_not_nil assigns(:comments)
+ end
+
+ def test13_edit_user
+ get :list
+ session['user'] = User.find(1)
+ post :edit, :id => session['user'].id, :user => { :name => 'Onno Renamed'}
+ assert_response :success
+ assert_template 'edit'
+ assert_not_nil assigns(:user)
+ assert_equal User.find(assigns(:user).id).name, 'Onno Renamed'
+ end
+
+ # Shows:
+ # 1. list of users contains links to make other admins the cadmin, and links to make other users admins
+ # 2. cadmin can make another user cadmin
+ # 3. cadmin can make another user cadmin after making another user cadmin
+ # 4. user can make cadmin cadmin after being made the cadmin
+ # 5. this is a transaction
+ def test14_cadmin
+ cadmin = User.find_central_admin
+ assert_equal 5, cadmin.id
+ user = User.find_all_by_admin('Y')[0]
+ assert_not_nil user
+ assert_not_nil cadmin
+ get :list
+ session['user'] = cadmin
+ # 1
+ get :list
+ assert_response :success
+ assert_template 'list'
+ User.find_all_by_admin('Y').each do |user|
+ assert_tag :tag => 'a', :attributes => {:href => "/users/cadmin/#{user.id}"}
+ assert_tag :tag => 'a', :attributes => {:href => "/users/admin/#{user.id}?admin=N"}
+ end
+ User.find_all_by_admin('N').each do |user|
+ assert_tag :tag => 'a', :attributes => {:href => "/users/admin/#{user.id}?admin=Y"}
+ end
+ # 2
+ assert_not_nil cadmin
+ assert_not_nil user
+ get :list
+ post :cadmin, :id => user.id
+ assert_redirected_to :action => 'list'
+ assert_equal '', assigns(:cadmin).errors.full_messages.join(", ") # cadmin
+ assert_equal '', assigns(:user).errors.full_messages.join(", ")
+ cadmin.reload
+ user.reload
+ assert !cadmin.cadmin?
+ assert cadmin.admin?
+ assert user.cadmin?
+ # 3
+ post :cadmin, :id => user.id
+ assert_unot_cadmin_message
+ # 4
+ session['user'] = user
+ post :cadmin, :id => cadmin.id
+ assert_redirected_to :action => 'list'
+ cadmin.reload
+ user.reload
+ assert cadmin.cadmin?
+ assert cadmin.admin?
+ assert !user.cadmin?
+ assert user.admin?
+ # 5
+ cadmin.name = nil # will cause save of this user to fail
+ User.cadmin(cadmin, user)
+ cadmin.reload
+ user.reload
+ assert cadmin.cadmin?
+ assert cadmin.admin?
+ assert !user.cadmin?
+ assert user.admin?
+ assert !cadmin.name.nil?
+ end
+
+ def test15_toggle_change_report_notification
+ # TODO implement functional test
+ end
+
+ def test16_notification
+ # TODO implement functional test
+ end
+
+ def test17_destroy_notification
+ # TODO implement functional test
+ end
+
+ def test18_make_otherusers_admin
+ # TODO implement functional test
+ end
+end
diff --git a/source/test/functional/versions_controller_test.rb b/source/test/functional/versions_controller_test.rb
new file mode 100644
index 0000000..209c609
--- /dev/null
+++ b/source/test/functional/versions_controller_test.rb
@@ -0,0 +1,274 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'versions_controller'
+require 'pathname'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+# Re-raise errors caught by the controller.
+class VersionsController; def rescue_action(e) raise e end; end
+
+class VersionsControllerTest < Test::Unit::TestCase
+
+ def setup
+ @controller = VersionsController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @openup0721 = Site.find_by_title('openup0721')
+ @admin = User.find_by_admin('Y')
+ @cadmin = User.find_central_admin
+ @user = User.find_by_admin('N')
+ end
+
+ # Shows
+ # 1. authentication required
+ # 2. all users can access version details
+ # 3. owner or cadmin are presented an edit link to version note
+ def test01_show
+ # 1
+ assert Version.count > 0
+ version = Version.find_first
+ assert_not_nil version
+ get :show, :id => version.id
+ assert_tologin
+ # 2
+ [@admin, @cadmin, @user].each do |user|
+ session['user'] = user
+ Version.find_all.each do |version|
+ get :show, :id => version.id
+ # 2
+ assert_response :success
+ assert_not_nil assigns(:version)
+ if mine?(assigns(:version)) || cadmin?
+ # 3
+ assert_tag :tag => 'a', :attributes => {:href => "/versions/edit/#{version.id.to_s}"}
+ end
+ end
+ end
+ end
+
+ # Shows:
+ # 1. @admin requests form
+ # 2. @admin submits change and fails (not owner)
+ # 3. @cadmin can update
+ # 4. owner can update
+ def test02_edit
+ page = Page.find_by_filename('artifact,_fdRfkBUJEdqrUt4zetC1gg.html')
+ assert !nil, page.checkout(@openupwiki)
+ version = page.versions.last
+ assert_equal 'test08_update_wiki', version.note
+ assert_equal @user, version.user
+ get :edit, :id => version.id
+ assert_tologin
+ # 1
+ session['user'] = @admin
+ get :edit, :id => version.id
+ # 2
+ post :edit, :id => version.id, :version => {:note => 'test08_update_wiki + update in test02_edit'}
+ assert_response :success
+ #assert_equal ::FLASH_NOT_OWNER, flash.now['error'] # flash.now tests don't work?
+ version.reload
+ assert_equal 'test08_update_wiki', version.note
+ # 3
+ session['user'] = @cadmin
+ post :edit, :id => version.id, :version => { :note => 'test08_update_wiki + update in test02_edit'}
+ assert_redirected_to :action => 'list', :page_id => version.page.id, :site_id => version.site.id
+ #assert_equal ::FLASH_NOT_OWNER, flash.now['error'] # flash.now tests don't work?
+ version.reload
+ assert_equal 'test08_update_wiki + update in test02_edit', version.note
+ # 4
+ session['user'] = version.user
+ post :edit, :id => version.id, :version => { :note => 'test08_update_wiki + update in test02_edit'}
+ assert_redirected_to :action => 'list', :page_id => version.page.id, :site_id => version.site.id
+ version.reload
+ assert_equal 'test08_update_wiki + update in test02_edit', version.note
+ end
+
+ # Shows:
+ # 1. user cannot assign self
+ # 2. admin can
+ # 3. owner (admin) can unassign
+ # 4. other admin cannot assign an already assigned record
+ # 5. but cadmin can
+ def test03_review
+ get :new
+ admin2 = (User.find_all_by_admin('Y') - [@admin])[0]
+ assert_not_nil admin2
+ page = Page.find_by_filename('artifact,_fdRfkBUJEdqrUt4zetC1gg.html')
+ assert !nil, page.checkout(@openupwiki)
+ assert !@user.admin?
+ version = page.versions.last
+ assert_equal nil, version.reviewer
+ # 1
+ session['user'] = @user
+ post :review, :id => version.id
+ assert_unot_admin_message
+ version.reload
+ assert_equal nil, version.reviewer
+ # 2
+ session['user'] = @admin
+ post :review, :id => version.id
+ assert_response :success
+ version.reload
+ assert_equal @admin, version.reviewer
+ # 3
+ post :review, :id => version.id
+ assert_response :success
+ version.reload
+ assert_equal nil, version.reviewer
+ post :review, :id => version.id
+ version.reload
+ assert_equal @admin, version.reviewer
+ # 4
+ session['user'] = admin2
+ post :review, :id => version.id
+ assert_response :success
+ version.reload
+ assert_equal @admin, version.reviewer
+ # 5
+ session['user'] = @cadmin
+ post :review, :id => version.id
+ assert_response :success
+ version.reload
+ assert_equal @cadmin, version.reviewer #TODO remove
+ # 6
+ post :review, :id => version.id
+ assert_response :success
+ version.reload
+ assert_equal nil, version.reviewer
+ end
+
+ # Shows
+ # 1. it is possible to display a version of a page in markdown format
+ def test04_markdown
+ get :new
+ page = Page.find_by_filename('artifact,_fdRfkBUJEdqrUt4zetC1gg.html')
+ version = page.versions[0]
+ assert !File.exists?(version.markdownpath)
+ assert_not_nil version
+ session['user'] = @user
+ get :markdown, :id => version.id
+ assert_response :success
+ assert File.exists?(version.markdownpath)
+ assert File.compare(version.markdownpath, "#{ENV['EPFWIKI_ROOT_DIR']}test/functional/versions_controller_test/version1.txt")
+ end
+
+ # Shows:
+ # 1. user cannot toggle a version 'done' or 'todo'
+ # 2. admins can
+ def test05_toggle_done
+ get :listall
+ page = Page.find_by_filename('artifact,_fdRfkBUJEdqrUt4zetC1gg.html')
+ version = page.versions[0]
+ assert_equal 'Y', version.done
+ # 1
+ session['user'] = @user
+ get :toggle_done, :id => version.id
+ assert_unot_admin_message
+ version.reload
+ assert_equal 'Y', version.done
+ # 2
+ session['user'] = @admin
+ get :toggle_done, :id => version.id
+ version.reload
+ assert_equal 'N', version.done
+ get :toggle_done, :id => version.id
+ version.reload
+ assert_equal 'Y', version.done
+ end
+
+ # Shows:
+ # 1. all users can request list of versions
+ # 2. users are presented a link to list of all versions (not todo, done)
+ # 2. only admins are presented links (tabs) to access those lists
+ def test06_list
+ get :new
+ [@user, @admin].each do |user|
+ session['user'] = user
+ get :listall
+ assert_response :success
+ get :listtodo
+ assert_response :success
+ get :listdone
+ assert_response :success
+ get :listcheckouts
+ assert_response :success
+ end
+ session['user'] = @user
+ get :listall
+ assert_response :success
+ assert_no_tag :tag => 'a', :attributes => {:href => 'versions/listtodo'}
+ assert_no_tag :tag => 'a', :attributes => {:href => 'versions/listdone'}
+ #assert_tag :tag => 'a', :attributes => {:href => 'versions/listcheckouts'}
+ #assert_tag :tag => 'a', :attributes => {:href => 'versions/listall'}
+ #session['user'] = @admin
+ #sget :listall
+ #assert_response :success
+ #assert_tag :tag => 'a', :attributes => {:href => 'versions/listtodo'}
+ #assert_tag :tag => 'a', :attributes => {:href => 'versions/listdone'}
+ #assert_tag :tag => 'a', :attributes => {:href => 'versions/listcheckouts'}
+ #assert_tag :tag => 'a', :attributes => {:href => 'versions/listall'}
+ #get :listtodo
+ #assert_response :success
+ #get :listcheckouts
+ #assert_response :success
+ #get :listdone
+ #assert_response :success
+ end
+
+ # Shows:
+ # 1. user can compare version 2 of any_role with the other versions of the page
+ # 2. user does compare with previous (version 1)
+ # 3. a diff file is generated
+ # 4. the diff file is only generated once, unless the version files involved in the compare change
+ # 5. identical files TODO R? implemented functional test
+ def test07_compare
+ page = Page.find_by_filename('any_role,_3TCEoeB5EdqnKu908IEluw.html')
+ version = page.versions.last
+ previous_version = version.previous_version
+ assert_not_nil previous_version
+ assert_equal 2, version.version
+ get :listall
+ # 1
+ session['user'] = @user
+ get :compare, :id => version.id
+ assert_response :success
+ page.versions_in_site(@openupwiki).each do |version|
+ assert_tag :tag => 'option', :attributes => {:value => version.id}
+ end
+ # 2
+ assert !File.exists?(path2markdowndiff(version,previous_version))
+ post :compare, :id => version.id, :source_version_id => previous_version.id
+ assert_response :success
+ # 3
+ assert File.exists?(path2markdowndiff(version,previous_version))
+ mtime = File.mtime(path2markdowndiff(version,previous_version))
+ assert_equal mtime, File.mtime(path2markdowndiff(version,previous_version))
+ # 4
+ post :compare, :id => version.id, :source_version_id => previous_version.id
+ assert_response :success
+ # same diff
+ assert_equal mtime, File.mtime(path2markdowndiff(version,previous_version))
+ version.html(version.html)
+ post :compare, :id => version.id, :source_version_id => previous_version.id
+ assert_response :success
+ # newer diff because version file changed
+ # TODO R? implement functional test
+ # assert File.mtime(path2markdowndiff(version,previous_version)) == mtime # fails
+ # assert File.mtime(path2markdowndiff(version,previous_version)) > mtime # fails
+ # assert File.mtime(path2markdowndiff(version,previous_version)) < mtime # fails ????
+ end
+
+end
\ No newline at end of file
diff --git a/source/test/functional/versions_controller_test/version1.txt b/source/test/functional/versions_controller_test/version1.txt
new file mode 100644
index 0000000..121872e
--- /dev/null
+++ b/source/test/functional/versions_controller_test/version1.txt
@@ -0,0 +1,30 @@
+Concept: Artifact [][1]
+![][2]
+
+![][3]
+Artifact is a Work Product that provides a description and definition for tangible, non-trivial work products.
+
+Main Description
+
+Artifacts are tangible well-defined Work Products consumed, produced, or modified by Tasks. Artifacts may be composed of other Artifacts. For example, a model Artifact can be composed of model elements, which are also Artifacts. They may serve as a basis for defining Reusable Assets. Roles use Artifacts to perform Tasks and produce Artifacts in the course of performing Tasks.
+
+Artifacts are the responsibility of a single Role, making responsibility easy to identify and understand, and promoting the idea that every piece of information produced in the method requires the appropriate set of skills. Even though one Role might "own" a specific type of Artifact, other Roles can still use the Artifacts, and perhaps even update them if the Role has been given permission to do so.
+
+**Artifacts are generally _not_ documents**. Many methods have an excessive focus on documents, and in particular on _paper documentation_. The most efficient and pragmatic approach to managing project Artifacts is to maintain them _within_ the appropriate tool used to create and manage them. When necessary, one may generate documents (snapshots) from these tools, on a just-in-time basis.
+
+Examples Artifacts:
+
+ * A use case specification stored in a word processor tool
+ * A design model stored in a visual modeling tool.
+ * A project plan stored in a project planning tool.
+ * A defect stored in a change requests tools
+ * A project requirements database in a requirements management tool.
+
+Note also that formats such as on **whiteboards** or **flip charts** can be used to capture pictorial information such as UML diagrams, tabular information such as short lists of status information or even textual information such as short vision statements. These formats work well for smaller, collocated teams where all team members have ready access to these resources.
+
+However, there are still Artifacts which either have to be or are best suited to being plain text documents, as in the case of external input to the project, or in some cases where it is simply the best means of presenting descriptive information. Where possible, teams should consider using collaborative **Work Group** tools, such as WikiWiki webs or Groove to capture textual documentation electronically, thus simplifying ongoing content and version management. This is especially of importance where historic records must be maintained for purposes such as fulfilling audit requirements. For any nontrivial development effort, especially where large development teams are involved, Work Products **are** **most likely to be subject to version control and configuration management.** This is sometimes only achieved by versioning the container Work Product, when it is not possible to do it for the elementary, contained Work Products. For example, in software development, you may control the versions of a whole design model, or design package, and not the individual classes they contain.
+
+ [1]: ./../../../index.htm
+ [2]: ./../../../images/shim.gif
+ [3]: ./../../../images/concept.gif
+
diff --git a/source/test/integration.bat b/source/test/integration.bat
new file mode 100644
index 0000000..a565e54
--- /dev/null
+++ b/source/test/integration.bat
@@ -0,0 +1,2 @@
+call rake db:test:prepare
+ruby integration/setup_and_sign_in_test.rb
diff --git a/source/test/integration/creating_sites_and_wikis_test.rb b/source/test/integration/creating_sites_and_wikis_test.rb
new file mode 100644
index 0000000..c37c079
--- /dev/null
+++ b/source/test/integration/creating_sites_and_wikis_test.rb
@@ -0,0 +1,30 @@
+require "#{File.dirname(__FILE__)}/../test_helper"
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class CreatingSitesAndWikisTest < ActionController::IntegrationTest
+ # fixtures :your, :models
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+
+ def test01_create_site
+ assert User.count > 0
+ cadmin = User.find_central_admin
+ assert_not_nil cadmin
+
+ end
+end
diff --git a/source/test/integration/setup_and_sign_in_test.rb b/source/test/integration/setup_and_sign_in_test.rb
new file mode 100644
index 0000000..d519c30
--- /dev/null
+++ b/source/test/integration/setup_and_sign_in_test.rb
@@ -0,0 +1,167 @@
+require "#{File.dirname(__FILE__)}/../test_helper"
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class SetupAndSignInTest < ActionController::IntegrationTest
+ # If there are no users:
+ # * all request are redirected to the new page
+ # * the new page can be used to create the central admin account
+ # After the first user is created (User.count > 0) it is not possible to create the central admin user
+ def test01_signup_central_admin
+ assert_equal 0, User.count
+ get "login/login"
+ assert_redirected_to :action => 'new_cadmin'
+ # fields cannot be null
+ post "login/new_cadmin"
+ assert_response :success
+ assert_errors
+ assert_equal 0, User.count
+ # no password confirmation
+ post "login/new_cadmin", :user => {:name => "cadmin", :email => "cadmin@logicacmg.com", :password => "cadmin"}
+ assert_equal "Password confirmation can't be blank",assigns(:user).errors.full_messages.join(', ')
+ assert_response :success #302?
+ assert_equal 0, User.count
+ assert_errors
+ # passwords don't match
+ post "login/new_cadmin", :user => {:name => "cadmin", :email => "cadmin@logicacmg.com", :password => "cadmin", :password_confirmation => ""}
+ assert_equal "Password confirmation can't be blank, Password doesn't match confirmation",assigns(:user).errors.full_messages.join(', ')
+ assert_response :success #302?
+ assert_equal 0, User.count
+ assert_errors
+ # passwords should be present
+ post "login/new_cadmin", :user => {:name => "cadmin", :email => "cadmin@logicacmg.com"}
+ assert_equal "Password confirmation can't be blank, Password can't be blank",assigns(:user).errors.full_messages.join(', ')
+ assert_equal 0, User.count
+ assert_response :success
+ assert_errors
+ post "login/new_cadmin", :user => {:name => "cadmin", :email => "cadmin@logicacmg.com", :password => "cadmin", :password_confirmation => "cadmin"}
+ assert_equal "",assigns(:user).errors.full_messages.join(', ')
+ assert_equal 1, User.count
+ cadmin = User.find_central_admin
+ assert_not_nil cadmin
+ assert_redirected_to :action => 'login'
+ post "login/new_cadmin", :user => {:name => "cadmin", :email => "cadmin@logicacmg.com", :password => "cadmin", :password_confirmation => "cadmin"}
+ assert_equal LoginController::FLASH_CENTRAL_ADMIN_ALREADY_CREATED, flash['error']
+ assert_equal 1, User.count
+ assert_redirected_to :action => 'login'
+ end
+
+ # if ENV['EPFWIKI_DOMAINS'] is set sign-up is restricted to those domains
+ # if ENV['EPFWIKI_GENERATE_PASSWORDS'] = '1' passwords are generated
+ def test02_sign_up
+ @emails = ActionMailer::Base::deliveries
+ @emails.clear
+ ENV['EPFWIKI_GENERATE_PASSWORDS'] = '1'
+ user_count = User.count
+ # 1 . sign with domain restriction
+ get "login/sign_up"
+ assert_field("user_email")
+ assert_field("user_name")
+ assert_no_field("user_password")
+ assert_no_field("user_password_confirmation")
+ assert_tag :tag => "select", :attributes => {:name => "user[email_extension]"}
+ @html_document = nil # workaround for bug in assert_tag used in assert_errors
+ post "login/sign_up", :user => {:name => "user1", :email => "user1", :email_extension => "@somedomain.nl"}
+ assert_errors
+# assert_tag :tag => "div", :attributes => { :class => "fieldWithErrors" }
+ assert_response :success
+ assert_equal user_count, User.count
+ user = assigns(:user)
+ assert_equal "Email domain not valid",user.errors.full_messages.join(', ')
+ # this domain is allowed, the user is created
+ post "login/sign_up", :user => {:name => "user1", :email=>"user1", :email_extension => "@epf.org"}
+ user = assigns(:user)
+ assert_redirected_to :action => 'login'
+ assert_equal user_count + 1 , User.count
+ assert_equal 1, @emails.size
+ email = @emails.first
+ assert_equal("[#{ENV['EPFWIKI_APP_NAME']}] Welcome to #{ENV['EPFWIKI_APP_NAME']}", email.subject)
+ assert_equal("user1@epf.org", email.to[0])
+ assert_equal([ENV['EPFWIKI_REPLY_ADDRESS']], email.from)
+ assert_redirected_to :action => 'login'
+ assert_equal LoginController::FLASH_PW_SENT, flash['success']
+ # cannot sign up with already taken name, email
+ @html_document = nil
+ post "login/sign_up", :user => {:name => "user1", :email => "user1", :email_extension => "@epf.org"}
+ assert_equal "Name has already been taken, Email has already been taken",assigns(:user).errors.full_messages.join(', ')
+ # sign up without domain restriction
+ ENV['EPFWIKI_DOMAINS'] = nil
+ get "login/sign_up"
+ assert_field("user_email")
+ assert_field("user_name")
+ assert_no_field("user_password")
+ assert_no_field("user_password_confirmation")
+ assert_no_tag :tag => "select", :attributes => {:name => "email_extension"}
+ user_count = User.count
+ @html_document = nil
+ post "login/sign_up", :user => {:name => "user2", :email => "user2@xyz.com"}
+ assert_equal user_count + 1, User.count
+ assert_redirected_to :controller => 'login', :action => 'login'
+ #assert_equal "Name has already been taken, Email has already been taken",assigns(:user).errors.full_messages.join(', ')
+ # sign up passwords are generated
+ ENV['EPFWIKI_GENERATE_PASSWORDS'] = '0'
+ @html_document = nil
+ get "login/sign_up"
+ assert_field("user_email")
+ assert_field("user_name")
+ assert_field("user_password")
+ assert_field("user_password_confirmation")
+ assert_no_tag :tag => "select", :attributes => {:name => "email_extension"}
+ user_count = User.count
+ # user exists
+ @html_document = nil
+ post "login/sign_up", :user => {:name => "user2", :email => "user2@xyz.com"}
+ assert_equal "Name has already been taken, Password confirmation can't be blank, Password can't be blank, Email has already been taken",assigns(:user).errors.full_messages.join(', ')
+ assert_equal user_count, User.count
+ assert_errors
+ # creating user3
+ @html_document = nil
+ post "login/sign_up", :user => {:name => "user3", :email => "user3@xyz.com", :password => 'user3', :password_confirmation => 'user3'}
+ assert_equal LoginController::FLASH_PW_CONFIRMATION_EMAIL_SENT, flash['success']
+ assert_equal "",assigns(:user).errors.full_messages.join(', ')
+ assert_equal user_count + 1, User.count
+ assert_redirected_to :action => 'login'
+ assert_equal Digest::SHA1.hexdigest('user3'), assigns(:user).hashed_password
+ get "login/login"
+ assert_response :success
+ # assert_field("user_email")#TODO: this causes some strange error
+ # assert_field("user_password") #TODO: this causes some strange error
+ # user3 cannot sign-in, it needs to be confirmed
+ user3 = User.find_by_name('user3')
+ post "login/login" , :user => {:email => 'user3@epf.org', :password => 'user3'}
+ assert_equal LoginController::FLASH_INVALID_PW, flash['notice']
+ # cannot confirm with wrong token
+ # ? log reports a RunTimeError but then the assert says there is no runtime error! assert_raise(RuntimeError){ get "login/confirm_account", :id => user3.id, :tk => "anystring"}
+ get "login/confirm_account", :id => user3.id, :tk => "anystring"
+ user3 = User.find_by_name('user3')
+ assert_equal nil, user3.confirmed_on
+ # can confirm with right token
+ get "login/confirm_account", :id => user3.id, :tk => Digest::SHA1.hexdigest(user3.hashed_password)
+ assert_equal LoginController::FLASH_PASSWORD_ACTIVATED, flash['success']
+ assert_not_nil assigns(:user).confirmed_on
+ # user can now logon
+ # user can sign in and check that they want to be remembered
+ post "login/login" , :user => {:email => 'user3@xyz.com', :password => 'user3', :remember_me => 0}
+ assert_equal User.find_by_name("user3"), session['user']
+ assert_not_nil cookies
+ # TODO: NOTE: why can't we use cookies[:epfwiki_id] anymore?
+ assert_equal cookies["epfwiki_id"], session['user'].id.to_s
+ # automatically sign-in for remembered users
+ # redirected to user details or requested page (not tested)
+ get "login/login"
+ assert_redirected_to :controller => "users", :action => "show", :id => cookies[:epfwiki_id]
+ end
+
+end
diff --git a/source/test/setup.bat b/source/test/setup.bat
new file mode 100644
index 0000000..7a25679
--- /dev/null
+++ b/source/test/setup.bat
@@ -0,0 +1,10 @@
+call cleanup.bat
+mkdir ..\public\test_sites
+echo data\OpenUP-Basic_published_20060721%EPFWIKI_TESTDATA%.zip
+copy data\OpenUP-Basic_published_20060721%EPFWIKI_TESTDATA%.zip ..\public\test_sites\OpenUP-Basic_published_20060721%EPFWIKI_TESTDATA%.zip
+copy data\OpenUP-Basic_published_20060728%EPFWIKI_TESTDATA%.zip ..\public\test_sites\OpenUP-Basic_published_20060728%EPFWIKI_TESTDATA%.zip
+copy data\OpenUP-Basic_published_20060825%EPFWIKI_TESTDATA%.zip ..\public\test_sites\OpenUP-Basic_published_20060825%EPFWIKI_TESTDATA%.zip
+echo on
+mysql -h localhost -u epfwiki -pikiwpur --execute "drop database epfwiki_test"
+mysql -h localhost -u epfwiki -pikiwpur --execute "create database epfwiki_test"
+call rake migrate version=1 > test.bat.migration.log
\ No newline at end of file
diff --git a/source/test/test.bat b/source/test/test.bat
new file mode 100644
index 0000000..6fd34cc
--- /dev/null
+++ b/source/test/test.bat
@@ -0,0 +1,14 @@
+set RAILS_ENV=test
+echo off
+cls
+set EPFWIKI_TESTDATA=test
+REM set EPFWIKI_TESTDATA=
+
+REM call setup.bat
+REM call unit.bat
+
+call setup.bat
+call functional.bat
+
+REM call setup.bat
+REM call integration.bat
\ No newline at end of file
diff --git a/source/test/test_all.bat b/source/test/test_all.bat
new file mode 100644
index 0000000..ca97707
--- /dev/null
+++ b/source/test/test_all.bat
@@ -0,0 +1,14 @@
+set RAILS_ENV=test
+echo off
+cls
+set EPFWIKI_TESTDATA=test
+REM set EPFWIKI_TESTDATA=
+
+call setup.bat
+call unit.bat
+
+call setup.bat
+call functional.bat
+
+call setup.bat
+call integration.bat
\ No newline at end of file
diff --git a/source/test/test_helper.rb b/source/test/test_helper.rb
new file mode 100644
index 0000000..f3cb0c3
--- /dev/null
+++ b/source/test/test_helper.rb
@@ -0,0 +1,175 @@
+ENV["RAILS_ENV"] = "test"
+require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
+require 'test_help'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class Test::Unit::TestCase
+ # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
+ # TODO: comment that unit tests depend on each other
+ self.use_transactional_fixtures = false
+
+ # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
+ self.use_instantiated_fixtures = false
+
+ # Add more helper methods to be used by all tests here...
+
+ def create_openup0825
+ site = Site.new_baseline_process(:folder => openup0825_folder, :title => 'openup0825', :user_id => User.find_central_admin.id, :baseline_baseline => 'OUP_20060825')
+ site.unzip_upload
+ # TODO: without second call below, the site cannot be saved because of a missing baseline
+ site = Site.new_baseline_process(:folder => openup0825_folder, :title => 'openup0825', :user_id => User.find_central_admin.id, :baseline_baseline => 'OUP_20060825')
+ if site.save
+ return site
+ else
+ raise "Failed to create openup0825"
+ end
+ end
+
+ # Special assert created for researching the mistery of disappearing associations
+ # when running unit tests.
+ def assert_openup0721
+ openup0721 = Site.find_by_title('openup0721')
+ if !openup0721.nil?
+ assert_equal 8, openup0721.pages.size
+ end
+ end
+
+ def openup0825_folder
+ return "OpenUP-Basic_published_20060825#{ENV['EPFWIKI_TESTDATA']}"
+ end
+
+ def openup0721_folder
+ return "OpenUP-Basic_published_20060721#{ENV['EPFWIKI_TESTDATA']}"
+ end
+
+ def openup0728_folder
+ return "OpenUP-Basic_published_20060728#{ENV['EPFWIKI_TESTDATA']}"
+ end
+
+ def assert_field(name)
+ assert_tag :tag => "input", :attributes => {:id => name}
+ end
+
+ def assert_no_field(name)
+ assert_no_tag :tag => "input", :attributes => {:id => name}
+ end
+
+ def assert_errors(object = nil)
+ if object
+ object.errors.full_messages.each do |message|
+ assert_tag :content => message
+ end
+ else
+ assert_tag error_message_field
+ end
+ end
+
+ def assert_no_errors(object = nil)
+ if object
+ object.errors.full_messages.each do |message|
+ assert_no_tag :content => message
+ end
+ else
+ assert_no_tag error_message_field
+ end
+ end
+
+ def assert_pattern(pat, html, result)
+ html =~ pat
+ assert_equal result, $&
+ end
+
+ def error_message_field
+ {:tag => 'div', :attributes => { :class => 'errorExplanation', :id => 'errorExplanation' }}
+ end
+
+ def assert_save(object)
+ if !object.save
+ assert_equal '', object.errors.full_messages.join(", ")
+ end
+ end
+
+ def assert_enhanced_file(path)
+ html = IO.readlines(path).join
+ assert_not_nil html.index('<!-- epfwiki iframe start -->')
+ assert_not_nil html.index('onload')
+ assert_equal nil, html.index('<!-- treebrowser tag -->')
+ assert_equal nil, html.index('<!-- copyright statement -->')
+ end
+
+ def assert_version_file(path)
+ html = IO.readlines(path).join
+ assert_equal nil, html.index('<!-- epfwiki iframe start -->')
+ assert_not_nil html.index('<body>')
+ assert_not_nil html.index('<!-- treebrowser tag -->')
+ #assert_not_nil html.index('<!-- copyright statement -->')
+ end
+
+
+ def assert_kind_of_checkout(checkout)
+ assert_kind_of Checkout, checkout
+ assert File.exists?(checkout.version.path)
+ end
+
+ def create_cadmin
+ cadmin = User.new_cadmin(:id => 5, :name => 'onno', :email => 'Onno@noneExistingDomain.Com', :password => 'xyz', :password_confirmation => 'xyz')
+ return cadmin
+ end
+
+ def logonUser
+ get :index
+ session['user'] = User.find(4)
+ end
+ def logonUser3
+ get :index
+ session['user'] = User.find(3)
+ end
+ def logonUser4
+ get :index
+ session['user'] = User.find(3)
+ end
+ def logonUser5
+ get :index
+ session['user'] = User.find(5)
+ end
+ def logonCentralAdmin
+ get :index
+ session['user'] = User.find_central_admin
+ end
+ def logonAdmin
+ get :index
+ session['user'] = User.find(2)
+ end
+ def assert_tologin
+ #assert_equal ::MSG_LOGIN, flash['notice']
+ assert_equal @request.request_uri, session["return_to"]
+ assert_redirected_to :controller => 'login'
+ end
+ def assert_unot_admin_message
+ assert_equal LoginController::FLASH_UNOT_ADMIN, flash['error']
+ assert_redirected_to :controller => "other", :action => "error"
+ end
+ def assert_unot_cadmin_message
+ assert_equal LoginController::FLASH_UNOT_CADMIN, flash['error']
+ assert_redirected_to :controller => "other", :action => "error"
+ end
+
+ def assert_illegal_get
+ assert_redirected_to :controller => 'other', :action => 'error'
+ assert ::FLASH_USE_POST_NOT_GET, flash['error']
+ end
+
+end
\ No newline at end of file
diff --git a/source/test/test_migration.bat b/source/test/test_migration.bat
new file mode 100644
index 0000000..8f57332
--- /dev/null
+++ b/source/test/test_migration.bat
@@ -0,0 +1,8 @@
+cls
+set EPFWIKI_MIGRATION_WIKIS_PATH=D:/rupwiki/prod/public/wikis/
+mysql -h localhost -u epfwiki -pikiwpur --execute "drop database epfwiki_test"
+mysql -h localhost -u epfwiki -pikiwpur < data/migration/rupwiki.sql
+call rake db:schema:dump
+call rake migrate > migrate.log
+REM TODO call rake migrate version=16 >> migrate.log
+REM TODO call rake migrate >> migrate.log
diff --git a/source/test/unit.bat b/source/test/unit.bat
new file mode 100644
index 0000000..6b727ef
--- /dev/null
+++ b/source/test/unit.bat
@@ -0,0 +1,7 @@
+call rake db:test:prepare
+ruby unit/site_test.rb
+ruby unit/user_test.rb
+ruby unit/page_test.rb
+ruby unit/checkout_test.rb
+ruby unit/version_test.rb
+ruby unit/difference_analysis_test.rb
diff --git a/source/test/unit/checkout_test.rb b/source/test/unit/checkout_test.rb
new file mode 100644
index 0000000..6c71aa3
--- /dev/null
+++ b/source/test/unit/checkout_test.rb
@@ -0,0 +1,169 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class CheckoutTest < Test::Unit::TestCase
+ fixtures :users, :checkouts
+
+
+ def setup
+ @onno = User.find(1)
+ @onno_cadmin = User.find(5)
+ @user4 = User.find(4)
+ @user3 = User.find(3)
+ end
+
+ # Shows:
+ # 1. we cannot check out a page of a baseline process
+ # 2. we can check out a page by supplying the user, page and site
+ # 3. we cannot check out the same page twice
+ # 4. we can undo a checkout
+ # 5. we cannot checkout a page in a site that has not been wikified yet
+ # 6. we can supply a note with a checkout
+ # 7. checkout removes
+ def test01_new
+ # assert_kind_of Checkout, @checkout
+ rel_path = 'requirements,_allMQMWfEdqiT9CqkRksWQ.html' if ENV['EPFWIKI_TESTDATA'] == 'test'
+ rel_path = 'openup_basic/domains/requirements,_allMQMWfEdqiT9CqkRksWQ.html' if ENV['EPFWIKI_TESTDATA'] != 'test'
+ # 1
+ openup0721 = Site.find_by_folder(openup0721_folder)
+ assert_equal 8, openup0721.pages.size if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 617, openup0721.pages.size if ENV['EPFWIKI_TESTDATA'] != 'test'
+ page = Page.find_by_rel_path(rel_path)
+ assert_not_nil page
+ version_count = Version.count
+ checkout_count = Checkout.count
+ html_files_count = Site.files_html(openup0721.path).size
+ checkout = Checkout.new(:user => @onno, :page => page, :site => openup0721)
+ assert !checkout.save
+ assert_equal 'Version can\'t be blank, Site can\'t be a baseline process', checkout.errors.full_messages.join(", ")
+ assert_equal version_count, Version.count
+ assert_equal checkout_count, Checkout.count
+ assert_equal html_files_count, Site.files_html(openup0721.path).size
+ # 2
+ openupwiki = Site.find_wikis[0]
+ version_count = Version.count
+ checkout_count = Checkout.count
+ html_files_count = Site.files_html(openup0721.path).size
+ checkout = Checkout.new(:user => @onno, :page => page, :site => openupwiki)
+ assert checkout.save
+ assert_equal version_count + 2, Version.count # Baseversion + checked-out version
+ assert_equal checkout_count + 1, Checkout.count
+ assert_equal checkout.baseline, openupwiki.baseline
+ assert_equal openupwiki, checkout.site # created checkout
+ assert_equal page, checkout.page
+ assert_equal @onno, checkout.user
+ version = checkout.version # version created
+ assert_equal @onno, version.user
+ assert_equal openupwiki, version.site
+ assert_equal page, version.page
+ assert File.exists?(version.path)
+ # 3
+ checkout = Checkout.new(:user => @onno, :page => page, :site => openupwiki)
+ assert !checkout.save
+ assert_equal 'Version can\'t be blank, Checkout already exists', checkout.errors.full_messages.join(", ")
+ assert_equal version_count + 2, Version.count # same as before, nothing changed
+ assert_equal checkout_count + 1, Checkout.count
+ # 4
+ assert_equal 1, Checkout.count
+ checkout = Checkout.find_first
+ assert_kind_of_checkout(checkout)
+ version_path = checkout.version.path
+ checkout.undo
+ assert_equal version_count + 1, Version.count
+ assert_equal checkout_count, Checkout.count
+ assert !File.exists?(version_path)
+ # 5 TODO R? implement unit test
+ # 6 TODO R? implement unit test
+ checkout = Checkout.new(:user => @onno, :page => page, :site => openupwiki, :note => 'My checkout')
+ assert checkout.save
+ assert_equal 'My checkout', checkout.version.note
+ end
+ # Shows:
+ # 1. an admin or user cannot checkin a file of another user
+ # 2. owner (who is not an admin) can checkin
+ # 3. cadmin can check in
+ # 4. html can be supplied during checkin
+ # 5. don't supply html which will checkin using the version file
+ # 6. the version file does not contain wiki tags
+ # 7. after checkin the page does
+ def test02_checkin
+ openupwiki = Site.find_wikis[0]
+ page = Page.find_by_filename('artifact,_fdRfkBUJEdqrUt4zetC1gg.html')
+ checkout = Checkout.new(:user => @user4, :page => page, :site => openupwiki, :note => 'Another checkout')
+ assert checkout.save!
+ assert_kind_of_checkout(checkout)
+ #checkout = Checkout.find_first
+ checkout.reload
+ checkout_id = checkout.id
+ # 1 admin
+ assert_raise(RuntimeError) {checkout.checkin(@onno)}
+ # 1 ordinary user
+ assert_raise(RuntimeError) {checkout.checkin(@user3)}
+ # 2
+ checkout.checkin(@user4)
+ assert !Checkout.exists?(checkout_id)
+ # 3
+ checkout = Checkout.new(:user => @user4, :page => page, :site => openupwiki, :note => 'Another checkout')
+ assert checkout.save!
+ checkout_id = checkout.id
+ checkout.checkin(@onno_cadmin)
+ assert !Checkout.exists?(checkout_id)
+ # 4
+ checkout = Checkout.new(:user => @user4, :page => page, :site => openupwiki, :note => 'Another checkout')
+ assert checkout.save!
+ version = checkout.version
+ checkout_id = checkout.id
+ html = checkout.version.html
+ html = html.gsub('making responsibility easy to identify','##replaced text##')
+ checkout.checkin(@user4, html)
+ assert !Checkout.exists?(checkout_id)
+ assert version.html.index('##replaced text##')
+ assert page.html(version.site).index('##replaced text##')
+ # 5
+ # 6
+ checkout = Checkout.new(:user => @user4, :page => page, :site => openupwiki, :note => 'Another checkout')
+ assert checkout.save!
+ version = checkout.version
+ html_version = version.html
+ html_page = version.page.html(version.site)
+ # removed stuff in version file
+ assert_equal nil, html_version.index('body onload') # onload was removed
+ assert_equal nil, html_version.index('<!-- epfwiki head start -->') # wiki stuff removed
+ assert_equal nil, html_version.index('<!-- epfwiki iframe start -->')
+ # replaced stuff in version file
+ assert_not_nil html_version.index('<!-- treebrowser tag -->')
+ assert_not_nil html_version.index('<!-- copyright statement -->')
+ # stuff to be removed from page
+ assert_not_nil html_page.index('body onload')
+ #assert_not_nil html_page.index('<!-- epfwiki head start -->') # TODO remove
+ #assert_not_nil html_page.index('<!-- epfwiki iframe start -->') # TODO remove
+ # stuff to be replace in page
+ assert_not_nil html_page.index('treebrowser.js')
+ assert_not_nil html_page.index('class="copyright"')
+ # 7
+ html_version = html_version.gsub('making responsibility easy to identify','##replaced text##')
+ checkout.checkin(@user4, html_version)
+ html_page = version.page.html(version.site)
+ # stuff to be removed from page back in page
+ assert_not_nil html_page.index('##replaced text##')
+ assert_not_nil html_page.index('body onload')
+ #assert_not_nil html_page.index('<!-- epfwiki head start -->') # TODO remove
+ #assert_not_nil html_page.index('<!-- epfwiki iframe start -->') # TODO Remove
+ # stuff to be replaced in page back in page
+ assert_not_nil html_page.index('treebrowser.js')
+ assert_not_nil html_page.index('class="copyright"')
+ end
+end
diff --git a/source/test/unit/difference_analysis_test.rb b/source/test/unit/difference_analysis_test.rb
new file mode 100644
index 0000000..ae49009
--- /dev/null
+++ b/source/test/unit/difference_analysis_test.rb
@@ -0,0 +1,88 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class DifferenceAnalysisTest < Test::Unit::TestCase
+ fixtures :users
+
+ def setup
+ # @test = Test.find(1)
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @openup0721 = Site.find_by_folder(openup0721_folder)
+ @openup0728 = Site.find_by_folder(openup0728_folder)
+ @openup0825 = Site.find_by_folder(openup0825_folder)
+ @onno = User.find(1)
+ @onno_cadmin = User.find(5)
+ @user4 = User.find(4)
+ @user3 = User.find(3)
+ end
+
+ # Shows:
+ # 1. a site and site_from need to be present
+ # 2. the site and from site need to be different
+ # 3. the sites need to be a baseline processes
+ def test01_new
+ # 1
+ difference_analysis = DifferenceAnalysis.new()
+ assert !difference_analysis.save
+ assert_equal 'Site can\'t be blank, Site id from can\'t be blank', difference_analysis.errors.full_messages.join(', ')
+ difference_analysis = DifferenceAnalysis.new(:site => @openup0721)
+ assert !difference_analysis.save
+ assert_equal 'Site id from can\'t be blank', difference_analysis.errors.full_messages.join(', ')
+ difference_analysis = DifferenceAnalysis.new(:site_from => @openup0721)
+ assert !difference_analysis.save
+ assert_equal 'Site can\'t be blank', difference_analysis.errors.full_messages.join(', ')
+ # 2
+ difference_analysis = DifferenceAnalysis.new(:site =>@openup0721, :site_from =>@openup0721)
+ assert !difference_analysis.save
+ assert_equal 'Site cannot compare with itself', difference_analysis.errors.full_messages.join(', ')
+ # 3
+ difference_analysis = DifferenceAnalysis.new(:site => @openupwiki, :site_from =>@openup0721)
+ assert !difference_analysis.save
+ assert_equal 'Site is not a baseline process', difference_analysis.errors.full_messages.join(', ')
+ difference_analysis = DifferenceAnalysis.new(:site => @openup0721, :site_from =>@openupwiki)
+ assert !difference_analysis.save
+ assert_equal 'Site from is not a baseline process', difference_analysis.errors.full_messages.join(', ')
+ end
+
+ # Shows:
+ #
+ def test02_perform_analysis
+ difference_analysis_item_count = DifferenceAnalysisItem.count
+ difference_analysis = DifferenceAnalysis.new(:site => @openup0721, :site_from => @openup0728)
+ assert difference_analysis.save
+ difference_analysis.reload
+ difference_analysis.perform_analysis
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 10, difference_analysis.items.size
+ assert difference_analysis.save
+ assert_equal 10, difference_analysis.items.size
+ assert_equal 2, difference_analysis.items_removed.size
+ assert_equal 8, difference_analysis.items_equal.size
+ assert_equal 0, difference_analysis.items_changed.size
+ assert_equal 0, difference_analysis.items_htmlchanged.size
+ assert_equal 0, difference_analysis.items_new.size
+ else
+ assert_equal 617, DifferenceAnalysisItem.count #? not saved yet????
+ assert difference_analysis.save
+ assert_equal 617, DifferenceAnalysisItem.count
+ assert_equal 0, difference_analysis.items_removed.size
+ assert_equal 464, difference_analysis.items_equal.size
+ assert_equal 9, difference_analysis.items_changed.size
+ assert_equal 144, difference_analysis.items_htmlchanged.size
+ assert_equal 0, difference_analysis.items_new.size
+ end
+ end
+end
diff --git a/source/test/unit/page_test.rb b/source/test/unit/page_test.rb
new file mode 100644
index 0000000..807e42f
--- /dev/null
+++ b/source/test/unit/page_test.rb
@@ -0,0 +1,228 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class PageTest < Test::Unit::TestCase
+ fixtures :users
+
+ def setup
+ @openupwiki = Site.find_by_title('OpenUP Wiki')
+ @openup0721 = Site.find_by_folder(openup0721_folder)
+ @openup0728 = Site.find_by_folder(openup0728_folder)
+ @openup0825 = Site.find_by_folder(openup0825_folder)
+ @html = IO.readlines('unit/page_test/test_html.txt').join.split("####")
+ @onno = User.find(1)
+ @onno_cadmin = User.find(5)
+ @user4 = User.find(4)
+ @user3 = User.find(3)
+ end
+
+ def test01_find_or_new
+ treebrowser_tag_count = 0
+ copyright_tag_count = 0
+ text_count = 0
+ body_tag_count = 0
+ @openupwiki.pages.each do |page|
+ find_page = Page.find_or_new({:rel_path => page.rel_path}, @openupwiki)
+ assert_not_nil find_page
+ assert_equal page, find_page
+ treebrowser_tag_count = treebrowser_tag_count + 1 if !find_page.treebrowser_tag.nil?
+ copyright_tag_count = copyright_tag_count + 1 if !find_page.copyright_tag.nil?
+ text_count = text_count + 1 if !find_page.text.nil?
+ body_tag_count = body_tag_count + 1 if !find_page.body_tag.nil?
+ end
+ assert_equal 503, treebrowser_tag_count if ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 617, copyright_tag_count if ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 617, text_count if ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 617, body_tag_count if ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 8, treebrowser_tag_count if !ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 10, copyright_tag_count if !ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 10, text_count if !ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal 10, body_tag_count if !ENV['EPFWIKI_TESTDATA'].blank?
+ end
+
+ def test02_treebrowser_pattern
+ assert_pattern(Page::TREEBROWSER_PATTERN, @html[0],
+ "<script src=\"./../../../scripts/treebrowser.js\" type=\"text/javascript\" language=\"JavaScript\"></script>")
+ assert_pattern(Page::TREEBROWSER_PATTERN, @html[1],
+ "<script src=./../../../scripts/treebrowser.js\" type=\"text/javascript\" language=\"JavaScript\"></script>")
+ assert_pattern(Page::TREEBROWSER_PATTERN, @html[2],
+ "<scRipT SrC=./../../../../../../../../scripts/treebrowser.js\" type=\"text/javascript\" language=\"JavaScript\"></scripT>")
+ assert_pattern(Page::TREEBROWSER_PATTERN, @html[3],
+ "<script src=\"./../../scripts/treebrowser.js\" type=\"text/javascript\" language=\"JavaScript\"></script>")
+ end
+
+ def test03_body_tag_pattern
+ assert_pattern(Page::BODY_TAG_PATTERN, @html[0],
+ "<body onload=\"createSectionLinks('div', 'sectionHeading', './../../../images/');\">")
+ assert_pattern(Page::BODY_TAG_PATTERN, @html[1],
+ "<BoDy>")
+ assert_pattern(Page::BODY_TAG_PATTERN, @html[4],
+ "<body onload=\"createSectionLinks('div', 'sectionHeading', './../../../images/');\">")
+ end
+
+ def test05_iframe_pattern
+ assert_pattern(Page::IFRAME_PATTERN, @html[4],
+ "<!-- epfwiki iframe start -->\n<script language=\"JavaScript\">\n\n aURL = \"http://localhost:3000/epfwiki/toolbar?url=\" + document.location.href;\n\n document.write(\" <div id=\\\"topbar\\\">\\n\");\n\n document.write(\" <iframe width=\\\"100%\\\" height=\\\"25\\\" frameborder=\\\"0\\\" src=\\\"\" + aURL + \"\\\" scrolling=\\\"no\\\" marginwidth=\\\"0\\\">\\n\");\n\n document.writeln(\" </div>\");\n\n </script>\n<!-- epfwiki iframe end -->")
+ end
+
+ def test06_shim_tag_pattern
+ assert_pattern(Page::SHIM_TAG_PATTERN, @html[4],
+ "images/shim.gif\"></td>")
+ assert_pattern(Page::SHIM_TAG_PATTERN,@html[2],
+ "images/shim.gif\" />\n </td>")
+ assert_pattern(Page::SHIM_TAG_PATTERN, @html[3],
+ "images/shim.gif\"></td>")
+ end
+
+ def test07_copyright_pattern
+ assert_pattern(Page::COPYRIGHT_PATTERN, @html[5],
+ "<p>Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.\n\n <br />This program and the accompanying materials are made available under the\n\n <br />\n\n <a href=\"http://www.eclipse.org/org/documents/epl-v10.php\" target=\"_blank\">Eclipse Public License v1.0</a> which accompanies this distribution.</p>")
+ assert_pattern(Page::COPYRIGHT_PATTERN, @html[2],
+ "<p>\n Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.<br />\n This program and the accompanying materials are made available under the<br />\n <a href=\"http://www.eclipse.org/org/documents/epl-v10.php\" target=\"_blank\">Eclipse Public License v1.0</a> which\n accompanies this distribution.\n</p>")
+ end
+
+
+ # Shows:
+ # 1. can extract title from the file using Page.title_from_file
+ def test09_title_from_file
+ openup0721 = Site.find_by_folder(openup0721_folder)
+ filenames = Array.new
+ filenames << ['about_base_concepts,_uvje4D_fEdqDFvujd6NHiA.html','Supporting Material: About Base Concepts']
+ filenames << ['any_role,_3TCEoeB5EdqnKu908IEluw.html', 'Role Descriptor: Any Role']
+ filenames << ['determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html', 'Activity: Determine Architectural Feasibility']
+ for filename in filenames
+ page = Page.find_by_filename(filename[0])
+ assert_not_nil page
+ assert_equal filename[1], page.title_from_file(openup0721)
+ end
+ pages = Page.find_all
+ end
+
+ # Shows:
+ # 1. requesting Site.templates creates a templates dir and pages
+ # 2. new Page based on a template create a Page, a Version, a Checkout
+ # 3. a Page file does not exist after new page, before checkin
+ # 4. a Version file is created and prepared for edit
+ def test10_new_page_using_template
+ assert !File.exists?(@openupwiki.templates_dir)
+ version_count = Version.count
+ page_count = Page.count
+ checkout_count = Checkout.count
+ templates = @openupwiki.templates
+ assert_equal 2, templates.size
+ for template in templates
+ assert_enhanced_file(template.path(@openupwiki))
+ end
+ assert_equal 2, Page.count - page_count
+ assert_equal 2, Version.count - version_count
+ assert_equal 0, Checkout.count - checkout_count
+ # 2
+ tool_tpl = Page.find_by_filename('Tool Mentor Template.html')
+ source_version = Version.find_current_version(@openupwiki, tool_tpl)
+ new_page = Page.new(:presentation_name => 'New Tool Mentor created in test10_new_page_using_tempalte', :source_version => source_version, :user => @onno, :site => @openupwiki)
+ assert_equal 2, Page.count - page_count
+ assert_equal 2, Version.count - version_count
+ assert_equal 0, Checkout.count - checkout_count
+ assert new_page.save
+ assert_equal 3, Page.count - page_count # extra page
+ assert_equal 3, Version.count - version_count # extra version
+ assert_equal 1, Checkout.count - checkout_count # 1 checkout
+ checkout = new_page.checkout(@openupwiki)
+ new_page.reload
+ assert_equal 'New Tool Mentor created in test10_new_page_using_tempalte', new_page.presentation_name
+ assert_equal 'new_tool_mentor_created_in_test10_new_page_using_tempalte.html', new_page.filename
+ assert_equal "#{ENV['EPFWIKI_ROOT_DIR']}public/#{ENV['EPFWIKI_WIKIS_FOLDER']}/openup/wiki/new/#{new_page.filename}", new_page.path(@openupwiki)
+ # 3
+ assert !File.exists?(new_page.path(@openupwiki))
+ # 4
+ assert File.exists?(checkout.version.path)
+ assert_version_file(checkout.version.path)
+ end
+
+ def test11_treebrowser
+ assert_pattern(Page::TREEBROWSER_PATTERN, @html[7],"<script src=\"./../../scripts/treebrowser.js\" type=\"text/javascript\" language=\"JavaScript\"></script>")
+ assert_pattern(Page::TREEBROWSER_PATTERN, @html[8],"<script src=\"./../../scripts/treebrowser.js\" type=\"text/javascript\" language=\"JavaScript\"></script>")
+ end
+
+ def test12_element_type_pattern
+
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[9], '<meta content="Checklist" name="element_type">')
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[10], '<meta content=Checklist name=element_type>') #'< MetA name="element_type" content="Tool Mentor" >'
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[11], nil)
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[12], '<META NAME="element_type" CONTENT=" Tool Mentor " >')
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[13], '<meta content="Checklist" name="element_type">')
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[14], '<meta content="Checklist" name="element_type">')
+ assert_pattern(Page::ELEMENT_TYPE_PATTERN, @html[15], nil)
+ assert_equal 'Checklist', Page.meta_tag_content_type(@html[9])
+ assert_equal 'Checklist', Page.meta_tag_content_type(@html[10])
+ assert_equal '', Page.meta_tag_content_type(@html[11])
+ assert_equal 'Tool mentor', Page.meta_tag_content_type(@html[12])
+ assert_equal 'Checklist', Page.meta_tag_content_type(@html[13])
+ assert_equal 'Checklist', Page.meta_tag_content_type(@html[14])
+ assert_equal '', Page.meta_tag_content_type(@html[15])
+ end
+
+ # Shows:
+ # 1. we replace 'UMA Method Architecture' with 'Unified Method Architecture (UMA)' in about base concepts
+ # 2. we create a new page based on that changed version and then remove 'Method'
+ def test13_new_page_using_other_page
+ # 1
+ page = Page.find_by_filename('about_base_concepts,_uvje4D_fEdqDFvujd6NHiA.html')
+ assert_equal 0, page.versions.size
+ checkout = Checkout.new(:user => @onno, :page => page, :site => @openupwiki, :note => 'test13_new_page_using_other_page')
+ assert checkout.save
+ checkout.reload
+ page.reload
+ assert_equal 'test13_new_page_using_other_page', checkout.version.note
+ assert_equal 2, page.versions.size
+ assert_equal 1, checkout.version.version
+ checkout.checkin(@onno, checkout.version.html.gsub('UMA Method Architecture', 'Unified Method Architecture (UMA)'))
+ version = Version.find_current_version(@openupwiki, page)
+ assert_equal 1, version.version
+ assert version.html.index('Unified Method Architecture (UMA)')
+ assert page.html(@openupwiki).index('Unified Method Architecture (UMA)')
+ assert_enhanced_file(page.path(@openupwiki))
+ assert_version_file(version.path)
+ # 2
+ pages_count = @openupwiki.pages.size
+ page = Page.new(:presentation_name => 'New page created using base concepts', :source_version => version, :user => @onno, :site => @openupwiki)
+ assert page.save
+ page.reload
+ @openupwiki.reload
+ assert_equal pages_count + 1, @openupwiki.pages.size
+ assert_equal 1, page.versions.size
+ assert_equal version, page.versions[0].source_version
+ assert page.versions[0].previous_version.nil?
+ checkout = page.checkout(@openupwiki)
+ assert_not_nil checkout
+ assert checkout.version.html.index('Unified Method Architecture (UMA)')
+ checkout.checkin(@onno, checkout.version.html.gsub('Unified Method Architecture (UMA)','Unified Architecture (UMA)'))
+ version = Version.find_current_version(@openupwiki, page)
+ assert_equal 1, version.version
+ assert version.html.index('Unified Architecture (UMA)')
+ assert page.html(@openupwiki).index('Unified Architecture (UMA)')
+ assert_enhanced_file(page.path(@openupwiki))
+ assert_version_file(version.path)
+ end
+
+ def showRE(a,re)
+ if a =~ re
+ puts "#{$`}<<#{$&}>>#{$'}"
+ else
+ puts "no match"
+ end
+ end
+end
diff --git a/source/test/unit/page_test/test_html.txt b/source/test/unit/page_test/test_html.txt
new file mode 100644
index 0000000..2940e57
--- /dev/null
+++ b/source/test/unit/page_test/test_html.txt
@@ -0,0 +1,1386 @@
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Concept: Collaborate to align interests and share understanding</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Concept" name="uma.type">
+<meta content="core_principle_collaborate" name="uma.name">
+<meta content="Collaborate to align interests and share understanding" name="uma.presentationName">
+<meta name="element_type" content="concept">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ </script>
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../../images/');">
+<table width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top"><a name="Top"></a>
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Concept: Collaborate to align interests and share understanding</td><td align="right" class="expandCollapseLink" width="100%"><a href="./../../../index.htm"></a><script src="./../../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="100%">
+<tr>
+<td class="pageTitleSeparator"><img height="1" alt="" src="./../../../images/shim.gif"></td>
+</tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../../images/concept.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">Develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants and help them develop a shared understanding of the project.</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Main Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell"><H3>Collaborate to align interests and share understanding </H3>
+<P>Software is created by people with different interests and skills who must work together to create software effectively. Therefore develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants (e.g. development team, quality assurance, product stakeholders, customers) and help project participants develop a shared understanding of the project. </P>
+<H3>Practices </H3>
+<H4>Maintain a Common Understanding </H4>
+<P>Project participants require a common understanding of a project to cooperative effectively. Without a common understanding among project participants disorder sets in because they cannot align their interests and will work at cross purposes to one another. </P>
+<P>Therefore be proactive communicating and sharing information with project participants and do not assume everyone will just find what they need to know or has the same understanding of the project as everyone else. Use work products such as the vision and requirements to align the understanding of the stake holders and developers. Use the architecture to focus and align the interests of the developers. At the end of each iteration get agreement iteration goals have been reached and if not then what remedial actions must be taken. </P>The <a class=elementlinkwithusertext href="./resources/core_principle_focus,_9gocwMvoEdqukPpotm3DYg.html" guid="_9gocwMvoEdqukPpotm3DYg">Focus</a> principle helps to maintain a common understanding.<BR>
+<H4>Foster a High Trust Environment </H4>
+<P>People who do not feel safe will not communicate their ideas, take the initiative, or admit their ignorance. This leads to work environments where actions must be laboriously and expensively negotiated and work which must be carefully monitored and audited. </P>
+<P>Therefore take actions that will foster a high trust environment: </P>
+<UL>
+<LI>Manage by intent - create an environment where teams manage themselves and managers mentor teams to complete their objectives.
+<LI>Tear down the walls – work to remove both the physical and mental barriers that inhibit development of a common understanding between project participants.
+<LI>Walk mile (or a kilometer and a half) in someone else’s shoes – respect and try to understand the perspective of others before criticizing their ideas or responding to their criticism. </LI></UL>
+<H4>Share Responsibility<BR></H4>
+<P>When a person works alone communications can stop and they can “go dark” Their understanding of the project may become misaligned with the rest of the team. They may get into trouble and not ask for help, or not realize the team is in trouble. In the worse situations trust breaks down as people see the team working at cross purposes to their interests. </P>
+<P>Therefore, while project participants have primary responsibility for their work products, responsibility for work products is shared. Nothing is someone elseÂ’s job. It may mean either taking up slack and working with someone whoÂ’s lagging for some reason or asking for help. Experienced staff should be extra vigilant and watch over less experienced staff encouraging them to ask for help if necessary. </P>
+<P>The collaborative practice Foster a High Trust Environment reinforces sharing responsibility by making it safe for people to take the initiative, or to admit their ignorance. </P>
+<H4>Learn Continuously </H4>
+<P>Not only is software development a fast developing field where technical skills rapidly become obsolescent, it is also an experimental field where software is developed often by a process that resembles trial and error. Furthermore, software is developed by teams of people. </P>
+<P>Therefore continuously develop both your technical and interpersonal skills. Learn from the examples of your colleagues. Take the opportunity to be both a student and a teacher to your colleagues. Always increase your personal ability to overcome your own antagonism towards other team members. </P>
+<P>The <a class=elementlinkwithusertext href="./resources/core_principle_evolve,_GXiogMvoEdqukPpotm3DYg.html" guid="_GXiogMvoEdqukPpotm3DYg">Evolve</a> principle closely supports continuous learning. Learn Continuously helps develop trust.</P>
+<H4 style="MARGIN: 12pt 0in 3pt">Organize around the architecture</H4>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt"> </P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt">As projects grow in size, communication between team members becomes increasingly complex. </P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p> </o:p></P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt">Therefore organize the team around the architecture of the system so all team members understand the overall system but can focus primarily on a subset of a system, that is, one or more subsystems are assigned to them. Organizing around the architecture also helps with communication by providing the team with a common vocabulary and shared mental model of the system. However, be watchful that individuals and teams organized this way do not form a "silo" mentality where they focus striclty on their sub-systems and become ignorant of the other subsystems.</P>
+<P><BR> </P></td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.<br />
+ This program and the accompanying materials are made available under the<br />
+ <a href="http://www.eclipse.org/org/documents/epl-v10.php" target="_blank">Eclipse Public License v1.0</a> which
+ accompanies this distribution.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
+#### 1
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Concept: Collaborate to align interests and share understanding</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Concept" name="uma.type">
+<meta content="core_principle_collaborate" name="uma.name">
+<meta content="Collaborate to align interests and share understanding" name="uma.presentationName">
+<meta name="element_type" content="concept">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ </script>
+</head>
+<BoDy>
+<table width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top"><a name="Top"></a>
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Concept: Collaborate to align interests and share understanding</td><td align="right" class="expandCollapseLink" width="100%"><a href="./../../../index.htm"></a><script src=./../../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="100%">
+ <tr> <td class="pageTitleSeparator"> <img height="1" alt="" src="../../images/shim.gif" /> </td> </tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../../images/concept.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">Develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants and help them develop a shared understanding of the project.</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Main Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell"><H3>Collaborate to align interests and share understanding </H3>
+<P>Software is created by people with different interests and skills who must work together to create software effectively. Therefore develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants (e.g. development team, quality assurance, product stakeholders, customers) and help project participants develop a shared understanding of the project. </P>
+<H3>Practices </H3>
+<H4>Maintain a Common Understanding </H4>
+<P>Project participants require a common understanding of a project to cooperative effectively. Without a common understanding among project participants disorder sets in because they cannot align their interests and will work at cross purposes to one another. </P>
+<P>Therefore be proactive communicating and sharing information with project participants and do not assume everyone will just find what they need to know or has the same understanding of the project as everyone else. Use work products such as the vision and requirements to align the understanding of the stake holders and developers. Use the architecture to focus and align the interests of the developers. At the end of each iteration get agreement iteration goals have been reached and if not then what remedial actions must be taken. </P>The <a class=elementlinkwithusertext href="./resources/core_principle_focus,_9gocwMvoEdqukPpotm3DYg.html" guid="_9gocwMvoEdqukPpotm3DYg">Focus</a> principle helps to maintain a common understanding.<BR>
+<H4>Foster a High Trust Environment </H4>
+<P>People who do not feel safe will not communicate their ideas, take the initiative, or admit their ignorance. This leads to work environments where actions must be laboriously and expensively negotiated and work which must be carefully monitored and audited. </P>
+<P>Therefore take actions that will foster a high trust environment: </P>
+<UL>
+<LI>Manage by intent - create an environment where teams manage themselves and managers mentor teams to complete their objectives.
+<LI>Tear down the walls – work to remove both the physical and mental barriers that inhibit development of a common understanding between project participants.
+<LI>Walk mile (or a kilometer and a half) in someone else’s shoes – respect and try to understand the perspective of others before criticizing their ideas or responding to their criticism. </LI></UL>
+<H4>Share Responsibility<BR></H4>
+<P>When a person works alone communications can stop and they can “go dark” Their understanding of the project may become misaligned with the rest of the team. They may get into trouble and not ask for help, or not realize the team is in trouble. In the worse situations trust breaks down as people see the team working at cross purposes to their interests. </P>
+<P>Therefore, while project participants have primary responsibility for their work products, responsibility for work products is shared. Nothing is someone elseÂ’s job. It may mean either taking up slack and working with someone whoÂ’s lagging for some reason or asking for help. Experienced staff should be extra vigilant and watch over less experienced staff encouraging them to ask for help if necessary. </P>
+<P>The collaborative practice Foster a High Trust Environment reinforces sharing responsibility by making it safe for people to take the initiative, or to admit their ignorance. </P>
+<H4>Learn Continuously </H4>
+<P>Not only is software development a fast developing field where technical skills rapidly become obsolescent, it is also an experimental field where software is developed often by a process that resembles trial and error. Furthermore, software is developed by teams of people. </P>
+<P>Therefore continuously develop both your technical and interpersonal skills. Learn from the examples of your colleagues. Take the opportunity to be both a student and a teacher to your colleagues. Always increase your personal ability to overcome your own antagonism towards other team members. </P>
+<P>The <a class=elementlinkwithusertext href="./resources/core_principle_evolve,_GXiogMvoEdqukPpotm3DYg.html" guid="_GXiogMvoEdqukPpotm3DYg">Evolve</a> principle closely supports continuous learning. Learn Continuously helps develop trust.</P>
+<H4 style="MARGIN: 12pt 0in 3pt">Organize around the architecture</H4>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt"> </P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt">As projects grow in size, communication between team members becomes increasingly complex. </P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p> </o:p></P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt">Therefore organize the team around the architecture of the system so all team members understand the overall system but can focus primarily on a subset of a system, that is, one or more subsystems are assigned to them. Organizing around the architecture also helps with communication by providing the team with a common vocabulary and shared mental model of the system. However, be watchful that individuals and teams organized this way do not form a "silo" mentality where they focus striclty on their sub-systems and become ignorant of the other subsystems.</P>
+<P><BR> </P></td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.<br />
+ This program and the accompanying materials are made available under the<br />
+ <a href="http://www.eclipse.org/org/documents/epl-v10.php" target="_blank">Eclipse Public License v1.0</a> which
+ accompanies this distribution.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
+#### 2
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Concept: Collaborate to align interests and share understanding</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Concept" name="uma.type">
+<meta content="core_principle_collaborate" name="uma.name">
+<meta content="Collaborate to align interests and share understanding" name="uma.presentationName">
+<meta name="element_type" content="concept">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ </script>
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../../images/');">
+<table width="100%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top"><a name="Top"></a>
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Concept: Collaborate to align interests and share understanding</td><td align="right" class="expandCollapseLink" width="100%"><a href="./../../../index.htm"></a><scRipT SrC=./../../../../../../../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></scripT></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" wid<tr>
+<td class="pageTitleSeparator"> <img height="1" alt="" src="./../../images/shim.gif" />
+ </td>
+
+
+</tr>tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../../images/concept.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">Develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants and help them develop a shared understanding of the project.</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Main Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell"><H3>Collaborate to align interests and share understanding </H3>
+<P>Software is created by people with different interests and skills who must work together to create software effectively. Therefore develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants (e.g. development team, quality assurance, product stakeholders, customers) and help project participants develop a shared understanding of the project. </P>
+<H3>Practices </H3>
+<H4>Maintain a Common Understanding </H4>
+<P>Project participants require a common understanding of a project to cooperative effectively. Without a common understanding among project participants disorder sets in because they cannot align their interests and will work at cross purposes to one another. </P>
+<P>Therefore be proactive communicating and sharing information with project participants and do not assume everyone will just find what they need to know or has the same understanding of the project as everyone else. Use work products such as the vision and requirements to align the understanding of the stake holders and developers. Use the architecture to focus and align the interests of the developers. At the end of each iteration get agreement iteration goals have been reached and if not then what remedial actions must be taken. </P>The <a class=elementlinkwithusertext href="./resources/core_principle_focus,_9gocwMvoEdqukPpotm3DYg.html" guid="_9gocwMvoEdqukPpotm3DYg">Focus</a> principle helps to maintain a common understanding.<BR>
+<H4>Foster a High Trust Environment </H4>
+<P>People who do not feel safe will not communicate their ideas, take the initiative, or admit their ignorance. This leads to work environments where actions must be laboriously and expensively negotiated and work which must be carefully monitored and audited. </P>
+<P>Therefore take actions that will foster a high trust environment: </P>
+<UL>
+<LI>Manage by intent - create an environment where teams manage themselves and managers mentor teams to complete their objectives.
+<LI>Tear down the walls – work to remove both the physical and mental barriers that inhibit development of a common understanding between project participants.
+<LI>Walk mile (or a kilometer and a half) in someone else’s shoes – respect and try to understand the perspective of others before criticizing their ideas or responding to their criticism. </LI></UL>
+<H4>Share Responsibility<BR></H4>
+<P>When a person works alone communications can stop and they can “go dark” Their understanding of the project may become misaligned with the rest of the team. They may get into trouble and not ask for help, or not realize the team is in trouble. In the worse situations trust breaks down as people see the team working at cross purposes to their interests. </P>
+<P>Therefore, while project participants have primary responsibility for their work products, responsibility for work products is shared. Nothing is someone elseÂ’s job. It may mean either taking up slack and working with someone whoÂ’s lagging for some reason or asking for help. Experienced staff should be extra vigilant and watch over less experienced staff encouraging them to ask for help if necessary. </P>
+<P>The collaborative practice Foster a High Trust Environment reinforces sharing responsibility by making it safe for people to take the initiative, or to admit their ignorance. </P>
+<H4>Learn Continuously </H4>
+<P>Not only is software development a fast developing field where technical skills rapidly become obsolescent, it is also an experimental field where software is developed often by a process that resembles trial and error. Furthermore, software is developed by teams of people. </P>
+<P>Therefore continuously develop both your technical and interpersonal skills. Learn from the examples of your colleagues. Take the opportunity to be both a student and a teacher to your colleagues. Always increase your personal ability to overcome your own antagonism towards other team members. </P>
+<P>The <a class=elementlinkwithusertext href="./resources/core_principle_evolve,_GXiogMvoEdqukPpotm3DYg.html" guid="_GXiogMvoEdqukPpotm3DYg">Evolve</a> principle closely supports continuous learning. Learn Continuously helps develop trust.</P>
+<H4 style="MARGIN: 12pt 0in 3pt">Organize around the architecture</H4>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt"> </P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt">As projects grow in size, communication between team members becomes increasingly complex. </P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p> </o:p></P>
+<P class=MsoNormal style="MARGIN: 0in 0in 0pt">Therefore organize the team around the architecture of the system so all team members understand the overall system but can focus primarily on a subset of a system, that is, one or more subsystems are assigned to them. Organizing around the architecture also helps with communication by providing the team with a common vocabulary and shared mental model of the system. However, be watchful that individuals and teams organized this way do not form a "silo" mentality where they focus striclty on their sub-systems and become ignorant of the other subsystems.</P>
+<P><BR> </P></td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.<br />
+ This program and the accompanying materials are made available under the<br />
+ <a href="http://www.eclipse.org/org/documents/epl-v10.php" target="_blank">Eclipse Public License v1.0</a> which
+ accompanies this distribution.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</body>
+</html>
+#### 3
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Task: Assess Results</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Task" name="uma.type">
+<meta content="assess_results" name="uma.name">
+<meta content="Assess Results" name="uma.presentationName">
+<meta content="Discipline:project_management:Project Management" name="uma.category">
+<meta name="element_type" content="activity">
+<meta content="description" name="filetype">
+<meta name="role" content="Project Manager">
+<link type="text/css" href="./../../css/default.css" rel="StyleSheet">
+<script src="./../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../';
+ imgPath = './../../images/';
+ </script>
+<!-- epfwiki head start -->
+<link type='text/css' href='http://localhost/stylesheets/epfwiki.css' rel='StyleSheet'/>
+<script src='http://localhost/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- epfwiki head end -->
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../images/'); createStepLinks('div', 'stepHeading');">
+<table width="99%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top">
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Task: Assess Results</td><td align="right" class="expandCollapseLink" width="99%"><a href="./../../index.htm"></a><script src="./../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="99%">
+<tr>
+<td class="pageTitleSeparator"><img height="1" alt="" src="./../../images/shim.gif"></td>
+</tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../images/task.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">Determine success or failure of the iteration. Apply the lessons learned to modify the project or improve the process.</td>
+</tr>
+<tr>
+<td>Discipline:
+ <a href="./../../openup_basic/disciplines/project_management,_0TqQ4MlgEdmt3adZL5Dmdw.html" guid="_0TqQ4MlgEdmt3adZL5Dmdw">Project Management</a></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Purpose</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell">To assess the results of planned goals and objectives.</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Roles</th><td width="42%" class="sectionTableCell">Primary Performer:
+ <ul>
+<li>
+<a href="./../../openup_basic/roles/project_manager,_0a0o0MlgEdmt3adZL5Dmdw.html" guid="_0a0o0MlgEdmt3adZL5Dmdw">Project Manager</a>
+</li>
+</ul>
+</td><td class="sectionTableCell">Additional Performers:
+ <ul>
+<li>
+<a href="./../../openup_basic/roles/stakeholder,_dTa6gMAYEdqX-s4mWhkyqQ.html" guid="_dTa6gMAYEdqX-s4mWhkyqQ">Stakeholder</a>
+</li>
+<li>
+<a href="./../../openup_basic/roles/any_role,_0dsWoMlgEdmt3adZL5Dmdw.html" guid="_0dsWoMlgEdmt3adZL5Dmdw">Any Role</a>
+</li>
+</ul>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Inputs</th><td width="42%" class="sectionTableCell">Mandatory:
+ <ul>
+<li>
+<a href="./../../openup_basic/workproducts/iteration_plan,_0aQBEslgEdmt3adZL5Dmdw.html" guid="_0aQBEslgEdmt3adZL5Dmdw">Iteration Plan</a>
+</li>
+<li>
+<a href="./../../openup_basic/workproducts/project_plan,_0a6vcMlgEdmt3adZL5Dmdw.html" guid="_0a6vcMlgEdmt3adZL5Dmdw">Project Plan</a>
+</li>
+</ul>
+</td><td class="sectionTableCell">Optional:
+ <ul>
+<li>
+<a href="./../../openup_basic/workproducts/status_assessment,_0bA2EMlgEdmt3adZL5Dmdw.html" guid="_0bA2EMlgEdmt3adZL5Dmdw">Status Assessment</a>
+</li>
+<li>
+<a href="./../../openup_basic/workproducts/vision,_0WVxcMlgEdmt3adZL5Dmdw.html" guid="_0WVxcMlgEdmt3adZL5Dmdw">Vision</a>
+</li>
+</ul>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Outputs</th><td colspan="2" class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../openup_basic/workproducts/status_assessment,_0bA2EMlgEdmt3adZL5Dmdw.html" guid="_0bA2EMlgEdmt3adZL5Dmdw">Status Assessment</a>
+</li>
+</ul>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Steps</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr>
+<td class="sectionTableCell">
+<div class="stepHeading">Assess results</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ The project manager needs to regularly assess the results as planned. For example, in iterative development, this will
+ be done at the end of each iteration. Even if he or she is not using iterative development, the manager
+ should define quantifiable goals for a given period to facilitate regular assessment of the project's progress.
+</p>
+<p>
+ Below are questions that project managers can ask themselves and the rest of the team to help know the project
+ status:
+</p>
+<div dir="ltr" style="MARGIN-LEFT: 2em; MARGIN-RIGHT: 0px">
+ <ul>
+ <li>
+ Were the defined goals and objectives met?
+ </li>
+ <li style="LIST-STYLE-TYPE: none">
+ <ul>
+ <li>
+ Were risks reduced or eliminated?
+ </li>
+ <li>
+ Did the release meet its functionality and quality goals? Did the release meet performance and capacity
+ goals?
+ </li>
+ </ul>
+ </li>
+ <li>
+ Are changes to the project plan required?
+ </li>
+ <li>
+ What portion of the current release will be baselined? What portion will need to be reworked?
+ </li>
+ <li>
+ Have new risks been identified?
+ </li>
+ <li>
+ Have there been external changes such as changes in the marketplace, in the user community, or in the
+ requirements?
+ </li>
+ </ul>
+</div>
+<p dir="ltr">
+ One very important aspect of project assessment is to base the assessments on objective measures, as much as it is
+ possible to do so. For example, to assess that a given requirement is developed, the project manager must check that
+ the corresponding test cases were successfully run against it, rather than considering it done when the implementation
+ is done.
+</p></td>
+</tr>
+</table>
+</div>
+<div class="stepHeading">Gather stakeholder feedback</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ Assessing the results is also a good opportunity to get feedback from the stakeholders.
+</p>
+<p>
+ This feedback can be gathered through ways such as giving stakeholders informal demonstrations of what's developed as
+
+ the project progress and sending partial deliveries to stakeholders. However the feedback is gathered, it is good to
+ record changes that could have an impact on the project's scope or duration.
+</p></td>
+</tr>
+</table>
+</div>
+<div class="stepHeading">Refine project scope and duration</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ Depending on the result assessment and the stakeholders' feedback, the project manager could need to revise the project
+ plan to adapt to those changes. If a change affects defined project milestones, the project manager should consult with
+ the stakeholders before committing to the changes.
+</p>
+<p>
+ Necessary changes can also encompass the need to acquire new resources, to absorb an unplanned effort increase, or be
+ something specialized able to implement a specific change request.
+</p></td>
+</tr>
+</table>
+</div>
+<div class="stepHeading">Close-out phase</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ This step is optional and must be performed only when the assessed period coincide with the end of a phase.
+</p>
+<p>
+ The end of a phase represents a point of synchronization of technical and management expectations and closure for
+ a project. In iterative development, it coincides with the end of an iteration. However, phase ends mark a point
+ when it is possible to consider re-scoping and even re-contracting a project. For example, the inception phase is
+ exploratory and may be appropriately performed under a time-and-materials contract or a cost-plus type of contract. The
+ elaboration phase could be done as a fixed-price contract or a cost-plus contract, depending on the extent to which the
+ development is unusual. By the construction and transition phases, enough is known about the system that fixed-price
+ contracts are more appealing to the acquirer and vendor.
+</p>
+<p>
+ The phase end is marked by a major milestone and a corresponding milestone review. The degree of formality of
+ these reviews depends on the project. The important thing is to take advantage of this milestone review to
+ achieve agreement among all stakeholders on the current state of the project. For more information, refer to <a class="elementLinkWithType" href="./../../openup_basic/guidances/concepts/milestones,_HNxbwMBJEdqSgKaj2SZBmg.html" guid="_HNxbwMBJEdqSgKaj2SZBmg">Concept: Milestones</a>.
+</p></td>
+</tr>
+</table>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">More Information</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Concepts</th><td class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../openup_basic/guidances/concepts/milestones,_HNxbwMBJEdqSgKaj2SZBmg.html" guid="_HNxbwMBJEdqSgKaj2SZBmg">Milestones</a>
+</li>
+</ul>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Guidelines</th><td class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../openup_basic/guidances/guidelines/status_assessment,_0daCwMlgEdmt3adZL5Dmdw.html" guid="_0daCwMlgEdmt3adZL5Dmdw">Status Assessment Representation</a>
+</li>
+<li>
+<a href="./../../openup_basic/guidances/guidelines/type_freq_assessments,_pI_-YMA5EdqSgKaj2SZBmg.html" guid="_pI_-YMA5EdqSgKaj2SZBmg">Type and Frequency of Assessments</a>
+</li>
+</ul>
+</td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.<br />
+ This program and the accompanying materials are made available under the<br />
+ <a href="http://www.eclipse.org/org/documents/epl-v10.php" target="_blank">Eclipse Public License v1.0</a> which
+ accompanies this distribution.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+
+<!-- epfwiki iframe start -->
+<script language="JavaScript">
+
+ aURL = "http://localhost/epfwiki/toolbar?url=" + document.location.href;
+
+ document.write(" <div id=\"topbar\">\n");
+
+ document.write(" <iframe width=\"100%\" height=\"25\" frameborder=\"0\" src=\"" + aURL + "\" scrolling=\"no\" marginwidth=\"0\">\n");
+
+ document.writeln(" </div>");
+
+ </script>
+<!-- epfwiki iframe end -->
+</body>
+</html>
+#### 4
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Guideline: Architectural Analysis for J2EE Applications</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta name="element_type" content="other">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ </script>
+<!-- epfwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/epfwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- epfwiki head end -->
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../../images/');">
+<table width="99%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top"><a name="Top"></a>
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td class="pageTitle">Guideline: Architectural Analysis for J2EE Applications</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="99%">
+<tr>
+<td class="pageTitleSeparator"><img height="1" alt="" src="./../../../images/shim.gif"></td>
+</tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../../images/guidance.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">This guideline discusses some of the technologies provided by J2EE that the Software Architect needs to consider.</td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Related Elements</th><td class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../../rup/tasks/architectural_analysis,{8CB48402-D4C5-4E17-BB33-507315CB1BBF}.html" guid="{8CB48402-D4C5-4E17-BB33-507315CB1BBF}">Architectural Analysis</a>
+</li>
+</ul>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Main Description</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell"><h3>
+ <a id="Introduction" name="Introduction"></a>Introduction
+</h3>
+<p>
+ <a class="elementLink" href="./../../../rup/tasks/architectural_analysis,{8CB48402-D4C5-4E17-BB33-507315CB1BBF}.html" guid="{8CB48402-D4C5-4E17-BB33-507315CB1BBF}">Architectural Analysis</a> is where the <a class="elementLink" href="./../../../rup/roles/rup_software_architect,{4AC346F0-E6FC-4D2C-8410-2EDF8DDDC91D}.html" guid="{4AC346F0-E6FC-4D2C-8410-2EDF8DDDC91D}">Software Architect</a> determines how to best leverage the technologies
+ provided by the <a class="elementLink" href="./../../../rup_j2ee_plug_in/guidances/concepts/java_2_platform_enterprise_edition_j2ee_overview,1.527482214591853E-307.html" guid="1.527482214591853E-307">Java 2 Platform Enterprise Edition (J2EE) Overview</a> to meet both the functional and
+ nonfunctional requirements of the system. This guideline discusses some of those technologies.
+</p>
+<h3>
+ <a id="J2EE_Deployment_Configurations" name="J2EE_Deployment_Configurations"></a>J2EE Deployment Configurations
+</h3>
+<p>
+ J2EE supports a number of <a class="elementLink" href="./../../../rup_j2ee_plug_in/guidances/concepts/j2ee_deployment_configurations,7.671163061311939E-306.html" guid="7.671163061311939E-306">J2EE Deployment Configurations</a>. Selecting a particular deployment
+ configuration is an important step in Architectural Analysis as it becomes the foundation on which the initial
+ architecture is based.
+</p>
+<p>
+ Selecting a J2EE deployment configuration drives the definition of the initial <a class="elementLink" href="./../../../rup/workproducts/rup_deployment_model,{5981B6BE-2FD1-4984-AA94-2F7428439BA6}.html" guid="{5981B6BE-2FD1-4984-AA94-2F7428439BA6}">Deployment Model</a>. The selected J2EE deployment configuration
+ defines the configuration of physical nodes (that is, machines) and logical nodes (<a class="elementLinkWithUserText" href="./../../../rup_j2ee_plug_in/guidances/concepts/java_2_platform_enterprise_edition_j2ee_overview,1.527482214591853E-307.html" guid="1.527482214591853E-307">J2EE containers</a>). This is where you decide whether or not you have a separate
+ Web server and an EJB server, and whether your clients are browsers using HTTP or are fat application clients.
+</p>
+<p>
+ Each of these deployment configurations exhibits different characteristics, so one should be selected based upon a
+ number of factors. Some factors that should be considered when selecting a deployment configuration include:
+ maintainability (how do you isolate changes in one tier so they don't affect other tiers, how easy is it to deploy
+ upgrades?), performance and scalability (how easy is it to add additional computing resources?), and reliability (what
+ happens if one of the resources goes down?).
+</p>
+<p>
+ The selection of a deployment configuration constrains a number of other architectural decisions regarding the
+ architectural mechanisms that must be defined, the application's concurrency (see <a class="elementLinkWithType" href="./../../../rup/tasks/describe_runtime_architecture,{4D35C038-A2D0-48B8-9ECD-52717FEAE33A}.html" guid="{4D35C038-A2D0-48B8-9ECD-52717FEAE33A}">Task: Describe the Run-time Architecture</a>), and the application's
+ distribution (see <a class="elementLinkWithType" href="./../../../rup/tasks/describe_distribution,{6A112808-0A90-427A-BAB9-E14F3FBF72B5}.html" guid="{6A112808-0A90-427A-BAB9-E14F3FBF72B5}">Task: Describe Distribution</a>).
+</p>
+<h3>
+ <a id="J2EE_Mechanisms" name="J2EE_Mechanisms"></a>J2EE Mechanisms
+</h3>
+<p>
+ The <a class="elementLink" href="./../../../rup_j2ee_plug_in/guidances/concepts/java_2_platform_enterprise_edition_j2ee_overview,1.527482214591853E-307.html" guid="1.527482214591853E-307">Java 2 Platform Enterprise Edition (J2EE) Overview</a> provides a number of mechanisms
+ that support the development of multi-tier enterprise systems (persistency, inter-process communication, transaction
+ management, security, etc.). During Architectural Analysis, the Software Architect defines what needs to be built,
+ as opposed to what will be provided by the J2EE platform.
+</p>
+<p>
+ Effective management of application state is an important aspect of designing distributed applications. For an overview
+ of some of the common design considerations and mechanisms for state management in a J2EE application, see <a class="elementLinkWithType" href="./../../../rup_j2ee_plug_in/guidances/guidelines/designing_state_for_j2ee_applications,7.896195949843941E-306.html" guid="7.896195949843941E-306">Guideline: Designing State for J2EE Applications</a>.
+</p>
+<br />
+<br /></td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ © Copyright IBM Corp. 1987, 2005. All Rights Reserved.
+</p></td>
+</tr>
+</table>
+</td><td width="24" valign="top"></td><td width="1%" valign="top">
+<p>
+<a href="./../../../index.htm"></a>
+</p>
+<script src="./../../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+
+<!-- epfwiki iframe start -->
+<script language="JavaScript">
+
+ aURL = "http://localhost:3000/epfwiki/toolbar?url=" + document.location.href;
+
+ document.write(" <div id=\"topbar\">\n");
+
+ document.write(" <iframe width=\"100%\" height=\"25\" frameborder=\"0\" src=\"" + aURL + "\" scrolling=\"no\" marginwidth=\"0\">\n");
+
+ document.writeln(" </div>");
+
+ </script>
+<!-- epfwiki iframe end -->
+</body>
+
+</html>
+#### 5
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <head>
+
+ <meta name="generator" content="HTML Tidy for Windows (vers 14 February 2006), see www.w3.org" />
+
+ <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
+
+ <title>Concept: Collaborate to align interests and share understanding</title>
+
+ <meta content="text/html; charset=us-ascii" http-equiv="Content-Type" />
+
+ <meta content="Concept" name="uma.type" />
+
+ <meta content="core_principle_collaborate" name="uma.name" />
+
+ <meta content="Collaborate to align interests and share understanding" name="uma.presentationName" />
+
+ <meta name="element_type" content="concept" />
+
+ <meta content="description" name="filetype" />
+
+ <meta name="role" content="" />
+
+ <link type="text/css" href="./../../../css/default.css" rel="StyleSheet" />
+
+ <script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script>
+
+ <script type="text/javascript" language="JavaScript">
+
+
+
+ backPath = './../../../';
+
+
+
+
+
+</script>
+
+ </head>
+
+ <body>
+
+ <table width="100%" cellspacing="0" cellpadding="0" border="0">
+
+ <tr>
+
+ <td valign="top">
+
+ <a name="Top"></a>
+
+ <table cellpadding="0" cellspacing="0" border="0">
+
+ <tr>
+
+ <td nowrap="true" class="pageTitle">Concept: Collaborate to align interests and share understanding</td>
+
+ <td align="right" class="expandCollapseLink" width="100%">
+
+ <a href="./../../../index.htm"></a>
+
+ <!-- treebrowser tag -->
+
+ </td>
+
+ </tr>
+
+ </table>
+
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
+
+ <tr>
+
+ <td class="pageTitleSeparator">
+
+ <img height="1" alt="" src="./../../../images/shim.gif" />
+
+ </td>
+
+ </tr>
+
+ </table>
+
+ <div class="overview">
+
+ <table cellpadding="0" cellspacing="0" border="0" width="97%">
+
+ <tr>
+
+ <td width="50">
+
+ <img alt="" src="./../../../images/concept.gif" />
+
+ </td>
+
+ <td>
+
+ <table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+
+ <tr>
+
+ <td valign="top">Develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants and help them develop a shared understanding of the project.</td>
+
+ </tr>
+
+ </table>
+
+ </td>
+
+ </tr>
+
+ </table>
+
+ </div>
+
+ <div class="sectionHeading">Main Description</div>
+
+ <div class="sectionContent">
+
+ <table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+
+ <tr valign="top">
+
+ <td class="sectionTableCell">
+
+ <h3>Collaborate to align interests and share understanding</h3>
+
+ <p>Software is created by people with different interests and skills who must work together to create software effectively. Therefore develop collaborative practices that foster a healthy team environment. Good collaborative practices align the interests of project participants (e.g. development team, quality assurance, product stakeholders, customers) and help project participants develop a shared understanding of the project.</p>
+
+ <h3>Practices</h3>
+
+ <h4>Maintain a Common Understanding</h4>
+
+ <p>Project participants require a common understanding of a project to cooperative effectively. Without a common understanding among project participants disorder sets in because they cannot align their interests and will work at cross purposes to one another.</p>
+
+ <p>Therefore be proactive communicating and sharing information with project participants and do not assume everyone will just find what they need to know or has the same understanding of the project as everyone else. Use work products such as the vision and requirements to align the understanding of the stake holders and developers. Use the architecture to focus and align the interests of the developers. At the end of each iteration get agreement iteration goals have been reached and if not then what remedial actions must be taken.</p>The
+
+ <a class="elementlinkwithusertext" href="./resources/core_principle_focus,_9gocwMvoEdqukPpotm3DYg.html" guid="_9gocwMvoEdqukPpotm3DYg">Focus</a> principle helps to maintain a common understanding.
+
+ <br />
+
+ <h4>Foster a High Trust Environment</h4>
+
+ <p>People who do not feel safe will not communicate their ideas, take the initiative, or admit their ignorance. This leads to work environments where actions must be laboriously and expensively negotiated and work which must be carefully monitored and audited.</p>
+
+ <p>Therefore take actions that will foster a high trust environment:</p>
+
+ <ul>
+
+ <li>Manage by intent - create an environment where teams manage themselves and managers mentor teams to complete their objectives.</li>
+
+ <li>Tear down the walls – work to remove both the physical and mental barriers that inhibit development of a common understanding between project participants.</li>
+
+ <li>Walk mile (or a kilometer and a half) in someone else’s shoes – respect and try to understand the perspective of others before criticizing their ideas or responding to their criticism.</li>
+
+ </ul>
+
+ <h4>Share Responsibility
+
+ <br /></h4>
+
+ <p>When a person works alone communications can stop and they can “go dark” Their understanding of the project may become misaligned with the rest of the team. They may get into trouble and not ask for help, or not realize the team is in trouble. In the worse situations trust breaks down as people see the team working at cross purposes to their interests.</p>
+
+ <p>Therefore, while project participants have primary responsibility for their work products, responsibility for work products is shared. Nothing is someone else’s job. It may mean either taking up slack and working with someone who’s lagging for some reason or asking for help. Experienced staff should be extra vigilant and watch over less experienced staff encouraging them to ask for help if necessary.</p>
+
+ <p>The collaborative practice Foster a High Trust Environment reinforces sharing responsibility by making it safe for people to take the initiative, or to admit their ignorance.</p>
+
+ <h4>Learn Continuously</h4>
+
+ <p>Not only is software development a fast developing field where technical skills rapidly become obsolescent, it is also an experimental field where software is developed often by a process that resembles trial and error. Furthermore, software is developed by teams of people.</p>
+
+ <p>Therefore continuously develop both your technical and interpersonal skills. Learn from the examples of your colleagues. Take the opportunity to be both a student and a teacher to your colleagues. Always increase your personal ability to overcome your own antagonism towards other team members.</p>
+
+ <p>The
+
+ <a class="elementlinkwithusertext" href="./resources/core_principle_evolve,_GXiogMvoEdqukPpotm3DYg.html" guid="_GXiogMvoEdqukPpotm3DYg">Evolve</a> principle closely supports continuous learning. Learn Continuously helps develop trust.</p>
+
+ <h4 style="MARGIN: 12pt 0in 3pt">Organize around the architecture</h4>
+
+ <p class="MsoNormal" style="MARGIN: 0in 0in 0pt"> </p>
+
+ <p class="MsoNormal" style="MARGIN: 0in 0in 0pt">As projects grow in size, communication between team members becomes increasingly complex.</p>
+
+ <p class="MsoNormal" style="MARGIN: 0in 0in 0pt"><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>
+
+ </p>
+
+ <p class="MsoNormal" style="MARGIN: 0in 0in 0pt">Therefore organize the team around the architecture of the system so all team members understand the overall system but can focus primarily on a subset of a system, that is, one or more subsystems are assigned to them. Organizing around the architecture also helps with communication by providing the team with a common vocabulary and shared mental model of the system. However, be watchful that individuals and teams organized this way do not form a "silo" mentality where they focus striclty on their sub-systems and become ignorant of the other subsystems.</p>
+
+ <p>
+
+ <br /> </p></td>
+
+ </tr>
+
+ </table>
+
+ </div>
+
+ <table cellpadding="0" cellspacing="0" border="0" class="copyright">
+
+ <tr>
+
+ <td class="copyright">
+
+ <p>Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.
+
+ <br />This program and the accompanying materials are made available under the
+
+ <br />
+
+ <a href="http://www.eclipse.org/org/documents/epl-v10.php" target="_blank">Eclipse Public License v1.0</a> which accompanies this distribution.</p>
+
+ <p>test</p>
+
+ </td>
+
+ </tr>
+
+ </table>
+
+ </td>
+
+ </tr>
+
+ </table>
+
+ </body>
+
+</html>
+#### 6
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Task: Assess Results</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Task" name="uma.type">
+<meta content="assess_results" name="uma.name">
+<meta content="Assess Results" name="uma.presentationName">
+<meta content="Discipline:project_management:Project Management" name="uma.category">
+<meta name="element_type" content="activity">
+<meta content="description" name="filetype">
+<meta name="role" content="Project Manager">
+<link type="text/css" href="./../../css/default.css" rel="StyleSheet">
+<script src="./../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../';
+ imgPath = './../../images/';
+ </script>
+<!-- epfwiki head start -->
+<link type='text/css' href='http://localhost/stylesheets/epfwiki.css' rel='StyleSheet'/>
+<script src='http://localhost/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- epfwiki head end -->
+</head>
+<body onload="createSectionLinks('div', 'sectionHeading', './../../images/'); createStepLinks('div', 'stepHeading');">
+<table width="99%" cellspacing="0" cellpadding="0" border="0">
+<tr>
+<td valign="top">
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Task: Assess Results</td><td align="right" class="expandCollapseLink" width="99%"><a href="./../../index.htm"></a><script src="./../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0" border="0" width="99%">
+<tr>
+<td class="pageTitleSeparator"><img height="1" alt="" src="./../../images/shim.gif"></td>
+</tr>
+</table>
+<div class="overview">
+<table cellpadding="0" cellspacing="0" border="0" width="97%">
+<tr>
+<td width="50"><img alt="" src="./../../images/task.gif"></td><td>
+<table cellpadding="0" cellspacing="0" border="0" class="overviewTable">
+<tr>
+<td valign="top">Determine success or failure of the iteration. Apply the lessons learned to modify the project or improve the process.</td>
+</tr>
+<tr>
+<td>Discipline:
+ <a href="./../../openup_basic/disciplines/project_management,_0TqQ4MlgEdmt3adZL5Dmdw.html" guid="_0TqQ4MlgEdmt3adZL5Dmdw">Project Management</a></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Purpose</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<td class="sectionTableCell">To assess the results of planned goals and objectives.</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Relationships</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Roles</th><td width="42%" class="sectionTableCell">Primary Performer:
+ <ul>
+<li>
+<a href="./../../openup_basic/roles/project_manager,_0a0o0MlgEdmt3adZL5Dmdw.html" guid="_0a0o0MlgEdmt3adZL5Dmdw">Project Manager</a>
+</li>
+</ul>
+</td><td class="sectionTableCell">Additional Performers:
+ <ul>
+<li>
+<a href="./../../openup_basic/roles/stakeholder,_dTa6gMAYEdqX-s4mWhkyqQ.html" guid="_dTa6gMAYEdqX-s4mWhkyqQ">Stakeholder</a>
+</li>
+<li>
+<a href="./../../openup_basic/roles/any_role,_0dsWoMlgEdmt3adZL5Dmdw.html" guid="_0dsWoMlgEdmt3adZL5Dmdw">Any Role</a>
+</li>
+</ul>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Inputs</th><td width="42%" class="sectionTableCell">Mandatory:
+ <ul>
+<li>
+<a href="./../../openup_basic/workproducts/iteration_plan,_0aQBEslgEdmt3adZL5Dmdw.html" guid="_0aQBEslgEdmt3adZL5Dmdw">Iteration Plan</a>
+</li>
+<li>
+<a href="./../../openup_basic/workproducts/project_plan,_0a6vcMlgEdmt3adZL5Dmdw.html" guid="_0a6vcMlgEdmt3adZL5Dmdw">Project Plan</a>
+</li>
+</ul>
+</td><td class="sectionTableCell">Optional:
+ <ul>
+<li>
+<a href="./../../openup_basic/workproducts/status_assessment,_0bA2EMlgEdmt3adZL5Dmdw.html" guid="_0bA2EMlgEdmt3adZL5Dmdw">Status Assessment</a>
+</li>
+<li>
+<a href="./../../openup_basic/workproducts/vision,_0WVxcMlgEdmt3adZL5Dmdw.html" guid="_0WVxcMlgEdmt3adZL5Dmdw">Vision</a>
+</li>
+</ul>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Outputs</th><td colspan="2" class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../openup_basic/workproducts/status_assessment,_0bA2EMlgEdmt3adZL5Dmdw.html" guid="_0bA2EMlgEdmt3adZL5Dmdw">Status Assessment</a>
+</li>
+</ul>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">Steps</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr>
+<td class="sectionTableCell">
+<div class="stepHeading">Assess results</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ The project manager needs to regularly assess the results as planned. For example, in iterative development, this will
+ be done at the end of each iteration. Even if he or she is not using iterative development, the manager
+ should define quantifiable goals for a given period to facilitate regular assessment of the project's progress.
+</p>
+<p>
+ Below are questions that project managers can ask themselves and the rest of the team to help know the project
+ status:
+</p>
+<div dir="ltr" style="MARGIN-LEFT: 2em; MARGIN-RIGHT: 0px">
+ <ul>
+ <li>
+ Were the defined goals and objectives met?
+ </li>
+ <li style="LIST-STYLE-TYPE: none">
+ <ul>
+ <li>
+ Were risks reduced or eliminated?
+ </li>
+ <li>
+ Did the release meet its functionality and quality goals? Did the release meet performance and capacity
+ goals?
+ </li>
+ </ul>
+ </li>
+ <li>
+ Are changes to the project plan required?
+ </li>
+ <li>
+ What portion of the current release will be baselined? What portion will need to be reworked?
+ </li>
+ <li>
+ Have new risks been identified?
+ </li>
+ <li>
+ Have there been external changes such as changes in the marketplace, in the user community, or in the
+ requirements?
+ </li>
+ </ul>
+</div>
+<p dir="ltr">
+ One very important aspect of project assessment is to base the assessments on objective measures, as much as it is
+ possible to do so. For example, to assess that a given requirement is developed, the project manager must check that
+ the corresponding test cases were successfully run against it, rather than considering it done when the implementation
+ is done.
+</p></td>
+</tr>
+</table>
+</div>
+<div class="stepHeading">Gather stakeholder feedback</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ Assessing the results is also a good opportunity to get feedback from the stakeholders.
+</p>
+<p>
+ This feedback can be gathered through ways such as giving stakeholders informal demonstrations of what's developed as
+
+ the project progress and sending partial deliveries to stakeholders. However the feedback is gathered, it is good to
+ record changes that could have an impact on the project's scope or duration.
+</p></td>
+</tr>
+</table>
+</div>
+<div class="stepHeading">Refine project scope and duration</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ Depending on the result assessment and the stakeholders' feedback, the project manager could need to revise the project
+ plan to adapt to those changes. If a change affects defined project milestones, the project manager should consult with
+ the stakeholders before committing to the changes.
+</p>
+<p>
+ Necessary changes can also encompass the need to acquire new resources, to absorb an unplanned effort increase, or be
+ something specialized able to implement a specific change request.
+</p></td>
+</tr>
+</table>
+</div>
+<div class="stepHeading">Close-out phase</div>
+<div class="stepContent">
+<table cellpadding="0" cellspacing="0" border="0" class="stepTable">
+<tr valign="top">
+<td><p>
+ This step is optional and must be performed only when the assessed period coincide with the end of a phase.
+</p>
+<p>
+ The end of a phase represents a point of synchronization of technical and management expectations and closure for
+ a project. In iterative development, it coincides with the end of an iteration. However, phase ends mark a point
+ when it is possible to consider re-scoping and even re-contracting a project. For example, the inception phase is
+ exploratory and may be appropriately performed under a time-and-materials contract or a cost-plus type of contract. The
+ elaboration phase could be done as a fixed-price contract or a cost-plus contract, depending on the extent to which the
+ development is unusual. By the construction and transition phases, enough is known about the system that fixed-price
+ contracts are more appealing to the acquirer and vendor.
+</p>
+<p>
+ The phase end is marked by a major milestone and a corresponding milestone review. The degree of formality of
+ these reviews depends on the project. The important thing is to take advantage of this milestone review to
+ achieve agreement among all stakeholders on the current state of the project. For more information, refer to <a class="elementLinkWithType" href="./../../openup_basic/guidances/concepts/milestones,_HNxbwMBJEdqSgKaj2SZBmg.html" guid="_HNxbwMBJEdqSgKaj2SZBmg">Concept: Milestones</a>.
+</p></td>
+</tr>
+</table>
+</div>
+</td>
+</tr>
+</table>
+</div>
+<div class="sectionHeading">More Information</div>
+<div class="sectionContent">
+<table cellpadding="0" cellspacing="0" border="0" class="sectionTable">
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Concepts</th><td class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../openup_basic/guidances/concepts/milestones,_HNxbwMBJEdqSgKaj2SZBmg.html" guid="_HNxbwMBJEdqSgKaj2SZBmg">Milestones</a>
+</li>
+</ul>
+</td>
+</tr>
+<tr valign="top">
+<th scope="row" class="sectionTableHeading">Guidelines</th><td class="sectionTableCell">
+<ul>
+<li>
+<a href="./../../openup_basic/guidances/guidelines/status_assessment,_0daCwMlgEdmt3adZL5Dmdw.html" guid="_0daCwMlgEdmt3adZL5Dmdw">Status Assessment Representation</a>
+</li>
+<li>
+<a href="./../../openup_basic/guidances/guidelines/type_freq_assessments,_pI_-YMA5EdqSgKaj2SZBmg.html" guid="_pI_-YMA5EdqSgKaj2SZBmg">Type and Frequency of Assessments</a>
+</li>
+</ul>
+</td>
+</tr>
+</table>
+</div>
+<table cellpadding="0" cellspacing="0" border="0" class="copyright">
+<tr>
+<td class="copyright"><p>
+ Copyright (c) 1987, 2006 IBM Corp. and others. All Rights Reserved.<br />
+ This program and the accompanying materials are made available under the<br />
+ <a href="http://www.eclipse.org/org/documents/epl-v10.php" target="_blank">Eclipse Public License v1.0</a> which
+ accompanies this distribution.
+</p></td>
+</tr>
+</table>
+</td>
+</tr>
+</table>
+
+<!-- epfwiki iframe start -->
+<script language="JavaScript">
+
+ aURL = "http://localhost/epfwiki/toolbar?url=" + document.location.href;
+
+ document.write(" <div id=\"topbar\">\n");
+
+ document.write(" <iframe width=\"100%\" height=\"25\" frameborder=\"0\" src=\"" + aURL + "\" scrolling=\"no\" marginwidth=\"0\">\n");
+
+ document.writeln(" </div>");
+
+ </script>
+<!-- epfwiki iframe end -->
+</body>
+
+</html>
+#### 7
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Checklist: ..</td><td align="right" class="expandCollapseLink" width="99%"><a href="./../../index.htm"></a><script src="./../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+#### 8
+<table cellpadding="0" cellspacing="0" border="0">
+<tr>
+<td nowrap="true" class="pageTitle">Tool Mentor: </td><td align="right" class="expandCollapseLink" width="99%"><a href="./../../index.htm"></a><script src="./../../scripts/treebrowser.js" type="text/javascript" language="JavaScript"></script></td>
+</tr>
+</table>
+#### 9
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Checklist" name="element_type">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+#### 10
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content=Checklist name=element_type>
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+#### 11
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+< MetA name="element_type" content="Tool Mentor" >
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+#### 12
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<META NAME="element_type" CONTENT=" Tool Mentor " >
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+#### 13
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Checklist" name="element_type">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+#### 14
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="Checklist" name="element_type">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+#### 15
+<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+<head>
+<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Checklist: Actor</title>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<meta content="description" name="filetype">
+<meta name="role" content="">
+<link type="text/css" href="./../../../css/default.css" rel="StyleSheet">
+<script src="./../../../scripts/contentpage.js" type="text/javascript" language="JavaScript"></script><script src="./../../../scripts/steps.js" type="text/javascript" language="JavaScript"></script><script type="text/javascript" language="JavaScript">
+ backPath = './../../../';
+ expandAllText = 'Expand All Check Items';
+ collapseAllText = 'Collapse All Check Items';
+ </script>
+<!-- rupwiki head start -->
+<link type='text/css' href='http://localhost:3000/stylesheets/rupwiki.css' rel='StyleSheet'/>
+<script src='http://localhost:3000/javascripts/wiki.js' type='text/javascript' language='JavaScript'></script>
+<!-- rupwiki head end -->
+</head>
+
+
+
diff --git a/source/test/unit/site_test.rb b/source/test/unit/site_test.rb
new file mode 100644
index 0000000..5ac6354
--- /dev/null
+++ b/source/test/unit/site_test.rb
@@ -0,0 +1,259 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class SiteTest < Test::Unit::TestCase
+ # fixtures :sites
+
+ def setup
+ #@site = Site.find(1)
+ #Site.destroy_all
+ #Baseline.destroy_all
+ end
+
+ # Shows:
+ # 1. we can unzip uploaded content
+ # 2. we cannot unzip same content twice
+ def test01_unzip_upload
+ site = Site.new_baseline_process(:folder => openup0721_folder)
+ # 1.
+ # assert_equal "#{ENV['EPFWIKI_ROOT_DIR']}script/other/unzip_upload.bat U: U:\\ROR\\epfwiki2\\ C:/apache-ant-1.6.2/bin/ant #{ENV['EPFWIKI_ROOT_DIR']}public/rupsites/OpenUP-Basic_published_20060721.zip #{ENV['EPFWIKI_ROOT_DIR']}public/rupsites/OpenUP-Basic_published_20060721", site.unzip_upload_cmdline
+ site.unzip_upload
+ assert File.exists?(site.path)
+ assert File.exists?(site.path2zip)
+ # 2
+ assert_raise(RuntimeError){site.unzip_upload}
+ site = Site.new_baseline_process(:folder => openup0728_folder)
+ site.unzip_upload
+ assert File.exists?(site.path)
+ assert File.exists?(site.path2zip)
+ assert_raise(RuntimeError){site.unzip_upload}
+ end
+
+ # Shows:
+ # 1. to create a new site we have to specifiy: title, folder, baseline, user
+ # 2. we cannot create a site from non-existing folder
+ # 3. we cannot create site a without specifying the baseline
+ # 4. we can create a site and this also defines a baseline, so a Baseline record is also created
+ # 5. we cannot create a site if the baseline already exists, was already defined (baseline.baseline needs to be unique)
+ # 6. we cannot use a folder twice (create two or more sites from the same folder)
+ def test02_new_baseline_process
+ cadmin = create_cadmin
+ cadmin.save
+ cadmin = User.find_central_admin
+ assert_not_nil cadmin
+ assert !User.find_central_admin.nil?
+ # 1.
+ site = Site.new_baseline_process()
+ assert !site.save
+ assert_equal "Title can't be blank, Folder should consist of letters, digits and underscores, Folder can't be blank, Baseline can't be blank, User can't be blank", site.errors.full_messages.join(", ")
+ assert !User.find_central_admin.nil?
+ # 2.
+ baseline_count = Baseline.count
+ site_count = Site.count
+ site = Site.new_baseline_process(:folder => 'nonexistingfolder', :title => 'test02_new_site', :user_id => cadmin.id, :baseline_baseline => 'OUP_20060721')
+ assert !site.save
+ assert_equal 'Folder doesn\'t exist, Baseline can\'t be blank', site.errors.full_messages.join(', ')
+ assert_equal baseline_count, Baseline.count
+ assert_equal site_count, Site.count
+ assert !User.find_central_admin.nil?
+ # 3.
+ site = Site.new_baseline_process(:folder => openup0721_folder, :title => 'OpenUP 20060721', :user_id => cadmin.id)
+ assert !site.save
+ assert_equal 'Baseline can\'t be blank', site.errors.full_messages.join(', ')
+ assert_equal baseline_count, Baseline.count
+ assert_equal site_count, Site.count
+ assert !User.find_central_admin.nil?
+ # 4.
+ site = Site.new_baseline_process(:folder => openup0721_folder, :title => 'openup0721', :user_id => User.find_central_admin.id, :baseline_baseline => 'OUP_20060721')
+ assert_not_nil site.baseline
+ assert_not_nil site.baselines
+ assert site.save
+ assert_equal '', site.errors.full_messages.join(', ')
+ assert_equal baseline_count + 1, Baseline.count
+ assert_equal site_count + 1, Site.count
+ site = Site.find(site.id)
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 8, site.wikifiable_files_count
+ assert_equal 8, site.html_files_count
+ else
+ assert_equal 617, site.wikifiable_files_count
+ assert_equal 633, site.html_files_count
+ end
+ assert !User.find_central_admin.nil?
+ # 5.
+ site = Site.new_baseline_process(:folder => openup0728_folder, :title => 'test02_new_site', :user_id => User.find_central_admin.id, :baseline_baseline => 'OUP_20060721')
+ assert !site.save
+ assert_equal 'Baseline has already been taken', site.errors.full_messages.join(', ')
+ assert_equal baseline_count + 1, Baseline.count
+ assert_equal site_count + 1, Site.count
+ # 6.
+ assert !User.find_central_admin.nil?
+ site = Site.new_baseline_process(:folder => openup0721_folder, :title => 'test02_new_site', :user_id => User.find_central_admin.id, :baseline_baseline => 'OUP_20060728')
+ assert !site.save
+ assert_equal 'Folder was already used to create a baseline process (static site)', site.errors.full_messages.join(', ')
+ assert_equal baseline_count + 1, Baseline.count
+ assert_equal site_count + 1, Site.count
+ assert !User.find_central_admin.nil?
+ end
+
+ # Shows:
+ # 1. to create a Wiki we need to specifiy a baseline process
+ # 2. we can create a Wiki or better schedule a Wiki te be created
+ # 3. a Wiki can only be created from a baseline process (static site, site_type is 'S')
+ def test03_new_wiki
+ assert !User.find_central_admin.nil?
+ # 1.
+ sites_count = Site.count
+ wiki = Site.new_wiki(:folder => 'openup', :title => 'OpenUP Wiki', :user_id => User.find_central_admin.id)
+ assert !wiki.save
+ assert_equal 'Baseline can\'t be blank', wiki.errors.full_messages.join(', ')
+ assert_equal sites_count, Site.count
+ # 2.
+ baseline_process = Site.find_by_folder_and_site_type(openup0721_folder,'S')
+ assert_not_nil baseline_process
+ wiki = Site.new_wiki(:folder => 'openup', :title => 'OpenUP Wiki', :user_id => User.find_central_admin.id, :site_id_baseline_process => baseline_process.id)
+ assert wiki.save
+ wiki.reload
+ assert_equal wiki.baseline_process.html_files_count, wiki.html_files_count
+ assert_equal wiki.baseline_process.wikifiable_files_count, wiki.wikifiable_files_count
+ assert_equal 'P', wiki.status
+ assert_equal 'W', wiki.site_type
+ # 3.
+ wiki2 = Site.new_wiki(:folder => 'openup2', :title => 'OpenUP Wiki2', :user_id => User.find_central_admin.id, :site_id_baseline_process => wiki.id)
+ assert !wiki2.save
+ assert_equal 'Baseline process not a baseline process (type is not \'S\'', wiki2.errors.full_messages.join(', ')
+ end
+
+ # Shows:
+ # 1. we cannot wikify a static site
+ # 2. we can wikify content in a Wiki site
+ # 3. the wikify operation will cause content of baseline process to be scanned (because it was not scanned yet)
+ # 4. scan of content has defines the baseline
+ # 5. TODO: test if content was wikified correctly
+ def test04_new_wiki
+ # 1
+ wiki = Site.find_by_site_type('S')
+ assert_not_nil wiki
+ assert_raise(RuntimeError) {wiki.wikify}
+ # 2
+ pending_wikis = Site.find_wikis_pending
+ pending_count = pending_wikis.size
+ assert_equal 1, pending_count
+ wiki = pending_wikis[0]
+ assert_not_nil wiki.baseline_process
+ baseline_process = Site.find(wiki.baseline_process.id) # TODO:
+ wiki.wikify
+ assert wiki.save
+ #assert_equal '', wiki.errors.full_messages.join(', ')
+ wiki.reload
+ assert_equal 0, Site.find_all_by_site_type('P').size #pass
+ assert_equal 1, Site.find_all_by_site_type('W').size #pass
+ baseline_process.reload
+ assert_not_nil baseline_process
+ assert_equal 'openup0721',baseline_process.title
+ assert_equal wiki.baseline, baseline_process.baseline
+ assert_equal 617, wiki.pages.size if ENV['EPFWIKI_TESTDATA'] != 'test'
+ assert_equal 8, wiki.pages.size if ENV['EPFWIKI_TESTDATA'] == 'test'
+ # 3
+ assert_equal wiki.pages.size, baseline_process.pages.size
+ # 4
+ assert_equal 617, wiki.baseline.pages.size if ENV['EPFWIKI_TESTDATA'] != 'test'
+ assert_equal 8, wiki.pages.size if ENV['EPFWIKI_TESTDATA'] == 'test'
+ end
+
+ # Shows:
+ # 1. can't update the site_type of a baseline process
+ # 2. can update a baseline process (site_type != 'W')
+ # 3. can't update a wiki with a current baseline process
+ # 4. can update or cancel a pending wiki
+ # 5. can't do the actual update when there is not baseline_process
+ # 6. we can do the actual update
+ def test05_update_wiki
+ # 1
+ site = Site.new_baseline_process(:folder => openup0728_folder, :title => 'openup0728', :user_id => User.find_central_admin.id, :baseline_baseline => 'OUP_20060728')
+ assert_equal 0, site.pages.size # content not scanned yet
+ assert_not_nil site.baseline
+ assert_not_nil site.baselines
+ assert site.save
+ assert_equal '', site.errors.full_messages.join(', ')
+ openup0721 = Site.find_by_folder(openup0721_folder)
+ openup0728 = Site.find_by_folder(openup0728_folder)
+ openupwiki = Site.find_by_folder('openup')
+ assert_not_nil openup0721
+ assert_not_nil openup0728
+ assert_not_nil openupwiki
+ openup0721.site_type = 'W'
+ assert !openup0721.save
+ assert_equal 'Site type can\'t be updated for a baseline process', openup0721.errors.full_messages.join(', ')
+ # 2
+ openup0721.baseline_process = openup0728
+ assert !openup0721.save
+ assert_equal 'Site type can\'t be updated for a baseline process', openup0721.errors.full_messages.join(', ')
+ # 3
+ openupwiki = Site.find_wikis[0]
+ openup0721 = Site.find_all[0]
+ openupwiki.baseline_process = openup0721
+ assert !openupwiki.save
+ assert_equal 'Baseline process is equal to current baseline, Baseline process was already used to create or update this site', openupwiki.errors.full_messages.join(', ')
+ # 4
+ openup0825 = create_openup0825
+ openupwiki.reload
+ assert_equal 'W', openupwiki.status
+ openupwiki.baseline_process = openup0728
+ assert openupwiki.save
+ openupwiki.reload
+ assert_equal 'U', openupwiki.status
+ openupwiki.baseline_process = openup0825
+ assert openupwiki.save
+ openupwiki.reload
+ assert_equal openup0825, openupwiki.baseline_process
+ assert_equal 'U', openupwiki.status
+ openupwiki.baseline_process = nil
+ assert openupwiki.save
+ openupwiki.reload
+ assert_equal 'W', openupwiki.status
+ # 5
+ assert_raise(RuntimeError) {openupwiki.update_wiki}
+ # 6
+ openupwiki.baseline_process = openup0728
+ assert_equal 0, openup0728.pages.size # content not scanned yet
+ assert openupwiki.save
+ openupwiki.update_wiki
+ assert openupwiki.save
+ assert_equal 617, openupwiki.pages.size if ENV['EPFWIKI_TESTDATA'] != 'test'
+ assert_equal 10, openupwiki.pages.size if ENV['EPFWIKI_TESTDATA'] == 'test'
+ openup0728.reload
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 10, openup0728.pages.size # content scan triggered by update
+ assert_equal 10, openup0728.baseline.pages.size
+ else
+ assert_equal 617, openup0728.pages.size # content scan triggered by update
+ assert_equal 617, openup0728.baseline.pages.size
+ end
+ end
+
+ def test06_wikifiable_files
+ bp = Site.find_by_title('openup0721')
+ wikifiable_files = bp.files_wikifiable
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ assert_equal 8, wikifiable_files.size # content scan triggered by update
+ assert_equal 8, wikifiable_files.size
+ else
+ assert_equal 617, wikifiable_files.size # content scan triggered by update
+ assert_equal 617, wikifiable_files.size
+ end
+ end
+end
diff --git a/source/test/unit/user_test.rb b/source/test/unit/user_test.rb
new file mode 100644
index 0000000..96c2e6e
--- /dev/null
+++ b/source/test/unit/user_test.rb
@@ -0,0 +1,229 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class UserTest < Test::Unit::TestCase
+ # the following line causes errors
+ fixtures :users
+
+ def setup
+ @user = User.find(1)
+ end
+
+ def test01_create
+ assert_kind_of User, @user
+ assert_equal 1, @user.id
+ assert_equal "onno.van.der.straaten@epf.org", @user.email
+ assert_equal "Onno", @user.name
+ assert_equal "localhost", @user.ip_address
+ assert_equal hash_pw("Onno"), @user.hashed_password
+ assert_equal "Y", @user.admin
+ #assert_equal "2006-01-01 00:00:00", @user.created_on
+ #assert_equal "2006-01-02 00:00:00", @user.updated_on
+ end
+
+ def test02_new_signup
+ assert User.count > 0
+ assert_equal "0", ENV['EPFWIKI_GENERATE_PASSWORDS']
+ assert_not_nil ENV['EPFWIKI_DOMAINS']
+ # we need params
+ user = User.new_signup({})
+ assert !user.save
+ assert_equal "Name can't be blank, Password confirmation can't be blank, Password can't be blank, Email is invalid, Email can't be blank, Email domain not valid", user.errors.full_messages.join(", ")
+ # password needs to be confirmed
+ user = User.new_signup({:name => "User10", :password => "User10", :email => "User10@epf.org"})
+ assert !user.save
+ assert_equal "Password confirmation can't be blank", user.errors.full_messages.join(", ")
+ # password needs to be confirmed 2
+ user = User.new_signup({:name => "User10", :password => "User10", :password_confirmation => "xyz", :email => "User10@epf.org"})
+ assert !user.save
+ assert_equal "Password doesn't match confirmation", user.errors.full_messages.join(", ")
+ # user created
+ user = User.new_signup({:name => "User10", :password => "User10", :password_confirmation => "User10", :email => "User10@epf.org"})
+ assert user.save
+ assert_equal "user10@epf.org", user.email
+ assert_equal nil, user.confirmed_on # account needs to be confirmed
+ assert_equal hash_pw('User10'), user.hashed_password
+ assert_equal nil, user.hashed_password_new
+ # cannot login, not confirmed
+ login_user = user.try_to_login
+ assert_equal nil, login_user
+ # confirm account
+# assert_equal hash_pw('User10'), user.hashed_password
+ user.confirm_account(hash_pw(user.hashed_password))
+ assert user.save
+ assert_not_nil user.confirmed_on
+ # can login
+ login_user = user.try_to_login
+ assert_not_nil login_user
+ #ENV['EPFWIKI_DOMAINS']
+ end
+
+ def test03_set_new_pw
+ # user created
+ user = User.new_signup({:name => "User11", :password => "User11", :password_confirmation => "User11", :email => "User11@epf.org"})
+ assert user.save
+ # confirm account
+ user.confirm_account(hash_pw(user.hashed_password))
+ assert user.save
+ assert_equal "", user.errors.full_messages.join(", ")
+ user = User.find_by_name('User11')
+ assert_not_nil user.confirmed_on
+ # can login
+ user.password = 'User11'
+ login_user = user.try_to_login
+ assert_not_nil login_user
+ # set new password
+ hashed_password = user.hashed_password
+ user.set_new_pw
+ new_pw = user.password
+ assert user.save
+ assert_equal "", user.errors.full_messages.join(", ")
+ user.reload
+ assert_not_nil user.confirmed_on
+ assert_equal hash_pw(new_pw), user.hashed_password_new
+ # we can still sign in with the old password
+ user.password = "User11"
+ login_user = user.try_to_login
+ assert_not_nil login_user
+ # we cannot sign in with the new password
+ user.password = new_pw
+ login_user = user.try_to_login
+ assert_equal nil, login_user
+ # cannot confirm with the wrong token
+ user = User.find_by_name('User11')
+ assert_raise(RuntimeError) {user.confirm_account("somewrongtoken")}
+ # confirm the account
+ user = User.find_by_name('User11')
+ #assert_equal hash_pw(hash_pw(new_pw)), hash_pw(user.hashed_password_new)
+ user.confirm_account(hash_pw(hash_pw(new_pw)))
+ assert_equal hash_pw(new_pw), user.hashed_password
+ user.save
+ assert_equal "", user.errors.full_messages.join(", ")
+ user = User.find_by_name('User11')
+ assert_not_equal hashed_password, user.hashed_password
+ assert_equal hash_pw(new_pw), user.hashed_password
+ assert_equal nil, user.hashed_password_new
+ assert_not_nil user.confirmed_on
+ # we can sign in with the new password
+ user.password = new_pw
+ login_user = user.try_to_login
+ assert_not_nil login_user
+ end
+
+ def test04_updates
+ user = User.find_by_name('User2')
+ user.name = "User2_test"
+ assert user.save
+ assert_equal "", user.errors.full_messages.join(", ")
+ end
+
+ def test05_change_password
+ user = User.find_by_name('User2')
+ assert_raise(RuntimeError) {user.change_password(User.new)}
+ assert_raise(RuntimeError) {user.change_password(User.new(:password =>'', :password_confirmation => ''))}
+ user.change_password(User.new(:password =>'xyz', :password_confirmation => '123'))
+ assert !user.save
+ assert_equal "Password doesn't match confirmation", user.errors.full_messages.join(", ")
+ user.change_password(User.new(:password =>'xyz', :password_confirmation => 'xyz'))
+ assert user.save
+ assert_equal '', user.errors.full_messages.join(', ')
+ user = User.find_by_name('User2')
+ user.password = 'xyz'
+ login_user = user.try_to_login
+ assert_equal hash_pw('xyz'), login_user.hashed_password
+ assert_not_nil login_user
+ end
+
+ # Shows:
+ # 1. Cannot update a user to Y or C without specifying the user
+ # 2. Cadmin can upgrade user to admin, downgrade to user, admin kan upgrade user to admin but not downgrade admin to user
+ # 3. Cadmin can make another user the cadmin
+ # . C -> Y or C -> N not possible
+ def test06_admin
+ cadmin = User.find_central_admin
+ user = User.find_all_by_admin('N')[0]
+ admin = User.find_all_by_admin('Y')[0]
+ assert_not_nil cadmin
+ assert_not_nil user
+ assert_not_nil admin
+ user.admin = 'Y'
+ assert !user.save
+ assert_equal 'Admin can only be set by an admin', user.errors.full_messages.join(", ")
+ user.admin = 'C'
+ assert !user.save
+ assert_equal 'Admin can only be set to C by the central admin', user.errors.full_messages.join(", ")
+ # 2
+ user.admin = 'Y'
+ user.user = cadmin
+ assert user.save
+ user.admin = 'N'
+ user.user = cadmin
+ assert user.save
+ user.admin = 'Y'
+ user.user = admin
+ assert user.save
+ user.admin = 'N'
+ user.user = admin
+ assert !user.save
+ assert_equal 'Admin can only be revoked by the central admin', user.errors.full_messages.join(", ")
+ user.user = cadmin
+ assert user.save
+ # 3
+ assert cadmin.cadmin?
+ User.cadmin(cadmin, user)
+ user.save
+ cadmin.save
+ assert_equal '', user.errors.full_messages.join(", ")
+ assert_equal '', cadmin.errors.full_messages.join(", ")
+ user.reload
+ cadmin.reload
+ assert user.cadmin?
+ assert !cadmin.cadmin?
+ assert_equal 'Y', cadmin.admin
+ assert_equal 'C', user.admin
+ end
+
+
+ # do this test the last because fixtures are not loaded for every test
+ def tst99_new_cadmin
+ params = {:name => 'onno', :email => 'Onno@epf.org', :password => 'xyz', :password_confirmation => 'xyz'}
+ # cannot create cadmin if there are users
+ assert_raise(RuntimeError) {cadmin = User.new_cadmin(params)}
+ User.delete_all
+ # params are needed
+ cadmin = User.new_cadmin({})
+ assert !cadmin.save
+ assert_equal "Name can't be blank, Password confirmation can't be blank, Password can't be blank, Email is invalid, Email can't be blank", cadmin.errors.full_messages.join(", ")
+ # password needs to be confirmed
+ cadmin = User.new_cadmin(:name => 'onno', :email => 'Onno@epf.org', :password => 'xyz', :password_confirmation => '123')
+ assert !cadmin.save
+ assert_equal "Password doesn't match confirmation", cadmin.errors.full_messages.join(", ")
+ # valid email is required
+ cadmin = User.new_cadmin(:name => 'onno', :email => 'Onno(at)epf.org', :password => 'xyz', :password_confirmation => 'xyz')
+ assert !cadmin.save
+ assert_equal "Email is invalid", cadmin.errors.full_messages.join(", ")
+ # cadmin is created, note domain restriction does not apply to cadmin account
+ cadmin = create_cadmin
+ assert cadmin.save
+ assert_equal "", cadmin.errors.full_messages.join(", ")
+ assert_equal 'onno@noneexistingdomain.com', cadmin.email # email set to downcase
+ assert_not_nil cadmin.hashed_password
+ assert_equal hash_pw('xyz'), cadmin.hashed_password # password is hashed and stored
+ assert_not_nil cadmin.confirmed_on # account or email does not need to be confirmed
+ # TODO: we can update attributes
+ end
+
+end
diff --git a/source/test/unit/version_test.rb b/source/test/unit/version_test.rb
new file mode 100644
index 0000000..0addc86
--- /dev/null
+++ b/source/test/unit/version_test.rb
@@ -0,0 +1,174 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+#--######################################################################
+# Copyright (c) 2006 LogicaCMG
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#
+# Onno van der Straaten:: initial implementation
+#++######################################################################
+# {Copyright (c) 2006 LogicaCMG}[link:files/COPYRIGHT.html]
+
+class VersionTest < Test::Unit::TestCase
+
+ fixtures :users #, :checkouts, :versions
+
+ def setup
+ @onno = User.find(1)
+ @onno_cadmin = User.find(5)
+ @user4 = User.find(4)
+ @user3 = User.find(3)
+ end
+
+ # Shows:
+ # 1. we cannot use find_current_version on a baseline process (we cannot create versions)
+ # 2. find_current_version does not create the baseversion
+ # 3. or find_current_version does create the baseversion
+ # 4. shows that the baseversion was prepared correctly using Page.prepare_html_for_editing
+ def test01_find_current_version
+ version_count = Version.count
+ openupwiki = Site.find_by_title('OpenUP Wiki')
+ openup0825 = Site.find_by_folder(openup0825_folder)
+ assert_not_nil openupwiki
+ page = Page.find_by_filename('determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html')
+ assert File.exists?(page.path(openupwiki))
+ html_before = IO.readlines(page.path(openupwiki))
+ assert_not_nil page
+ # 1
+ assert_raise(RuntimeError) {Version.find_current_version(openup0825, page)}
+ # 2
+ version = Version.find_current_version(openupwiki, page)
+ assert version.nil?
+ assert_equal version_count, Version.count # default not created
+ # 3
+ version = Version.find_current_version(openupwiki, page, true)
+ assert_not_nil version
+ assert version.save
+ version.reload
+ assert version_count + 1, Version.count
+ assert_equal 0, version.version
+ if ENV['EPFWIKI_TESTDATA'] == 'test'
+ #assert_equal "determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html_EPFWIKI_v0_OUP_20060728.html", version.filename
+ assert_equal 'determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html_EPFWIKI_v0_OUP_20060728.html', version.rel_path
+ else
+ #assert_equal "determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html_EPFWIKI_v0_OUP_20060728.html", version.filename
+ assert_equal 'openup_basic/capabilitypatterns/determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html_EPFWIKI_v0_OUP_20060728.html', version.rel_path
+ end
+
+ assert_equal 'OUP_20060728', version.baseline.baseline
+ assert File.exists?(version.path)
+ # 4
+ assert File.compare("#{ENV['EPFWIKI_ROOT_DIR']}test/unit/version_test/determine_architectural_feasibility_0oreoclgEdmt3adZL5Dmdw_desc.html_EPFWIKI_v0_OUP_20060728.html", version.path)
+ end
+
+ # Shows:
+ #
+ # When there is only the baseversion
+ # 1. Version.find_current_version creates a baseversion as there are no versions yet! This version is not saved yet!
+ # 2. a baseversion does not have a previous_version
+ # 3. this created baseversion is the current version
+ # 4. when creating version1 using Version.new_basedonversion, the baseversion is the first (0) version
+ # 5. we can create version2 based on version1
+ # Creating version2 based on version1
+ # 6. before changes version2 is equal to version1
+ # 7. we can rollback changes by creaint version3 based on version1
+ # 8. create a version using a version from another site, this will overwrite changes
+ def test02_version_types
+ openupwiki = Site.find_by_title('OpenUP Wiki')
+ openup0825 = Site.find_by_folder(openup0825_folder)
+ assert_not_nil openupwiki
+ page = Page.find_by_filename('implementation,_0TeDoMlgEdmt3adZL5Dmdw.html')
+ assert File.exists?(page.path(openupwiki))
+ baseversion = Version.find_current_version(openupwiki, page, true)
+ assert_equal 0, baseversion.version #baseversion, not saved yet!
+ assert baseversion.save
+ # 1
+ assert_equal baseversion, baseversion.baseversion
+ assert_equal 0, baseversion.version
+ # 2
+ assert_equal nil, baseversion.previous_version
+ # 3
+ assert_equal baseversion, baseversion.current_version
+ # creating a new version
+ version1 = Version.new_basedonversion(openupwiki, page, baseversion, @user4)
+ assert version1.save
+ version1.reload
+ version1.html('version1')
+ # 4
+ assert_equal baseversion, version1.baseversion
+ assert_equal 0, version1.baseversion.version
+ # 5
+ assert_equal 1, version1.version
+ # creating version2 based on version1
+ version2 = Version.new_basedonversion(openupwiki, page, version1, @user4)
+ assert version2.save
+ # 6
+ assert_equal version1.html, version2.html
+ version2.html('version2')
+ assert_equal 2, version2.version
+ # 7
+ version3 = Version.new_basedonversion(openupwiki, page, version1, @user4)
+ assert version3.save
+ assert_equal version3.html, version1.html
+ end
+
+ # Shows:
+ # 1. cannot checkout to baseline process, only to a Wiki
+ # 2. checkout to openupwiki2 creates version1, a baseversion is not created as the page doesn't exist openupwiki2
+ # 3. checkout to openupwiki2 creates version1 and a new baseversion
+ def test03_checkout_to_other_wiki
+ openupwiki = Site.find_by_title('OpenUP Wiki')
+ openupwiki2 = Site.new_wiki(:folder => 'openup2', :title => 'OpenUP Wiki2', :user_id => User.find_central_admin.id, :site_id_baseline_process => baseline_process = Site.find_by_folder_and_site_type(openup0721_folder,'S'))
+ assert openupwiki2.save
+ openup0825 = Site.find_by_folder(openup0825_folder)
+ # 1
+ page = Page.find_by_filename('implementation,_0TeDoMlgEdmt3adZL5Dmdw.html')
+ version_source = Version.find_current_version(openupwiki, page, true)
+ assert_equal 3, version_source.version
+ version_source.html('version3 from openupwiki')
+ assert_raise(RuntimeError) {version1 = Version.new_basedonversion(openup0825, page, version_source, @user4)}
+ # 2
+ baseversion = Version.find_current_version(openupwiki2, page) # we don't create the baseversion here
+ assert !File.exists?(page.path(openupwiki2)) # page does not exist in openupwiki2
+ assert_equal nil, baseversion
+ version1 = Version.new_basedonversion(openupwiki2, page, version_source, @user4)
+ assert version1.save
+ version1.reload
+ assert_equal 1, version1.version
+ assert_equal version_source.html, version1.html
+ assert version1.baseversion.nil?
+ #assert baseversion.html != version1.html
+ assert_equal version_source, version1.source_version
+ # 3
+ #page = Page.find_by_filename('')
+ end
+
+ def test04_rel_path_root
+ openupwiki = Site.find_by_title('OpenUP Wiki')
+ page = Page.find_by_filename('implementation,_0TeDoMlgEdmt3adZL5Dmdw.html')
+ assert_not_nil openupwiki
+ assert_not_nil page
+ version = Version.find_current_version(openupwiki, page)
+ assert_equal 3, version.version
+ if !ENV['EPFWIKI_TESTDATA'].blank?
+ assert_equal "#{ENV['EPFWIKI_WIKIS_FOLDER']}/openup/implementation,_0TeDoMlgEdmt3adZL5Dmdw.html_EPFWIKI_v3_OUP_20060728.html", version.rel_path_root
+ end
+ end
+
+ def test05_template_test
+ openupwiki = Site.find_by_title('OpenUP Wiki')
+ assert_not_nil openupwiki
+ ['Tool Mentor Template.html','Checklist Template.html'].each do |filename|
+ page = Page.find_by_filename(filename)
+ assert_not_nil page
+ page.versions.each do |version|
+ assert version.template?
+ end
+ end
+ end
+end
diff --git a/source/webrick_localhost.bat b/source/webrick_localhost.bat
new file mode 100644
index 0000000..5e42f05
--- /dev/null
+++ b/source/webrick_localhost.bat
@@ -0,0 +1 @@
+ruby script/server -b localhost -e %1 -p 3000
\ No newline at end of file