user = User.try_to_login(params[:login], params[:password])\r
if user\r
self.logged_in_user = user\r
- redirect_back_or_default :controller => 'account', :action => 'my_page'\r
+ redirect_back_or_default :controller => 'my', :action => 'page'\r
else\r
flash.now[:notice] = l(:notice_account_invalid_creditentials)\r
end\r
self.logged_in_user = nil\r
redirect_to :controller => ''\r
end\r
-\r
- # Show logged in user's page\r
- def my_page\r
- @user = self.logged_in_user\r
- @reported_issues = Issue.find(:all, :conditions => ["author_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC')\r
- @assigned_issues = Issue.find(:all, :conditions => ["assigned_to_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC')\r
- end\r
-\r
- # Edit logged in user's account\r
- def my_account\r
- @user = self.logged_in_user\r
- if request.post? and @user.update_attributes(@params[:user])\r
- set_localization\r
- flash.now[:notice] = l(:notice_account_updated)\r
- self.logged_in_user.reload\r
- end\r
- end\r
- \r
- # Change logged in user's password\r
- def change_password\r
- @user = self.logged_in_user\r
- flash[:notice] = l(:notice_can_t_change_password) and redirect_to :action => 'my_account' and return if @user.auth_source_id\r
- if @user.check_password?(@params[:password])\r
- @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]\r
- if @user.save\r
- flash[:notice] = l(:notice_account_password_updated)\r
- else\r
- render :action => 'my_account'\r
- return\r
- end\r
- else\r
- flash[:notice] = l(:notice_account_wrong_password)\r
- end\r
- redirect_to :action => 'my_account'\r
- end\r
\r
# Enable user to choose a new password\r
def lost_password\r
--- /dev/null
+# redMine - project management software
+# Copyright (C) 2006 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class MyController < ApplicationController
+ layout 'base'
+ before_filter :require_login
+
+ BLOCKS = { 'issues_assigned_to_me' => :label_assigned_to_me_issues,
+ 'issues_reported_by_me' => :label_reported_issues,
+ 'latest_news' => :label_news_latest,
+ 'calendar' => :label_calendar,
+ 'documents' => :label_document_plural
+ }.freeze
+
+ verify :xhr => true,
+ :session => :page_layout,
+ :only => [:add_block, :remove_block, :order_blocks]
+
+ def index
+ page
+ render :action => 'page'
+ end
+
+ # Show user's page
+ def page
+ @user = self.logged_in_user
+ @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] }
+ end
+
+ # Edit user's account
+ def account
+ @user = self.logged_in_user
+ if request.post? and @user.update_attributes(@params[:user])
+ set_localization
+ flash.now[:notice] = l(:notice_account_updated)
+ self.logged_in_user.reload
+ end
+ end
+
+ # Change user's password
+ def change_password
+ @user = self.logged_in_user
+ flash[:notice] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id
+ if @user.check_password?(@params[:password])
+ @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
+ if @user.save
+ flash[:notice] = l(:notice_account_password_updated)
+ else
+ render :action => 'account'
+ return
+ end
+ else
+ flash[:notice] = l(:notice_account_wrong_password)
+ end
+ redirect_to :action => 'account'
+ end
+
+ # User's page layout configuration
+ def page_layout
+ @user = self.logged_in_user
+ @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] }
+ session[:page_layout] = @blocks
+ %w(top left right).each {|f| session[:page_layout][f] ||= [] }
+ @block_options = []
+ BLOCKS.each {|k, v| @block_options << [l(v), k]}
+ end
+
+ # Add a block to user's page
+ # The block is added on top of the page
+ # params[:block] : id of the block to add
+ def add_block
+ @user = self.logged_in_user
+ block = params[:block]
+ # remove if already present in a group
+ %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block }
+ # add it on top
+ session[:page_layout]['top'].unshift block
+ render :partial => "block", :locals => {:user => @user, :block_name => block}
+ end
+
+ # Remove a block to user's page
+ # params[:block] : id of the block to remove
+ def remove_block
+ block = params[:block]
+ # remove block in all groups
+ %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block }
+ render :nothing => true
+ end
+
+ # Change blocks order on user's page
+ # params[:group] : group to order (top, left or right)
+ # params[:list-(top|left|right)] : array of block ids of the group
+ def order_blocks
+ group = params[:group]
+ group_items = params["list-#{group}"]
+ if group_items and group_items.is_a? Array
+ # remove group blocks if they are presents in other groups
+ %w(top left right).each {|f|
+ session[:page_layout][f] = (session[:page_layout][f] || []) - group_items
+ }
+ session[:page_layout][group] = group_items
+ end
+ render :nothing => true
+ end
+
+ # Save user's page layout
+ def page_layout_save
+ @user = self.logged_in_user
+ @user.pref[:my_page_layout] = session[:page_layout] if session[:page_layout]
+ @user.pref.save
+ session[:page_layout] = nil
+ redirect_to :action => 'page'
+ end
+end
--- /dev/null
+# redMine - project management software
+# Copyright (C) 2006 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module MyHelper
+end
\r
class User < ActiveRecord::Base\r
has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => true\r
+ has_many :projects, :through => :memberships\r
has_many :custom_values, :dependent => true, :as => :customized\r
+ has_one :preference, :dependent => true, :class_name => 'UserPreference'\r
belongs_to :auth_source\r
\r
attr_accessor :password, :password_confirmation\r
end\r
@role_for_projects[project_id]\r
end\r
+ \r
+ def pref\r
+ self.preference ||= UserPreference.new(:user => self)\r
+ end\r
\r
private\r
# Return password digest\r
--- /dev/null
+# redMine - project management software
+# Copyright (C) 2006 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class UserPreference < ActiveRecord::Base
+ belongs_to :user
+ serialize :others, Hash
+
+ attr_protected :others
+
+ def initialize(attributes = nil)
+ super
+ self.others ||= {}
+ end
+
+ def [](attr_name)
+ if attribute_present? attr_name
+ super
+ else
+ others[attr_name]
+ end
+ end
+
+ def []=(attr_name, value)
+ if attribute_present? attr_name
+ super
+ else
+ others.store attr_name, value
+ end
+ end
+end
+++ /dev/null
-<h2><%=l(:label_my_account)%></h2>
-\r
-<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />\r
-<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>,\r
-<%=l(:field_updated_on)%>: <%= format_time(@user.updated_on) %></p>\r
-
-<%= error_messages_for 'user' %>
-\r
- <div class="box">\r
- <h3><%=l(:label_information_plural)%></h3>\r
-
- <%= start_form_tag({:action => 'my_account'}, :class => "tabular") %>
-\r
- <!--[form:user]-->
- <p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label>
- <%= text_field 'user', 'firstname' %></p>
-\r
- <p><label for="user_lastname"><%=l(:field_lastname)%> <span class="required">*</span></label>
- <%= text_field 'user', 'lastname' %></p>
-
- <p><label for="user_mail"><%=l(:field_mail)%> <span class="required">*</span></label>
- <%= text_field 'user', 'mail', :size => 40 %></p>\r
- \r
- <p><label for="user_language"><%=l(:field_language)%></label>
- <%= select("user", "language", lang_options_for_select) %></p>
- <!--[eoform:user]-->\r
-\r
- <p><label for="user_mail_notification"><%=l(:field_mail_notification)%></label>
- <%= check_box 'user', 'mail_notification' %></p>\r
-
- <center><%= submit_tag l(:button_save) %></center>
- <%= end_form_tag %>\r
- </div>\r
-\r
-
-<% unless @user.auth_source_id %>\r
- <div class="box">\r
- <h3><%=l(:field_password)%></h3>\r
-
- <%= start_form_tag({:action => 'change_password'}, :class => "tabular") %>
-\r
- <p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label>
- <%= password_field_tag 'password', nil, :size => 25 %></p>
-\r
- <p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label>
- <%= password_field_tag 'new_password', nil, :size => 25 %></p>\r
-\r
- <p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label>
- <%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>\r
-
- <center><%= submit_tag l(:button_save) %></center>
- <%= end_form_tag %>\r
- </div>
-<% end %>\r
+++ /dev/null
-<h2><%=l(:label_my_page)%></h2>\r
-\r
-<p>\r
-<% unless @user.last_before_login_on.nil? %>\r
- <%=l(:label_last_login)%>: <%= format_time(@user.last_before_login_on) %>\r
-<% end %>\r
-</p>\r
-\r
-<div class="splitcontentleft">\r
- <h3><%=l(:label_reported_issues)%></h3>\r
- <%= render :partial => 'issues/list_simple', :locals => { :issues => @reported_issues } %>\r
- <% if @reported_issues.length > 0 %>\r
- <p><%=lwr(:label_last_updates, @reported_issues.length)%></p>\r
- <% end %>\r
-</div>\r
-<div class="splitcontentright">\r
-<h3><%=l(:label_assigned_to_me_issues)%></h3> \r
- <%= render :partial => 'issues/list_simple', :locals => { :issues => @assigned_issues } %>\r
- <% if @assigned_issues.length > 0 %>\r
- <p><%=lwr(:label_last_updates, @assigned_issues.length)%></p>\r
- <% end %>\r
-</div>
\ No newline at end of file
<div id="navigation">\r
<ul>\r
<li class="selected"><%= link_to l(:label_home), { :controller => '' }, :class => "picHome" %></li>\r
- <li><%= link_to l(:label_my_page), { :controller => 'account', :action => 'my_page'}, :class => "picUserPage" %></li>\r
+ <li><%= link_to l(:label_my_page), { :controller => 'my', :action => 'page'}, :class => "picUserPage" %></li>\r
<li><%= link_to l(:label_project_plural), { :controller => 'projects' }, :class => "picProject" %></li>\r
\r
<% unless @project.nil? || @project.id.nil? %>\r
<% end %>\r
\r
<% if loggedin? %>\r
- <li><%= link_to l(:label_my_account), { :controller => 'account', :action => 'my_account' }, :class => "picUser" %></li>\r
+ <li><%= link_to l(:label_my_account), { :controller => 'my', :action => 'account' }, :class => "picUser" %></li>\r
<% end %>\r
\r
<% if admin_loggedin? %>\r
--- /dev/null
+<div id="block_<%= block_name %>" class="mypage-box">\r
+\r
+ <div style="float:right;margin-right:16px;z-index:500;">\r
+ <%= link_to_remote "", {\r
+ :url => { :action => "remove_block", :block => block_name },\r
+ :complete => "removeBlock('block_#{block_name}')",\r
+ :loading => "Element.show('indicator')",\r
+ :loaded => "Element.hide('indicator')" },\r
+ :class => "close-icon"\r
+ %> \r
+ </div>\r
+ \r
+ <div class="handle">\r
+ <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %>\r
+ </div>\r
+</div>
\ No newline at end of file
--- /dev/null
+<h2><%=l(:label_my_account)%></h2>
+\r
+<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />\r
+<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>,\r
+<%=l(:field_updated_on)%>: <%= format_time(@user.updated_on) %></p>\r
+
+<%= error_messages_for 'user' %>
+\r
+ <div class="box">\r
+ <h3><%=l(:label_information_plural)%></h3>\r
+
+ <%= start_form_tag({:action => 'account'}, :class => "tabular") %>
+\r
+ <!--[form:user]-->
+ <p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label>
+ <%= text_field 'user', 'firstname' %></p>
+\r
+ <p><label for="user_lastname"><%=l(:field_lastname)%> <span class="required">*</span></label>
+ <%= text_field 'user', 'lastname' %></p>
+
+ <p><label for="user_mail"><%=l(:field_mail)%> <span class="required">*</span></label>
+ <%= text_field 'user', 'mail', :size => 40 %></p>\r
+ \r
+ <p><label for="user_language"><%=l(:field_language)%></label>
+ <%= select("user", "language", lang_options_for_select) %></p>
+ <!--[eoform:user]-->\r
+\r
+ <p><label for="user_mail_notification"><%=l(:field_mail_notification)%></label>
+ <%= check_box 'user', 'mail_notification' %></p>\r
+
+ <center><%= submit_tag l(:button_save) %></center>
+ <%= end_form_tag %>\r
+ </div>\r
+\r
+
+<% unless @user.auth_source_id %>\r
+ <div class="box">\r
+ <h3><%=l(:field_password)%></h3>\r
+
+ <%= start_form_tag({:action => 'change_password'}, :class => "tabular") %>
+\r
+ <p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label>
+ <%= password_field_tag 'password', nil, :size => 25 %></p>
+\r
+ <p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label>
+ <%= password_field_tag 'new_password', nil, :size => 25 %></p>\r
+\r
+ <p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label>
+ <%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>\r
+
+ <center><%= submit_tag l(:button_save) %></center>
+ <%= end_form_tag %>\r
+ </div>
+<% end %>\r
--- /dev/null
+<h3><%= l(:label_calendar) %></h3>\r
+\r
+<%\r
+@date_from = Date.today - (Date.today.cwday-1)\r
+@date_to = Date.today + (7-Date.today.cwday)\r
+@issues = Issue.find :all,\r
+ :conditions => ["issues.project_id in (#{@user.projects.collect{|m| m.id}.join(',')}) AND ((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?))", @date_from, @date_to, @date_from, @date_to],\r
+ :include => [:project, :tracker] unless @user.projects.empty?\r
+@issues ||= []\r
+%>\r
+\r
+<table class="calenderTable">\r
+<tr class="ListHead">\r
+<td></td>\r
+<% 1.upto(7) do |d| %>\r
+ <td align="center" width="14%"><%= day_name(d) %></td>\r
+<% end %>\r
+</tr>\r
+<tr height="100">\r
+<% day = @date_from\r
+while day <= @date_to\r
+ if day.cwday == 1 %>\r
+ <td valign="middle"><%= day.cweek %></td>\r
+ <% end %> \r
+ <td valign="top" width="14%" class="<%= day.month==@month ? "even" : "odd" %>">\r
+ <p align="right"><%= day==Date.today ? "<b>#{day.day}</b>" : day.day %></p> \r
+ <% day_issues = []\r
+ @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day } \r
+ day_issues.each do |i| %> \r
+ <%= if day == i.start_date and day == i.due_date\r
+ image_tag('arrow_bw')\r
+ elsif day == i.start_date\r
+ image_tag('arrow_from') \r
+ elsif day == i.due_date\r
+ image_tag('arrow_to') \r
+ end %>\r
+ <small><%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %></small><br />\r
+ <% end %>\r
+ </td>\r
+ <%= '</tr><tr height="100">' if day.cwday >= 7 and day!=@date_to %>\r
+ <%\r
+ day = day + 1\r
+end %>\r
+</tr>\r
+</table>
\ No newline at end of file
--- /dev/null
+<h3><%=l(:label_document_plural)%></h3>\r
+\r
+<ul>\r
+<% for document in Document.find :all,\r
+ :limit => 10,\r
+ :conditions => "documents.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})",\r
+ :include => [:project] %>\r
+ <li>\r
+ <b><%= link_to document.title, :controller => 'documents', :action => 'show', :id => document %></b>\r
+ <br />\r
+ <%= truncate document.description, 150 %><br />\r
+ <em><%= format_time(document.created_on) %></em><br /> \r
+ </li>\r
+<% end unless @user.projects.empty? %>\r
+</ul>
\ No newline at end of file
--- /dev/null
+<h3><%=l(:label_assigned_to_me_issues)%></h3>\r
+<% assigned_issues = Issue.find(:all, \r
+ :conditions => ["assigned_to_id=?", user.id],\r
+ :limit => 10, \r
+ :include => [ :status, :project, :tracker ], \r
+ :order => 'issues.updated_on DESC') %>\r
+<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %>\r
+<% if assigned_issues.length > 0 %>\r
+<p><%=lwr(:label_last_updates, assigned_issues.length)%></p>\r
+<% end %>\r
--- /dev/null
+<h3><%=l(:label_reported_issues)%></h3>\r
+<% reported_issues = Issue.find(:all, \r
+ :conditions => ["author_id=?", user.id],\r
+ :limit => 10, \r
+ :include => [ :status, :project, :tracker ], \r
+ :order => 'issues.updated_on DESC') %>\r
+<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %>\r
+<% if reported_issues.length > 0 %>\r
+<p><%=lwr(:label_last_updates, reported_issues.length)%></p>\r
+<% end %>
\ No newline at end of file
--- /dev/null
+<h3><%=l(:label_news_latest)%></h3>\r
+\r
+<ul>\r
+<% for news in News.find :all,\r
+ :limit => 10,\r
+ :conditions => "news.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})",\r
+ :include => [:project, :author] %>\r
+ <li><%= link_to news.title, :controller => 'news', :action => 'show', :id => news %><br />\r
+ <% unless news.summary.empty? %><%= news.summary %><br /><% end %>\r
+ <em><%= news.author.name %>, <%= format_time(news.created_on) %></em><br /> \r
+ </li>\r
+<% end unless @user.projects.empty? %>\r
+</ul>
\ No newline at end of file
--- /dev/null
+<h2><%=l(:label_my_page)%></h2>\r
+\r
+<div class="topright">\r
+ <small><%= link_to l(:label_personalize_page), :action => 'page_layout' %></small>\r
+</div>\r
+\r
+<div id="list-top">\r
+ <% @blocks['top'].each do |b| %>\r
+ <div class="mypage-box"> \r
+ <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %>\r
+ </div>\r
+ <% end if @blocks['top'] %>\r
+</div>\r
+\r
+<div id="list-left" class="splitcontentleft">\r
+ <% @blocks['left'].each do |b| %>\r
+ <div class="mypage-box"> \r
+ <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %>\r
+ </div>\r
+ <% end if @blocks['left'] %>\r
+</div>\r
+\r
+<div id="list-right" class="splitcontentright">\r
+ <% @blocks['right'].each do |b| %>\r
+ <div class="mypage-box"> \r
+ <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %>\r
+ </div>\r
+ <% end if @blocks['right'] %>\r
+</div>\r
+\r
--- /dev/null
+<script language="JavaScript">\r
+\r
+function recreateSortables() {\r
+ Sortable.destroy('list-top');\r
+ Sortable.destroy('list-left');\r
+ Sortable.destroy('list-right');\r
+ \r
+ Sortable.create("list-top", {constraint:false, containment:['list-top','list-left','list-right'], dropOnEmpty:true, handle:'handle', onUpdate:function(){new Ajax.Request('/my/order_blocks?group=top', {asynchronous:true, evalScripts:true, onComplete:function(request){new Effect.Highlight("list-top",{});}, onLoaded:function(request){Element.hide('indicator')}, onLoading:function(request){Element.show('indicator')}, parameters:Sortable.serialize("list-top")})}, only:'mypage-box', tag:'div'})\r
+ Sortable.create("list-left", {constraint:false, containment:['list-top','list-left','list-right'], dropOnEmpty:true, handle:'handle', onUpdate:function(){new Ajax.Request('/my/order_blocks?group=left', {asynchronous:true, evalScripts:true, onComplete:function(request){new Effect.Highlight("list-left",{});}, onLoaded:function(request){Element.hide('indicator')}, onLoading:function(request){Element.show('indicator')}, parameters:Sortable.serialize("list-left")})}, only:'mypage-box', tag:'div'})\r
+ Sortable.create("list-right", {constraint:false, containment:['list-top','list-left','list-right'], dropOnEmpty:true, handle:'handle', onUpdate:function(){new Ajax.Request('/my/order_blocks?group=right', {asynchronous:true, evalScripts:true, onComplete:function(request){new Effect.Highlight("list-right",{});}, onLoaded:function(request){Element.hide('indicator')}, onLoading:function(request){Element.show('indicator')}, parameters:Sortable.serialize("list-right")})}, only:'mypage-box', tag:'div'})\r
+}\r
+\r
+function updateSelect() {\r
+ s = $('block-select')\r
+ for (var i = 0; i < s.options.length; i++) {\r
+ if ($('block_' + s.options[i].value)) {\r
+ s.options[i].disabled = true;\r
+ } else {\r
+ s.options[i].disabled = false;\r
+ }\r
+ }\r
+ s.options[0].selected = true;\r
+}\r
+\r
+function afterAddBlock() {\r
+ recreateSortables();\r
+ updateSelect();\r
+}\r
+\r
+function removeBlock(block) {\r
+ $(block).parentNode.removeChild($(block));\r
+ updateSelect();\r
+}\r
+\r
+</script>\r
+\r
+<div style="float:right;">\r
+<%= start_form_tag({:action => "add_block"}, :id => "block-form") %>\r
+\r
+<%= select_tag 'block', "<option></option>" + options_for_select(@block_options), :id => "block-select", :class => "select-small" %>\r
+<small>\r
+<%= link_to_remote l(:button_add),\r
+ :url => { :action => "add_block" },\r
+ :with => "Form.serialize('block-form')",\r
+ :update => "list-top",\r
+ :position => :top,\r
+ :complete => "afterAddBlock();",\r
+ :loading => "Element.show('indicator')",\r
+ :loaded => "Element.hide('indicator')"\r
+ %>\r
+</small>\r
+<%= end_form_tag %> \r
+<small>|\r
+<%= link_to l(:button_save), :action => 'page_layout_save' %> |\r
+<%= link_to l(:button_cancel), :action => 'page' %>\r
+</small>\r
+</div>\r
+\r
+<div style="float:right;margin-right:20px;">\r
+<span id="indicator" style="display:none"><%= image_tag "loading.gif" %></span>\r
+</div>\r
+\r
+<h2><%=l(:label_my_page)%></h2>\r
+\r
+<div id="list-top" class="block-receiver">\r
+ <% @blocks['top'].each do |b| %>\r
+ <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %>\r
+ <% end if @blocks['top'] %>\r
+</div>\r
+\r
+<div id="list-left" class="splitcontentleft block-receiver">\r
+ <% @blocks['left'].each do |b| %>\r
+ <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %>\r
+ <% end if @blocks['left'] %>\r
+</div>\r
+\r
+<div id="list-right" class="splitcontentright block-receiver">\r
+ <% @blocks['right'].each do |b| %>\r
+ <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %>\r
+ <% end if @blocks['right'] %>\r
+</div>\r
+\r
+<%= sortable_element 'list-top',\r
+ :tag => 'div',\r
+ :only => 'mypage-box',\r
+ :handle => "handle",\r
+ :dropOnEmpty => true,\r
+ :containment => ['list-top', 'list-left', 'list-right'],\r
+ :constraint => false,\r
+ :complete => visual_effect(:highlight, 'list-top'), \r
+ :url => { :action => "order_blocks", :group => "top" },\r
+ :loading => "Element.show('indicator')",\r
+ :loaded => "Element.hide('indicator')"\r
+ %>\r
+ \r
+ \r
+<%= sortable_element 'list-left', \r
+ :tag => 'div',\r
+ :only => 'mypage-box',\r
+ :handle => "handle",\r
+ :dropOnEmpty => true,\r
+ :containment => ['list-top', 'list-left', 'list-right'],\r
+ :constraint => false,\r
+ :complete => visual_effect(:highlight, 'list-left'), \r
+ :url => { :action => "order_blocks", :group => "left" },\r
+ :loading => "Element.show('indicator')",\r
+ :loaded => "Element.hide('indicator')" %>\r
+ \r
+<%= sortable_element 'list-right', \r
+ :tag => 'div',\r
+ :only => 'mypage-box',\r
+ :handle => "handle",\r
+ :dropOnEmpty => true,\r
+ :containment => ['list-top', 'list-left', 'list-right'],\r
+ :constraint => false,\r
+ :complete => visual_effect(:highlight, 'list-right'), \r
+ :url => { :action => "order_blocks", :group => "right" },\r
+ :loading => "Element.show('indicator')",\r
+ :loaded => "Element.hide('indicator')" %>\r
+ \r
+<%= javascript_tag "updateSelect()" %>
\ No newline at end of file
--- /dev/null
+class CreateUserPreferences < ActiveRecord::Migration
+ def self.up
+ create_table :user_preferences do |t|
+ t.column "user_id", :integer, :default => 0, :null => false
+ t.column "others", :text
+ end
+ end
+
+ def self.down
+ drop_table :user_preferences
+ end
+end
\r
== xx/xx/2006 v0.x.x\r
\r
+* "my page" is now customizable \r
* improved issues change history\r
* new functionality: move an issue to another project or tracker\r
* new functionality: add a note to an issue\r
label_internal: Intern\r
label_last_changes: %d änderungen des Letzten\r
label_change_view_all: Alle änderungen ansehen\r
+label_personalize_page: Diese Seite personifizieren\r
\r
button_login: Einloggen\r
button_submit: Einreichen\r
button_view: Siehe\r
button_move: Bewegen\r
button_back: Rückkehr\r
+button_cancel: Annullieren\r
\r
text_select_mail_notifications: Aktionen für die Mailbenachrichtigung aktiviert werden soll.\r
text_regexp_info: eg. ^[A-Z0-9]+$\r
label_internal: Internal\r
label_last_changes: last %d changes\r
label_change_view_all: View all changes\r
+label_personalize_page: Personalize this page\r
\r
button_login: Login\r
button_submit: Submit\r
button_view: View\r
button_move: Move\r
button_back: Back\r
+button_cancel: Cancel\r
\r
text_select_mail_notifications: Select actions for which mail notifications should be sent.\r
text_regexp_info: eg. ^[A-Z0-9]+$\r
label_internal: Interno\r
label_last_changes: %d cambios del último\r
label_change_view_all: Ver todos los cambios\r
+label_personalize_page: Personalizar esta página\r
\r
button_login: Conexión\r
button_submit: Someter\r
button_view: Ver\r
button_move: Mover\r
button_back: Atrás\r
+button_cancel: Cancelar\r
\r
text_select_mail_notifications: Seleccionar las actividades que necesitan la activación de la notificación por mail.\r
text_regexp_info: eg. ^[A-Z0-9]+$\r
label_internal: Interne\r
label_last_changes: %d derniers changements\r
label_change_view_all: Voir tous les changements\r
+label_personalize_page: Personnaliser cette page\r
\r
button_login: Connexion\r
button_submit: Soumettre\r
-button_save: Valider\r
+button_save: Sauvegarder\r
button_check_all: Tout cocher\r
button_uncheck_all: Tout décocher\r
button_delete: Supprimer\r
button_view: Voir\r
button_move: Déplacer\r
button_back: Retour\r
+button_cancel: Annuler\r
\r
text_select_mail_notifications: Sélectionner les actions pour lesquelles la notification par mail doit être activée.\r
text_regexp_info: ex. ^[A-Z0-9]+$\r
line-height:1.5em;\r
}\r
\r
+a.close-icon {\r
+display:block;\r
+margin-top:3px;\r
+overflow:hidden;\r
+width:12px;\r
+height:12px;\r
+background-repeat: no-repeat;\r
+cursor:hand;\r
+cursor:pointer;\r
+background-image:url('../images/close.png');\r
+}\r
+\r
+a.close-icon:hover {\r
+background-image:url('../images/close_hl.png');\r
+}\r
+\r
.rightbox{\r
background: #fafbfc;\r
border: 1px solid #c0c0c0;\r
margin: 0 5px 5px;\r
}\r
\r
+.layout-active {\r
+background: #ECF3E1;\r
+}\r
+\r
+.block-receiver {\r
+border:1px dashed #c0c0c0;\r
+margin-bottom: 20px;\r
+padding: 15px 0 15px 0;\r
+}\r
+\r
+.mypage-box {\r
+margin:0 0 20px 0;\r
+color:#505050;\r
+line-height:1.5em;\r
+}\r
+\r
+.blocks {\r
+cursor: move;\r
+}\r
+\r
.topright{\r
position: absolute;\r
right: 25px;\r
--- /dev/null
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+first:
+ id: 1
+another:
+ id: 2
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+require 'my_controller'
+
+# Re-raise errors caught by the controller.
+class MyController; def rescue_action(e) raise e end; end
+
+class MyControllerTest < Test::Unit::TestCase
+ def setup
+ @controller = MyController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ end
+
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
# Replace this with your real tests.
def test_login
- get "account/my_page"
+ get "my/page"
assert_redirected_to "account/login"
log_user('jsmith', 'jsmith')
- get "account/my_account"
+ get "my/account"
assert_response :success
- assert_template "account/my_account"
+ assert_template "my/account"
end
def test_change_password
log_user('jsmith', 'jsmith')
- get "account/my_account"
+ get "my/account"
assert_response :success
- assert_template "account/my_account"
+ assert_template "my/account"
- post "account/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello2"
+ post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello2"
assert_response :success
- assert_template "account/my_account"
+ assert_template "my/account"
assert_tag :tag => "div", :attributes => { :class => "errorExplanation" }
- post "account/change_password", :password => 'jsmithZZ', :new_password => "hello", :new_password_confirmation => "hello"
- assert_redirected_to "account/my_account"
+ post "my/change_password", :password => 'jsmithZZ', :new_password => "hello", :new_password_confirmation => "hello"
+ assert_redirected_to "my/account"
assert_equal 'Wrong password', flash[:notice]
- post "account/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello"
- assert_redirected_to "account/my_account"
+ post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello"
+ assert_redirected_to "my/account"
log_user('jsmith', 'hello')
end
def test_my_account
log_user('jsmith', 'jsmith')
- get "account/my_account"
+ get "my/account"
assert_response :success
- assert_template "account/my_account"
+ assert_template "my/account"
- post "account/my_account", :user => {:firstname => "Joe", :login => "root", :admin => 1}
+ post "my/account", :user => {:firstname => "Joe", :login => "root", :admin => 1}
assert_response :success
- assert_template "account/my_account"
+ assert_template "my/account"
user = User.find(2)
assert_equal "Joe", user.firstname
assert_equal "jsmith", user.login
def test_my_page
log_user('jsmith', 'jsmith')
- get "account/my_page"
+ get "my/page"
assert_response :success
- assert_template "account/my_page"
+ assert_template "my/page"
end
def test_lost_password
assert_response :success
assert_template "account/login"
post "/account/login", :login => login, :password => password
- assert_redirected_to "account/my_page"
+ assert_redirected_to "my/page"
assert_equal login, User.find(session[:user_id]).login
end
end
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+
+class UserPreferenceTest < Test::Unit::TestCase
+ fixtures :user_preferences
+
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end