@@ -0,0 +1,128 | |||
|
1 | # redMine - project management software | |
|
2 | # Copyright (C) 2006 Jean-Philippe Lang | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or | |
|
5 | # modify it under the terms of the GNU General Public License | |
|
6 | # as published by the Free Software Foundation; either version 2 | |
|
7 | # of the License, or (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software | |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
|
17 | ||
|
18 | class MyController < ApplicationController | |
|
19 | layout 'base' | |
|
20 | before_filter :require_login | |
|
21 | ||
|
22 | BLOCKS = { 'issues_assigned_to_me' => :label_assigned_to_me_issues, | |
|
23 | 'issues_reported_by_me' => :label_reported_issues, | |
|
24 | 'latest_news' => :label_news_latest, | |
|
25 | 'calendar' => :label_calendar, | |
|
26 | 'documents' => :label_document_plural | |
|
27 | }.freeze | |
|
28 | ||
|
29 | verify :xhr => true, | |
|
30 | :session => :page_layout, | |
|
31 | :only => [:add_block, :remove_block, :order_blocks] | |
|
32 | ||
|
33 | def index | |
|
34 | page | |
|
35 | render :action => 'page' | |
|
36 | end | |
|
37 | ||
|
38 | # Show user's page | |
|
39 | def page | |
|
40 | @user = self.logged_in_user | |
|
41 | @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] } | |
|
42 | end | |
|
43 | ||
|
44 | # Edit user's account | |
|
45 | def account | |
|
46 | @user = self.logged_in_user | |
|
47 | if request.post? and @user.update_attributes(@params[:user]) | |
|
48 | set_localization | |
|
49 | flash.now[:notice] = l(:notice_account_updated) | |
|
50 | self.logged_in_user.reload | |
|
51 | end | |
|
52 | end | |
|
53 | ||
|
54 | # Change user's password | |
|
55 | def change_password | |
|
56 | @user = self.logged_in_user | |
|
57 | flash[:notice] = l(:notice_can_t_change_password) and redirect_to :action => 'account' and return if @user.auth_source_id | |
|
58 | if @user.check_password?(@params[:password]) | |
|
59 | @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] | |
|
60 | if @user.save | |
|
61 | flash[:notice] = l(:notice_account_password_updated) | |
|
62 | else | |
|
63 | render :action => 'account' | |
|
64 | return | |
|
65 | end | |
|
66 | else | |
|
67 | flash[:notice] = l(:notice_account_wrong_password) | |
|
68 | end | |
|
69 | redirect_to :action => 'account' | |
|
70 | end | |
|
71 | ||
|
72 | # User's page layout configuration | |
|
73 | def page_layout | |
|
74 | @user = self.logged_in_user | |
|
75 | @blocks = @user.pref[:my_page_layout] || { 'left' => ['issues_assigned_to_me'], 'right' => ['issues_reported_by_me'] } | |
|
76 | session[:page_layout] = @blocks | |
|
77 | %w(top left right).each {|f| session[:page_layout][f] ||= [] } | |
|
78 | @block_options = [] | |
|
79 | BLOCKS.each {|k, v| @block_options << [l(v), k]} | |
|
80 | end | |
|
81 | ||
|
82 | # Add a block to user's page | |
|
83 | # The block is added on top of the page | |
|
84 | # params[:block] : id of the block to add | |
|
85 | def add_block | |
|
86 | @user = self.logged_in_user | |
|
87 | block = params[:block] | |
|
88 | # remove if already present in a group | |
|
89 | %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } | |
|
90 | # add it on top | |
|
91 | session[:page_layout]['top'].unshift block | |
|
92 | render :partial => "block", :locals => {:user => @user, :block_name => block} | |
|
93 | end | |
|
94 | ||
|
95 | # Remove a block to user's page | |
|
96 | # params[:block] : id of the block to remove | |
|
97 | def remove_block | |
|
98 | block = params[:block] | |
|
99 | # remove block in all groups | |
|
100 | %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } | |
|
101 | render :nothing => true | |
|
102 | end | |
|
103 | ||
|
104 | # Change blocks order on user's page | |
|
105 | # params[:group] : group to order (top, left or right) | |
|
106 | # params[:list-(top|left|right)] : array of block ids of the group | |
|
107 | def order_blocks | |
|
108 | group = params[:group] | |
|
109 | group_items = params["list-#{group}"] | |
|
110 | if group_items and group_items.is_a? Array | |
|
111 | # remove group blocks if they are presents in other groups | |
|
112 | %w(top left right).each {|f| | |
|
113 | session[:page_layout][f] = (session[:page_layout][f] || []) - group_items | |
|
114 | } | |
|
115 | session[:page_layout][group] = group_items | |
|
116 | end | |
|
117 | render :nothing => true | |
|
118 | end | |
|
119 | ||
|
120 | # Save user's page layout | |
|
121 | def page_layout_save | |
|
122 | @user = self.logged_in_user | |
|
123 | @user.pref[:my_page_layout] = session[:page_layout] if session[:page_layout] | |
|
124 | @user.pref.save | |
|
125 | session[:page_layout] = nil | |
|
126 | redirect_to :action => 'page' | |
|
127 | end | |
|
128 | end |
@@ -0,0 +1,19 | |||
|
1 | # redMine - project management software | |
|
2 | # Copyright (C) 2006 Jean-Philippe Lang | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or | |
|
5 | # modify it under the terms of the GNU General Public License | |
|
6 | # as published by the Free Software Foundation; either version 2 | |
|
7 | # of the License, or (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software | |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
|
17 | ||
|
18 | module MyHelper | |
|
19 | end |
@@ -0,0 +1,44 | |||
|
1 | # redMine - project management software | |
|
2 | # Copyright (C) 2006 Jean-Philippe Lang | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or | |
|
5 | # modify it under the terms of the GNU General Public License | |
|
6 | # as published by the Free Software Foundation; either version 2 | |
|
7 | # of the License, or (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software | |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
|
17 | ||
|
18 | class UserPreference < ActiveRecord::Base | |
|
19 | belongs_to :user | |
|
20 | serialize :others, Hash | |
|
21 | ||
|
22 | attr_protected :others | |
|
23 | ||
|
24 | def initialize(attributes = nil) | |
|
25 | super | |
|
26 | self.others ||= {} | |
|
27 | end | |
|
28 | ||
|
29 | def [](attr_name) | |
|
30 | if attribute_present? attr_name | |
|
31 | super | |
|
32 | else | |
|
33 | others[attr_name] | |
|
34 | end | |
|
35 | end | |
|
36 | ||
|
37 | def []=(attr_name, value) | |
|
38 | if attribute_present? attr_name | |
|
39 | super | |
|
40 | else | |
|
41 | others.store attr_name, value | |
|
42 | end | |
|
43 | end | |
|
44 | end |
@@ -0,0 +1,16 | |||
|
1 | <div id="block_<%= block_name %>" class="mypage-box"> | |
|
2 | ||
|
3 | <div style="float:right;margin-right:16px;z-index:500;"> | |
|
4 | <%= link_to_remote "", { | |
|
5 | :url => { :action => "remove_block", :block => block_name }, | |
|
6 | :complete => "removeBlock('block_#{block_name}')", | |
|
7 | :loading => "Element.show('indicator')", | |
|
8 | :loaded => "Element.hide('indicator')" }, | |
|
9 | :class => "close-icon" | |
|
10 | %> | |
|
11 | </div> | |
|
12 | ||
|
13 | <div class="handle"> | |
|
14 | <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %> | |
|
15 | </div> | |
|
16 | </div> No newline at end of file |
@@ -0,0 +1,45 | |||
|
1 | <h3><%= l(:label_calendar) %></h3> | |
|
2 | ||
|
3 | <% | |
|
4 | @date_from = Date.today - (Date.today.cwday-1) | |
|
5 | @date_to = Date.today + (7-Date.today.cwday) | |
|
6 | @issues = Issue.find :all, | |
|
7 | :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], | |
|
8 | :include => [:project, :tracker] unless @user.projects.empty? | |
|
9 | @issues ||= [] | |
|
10 | %> | |
|
11 | ||
|
12 | <table class="calenderTable"> | |
|
13 | <tr class="ListHead"> | |
|
14 | <td></td> | |
|
15 | <% 1.upto(7) do |d| %> | |
|
16 | <td align="center" width="14%"><%= day_name(d) %></td> | |
|
17 | <% end %> | |
|
18 | </tr> | |
|
19 | <tr height="100"> | |
|
20 | <% day = @date_from | |
|
21 | while day <= @date_to | |
|
22 | if day.cwday == 1 %> | |
|
23 | <td valign="middle"><%= day.cweek %></td> | |
|
24 | <% end %> | |
|
25 | <td valign="top" width="14%" class="<%= day.month==@month ? "even" : "odd" %>"> | |
|
26 | <p align="right"><%= day==Date.today ? "<b>#{day.day}</b>" : day.day %></p> | |
|
27 | <% day_issues = [] | |
|
28 | @issues.each { |i| day_issues << i if i.start_date == day or i.due_date == day } | |
|
29 | day_issues.each do |i| %> | |
|
30 | <%= if day == i.start_date and day == i.due_date | |
|
31 | image_tag('arrow_bw') | |
|
32 | elsif day == i.start_date | |
|
33 | image_tag('arrow_from') | |
|
34 | elsif day == i.due_date | |
|
35 | image_tag('arrow_to') | |
|
36 | end %> | |
|
37 | <small><%= link_to "#{i.tracker.name} ##{i.id}", :controller => 'issues', :action => 'show', :id => i %>: <%= i.subject.sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)') %></small><br /> | |
|
38 | <% end %> | |
|
39 | </td> | |
|
40 | <%= '</tr><tr height="100">' if day.cwday >= 7 and day!=@date_to %> | |
|
41 | <% | |
|
42 | day = day + 1 | |
|
43 | end %> | |
|
44 | </tr> | |
|
45 | </table> No newline at end of file |
@@ -0,0 +1,15 | |||
|
1 | <h3><%=l(:label_document_plural)%></h3> | |
|
2 | ||
|
3 | <ul> | |
|
4 | <% for document in Document.find :all, | |
|
5 | :limit => 10, | |
|
6 | :conditions => "documents.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", | |
|
7 | :include => [:project] %> | |
|
8 | <li> | |
|
9 | <b><%= link_to document.title, :controller => 'documents', :action => 'show', :id => document %></b> | |
|
10 | <br /> | |
|
11 | <%= truncate document.description, 150 %><br /> | |
|
12 | <em><%= format_time(document.created_on) %></em><br /> | |
|
13 | </li> | |
|
14 | <% end unless @user.projects.empty? %> | |
|
15 | </ul> No newline at end of file |
@@ -0,0 +1,10 | |||
|
1 | <h3><%=l(:label_assigned_to_me_issues)%></h3> | |
|
2 | <% assigned_issues = Issue.find(:all, | |
|
3 | :conditions => ["assigned_to_id=?", user.id], | |
|
4 | :limit => 10, | |
|
5 | :include => [ :status, :project, :tracker ], | |
|
6 | :order => 'issues.updated_on DESC') %> | |
|
7 | <%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> | |
|
8 | <% if assigned_issues.length > 0 %> | |
|
9 | <p><%=lwr(:label_last_updates, assigned_issues.length)%></p> | |
|
10 | <% end %> |
@@ -0,0 +1,10 | |||
|
1 | <h3><%=l(:label_reported_issues)%></h3> | |
|
2 | <% reported_issues = Issue.find(:all, | |
|
3 | :conditions => ["author_id=?", user.id], | |
|
4 | :limit => 10, | |
|
5 | :include => [ :status, :project, :tracker ], | |
|
6 | :order => 'issues.updated_on DESC') %> | |
|
7 | <%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> | |
|
8 | <% if reported_issues.length > 0 %> | |
|
9 | <p><%=lwr(:label_last_updates, reported_issues.length)%></p> | |
|
10 | <% end %> No newline at end of file |
@@ -0,0 +1,13 | |||
|
1 | <h3><%=l(:label_news_latest)%></h3> | |
|
2 | ||
|
3 | <ul> | |
|
4 | <% for news in News.find :all, | |
|
5 | :limit => 10, | |
|
6 | :conditions => "news.project_id in (#{@user.projects.collect{|m| m.id}.join(',')})", | |
|
7 | :include => [:project, :author] %> | |
|
8 | <li><%= link_to news.title, :controller => 'news', :action => 'show', :id => news %><br /> | |
|
9 | <% unless news.summary.empty? %><%= news.summary %><br /><% end %> | |
|
10 | <em><%= news.author.name %>, <%= format_time(news.created_on) %></em><br /> | |
|
11 | </li> | |
|
12 | <% end unless @user.projects.empty? %> | |
|
13 | </ul> No newline at end of file |
@@ -0,0 +1,30 | |||
|
1 | <h2><%=l(:label_my_page)%></h2> | |
|
2 | ||
|
3 | <div class="topright"> | |
|
4 | <small><%= link_to l(:label_personalize_page), :action => 'page_layout' %></small> | |
|
5 | </div> | |
|
6 | ||
|
7 | <div id="list-top"> | |
|
8 | <% @blocks['top'].each do |b| %> | |
|
9 | <div class="mypage-box"> | |
|
10 | <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> | |
|
11 | </div> | |
|
12 | <% end if @blocks['top'] %> | |
|
13 | </div> | |
|
14 | ||
|
15 | <div id="list-left" class="splitcontentleft"> | |
|
16 | <% @blocks['left'].each do |b| %> | |
|
17 | <div class="mypage-box"> | |
|
18 | <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> | |
|
19 | </div> | |
|
20 | <% end if @blocks['left'] %> | |
|
21 | </div> | |
|
22 | ||
|
23 | <div id="list-right" class="splitcontentright"> | |
|
24 | <% @blocks['right'].each do |b| %> | |
|
25 | <div class="mypage-box"> | |
|
26 | <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> | |
|
27 | </div> | |
|
28 | <% end if @blocks['right'] %> | |
|
29 | </div> | |
|
30 |
@@ -0,0 +1,121 | |||
|
1 | <script language="JavaScript"> | |
|
2 | ||
|
3 | function recreateSortables() { | |
|
4 | Sortable.destroy('list-top'); | |
|
5 | Sortable.destroy('list-left'); | |
|
6 | Sortable.destroy('list-right'); | |
|
7 | ||
|
8 | 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'}) | |
|
9 | 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'}) | |
|
10 | 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'}) | |
|
11 | } | |
|
12 | ||
|
13 | function updateSelect() { | |
|
14 | s = $('block-select') | |
|
15 | for (var i = 0; i < s.options.length; i++) { | |
|
16 | if ($('block_' + s.options[i].value)) { | |
|
17 | s.options[i].disabled = true; | |
|
18 | } else { | |
|
19 | s.options[i].disabled = false; | |
|
20 | } | |
|
21 | } | |
|
22 | s.options[0].selected = true; | |
|
23 | } | |
|
24 | ||
|
25 | function afterAddBlock() { | |
|
26 | recreateSortables(); | |
|
27 | updateSelect(); | |
|
28 | } | |
|
29 | ||
|
30 | function removeBlock(block) { | |
|
31 | $(block).parentNode.removeChild($(block)); | |
|
32 | updateSelect(); | |
|
33 | } | |
|
34 | ||
|
35 | </script> | |
|
36 | ||
|
37 | <div style="float:right;"> | |
|
38 | <%= start_form_tag({:action => "add_block"}, :id => "block-form") %> | |
|
39 | ||
|
40 | <%= select_tag 'block', "<option></option>" + options_for_select(@block_options), :id => "block-select", :class => "select-small" %> | |
|
41 | <small> | |
|
42 | <%= link_to_remote l(:button_add), | |
|
43 | :url => { :action => "add_block" }, | |
|
44 | :with => "Form.serialize('block-form')", | |
|
45 | :update => "list-top", | |
|
46 | :position => :top, | |
|
47 | :complete => "afterAddBlock();", | |
|
48 | :loading => "Element.show('indicator')", | |
|
49 | :loaded => "Element.hide('indicator')" | |
|
50 | %> | |
|
51 | </small> | |
|
52 | <%= end_form_tag %> | |
|
53 | <small>| | |
|
54 | <%= link_to l(:button_save), :action => 'page_layout_save' %> | | |
|
55 | <%= link_to l(:button_cancel), :action => 'page' %> | |
|
56 | </small> | |
|
57 | </div> | |
|
58 | ||
|
59 | <div style="float:right;margin-right:20px;"> | |
|
60 | <span id="indicator" style="display:none"><%= image_tag "loading.gif" %></span> | |
|
61 | </div> | |
|
62 | ||
|
63 | <h2><%=l(:label_my_page)%></h2> | |
|
64 | ||
|
65 | <div id="list-top" class="block-receiver"> | |
|
66 | <% @blocks['top'].each do |b| %> | |
|
67 | <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> | |
|
68 | <% end if @blocks['top'] %> | |
|
69 | </div> | |
|
70 | ||
|
71 | <div id="list-left" class="splitcontentleft block-receiver"> | |
|
72 | <% @blocks['left'].each do |b| %> | |
|
73 | <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> | |
|
74 | <% end if @blocks['left'] %> | |
|
75 | </div> | |
|
76 | ||
|
77 | <div id="list-right" class="splitcontentright block-receiver"> | |
|
78 | <% @blocks['right'].each do |b| %> | |
|
79 | <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> | |
|
80 | <% end if @blocks['right'] %> | |
|
81 | </div> | |
|
82 | ||
|
83 | <%= sortable_element 'list-top', | |
|
84 | :tag => 'div', | |
|
85 | :only => 'mypage-box', | |
|
86 | :handle => "handle", | |
|
87 | :dropOnEmpty => true, | |
|
88 | :containment => ['list-top', 'list-left', 'list-right'], | |
|
89 | :constraint => false, | |
|
90 | :complete => visual_effect(:highlight, 'list-top'), | |
|
91 | :url => { :action => "order_blocks", :group => "top" }, | |
|
92 | :loading => "Element.show('indicator')", | |
|
93 | :loaded => "Element.hide('indicator')" | |
|
94 | %> | |
|
95 | ||
|
96 | ||
|
97 | <%= sortable_element 'list-left', | |
|
98 | :tag => 'div', | |
|
99 | :only => 'mypage-box', | |
|
100 | :handle => "handle", | |
|
101 | :dropOnEmpty => true, | |
|
102 | :containment => ['list-top', 'list-left', 'list-right'], | |
|
103 | :constraint => false, | |
|
104 | :complete => visual_effect(:highlight, 'list-left'), | |
|
105 | :url => { :action => "order_blocks", :group => "left" }, | |
|
106 | :loading => "Element.show('indicator')", | |
|
107 | :loaded => "Element.hide('indicator')" %> | |
|
108 | ||
|
109 | <%= sortable_element 'list-right', | |
|
110 | :tag => 'div', | |
|
111 | :only => 'mypage-box', | |
|
112 | :handle => "handle", | |
|
113 | :dropOnEmpty => true, | |
|
114 | :containment => ['list-top', 'list-left', 'list-right'], | |
|
115 | :constraint => false, | |
|
116 | :complete => visual_effect(:highlight, 'list-right'), | |
|
117 | :url => { :action => "order_blocks", :group => "right" }, | |
|
118 | :loading => "Element.show('indicator')", | |
|
119 | :loaded => "Element.hide('indicator')" %> | |
|
120 | ||
|
121 | <%= javascript_tag "updateSelect()" %> No newline at end of file |
@@ -0,0 +1,12 | |||
|
1 | class CreateUserPreferences < ActiveRecord::Migration | |
|
2 | def self.up | |
|
3 | create_table :user_preferences do |t| | |
|
4 | t.column "user_id", :integer, :default => 0, :null => false | |
|
5 | t.column "others", :text | |
|
6 | end | |
|
7 | end | |
|
8 | ||
|
9 | def self.down | |
|
10 | drop_table :user_preferences | |
|
11 | end | |
|
12 | end |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
|
1 | NO CONTENT: new file 100644, binary diff hidden |
@@ -0,0 +1,5 | |||
|
1 | # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html | |
|
2 | first: | |
|
3 | id: 1 | |
|
4 | another: | |
|
5 | id: 2 |
@@ -0,0 +1,18 | |||
|
1 | require File.dirname(__FILE__) + '/../test_helper' | |
|
2 | require 'my_controller' | |
|
3 | ||
|
4 | # Re-raise errors caught by the controller. | |
|
5 | class MyController; def rescue_action(e) raise e end; end | |
|
6 | ||
|
7 | class MyControllerTest < Test::Unit::TestCase | |
|
8 | def setup | |
|
9 | @controller = MyController.new | |
|
10 | @request = ActionController::TestRequest.new | |
|
11 | @response = ActionController::TestResponse.new | |
|
12 | end | |
|
13 | ||
|
14 | # Replace this with your real tests. | |
|
15 | def test_truth | |
|
16 | assert true | |
|
17 | end | |
|
18 | end |
@@ -0,0 +1,10 | |||
|
1 | require File.dirname(__FILE__) + '/../test_helper' | |
|
2 | ||
|
3 | class UserPreferenceTest < Test::Unit::TestCase | |
|
4 | fixtures :user_preferences | |
|
5 | ||
|
6 | # Replace this with your real tests. | |
|
7 | def test_truth | |
|
8 | assert true | |
|
9 | end | |
|
10 | end |
@@ -40,7 +40,7 class AccountController < ApplicationController | |||
|
40 | 40 | user = User.try_to_login(params[:login], params[:password]) |
|
41 | 41 | if user |
|
42 | 42 | self.logged_in_user = user |
|
43 |
redirect_back_or_default :controller => ' |
|
|
43 | redirect_back_or_default :controller => 'my', :action => 'page' | |
|
44 | 44 | else |
|
45 | 45 | flash.now[:notice] = l(:notice_account_invalid_creditentials) |
|
46 | 46 | end |
@@ -53,41 +53,6 class AccountController < ApplicationController | |||
|
53 | 53 | redirect_to :controller => '' |
|
54 | 54 | end |
|
55 | 55 | |
|
56 | # Show logged in user's page | |
|
57 | def my_page | |
|
58 | @user = self.logged_in_user | |
|
59 | @reported_issues = Issue.find(:all, :conditions => ["author_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC') | |
|
60 | @assigned_issues = Issue.find(:all, :conditions => ["assigned_to_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC') | |
|
61 | end | |
|
62 | ||
|
63 | # Edit logged in user's account | |
|
64 | def my_account | |
|
65 | @user = self.logged_in_user | |
|
66 | if request.post? and @user.update_attributes(@params[:user]) | |
|
67 | set_localization | |
|
68 | flash.now[:notice] = l(:notice_account_updated) | |
|
69 | self.logged_in_user.reload | |
|
70 | end | |
|
71 | end | |
|
72 | ||
|
73 | # Change logged in user's password | |
|
74 | def change_password | |
|
75 | @user = self.logged_in_user | |
|
76 | flash[:notice] = l(:notice_can_t_change_password) and redirect_to :action => 'my_account' and return if @user.auth_source_id | |
|
77 | if @user.check_password?(@params[:password]) | |
|
78 | @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] | |
|
79 | if @user.save | |
|
80 | flash[:notice] = l(:notice_account_password_updated) | |
|
81 | else | |
|
82 | render :action => 'my_account' | |
|
83 | return | |
|
84 | end | |
|
85 | else | |
|
86 | flash[:notice] = l(:notice_account_wrong_password) | |
|
87 | end | |
|
88 | redirect_to :action => 'my_account' | |
|
89 | end | |
|
90 | ||
|
91 | 56 | # Enable user to choose a new password |
|
92 | 57 | def lost_password |
|
93 | 58 | if params[:token] |
@@ -19,7 +19,9 require "digest/sha1" | |||
|
19 | 19 | |
|
20 | 20 | class User < ActiveRecord::Base |
|
21 | 21 | has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => true |
|
22 | has_many :projects, :through => :memberships | |
|
22 | 23 | has_many :custom_values, :dependent => true, :as => :customized |
|
24 | has_one :preference, :dependent => true, :class_name => 'UserPreference' | |
|
23 | 25 | belongs_to :auth_source |
|
24 | 26 | |
|
25 | 27 | attr_accessor :password, :password_confirmation |
@@ -115,6 +117,10 class User < ActiveRecord::Base | |||
|
115 | 117 | @role_for_projects[project_id] |
|
116 | 118 | end |
|
117 | 119 | |
|
120 | def pref | |
|
121 | self.preference ||= UserPreference.new(:user => self) | |
|
122 | end | |
|
123 | ||
|
118 | 124 | private |
|
119 | 125 | # Return password digest |
|
120 | 126 | def self.hash_password(clear_password) |
@@ -70,7 +70,7 var menu_contenu=' \ | |||
|
70 | 70 | <div id="navigation"> |
|
71 | 71 | <ul> |
|
72 | 72 | <li class="selected"><%= link_to l(:label_home), { :controller => '' }, :class => "picHome" %></li> |
|
73 |
<li><%= link_to l(:label_my_page), { :controller => ' |
|
|
73 | <li><%= link_to l(:label_my_page), { :controller => 'my', :action => 'page'}, :class => "picUserPage" %></li> | |
|
74 | 74 | <li><%= link_to l(:label_project_plural), { :controller => 'projects' }, :class => "picProject" %></li> |
|
75 | 75 | |
|
76 | 76 | <% unless @project.nil? || @project.id.nil? %> |
@@ -78,7 +78,7 var menu_contenu=' \ | |||
|
78 | 78 | <% end %> |
|
79 | 79 | |
|
80 | 80 | <% if loggedin? %> |
|
81 |
<li><%= link_to l(:label_my_account), { :controller => ' |
|
|
81 | <li><%= link_to l(:label_my_account), { :controller => 'my', :action => 'account' }, :class => "picUser" %></li> | |
|
82 | 82 | <% end %> |
|
83 | 83 | |
|
84 | 84 | <% if admin_loggedin? %> |
@@ -9,7 +9,7 | |||
|
9 | 9 | <div class="box"> |
|
10 | 10 | <h3><%=l(:label_information_plural)%></h3> |
|
11 | 11 | |
|
12 |
<%= start_form_tag({:action => ' |
|
|
12 | <%= start_form_tag({:action => 'account'}, :class => "tabular") %> | |
|
13 | 13 | |
|
14 | 14 | <!--[form:user]--> |
|
15 | 15 | <p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label> |
@@ -7,6 +7,7 http://redmine.org/ | |||
|
7 | 7 | |
|
8 | 8 | == xx/xx/2006 v0.x.x |
|
9 | 9 | |
|
10 | * "my page" is now customizable | |
|
10 | 11 | * improved issues change history |
|
11 | 12 | * new functionality: move an issue to another project or tracker |
|
12 | 13 | * new functionality: add a note to an issue |
@@ -257,6 +257,7 label_gantt_chart: Gantt Diagramm | |||
|
257 | 257 | label_internal: Intern |
|
258 | 258 | label_last_changes: %d änderungen des Letzten |
|
259 | 259 | label_change_view_all: Alle änderungen ansehen |
|
260 | label_personalize_page: Diese Seite personifizieren | |
|
260 | 261 | |
|
261 | 262 | button_login: Einloggen |
|
262 | 263 | button_submit: Einreichen |
@@ -278,6 +279,7 button_list: Aufzulisten | |||
|
278 | 279 | button_view: Siehe |
|
279 | 280 | button_move: Bewegen |
|
280 | 281 | button_back: Rückkehr |
|
282 | button_cancel: Annullieren | |
|
281 | 283 | |
|
282 | 284 | text_select_mail_notifications: Aktionen für die Mailbenachrichtigung aktiviert werden soll. |
|
283 | 285 | text_regexp_info: eg. ^[A-Z0-9]+$ |
@@ -257,6 +257,7 label_gantt_chart: Gantt chart | |||
|
257 | 257 | label_internal: Internal |
|
258 | 258 | label_last_changes: last %d changes |
|
259 | 259 | label_change_view_all: View all changes |
|
260 | label_personalize_page: Personalize this page | |
|
260 | 261 | |
|
261 | 262 | button_login: Login |
|
262 | 263 | button_submit: Submit |
@@ -278,6 +279,7 button_list: List | |||
|
278 | 279 | button_view: View |
|
279 | 280 | button_move: Move |
|
280 | 281 | button_back: Back |
|
282 | button_cancel: Cancel | |
|
281 | 283 | |
|
282 | 284 | text_select_mail_notifications: Select actions for which mail notifications should be sent. |
|
283 | 285 | text_regexp_info: eg. ^[A-Z0-9]+$ |
@@ -257,6 +257,7 label_gantt_chart: Diagrama de Gantt | |||
|
257 | 257 | label_internal: Interno |
|
258 | 258 | label_last_changes: %d cambios del último |
|
259 | 259 | label_change_view_all: Ver todos los cambios |
|
260 | label_personalize_page: Personalizar esta página | |
|
260 | 261 | |
|
261 | 262 | button_login: Conexión |
|
262 | 263 | button_submit: Someter |
@@ -278,6 +279,7 button_list: Listar | |||
|
278 | 279 | button_view: Ver |
|
279 | 280 | button_move: Mover |
|
280 | 281 | button_back: Atrás |
|
282 | button_cancel: Cancelar | |
|
281 | 283 | |
|
282 | 284 | text_select_mail_notifications: Seleccionar las actividades que necesitan la activación de la notificación por mail. |
|
283 | 285 | text_regexp_info: eg. ^[A-Z0-9]+$ |
@@ -258,10 +258,11 label_gantt_chart: Diagramme de Gantt | |||
|
258 | 258 | label_internal: Interne |
|
259 | 259 | label_last_changes: %d derniers changements |
|
260 | 260 | label_change_view_all: Voir tous les changements |
|
261 | label_personalize_page: Personnaliser cette page | |
|
261 | 262 | |
|
262 | 263 | button_login: Connexion |
|
263 | 264 | button_submit: Soumettre |
|
264 |
button_save: |
|
|
265 | button_save: Sauvegarder | |
|
265 | 266 | button_check_all: Tout cocher |
|
266 | 267 | button_uncheck_all: Tout décocher |
|
267 | 268 | button_delete: Supprimer |
@@ -279,6 +280,7 button_list: Lister | |||
|
279 | 280 | button_view: Voir |
|
280 | 281 | button_move: Déplacer |
|
281 | 282 | button_back: Retour |
|
283 | button_cancel: Annuler | |
|
282 | 284 | |
|
283 | 285 | text_select_mail_notifications: Sélectionner les actions pour lesquelles la notification par mail doit être activée. |
|
284 | 286 | text_regexp_info: ex. ^[A-Z0-9]+$ |
@@ -379,6 +379,22 color:#505050; | |||
|
379 | 379 | line-height:1.5em; |
|
380 | 380 | } |
|
381 | 381 | |
|
382 | a.close-icon { | |
|
383 | display:block; | |
|
384 | margin-top:3px; | |
|
385 | overflow:hidden; | |
|
386 | width:12px; | |
|
387 | height:12px; | |
|
388 | background-repeat: no-repeat; | |
|
389 | cursor:hand; | |
|
390 | cursor:pointer; | |
|
391 | background-image:url('../images/close.png'); | |
|
392 | } | |
|
393 | ||
|
394 | a.close-icon:hover { | |
|
395 | background-image:url('../images/close_hl.png'); | |
|
396 | } | |
|
397 | ||
|
382 | 398 | .rightbox{ |
|
383 | 399 | background: #fafbfc; |
|
384 | 400 | border: 1px solid #c0c0c0; |
@@ -388,6 +404,26 position: relative; | |||
|
388 | 404 | margin: 0 5px 5px; |
|
389 | 405 | } |
|
390 | 406 | |
|
407 | .layout-active { | |
|
408 | background: #ECF3E1; | |
|
409 | } | |
|
410 | ||
|
411 | .block-receiver { | |
|
412 | border:1px dashed #c0c0c0; | |
|
413 | margin-bottom: 20px; | |
|
414 | padding: 15px 0 15px 0; | |
|
415 | } | |
|
416 | ||
|
417 | .mypage-box { | |
|
418 | margin:0 0 20px 0; | |
|
419 | color:#505050; | |
|
420 | line-height:1.5em; | |
|
421 | } | |
|
422 | ||
|
423 | .blocks { | |
|
424 | cursor: move; | |
|
425 | } | |
|
426 | ||
|
391 | 427 | .topright{ |
|
392 | 428 | position: absolute; |
|
393 | 429 | right: 25px; |
@@ -22,44 +22,44 class AccountTest < ActionController::IntegrationTest | |||
|
22 | 22 | |
|
23 | 23 | # Replace this with your real tests. |
|
24 | 24 | def test_login |
|
25 |
get " |
|
|
25 | get "my/page" | |
|
26 | 26 | assert_redirected_to "account/login" |
|
27 | 27 | log_user('jsmith', 'jsmith') |
|
28 | 28 | |
|
29 |
get " |
|
|
29 | get "my/account" | |
|
30 | 30 | assert_response :success |
|
31 |
assert_template " |
|
|
31 | assert_template "my/account" | |
|
32 | 32 | end |
|
33 | 33 | |
|
34 | 34 | def test_change_password |
|
35 | 35 | log_user('jsmith', 'jsmith') |
|
36 |
get " |
|
|
36 | get "my/account" | |
|
37 | 37 | assert_response :success |
|
38 |
assert_template " |
|
|
38 | assert_template "my/account" | |
|
39 | 39 | |
|
40 |
post " |
|
|
40 | post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello2" | |
|
41 | 41 | assert_response :success |
|
42 |
assert_template " |
|
|
42 | assert_template "my/account" | |
|
43 | 43 | assert_tag :tag => "div", :attributes => { :class => "errorExplanation" } |
|
44 | 44 | |
|
45 |
post " |
|
|
46 |
assert_redirected_to " |
|
|
45 | post "my/change_password", :password => 'jsmithZZ', :new_password => "hello", :new_password_confirmation => "hello" | |
|
46 | assert_redirected_to "my/account" | |
|
47 | 47 | assert_equal 'Wrong password', flash[:notice] |
|
48 | 48 | |
|
49 |
post " |
|
|
50 |
assert_redirected_to " |
|
|
49 | post "my/change_password", :password => 'jsmith', :new_password => "hello", :new_password_confirmation => "hello" | |
|
50 | assert_redirected_to "my/account" | |
|
51 | 51 | log_user('jsmith', 'hello') |
|
52 | 52 | end |
|
53 | 53 | |
|
54 | 54 | def test_my_account |
|
55 | 55 | log_user('jsmith', 'jsmith') |
|
56 |
get " |
|
|
56 | get "my/account" | |
|
57 | 57 | assert_response :success |
|
58 |
assert_template " |
|
|
58 | assert_template "my/account" | |
|
59 | 59 | |
|
60 |
post " |
|
|
60 | post "my/account", :user => {:firstname => "Joe", :login => "root", :admin => 1} | |
|
61 | 61 | assert_response :success |
|
62 |
assert_template " |
|
|
62 | assert_template "my/account" | |
|
63 | 63 | user = User.find(2) |
|
64 | 64 | assert_equal "Joe", user.firstname |
|
65 | 65 | assert_equal "jsmith", user.login |
@@ -68,9 +68,9 class AccountTest < ActionController::IntegrationTest | |||
|
68 | 68 | |
|
69 | 69 | def test_my_page |
|
70 | 70 | log_user('jsmith', 'jsmith') |
|
71 |
get " |
|
|
71 | get "my/page" | |
|
72 | 72 | assert_response :success |
|
73 |
assert_template " |
|
|
73 | assert_template "my/page" | |
|
74 | 74 | end |
|
75 | 75 | |
|
76 | 76 | def test_lost_password |
@@ -49,7 +49,7 class Test::Unit::TestCase | |||
|
49 | 49 | assert_response :success |
|
50 | 50 | assert_template "account/login" |
|
51 | 51 | post "/account/login", :login => login, :password => password |
|
52 |
assert_redirected_to " |
|
|
52 | assert_redirected_to "my/page" | |
|
53 | 53 | assert_equal login, User.find(session[:user_id]).login |
|
54 | 54 | end |
|
55 | 55 | end |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now