diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index 69dda5be0..fa2784f22 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -1,282 +1,282 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 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 "users_base" - before_filter :require_login - - helper :issues - helper :users - helper :custom_fields - - BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, - 'issuesreportedbyme' => :label_reported_issues, - 'issueswatched' => :label_watched_issues, - 'news' => :label_news_latest, - 'calendar' => :label_calendar, - 'documents' => :label_document_plural, - 'timelog' => :label_spent_time - }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze - - DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'], - 'right' => ['issuesreportedbyme'] - }.freeze - - def index - - page - render :action => 'page' - end - - # Show user's page - def page - @user = User.current - @Issues= Issue.visible.open. - where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) - @limit = 10 - @feedback_count = @Issues.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @curse_attachments = @Issues[@offset, @limit] - - @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT - end - - def page2 - @limit = 10 - @user = User.current - @Issues= Issue.visible.open. - where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) - @feedback_count = @Issues.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @curse_attachments = @Issues[@offset, @limit] - @state = false - @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT - respond_to do |format| - format.js - end - end - - # Edit user's account - def account - @user = User.current - lg=@user.login - @pref = @user.pref - diskfile = disk_filename('User', @user.id) - diskfile1 = diskfile + 'temp' - if request.post? - @user.safe_attributes = params[:user] - @user.pref.attributes = params[:pref] - @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') - @user.login = params[:login] - unless @user.user_extensions.nil? - if @user.user_extensions.identity == 2 - @user.firstname = params[:enterprise_name] - end - end - - @se = @user.extensions - @se.school_id = params[:occupation] if params[:occupation] - @se.gender = params[:gender] - @se.location = params[:province] if params[:province] - @se.location_city = params[:city] if params[:city] - @se.identity = params[:identity].to_i if params[:identity] - @se.technical_title = params[:technical_title] if params[:technical_title] - @se.student_id = params[:no] if params[:no] - - if @user.save && @se.save - # 头像保存 - if File.exist?(diskfile1) - if File.exist?(diskfile) - File.delete(diskfile) - end - File.open(diskfile1, "rb") do |f| - buffer = f.read(10) - if buffer != "DELETE" - File.open(diskfile1, "rb") do |f1| - File.open(diskfile, "wb") do |f| - buffer = "" - while (buffer = f1.read(8192)) - f.write(buffer) - end - end - end - - # File.rename(diskfile + 'temp',diskfile); - end - end - end - - # 确保文件被删除 - if File.exist?(diskfile1) - File.delete(diskfile1) - end - - @user.pref.save - @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) - set_language_if_valid @user.language - flash[:notice] = l(:notice_account_updated) - redirect_to user_url(@user) - return - else - # 确保文件被删除 - if File.exist?(diskfile1) - File.delete(diskfile1) - end - @user.login = lg - end - else - # 确保文件被删除 - if File.exist?(diskfile1) - File.delete(diskfile1) - end - end - end - - # Destroys user's account - def destroy - @user = User.current - unless @user.own_account_deletable? - redirect_to my_account_url - return - end - - if request.post? && params[:confirm] - @user.destroy - if @user.destroyed? - logout_user - flash.now[:notice] = l(:notice_account_deleted) - end - redirect_to home_url - end - end - - # Manage user's password - def password - @user = User.current - unless @user.change_password_allowed? - flash.now[:error] = l(:notice_can_t_change_password) - redirect_to my_account_url - return - end - if request.post? - if @user.check_password?(params[:password]) - @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] - - if @user.save - flash.now[:notice] = l(:notice_account_password_updated) - redirect_to my_account_url - end - else - flash.now[:error] = l(:notice_account_wrong_password) - end - end - end - - # Create a new feeds key - def reset_rss_key - if request.post? - if User.current.rss_token - User.current.rss_token.destroy - User.current.reload - end - User.current.rss_key - flash[:notice] = l(:notice_feeds_access_key_reseted) - end - redirect_to my_account_url - end - - # Create a new API key - def reset_api_key - if request.post? - if User.current.api_token - User.current.api_token.destroy - User.current.reload - end - User.current.api_key - flash[:notice] = l(:notice_api_access_key_reseted) - end - redirect_to my_account_url - end - - # User's page layout configuration - def page_layout - @user = User.current - @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup - @block_options = [] - BLOCKS.each do |k, v| - unless %w(top left right).detect {|f| (@blocks[f] ||= []).include?(k)} - @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize] - end - end - 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 - block = params[:block].to_s.underscore - if block.present? && BLOCKS.key?(block) - @user = User.current - layout = @user.pref[:my_page_layout] || {} - # remove if already present in a group - %w(top left right).each {|f| (layout[f] ||= []).delete block } - # add it on top - layout['top'].unshift block - @user.pref[:my_page_layout] = layout - @user.pref.save - end - redirect_to my_page_layout_url - end - - # Remove a block to user's page - # params[:block] : id of the block to remove - def remove_block - block = params[:block].to_s.underscore - @user = User.current - # remove block in all groups - layout = @user.pref[:my_page_layout] || {} - %w(top left right).each {|f| (layout[f] ||= []).delete block } - @user.pref[:my_page_layout] = layout - @user.pref.save - redirect_to my_page_layout_url - 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] - @user = User.current - if group.is_a?(String) - group_items = (params["blocks"] || []).collect(&:underscore) - group_items.each {|s| s.sub!(/^block_/, '')} - if group_items and group_items.is_a? Array - layout = @user.pref[:my_page_layout] || {} - # remove group blocks if they are presents in other groups - %w(top left right).each {|f| - layout[f] = (layout[f] || []) - group_items - } - layout[group] = group_items - @user.pref[:my_page_layout] = layout - @user.pref.save - end - end - render :nothing => true - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 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 "users_base" + before_filter :require_login + + helper :issues + helper :users + helper :custom_fields + + BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, + 'issuesreportedbyme' => :label_reported_issues, + 'issueswatched' => :label_watched_issues, + 'news' => :label_news_latest, + 'calendar' => :label_calendar, + 'documents' => :label_document_plural, + 'timelog' => :label_spent_time + }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze + + DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'], + 'right' => ['issuesreportedbyme'] + }.freeze + + def index + + page + render :action => 'page' + end + + # Show user's page + def page + @user = User.current + @Issues= Issue.visible.open. + where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) + @limit = 10 + @feedback_count = @Issues.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @curse_attachments = @Issues[@offset, @limit] + + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT + end + + def page2 + @limit = 10 + @user = User.current + @Issues= Issue.visible.open. + where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) + @feedback_count = @Issues.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @curse_attachments = @Issues[@offset, @limit] + @state = false + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT + respond_to do |format| + format.js + end + end + + # Edit user's account + def account + @user = User.current + lg=@user.login + @pref = @user.pref + diskfile = disk_filename('User', @user.id) + diskfile1 = diskfile + 'temp' + if request.post? + @user.safe_attributes = params[:user] + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + @user.login = params[:login] + unless @user.user_extensions.nil? + if @user.user_extensions.identity == 2 + @user.firstname = params[:enterprise_name] + end + end + + @se = @user.extensions + @se.school_id = params[:occupation] if params[:occupation] + @se.gender = params[:gender] + @se.location = params[:province] if params[:province] + @se.location_city = params[:city] if params[:city] + @se.identity = params[:identity].to_i if params[:identity] + @se.technical_title = params[:technical_title] if params[:technical_title] + @se.student_id = params[:no] if params[:no] + + if @user.save && @se.save + # 头像保存 + if File.exist?(diskfile1) + if File.exist?(diskfile) + File.delete(diskfile) + end + File.open(diskfile1, "rb") do |f| + buffer = f.read(10) + if buffer != "DELETE" + File.open(diskfile1, "rb") do |f1| + File.open(diskfile, "wb") do |f| + buffer = "" + while (buffer = f1.read(8192)) + f.write(buffer) + end + end + end + + # File.rename(diskfile + 'temp',diskfile); + end + end + end + + # 确保文件被删除 + if File.exist?(diskfile1) + File.delete(diskfile1) + end + + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + set_language_if_valid @user.language + flash[:notice] = l(:notice_account_updated) + redirect_to user_url(@user) + return + else + # 确保文件被删除 + if File.exist?(diskfile1) + File.delete(diskfile1) + end + @user.login = lg + end + else + # 确保文件被删除 + if File.exist?(diskfile1) + File.delete(diskfile1) + end + end + end + + # Destroys user's account + def destroy + @user = User.current + unless @user.own_account_deletable? + redirect_to my_account_url + return + end + + if request.post? && params[:confirm] + @user.destroy + if @user.destroyed? + logout_user + flash.now[:notice] = l(:notice_account_deleted) + end + redirect_to home_url + end + end + + # Manage user's password + def password + @user = User.current + unless @user.change_password_allowed? + flash.now[:error] = l(:notice_can_t_change_password) + redirect_to my_account_url + return + end + if request.post? + if @user.check_password?(params[:password]) + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + + if @user.save + flash.now[:notice] = l(:notice_account_password_updated) + redirect_to my_account_url + end + else + flash.now[:error] = l(:notice_account_wrong_password) + end + end + end + + # Create a new feeds key + def reset_rss_key + if request.post? + if User.current.rss_token + User.current.rss_token.destroy + User.current.reload + end + User.current.rss_key + flash[:notice] = l(:notice_feeds_access_key_reseted) + end + redirect_to my_account_url + end + + # Create a new API key + def reset_api_key + if request.post? + if User.current.api_token + User.current.api_token.destroy + User.current.reload + end + User.current.api_key + flash[:notice] = l(:notice_api_access_key_reseted) + end + redirect_to my_account_url + end + + # User's page layout configuration + def page_layout + @user = User.current + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup + @block_options = [] + BLOCKS.each do |k, v| + unless %w(top left right).detect {|f| (@blocks[f] ||= []).include?(k)} + @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize] + end + end + 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 + block = params[:block].to_s.underscore + if block.present? && BLOCKS.key?(block) + @user = User.current + layout = @user.pref[:my_page_layout] || {} + # remove if already present in a group + %w(top left right).each {|f| (layout[f] ||= []).delete block } + # add it on top + layout['top'].unshift block + @user.pref[:my_page_layout] = layout + @user.pref.save + end + redirect_to my_page_layout_url + end + + # Remove a block to user's page + # params[:block] : id of the block to remove + def remove_block + block = params[:block].to_s.underscore + @user = User.current + # remove block in all groups + layout = @user.pref[:my_page_layout] || {} + %w(top left right).each {|f| (layout[f] ||= []).delete block } + @user.pref[:my_page_layout] = layout + @user.pref.save + redirect_to my_page_layout_url + 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] + @user = User.current + if group.is_a?(String) + group_items = (params["blocks"] || []).collect(&:underscore) + group_items.each {|s| s.sub!(/^block_/, '')} + if group_items and group_items.is_a? Array + layout = @user.pref[:my_page_layout] || {} + # remove group blocks if they are presents in other groups + %w(top left right).each {|f| + layout[f] = (layout[f] || []) - group_items + } + layout[group] = group_items + @user.pref[:my_page_layout] = layout + @user.pref.save + end + end + render :nothing => true + end +end diff --git a/app/views/activities/index.html.erb b/app/views/activities/index.html.erb index ef52a164d..694af0a14 100644 --- a/app/views/activities/index.html.erb +++ b/app/views/activities/index.html.erb @@ -1,101 +1,101 @@ -

<%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %>

-

- <%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %> -

-
- <% @events_by_day.keys.sort.reverse.each do |day| %> -

-
- <% sort_activity_events(@events_by_day[day]).each do |e, in_group| -%> -
- - - - - -
- - <%= image_tag(url_to_avatar(e.event_author), :class => "avatar") %> - - - - - - - - - - - - -
- - <%= h(e.project) if @project.nil? || @project != e.project %> - - - <%= l(:label_new_activity) %> - - <%= link_to format_activity_title(e.event_title), e.event_url %> -
-

- <%= format_activity_description(e.event_description) %> -

-
- - <%= format_activity_day(day) %> - <%= format_time(e.event_datetime, false) %> - - - <%= link_to_user(e.event_author) if e.respond_to?(:event_author) %> -
-
-
- <% end -%> -
- <% end -%> -
- - -<%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %> - -<% other_formats_links do |f| %> - <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> -<% end %> - -<% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %> -<% end %> - -<% content_for :sidebar do %> -<%= form_tag({}, :method => :get) do %> -

<%= l(:label_activity) %>

-

- <% @activity.event_types.each do |t| %> - <%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> - -
- <% end %> -

-<% if @project && @project.descendants.active.any? %> -<%= hidden_field_tag 'with_subprojects', 0 %> -

- -

-<% end %> -<%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %> -

- <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %> -

-<% end %> -<% end %> - -<% html_title(l(:label_activity), @author) -%> +

<%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %>

+

+ <%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %> +

+
+ <% @events_by_day.keys.sort.reverse.each do |day| %> +

+
+ <% sort_activity_events(@events_by_day[day]).each do |e, in_group| -%> +
+ + + + + +
+ + <%= image_tag(url_to_avatar(e.event_author), :class => "avatar") %> + + + + + + + + + + + + +
+ + <%= h(e.project) if @project.nil? || @project != e.project %> + + + <%= l(:label_new_activity) %> + + <%= link_to format_activity_title(e.event_title), e.event_url %> +
+

+ <%= format_activity_description(e.event_description) %> +

+
+ + <%= format_activity_day(day) %> + <%= format_time(e.event_datetime, false) %> + + + <%= link_to_user(e.event_author) if e.respond_to?(:event_author) %> +
+
+
+ <% end -%> +
+ <% end -%> +
+ + +<%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %> +<% end %> + +<% content_for :sidebar do %> +<%= form_tag({}, :method => :get) do %> +

<%= l(:label_activity) %>

+

+ <% @activity.event_types.each do |t| %> + <%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> + +
+ <% end %> +

+<% if @project && @project.descendants.active.any? %> +<%= hidden_field_tag 'with_subprojects', 0 %> +

+ +

+<% end %> +<%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %> +

+ <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %> +

+<% end %> +<% end %> + +<% html_title(l(:label_activity), @author) -%> diff --git a/app/views/contestnotifications/index.html.erb b/app/views/contestnotifications/index.html.erb index a4dacd523..cf7ebe508 100644 --- a/app/views/contestnotifications/index.html.erb +++ b/app/views/contestnotifications/index.html.erb @@ -1,151 +1,151 @@ - - - - <%= l(:label_notification) %> - -<% if User.current.logged? && (User.current.admin? ||User.current == @contest.author) %> - <%= link_to(l(:bale_news_notice), - new_contest_contestnotification_path(@contest), - :class => 'icon icon-add', - :onclick => 'showAndScrollTo("add-contestnotifications", "contestnotifications_title"); return false;') %> -<% end %> -<% if @contest %> - -
-<% end %> -
- -
- - <%= image_tag(url_to_avatar(@contest.author), :class => "avatar")%> - - - - <%= render :partial => "/praise_tread/praise_tread", - :locals => {:obj => @contest, - :show_flag => true, - :user_id =>User.current.id, - :horizontal => false} - %> - -

- <%= link_to(@contest.author.lastname+@contest.author.firstname, - user_path(@contest.author))%> - :<%= @contest.name %> -

-

- - <%= l(:label_bids_reward_method) %> - - <%= @contest.budget%> - - -

-
- <%= @contest.description %> -
-
-
- -
- -

- <% @contestnotificationss.each do |contestnotifications| %> - - - - - -
- <%= link_to image_tag(url_to_avatar(contestnotifications.author), :class => "avatar"), user_path(contestnotifications.author) %> - - - - - - - - - - - - - -
- - <%= link_to_user(contestnotifications.author) if contestnotifications.respond_to?(:author) %> - - - <%= l(:label_project_notice) %> - - - <%= link_to h(contestnotifications.title), contest_contestnotification_path(@contest, contestnotifications) %> - - - <%= link_to l(:button_edit), edit_contest_contestnotification_path(@contest, contestnotifications) if (User.current.admin? && User.current.logged? )||(User.current == @contest.author && User.current.logged?) %> - <%= delete_link contest_contestnotification_path(@contest, contestnotifications) if (User.current.admin? && User.current.logged? )||(User.current == @contest.author && User.current.logged?) %> - -
- - <%= textilizable(contestnotifications, :description) %> - -
- <%= l :label_update_time %> -   - <%= format_time(contestnotifications.created_at) %> - - - <%= link_to l(:label_check_comment), contest_contestnotification_path(@contest, contestnotifications) %> -
-
- <% end %> - -
- -
- - - <% content_for :header_tags do %> - <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> - <%= stylesheet_link_tag 'scm' %> - <% end %> - - <% html_title(l(:label_contest_notification)) -%> -
- - - + + + + <%= l(:label_notification) %> + +<% if User.current.logged? && (User.current.admin? ||User.current == @contest.author) %> + <%= link_to(l(:bale_news_notice), + new_contest_contestnotification_path(@contest), + :class => 'icon icon-add', + :onclick => 'showAndScrollTo("add-contestnotifications", "contestnotifications_title"); return false;') %> +<% end %> +<% if @contest %> + +
+<% end %> +
+ +
+ + <%= image_tag(url_to_avatar(@contest.author), :class => "avatar")%> + + + + <%= render :partial => "/praise_tread/praise_tread", + :locals => {:obj => @contest, + :show_flag => true, + :user_id =>User.current.id, + :horizontal => false} + %> + +

+ <%= link_to(@contest.author.lastname+@contest.author.firstname, + user_path(@contest.author))%> + :<%= @contest.name %> +

+

+ + <%= l(:label_bids_reward_method) %> + + <%= @contest.budget%> + + +

+
+ <%= @contest.description %> +
+
+
+ +
+ +

+ <% @contestnotificationss.each do |contestnotifications| %> + + + + + +
+ <%= link_to image_tag(url_to_avatar(contestnotifications.author), :class => "avatar"), user_path(contestnotifications.author) %> + + + + + + + + + + + + + +
+ + <%= link_to_user(contestnotifications.author) if contestnotifications.respond_to?(:author) %> + + + <%= l(:label_project_notice) %> + + + <%= link_to h(contestnotifications.title), contest_contestnotification_path(@contest, contestnotifications) %> + + + <%= link_to l(:button_edit), edit_contest_contestnotification_path(@contest, contestnotifications) if (User.current.admin? && User.current.logged? )||(User.current == @contest.author && User.current.logged?) %> + <%= delete_link contest_contestnotification_path(@contest, contestnotifications) if (User.current.admin? && User.current.logged? )||(User.current == @contest.author && User.current.logged?) %> + +
+ + <%= textilizable(contestnotifications, :description) %> + +
+ <%= l :label_update_time %> +   + <%= format_time(contestnotifications.created_at) %> + + + <%= link_to l(:label_check_comment), contest_contestnotification_path(@contest, contestnotifications) %> +
+
+ <% end %> + +
+ +
+ + + <% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> + <%= stylesheet_link_tag 'scm' %> + <% end %> + + <% html_title(l(:label_contest_notification)) -%> +
+ + + \ No newline at end of file diff --git a/app/views/contests/index.html.erb b/app/views/contests/index.html.erb index b8033f89f..0c6b0e109 100644 --- a/app/views/contests/index.html.erb +++ b/app/views/contests/index.html.erb @@ -1,53 +1,53 @@ -
- <%= form_tag({:controller => 'contests', :action => 'index'}, :method => :get) do %> - - - - - - - - - - - -
<%= l(:label_contest_innovate) %><%= l(:label_user_location) %> : - <% if User.current.logged? %> - <% unless User.current.user_extensions.identity == 1 %> - <%= link_to(l(:label_newtype_contest), new_contest_contests_path, :class => 'icon icon-add', :target => "_blank") %> - - <% end %> - <% end %> - - -
- - <%= link_to request.host()+"/contests", contests_path %> - - - - <%=link_to l(:field_homepage), home_path %> > - <%=link_to l(:label_contest_innovate), :controller => 'contests', :action => 'index' %> - -
- <% end %> -
-<% if @contests.size > 0%> - <%= sort_contest(@s_state)%> -
- <%= render :partial => 'contest_list', :locals => {:contests => @contests, :contest_pages => @contest_pages} %> -
-<% elsif @is_search%> - <%= render :partial => "layouts/no_content"%> -<% else %> - <%= sort_contest(@s_state)%> -
- <%= render :partial => 'contest_list', :locals => {:contests => @contests, :contest_pages => @contest_pages} %> -
-<% end %> - -<% html_title l(:label_contest_list)%> +
+ <%= form_tag({:controller => 'contests', :action => 'index'}, :method => :get) do %> + + + + + + + + + + + +
<%= l(:label_contest_innovate) %><%= l(:label_user_location) %> : + <% if User.current.logged? %> + <% unless User.current.user_extensions.identity == 1 %> + <%= link_to(l(:label_newtype_contest), new_contest_contests_path, :class => 'icon icon-add', :target => "_blank") %> + + <% end %> + <% end %> + + +
+ + <%= link_to request.host()+"/contests", contests_path %> + + + + <%=link_to l(:field_homepage), home_path %> > + <%=link_to l(:label_contest_innovate), :controller => 'contests', :action => 'index' %> + +
+ <% end %> +
+<% if @contests.size > 0%> + <%= sort_contest(@s_state)%> +
+ <%= render :partial => 'contest_list', :locals => {:contests => @contests, :contest_pages => @contest_pages} %> +
+<% elsif @is_search%> + <%= render :partial => "layouts/no_content"%> +<% else %> + <%= sort_contest(@s_state)%> +
+ <%= render :partial => 'contest_list', :locals => {:contests => @contests, :contest_pages => @contest_pages} %> +
+<% end %> + +<% html_title l(:label_contest_list)%> diff --git a/app/views/courses/_join_private_course.html.erb b/app/views/courses/_join_private_course.html.erb index eaa325bb7..65dd04aa6 100644 --- a/app/views/courses/_join_private_course.html.erb +++ b/app/views/courses/_join_private_course.html.erb @@ -1,75 +1,75 @@ - - - - - 快速进入课程通道 - - - - - -
-
-
-

快速进入课程通道

-

只要持有课程ID和密码,就可快速加入所在课程。课程页面搜索不到的私有课程只能从此通道进入哦!

-
-
- <%= form_tag({:controller => 'courses', - :action => 'join'}, - :remote => true, - :method => :post, - :id => 'new-watcher-form') do %> - - <% end%> -
-
-
- - - + + + + + 快速进入课程通道 + + + + + +
+
+
+

快速进入课程通道

+

只要持有课程ID和密码,就可快速加入所在课程。课程页面搜索不到的私有课程只能从此通道进入哦!

+
+
+ <%= form_tag({:controller => 'courses', + :action => 'join'}, + :remote => true, + :method => :post, + :id => 'new-watcher-form') do %> + + <% end%> +
+
+
+ + + diff --git a/app/views/settings/_projects.html.erb b/app/views/settings/_projects.html.erb index f9ac36d4e..b0526f5de 100644 --- a/app/views/settings/_projects.html.erb +++ b/app/views/settings/_projects.html.erb @@ -1,26 +1,26 @@ -<%= form_tag({:action => 'edit', :tab => 'projects'}) do %> -
-

- <%= setting_check_box :default_projects_public %> -

- -

- <%= setting_multiselect(:default_projects_modules, - Redmine::AccessControl.available_project_modules.collect {|m| [l_or_humanize(m, :prefix => "project_module_"), m.to_s]}) %> -

- -

- <%= setting_multiselect(:default_projects_tracker_ids, Tracker.sorted.all.collect {|t| [t.name, t.id.to_s]}) %> -

- -

- <%= setting_check_box :sequential_project_identifiers %> -

- -

<%= setting_select :new_project_user_role_id, Role.find_all_givable.collect {|r| [r.name, r.id.to_s]}, - :blank => "--- #{l(:actionview_instancetag_blank_option)} ---" %> -

-
- - <%= submit_tag l(:button_save) %> -<% end %> +<%= form_tag({:action => 'edit', :tab => 'projects'}) do %> +
+

+ <%= setting_check_box :default_projects_public %> +

+ +

+ <%= setting_multiselect(:default_projects_modules, + Redmine::AccessControl.available_project_modules.collect {|m| [l_or_humanize(m, :prefix => "project_module_"), m.to_s]}) %> +

+ +

+ <%= setting_multiselect(:default_projects_tracker_ids, Tracker.sorted.all.collect {|t| [t.name, t.id.to_s]}) %> +

+ +

+ <%= setting_check_box :sequential_project_identifiers %> +

+ +

<%= setting_select :new_project_user_role_id, Role.find_all_givable.collect {|r| [r.name, r.id.to_s]}, + :blank => "--- #{l(:actionview_instancetag_blank_option)} ---" %> +

+
+ + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/welcome/contest.html.erb b/app/views/welcome/contest.html.erb index 7b1de2d83..e5c169804 100644 --- a/app/views/welcome/contest.html.erb +++ b/app/views/welcome/contest.html.erb @@ -1,301 +1,301 @@ -<% - @nav_dispaly_contest_label = 1 - @nav_dispaly_store_all_label = 1 -%> -<%= stylesheet_link_tag 'welcome' %> - - - - - -
- <%#= render partial: 'wei_xin' %> -
- -
- <% if get_avatar?(@contest_page) %> - <%= image_tag(url_to_avatar(@contest_page), width:@contest_page.image_width,height: @contest_page.image_height) %> - <% else %> - <%= image_tag '/images/transparent.png', width:@contest_page.image_width,height: @contest_page.image_height %> - <% end %> -
-
- <% unless @contest_page.nil? %> - <%= @contest_page.title %> , <%= @contest_page.description %> - <% end %> -
- - -
- <%= form_tag({controller: :welcome, action: :search }, method: :get) do %> - <%= text_field_tag 'name', params[:name], :placeholder => l(:label_search_intimation), name: "name", :class => 'blueinputbar', :style => 'width:240px; padding-right:50px;'%> -   - <%= hidden_field_tag 'project_type', params[:project_type] %> - <%= submit_tag l(:label_search), :class => "enterprise", :name => "contests_search" %> - <% end %> - -
-
-
-
- -
- -
-

<%=l(:label_current_hot_contest)%>

- - <% if User.current.logged? %> - <% unless User.current.user_extensions.identity == 1 %> - <%= link_to(l(:label_newtype_contest), new_contest_contests_path, :class => 'icon icon-add') %> - <% end %> - <% end %> -    - <%= link_to l(:label_more), {:controller => 'contests', :action => 'index'}, :target => "_blank" %> - -
-
- <% find_all_hot_contest.map do |contest| break if(contest == find_all_hot_contest[5]) %> -
  • -
    - <%= image_tag('/images/contest1.png')%> -
    -
    - <%= link_to(contest.name.truncate(50, omission: '...'), contest_contestnotifications_path(contest.id), :class => "d-g-blue d-p-project-name", :title => "#{contest.name}", :target => "_blank") %> - <% if contest.id == 2 or contest.id == 3 or contest.id == 6 %> - (<%= link_to("#{contest.projects.where('is_public=1').count}"+l(:label_work_quantity), show_attendingcontest_contest_path(contest), :target => "_blank") %>) - <% else %> - (<%= link_to("#{contest.contesting_softapplications.count}"+l(:label_work_quantity), show_attendingcontest_contest_path(contest), :target => "_blank") %>) - <% end %> -
    - -
    - <%=contest.description.truncate(100, omission: '...')%> -

    - -
    - <%=l(:label_release_time)%>: <%=format_time contest.created_on %> -
    -
  • - <% end; reset_cycle %> -
    -
    -
    - - -
    -

    - <%=l(:label_notification)%> -

    - - -
    - -
    -

    - <%=l(:label_issue_feedback_activities)%> - <%= link_to l(:label_my_question), newbie_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> - <%= link_to l(:label_my_feedback), suggestion_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> -

    - <%= link_to l(:label_more_information), forums_path %> -
    - -
    -
    - - - -
    -

    <%=l(:label_current_attendingcontest_work)%>

    - <%= link_to l(:label_more_information), {:controller => 'softapplications', :action => 'index'}, :target => "_blank" %> -
    - <% if Softapplication.count > 0%> -
    - <% find_all_hot_softapplication.map do |softapplication| break if(softapplication == find_all_hot_softapplication[5]) %> - -
  • -
    - <%= image_tag('/images/app1.png')%> -
    - -
    - <%= link_to(softapplication.name, softapplication_path(softapplication.id), :class => "d-g-blue d-p-project-name", :title => "#{softapplication.name}", :target => "_blank") %> -
    - -
    - ><%=softapplication.description.to_s.truncate(50, omission: '...')%> -

    - -
    - <%=l(:label_release_time)%>: <%=format_time softapplication.created_at %> -
    - -
  • - <% end; reset_cycle %> - -
    - <% else %> -

    <%= l(:label_no_ftapplication) %>

    - - <% end %> -
    -
    - - - -
    -<%= render partial: 'link_to_another' %> - - - +<% + @nav_dispaly_contest_label = 1 + @nav_dispaly_store_all_label = 1 +%> +<%= stylesheet_link_tag 'welcome' %> + + + + + +
    + <%#= render partial: 'wei_xin' %> +
    + +
    + <% if get_avatar?(@contest_page) %> + <%= image_tag(url_to_avatar(@contest_page), width:@contest_page.image_width,height: @contest_page.image_height) %> + <% else %> + <%= image_tag '/images/transparent.png', width:@contest_page.image_width,height: @contest_page.image_height %> + <% end %> +
    +
    + <% unless @contest_page.nil? %> + <%= @contest_page.title %> , <%= @contest_page.description %> + <% end %> +
    + + +
    + <%= form_tag({controller: :welcome, action: :search }, method: :get) do %> + <%= text_field_tag 'name', params[:name], :placeholder => l(:label_search_intimation), name: "name", :class => 'blueinputbar', :style => 'width:240px; padding-right:50px;'%> +   + <%= hidden_field_tag 'project_type', params[:project_type] %> + <%= submit_tag l(:label_search), :class => "enterprise", :name => "contests_search" %> + <% end %> + +
    +
    +
    +
    + +
    + +
    +

    <%=l(:label_current_hot_contest)%>

    + + <% if User.current.logged? %> + <% unless User.current.user_extensions.identity == 1 %> + <%= link_to(l(:label_newtype_contest), new_contest_contests_path, :class => 'icon icon-add') %> + <% end %> + <% end %> +    + <%= link_to l(:label_more), {:controller => 'contests', :action => 'index'}, :target => "_blank" %> + +
    +
    + <% find_all_hot_contest.map do |contest| break if(contest == find_all_hot_contest[5]) %> +
  • +
    + <%= image_tag('/images/contest1.png')%> +
    +
    + <%= link_to(contest.name.truncate(50, omission: '...'), contest_contestnotifications_path(contest.id), :class => "d-g-blue d-p-project-name", :title => "#{contest.name}", :target => "_blank") %> + <% if contest.id == 2 or contest.id == 3 or contest.id == 6 %> + (<%= link_to("#{contest.projects.where('is_public=1').count}"+l(:label_work_quantity), show_attendingcontest_contest_path(contest), :target => "_blank") %>) + <% else %> + (<%= link_to("#{contest.contesting_softapplications.count}"+l(:label_work_quantity), show_attendingcontest_contest_path(contest), :target => "_blank") %>) + <% end %> +
    + +
    + <%=contest.description.truncate(100, omission: '...')%> +

    + +
    + <%=l(:label_release_time)%>: <%=format_time contest.created_on %> +
    +
  • + <% end; reset_cycle %> +
    +
    +
    + + +
    +

    + <%=l(:label_notification)%> +

    + + +
    + +
    +

    + <%=l(:label_issue_feedback_activities)%> + <%= link_to l(:label_my_question), newbie_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> + <%= link_to l(:label_my_feedback), suggestion_send_path, {:class => 'orangeButton idea_btn', :style => "color: #EEEEEE" }%> +

    + <%= link_to l(:label_more_information), forums_path %> +
    + +
    +
    + + + +
    +

    <%=l(:label_current_attendingcontest_work)%>

    + <%= link_to l(:label_more_information), {:controller => 'softapplications', :action => 'index'}, :target => "_blank" %> +
    + <% if Softapplication.count > 0%> +
    + <% find_all_hot_softapplication.map do |softapplication| break if(softapplication == find_all_hot_softapplication[5]) %> + +
  • +
    + <%= image_tag('/images/app1.png')%> +
    + +
    + <%= link_to(softapplication.name, softapplication_path(softapplication.id), :class => "d-g-blue d-p-project-name", :title => "#{softapplication.name}", :target => "_blank") %> +
    + +
    + ><%=softapplication.description.to_s.truncate(50, omission: '...')%> +

    + +
    + <%=l(:label_release_time)%>: <%=format_time softapplication.created_at %> +
    + +
  • + <% end; reset_cycle %> + +
    + <% else %> +

    <%= l(:label_no_ftapplication) %>

    + + <% end %> +
    +
    + + + +
    +<%= render partial: 'link_to_another' %> + + + diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index b76b14e1d..4fc08d41f 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -1,193 +1,193 @@ -<% @nav_dispaly_project_label = 1 - @nav_dispaly_forum_label = 1 %> -<%= stylesheet_link_tag 'welcome' %> -<%= javascript_include_tag 'welcome' %> - - -
    - <%#= render partial: 'wei_xin' %> -
    -
    - - <% if get_avatar?(@first_page) %> - <%= image_tag(url_to_avatar(@first_page), width:@first_page.image_width,height: @first_page.image_height) %> - <% else %> - <%= image_tag '/images/transparent.png', width:@first_page.image_width,height: @first_page.image_height %> - <% end %> - -
    -
    - <% unless @first_page.nil? %> - <%= @first_page.description.html_safe %> - <% end %> -
    - -
    -
    -
    - -
    - -
    -

    - <%= l(:lable_hot_projects)%> -

    - - <% if User.current.logged? %> - <%= link_to(l(:label_project_new), {:controller => 'projects', - :action => 'new', - :course => 0, - :project_type =>( @project_type||=0)}, - :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> - <% end %> -    - <%= link_to l(:label_more), { :controller => 'projects', - :action => 'index', - :project_type => 0, - :host => Setting.project_domain}, - :target => "_blank" %> - -
    - -
    -
    - -
    - -
    - -
    - -
    - -
    +<% @nav_dispaly_project_label = 1 + @nav_dispaly_forum_label = 1 %> +<%= stylesheet_link_tag 'welcome' %> +<%= javascript_include_tag 'welcome' %> + + +
    + <%#= render partial: 'wei_xin' %> +
    +
    + + <% if get_avatar?(@first_page) %> + <%= image_tag(url_to_avatar(@first_page), width:@first_page.image_width,height: @first_page.image_height) %> + <% else %> + <%= image_tag '/images/transparent.png', width:@first_page.image_width,height: @first_page.image_height %> + <% end %> + +
    +
    + <% unless @first_page.nil? %> + <%= @first_page.description.html_safe %> + <% end %> +
    + +
    +
    +
    + +
    + +
    +

    + <%= l(:lable_hot_projects)%> +

    + + <% if User.current.logged? %> + <%= link_to(l(:label_project_new), {:controller => 'projects', + :action => 'new', + :course => 0, + :project_type =>( @project_type||=0)}, + :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> + <% end %> +    + <%= link_to l(:label_more), { :controller => 'projects', + :action => 'index', + :project_type => 0, + :host => Setting.project_domain}, + :target => "_blank" %> + +
    + +
    +
    + +
    + +
    + +
    + +
    + +
    <%= render partial: 'link_to_another' %> \ No newline at end of file diff --git a/app/views/wiki/diff.html.erb b/app/views/wiki/diff.html.erb index 0bdbc88dc..c4769cdfa 100644 --- a/app/views/wiki/diff.html.erb +++ b/app/views/wiki/diff.html.erb @@ -1,33 +1,33 @@ -
    - <%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> -
    - -<%= wiki_page_breadcrumb(@page) %> - -

    - <%= h(@page.pretty_title) %> -

    - -

    - <%= l(:label_version) %> - <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %> - - (<%= @diff.content_from.author ? @diff.content_from.author.name : l(:label_user_anonymous)%>, - <%= format_time(@diff.content_from.updated_on) %>) - -→ - <%= l(:label_version) %> - <%= link_to @diff.content_to.version, :action => 'show', - :id => @page.title, :project_id => @page.project, - :version => @diff.content_to.version %> - / - <%= @page.content.version %> - - (<%= @diff.content_to.author ? link_to_user(@diff.content_to.author.name) : l(:label_user_anonymous)%>, - <%= format_time(@diff.content_to.updated_on) %>) - -

    - -
    - <%= simple_format_without_paragraph @diff.to_html %> -
    +
    + <%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +

    + <%= h(@page.pretty_title) %> +

    + +

    + <%= l(:label_version) %> + <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %> + + (<%= @diff.content_from.author ? @diff.content_from.author.name : l(:label_user_anonymous)%>, + <%= format_time(@diff.content_from.updated_on) %>) + +→ + <%= l(:label_version) %> + <%= link_to @diff.content_to.version, :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => @diff.content_to.version %> + / + <%= @page.content.version %> + + (<%= @diff.content_to.author ? link_to_user(@diff.content_to.author.name) : l(:label_user_anonymous)%>, + <%= format_time(@diff.content_to.updated_on) %>) + +

    + +
    + <%= simple_format_without_paragraph @diff.to_html %> +
    diff --git a/app/views/wiki/edit.html.erb b/app/views/wiki/edit.html.erb index 6154ca22d..1fdbcf92f 100644 --- a/app/views/wiki/edit.html.erb +++ b/app/views/wiki/edit.html.erb @@ -1,62 +1,62 @@ -<%= wiki_page_breadcrumb(@page) %> - - -

    - <%= h @page.pretty_title %> -

    - -<%= form_for @content, :as => :content, - :url => {:action => 'update', :id => @page.title}, - :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> - <%= f.hidden_field :version %> - <% if @section %> - <%= hidden_field_tag 'section', @section %> - <%= hidden_field_tag 'section_hash', @section_hash %> - <% end %> - <%= error_messages_for 'content' %> - -
    -

    - <%=text_area_tag 'content[text]', @text, :required => true, :id => 'editor02', :cols => 100, :rows => 25 %> -

    - -
    - -
    - <% if @page.safe_attribute_names.include?('parent_id') && @wiki.pages.any? %> - <%= fields_for @page do |fp| %> -

    - - <%= fp.select :parent_id,content_tag('option', '', :value => '') + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - @page.self_and_descendants, @page.parent) %> -

    - <% end %> - <% end %> - -

    - - <%= f.text_field :comments, :style => "width:75%;" %> -

    -

    - - <%= render :partial => 'attachments/form' %> -

    -
    - -

    - <%= submit_tag l(:button_save) %> -

    - <%= wikitoolbar_for 'content_text' %> -<% end %> -
    -<% content_for :header_tags do %> - <%= robot_exclusion_tag %> -<% end %> -<% html_title @page.pretty_title %> +<%= wiki_page_breadcrumb(@page) %> + + +

    + <%= h @page.pretty_title %> +

    + +<%= form_for @content, :as => :content, + :url => {:action => 'update', :id => @page.title}, + :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> + <%= f.hidden_field :version %> + <% if @section %> + <%= hidden_field_tag 'section', @section %> + <%= hidden_field_tag 'section_hash', @section_hash %> + <% end %> + <%= error_messages_for 'content' %> + +
    +

    + <%=text_area_tag 'content[text]', @text, :required => true, :id => 'editor02', :cols => 100, :rows => 25 %> +

    + +
    + +
    + <% if @page.safe_attribute_names.include?('parent_id') && @wiki.pages.any? %> + <%= fields_for @page do |fp| %> +

    + + <%= fp.select :parent_id,content_tag('option', '', :value => '') + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - @page.self_and_descendants, @page.parent) %> +

    + <% end %> + <% end %> + +

    + + <%= f.text_field :comments, :style => "width:75%;" %> +

    +

    + + <%= render :partial => 'attachments/form' %> +

    +
    + +

    + <%= submit_tag l(:button_save) %> +

    + <%= wikitoolbar_for 'content_text' %> +<% end %> +
    +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> +<% html_title @page.pretty_title %> diff --git a/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb b/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb index f0f06ee26..609b35415 100644 --- a/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb +++ b/lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb @@ -1,170 +1,170 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 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 Redmine - module Acts - module Attachable - def self.included(base) - base.extend ClassMethods - end - - module ClassMethods - def acts_as_attachable(options = {}) - cattr_accessor :attachable_options - self.attachable_options = {} - attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym - attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym - - has_many :attachments, options.merge(:as => :container, - :order => "#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC", - :dependent => :destroy) - send :include, Redmine::Acts::Attachable::InstanceMethods - before_save :attach_saved_attachments - end - end - - module InstanceMethods - def self.included(base) - base.extend ClassMethods - end - - def attachments_visible?(user=User.current) - if self.respond_to?(:project) - (respond_to?(:visible?) ? visible?(user) : true) && - user.allowed_to?(self.class.attachable_options[:view_permission], self.project) - else - return true - end - - end - - def attachments_deletable?(user=User.current) - if (self.has_attribute?(:course) ||self.has_attribute?(:course_id)) && self.course - #默认给予删除自己上传的附件的权限 - (respond_to?(:visible?) ? visible?(user) : true) && - (user.allowed_to?(self.class.attachable_options[:delete_permission], self.course) || (self.has_attribute?(:author_id) && self.author == user)) - else - #默认给予删除自己上传的附件的权限 - (respond_to?(:visible?) ? visible?(user) : true) && - (user.allowed_to?(self.class.attachable_options[:delete_permission], self.project) || (self.has_attribute?(:author_id) && self.author == user)) - end - end - - def saved_attachments - @saved_attachments ||= [] - end - - def unsaved_attachments - @unsaved_attachments ||= [] - end - - # 设置资源文件的公开属性 - # add by nwb - def set_attachment_public(res) - # 公开的资源判断他的父级的公开属性 - if res.is_public - if( (self.class.to_s=="Project" && self.is_public == false) || - (self.has_attribute?(:project) && self.project && self.project.is_public == false) || - (self.has_attribute?(:board) && self.board.project && self.board.project.is_public == false) || - (self.class.to_s=="HomeworkAttach" && self.bid.reward_type == 3) || - (self.class.to_s=="Course" && self.is_public == false) || - (self.has_attribute?(:course) && self.course && self.course.is_public == false) || - (self.has_attribute?(:board) && self.board.course && self.board.course.is_public == false) - ) - res.is_public = false - end - end - end - - def save_attachmentsex(attachments, author=User.current,attachment_type) - @curattachment_type = attachment_type - result = save_attachments(attachments,author) - result - end - - def save_attachments(attachments, author=User.current) - # 清除临时文件 - if attachments - tempAttach = attachments[:dummy] - if tempAttach && tempAttach[:file] - attachments.delete(:dummy) - end - end - - if attachments.is_a?(Hash) - attachments = attachments.stringify_keys - attachments = attachments.to_a.sort {|a, b| - if a.first.to_i > 0 && b.first.to_i > 0 - a.first.to_i <=> b.first.to_i - elsif a.first.to_i > 0 - 1 - elsif b.first.to_i > 0 - -1 - else - a.first <=> b.first - end - } - attachments = attachments.map(&:last) - end - if attachments.is_a?(Array) - attachments.each do |attachment| - if attachment.is_a?(Hash) - a = nil - file = attachment['file'] - token = attachment['token'] - t = file && file.size > 0 - if file && file.size > 0 - a = Attachment.create(:file => file, :author => author) - elsif token - a = Attachment.find_by_token_only(token) - if a - a.filename = attachment['filename'] unless attachment['filename'].blank? - a.content_type = attachment['content_type'] - end - end - end - if a && !attachment['is_public_checkbox'] - a.is_public = false - elsif a && attachment['is_public_checkbox'] - a.is_public = true - end - set_attachment_public(a) if a - next unless a - a.description = attachment['description'].to_s.strip - a.attachtype = @curattachment_type - if a.new_record? - unsaved_attachments << a - else - saved_attachments << a - end - end - end - {:files => saved_attachments, :unsaved => unsaved_attachments} - end - - def attach_saved_attachments - saved_attachments.each do |attachment| - self.attachments << attachment - end - end - - module ClassMethods - end - end - end - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 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 Redmine + module Acts + module Attachable + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_attachable(options = {}) + cattr_accessor :attachable_options + self.attachable_options = {} + attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym + attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym + + has_many :attachments, options.merge(:as => :container, + :order => "#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC", + :dependent => :destroy) + send :include, Redmine::Acts::Attachable::InstanceMethods + before_save :attach_saved_attachments + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + end + + def attachments_visible?(user=User.current) + if self.respond_to?(:project) + (respond_to?(:visible?) ? visible?(user) : true) && + user.allowed_to?(self.class.attachable_options[:view_permission], self.project) + else + return true + end + + end + + def attachments_deletable?(user=User.current) + if (self.has_attribute?(:course) ||self.has_attribute?(:course_id)) && self.course + #默认给予删除自己上传的附件的权限 + (respond_to?(:visible?) ? visible?(user) : true) && + (user.allowed_to?(self.class.attachable_options[:delete_permission], self.course) || (self.has_attribute?(:author_id) && self.author == user)) + else + #默认给予删除自己上传的附件的权限 + (respond_to?(:visible?) ? visible?(user) : true) && + (user.allowed_to?(self.class.attachable_options[:delete_permission], self.project) || (self.has_attribute?(:author_id) && self.author == user)) + end + end + + def saved_attachments + @saved_attachments ||= [] + end + + def unsaved_attachments + @unsaved_attachments ||= [] + end + + # 设置资源文件的公开属性 + # add by nwb + def set_attachment_public(res) + # 公开的资源判断他的父级的公开属性 + if res.is_public + if( (self.class.to_s=="Project" && self.is_public == false) || + (self.has_attribute?(:project) && self.project && self.project.is_public == false) || + (self.has_attribute?(:board) && self.board.project && self.board.project.is_public == false) || + (self.class.to_s=="HomeworkAttach" && self.bid.reward_type == 3) || + (self.class.to_s=="Course" && self.is_public == false) || + (self.has_attribute?(:course) && self.course && self.course.is_public == false) || + (self.has_attribute?(:board) && self.board.course && self.board.course.is_public == false) + ) + res.is_public = false + end + end + end + + def save_attachmentsex(attachments, author=User.current,attachment_type) + @curattachment_type = attachment_type + result = save_attachments(attachments,author) + result + end + + def save_attachments(attachments, author=User.current) + # 清除临时文件 + if attachments + tempAttach = attachments[:dummy] + if tempAttach && tempAttach[:file] + attachments.delete(:dummy) + end + end + + if attachments.is_a?(Hash) + attachments = attachments.stringify_keys + attachments = attachments.to_a.sort {|a, b| + if a.first.to_i > 0 && b.first.to_i > 0 + a.first.to_i <=> b.first.to_i + elsif a.first.to_i > 0 + 1 + elsif b.first.to_i > 0 + -1 + else + a.first <=> b.first + end + } + attachments = attachments.map(&:last) + end + if attachments.is_a?(Array) + attachments.each do |attachment| + if attachment.is_a?(Hash) + a = nil + file = attachment['file'] + token = attachment['token'] + t = file && file.size > 0 + if file && file.size > 0 + a = Attachment.create(:file => file, :author => author) + elsif token + a = Attachment.find_by_token_only(token) + if a + a.filename = attachment['filename'] unless attachment['filename'].blank? + a.content_type = attachment['content_type'] + end + end + end + if a && !attachment['is_public_checkbox'] + a.is_public = false + elsif a && attachment['is_public_checkbox'] + a.is_public = true + end + set_attachment_public(a) if a + next unless a + a.description = attachment['description'].to_s.strip + a.attachtype = @curattachment_type + if a.new_record? + unsaved_attachments << a + else + saved_attachments << a + end + end + end + {:files => saved_attachments, :unsaved => unsaved_attachments} + end + + def attach_saved_attachments + saved_attachments.each do |attachment| + self.attachments << attachment + end + end + + module ClassMethods + end + end + end + end +end diff --git a/public/javascripts/attachments.js b/public/javascripts/attachments.js index 1504019d7..8ea71909b 100644 --- a/public/javascripts/attachments.js +++ b/public/javascripts/attachments.js @@ -1,233 +1,233 @@ -/* Redmine - project management software - Copyright (C) 2006-2013 Jean-Philippe Lang */ - -function postUpMsg(attachmentId) -{ - $.ajax({ - url: '/attachments/renderTag', - type: "GET", - data: { - attachmentId: attachmentId - } - - }) -} -function addFile(inputEl, file, eagerUpload) { - - if ($('#attachments_fields').children().length < 10) { - - var attachmentId = addFile.nextAttachmentId++; - - var fileSpan = $('', { 'id': 'attachments_' + attachmentId, 'class':'attachment' }); - - fileSpan.append( - $('', { 'type': 'text', 'class': 'filename readonly', 'name': 'attachments[' + attachmentId + '][filename]', 'readonly': 'readonly'} ).val(file.name), - $('', { 'type': 'text', 'class': 'description', 'name': 'attachments[' + attachmentId + '][description]', 'maxlength': 254, 'placeholder': $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload), - $('公开:').attr({ 'class': 'ispublic-label' }) , - $('', { 'type': 'checkbox', 'class': 'is_public_checkbox','value':1, 'name': 'attachments[' + attachmentId + '][is_public_checkbox]', checked:'checked' } ).toggle(!eagerUpload), - $(' ').attr({ 'href': "#", 'class': 'remove-upload', 'data-confirm' : "您确定要删除吗?" }).click(removeFile).toggle(!eagerUpload), - $('
    ', { 'class': 'div_attachments', 'name': 'div_'+'attachments_' + attachmentId} ) - ).appendTo('#attachments_fields'); - - if(eagerUpload) { - ajaxUpload(file, attachmentId, fileSpan, inputEl); - - } - return attachmentId; - } - return null; -} - -addFile.nextAttachmentId = 1; - -function ajaxUpload(file, attachmentId, fileSpan, inputEl) { - - function onLoadstart(e) { - fileSpan.removeClass('ajax-waiting'); - fileSpan.addClass('ajax-loading'); - $('input:submit', $(this).parents('form')).attr('disabled', 'disabled'); - } - - function onProgress(e) { - if(e.lengthComputable) { - this.progressbar( 'value', e.loaded * 100 / e.total ); - } - } - - function actualUpload(file, attachmentId, fileSpan, inputEl) { - - ajaxUpload.uploading++; - - uploadBlob(file, $(inputEl).data('upload-path'), attachmentId, { - loadstartEventHandler: onLoadstart.bind(progressSpan), - progressEventHandler: onProgress.bind(progressSpan) - }) - .done(function(result) { - progressSpan.progressbar( 'value', 100 ).remove(); - fileSpan.find('input.description, a').css('display', 'inline-block'); - fileSpan.find('input.is_public_checkbox, a').css('display', 'inline-block'); - }) - .fail(function(result) { - progressSpan.text(result.statusText); - if($("#network_issue")) - { - $("#network_issue").show(); - } - }).always(function() { - ajaxUpload.uploading--; - fileSpan.removeClass('ajax-loading'); - var form = fileSpan.parents('form'); - if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) { - $('input:submit', form).removeAttr('disabled'); - } - form.dequeue('upload'); - }); - - //gcm files count and add delete_all link - - var count=$('#attachments_fields>span').length; - $('#upload_file_count').html("已上传"+""+count+""+"个文件"); - - if(count>=1){ - var add_attachs=$('.add_attachment'); - var delete_all=$('.remove_all'); - if(delete_all.length<1){ - add_attachs.append($(" ").attr({"href":"javascript:void(0)", 'class': 'remove_all',"onclick": "removeAll()"})); - } - } - - //gcm - - } - - var progressSpan = $('
    ').insertAfter(fileSpan.find('input.filename')); - progressSpan.progressbar(); - fileSpan.addClass('ajax-waiting'); - - var maxSyncUpload = $(inputEl).data('max-concurrent-uploads'); - - if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload) - actualUpload(file, attachmentId, fileSpan, inputEl); - else - $(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl)); -} - -ajaxUpload.uploading = 0; - -function removeFile() { - $(this).parent('span').remove(); - return false; -} - -//gcm delete all file -function removeAll(){ - if(confirm("您确定要删除所有文件吗?")){ - $(".remove-upload").removeAttr("data-confirm"); - $(".remove-upload").click(); - } -// return false; -} -//gcm - -function uploadBlob(blob, uploadUrl, attachmentId, options) { - - var actualOptions = $.extend({ - loadstartEventHandler: $.noop, - progressEventHandler: $.noop - }, options); - - uploadUrl = uploadUrl + '?attachment_id=' + attachmentId; - if (blob instanceof window.File) { - uploadUrl += '&filename=' + encodeURIComponent(blob.name); - } - - return $.ajax(uploadUrl, { - type: 'POST', - contentType: 'application/octet-stream', - beforeSend: function(jqXhr) { - jqXhr.setRequestHeader('Accept', 'application/js'); - }, - xhr: function() { - var xhr = $.ajaxSettings.xhr(); - xhr.upload.onloadstart = actualOptions.loadstartEventHandler; - xhr.upload.onprogress = actualOptions.progressEventHandler; - return xhr; - }, - data: blob, - cache: false, - processData: false - }); -} - -function addInputFiles(inputEl) { - // var clearedFileInput = $(inputEl).clone().val(''); - - if (inputEl.files) { - // upload files using ajax - uploadAndAttachFiles(inputEl.files, inputEl); - // $(inputEl).remove(); - } else { - // browser not supporting the file API, upload on form submission - var attachmentId; - var aFilename = inputEl.value.split(/\/|\\/); - attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false); - if (attachmentId) { - $(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId); - } - } - - //clearedFileInput.insertAfter('#attachments_fields'); -} - -function uploadAndAttachFiles(files, inputEl) { - - var maxFileSize = $(inputEl).data('max-file-size'); - var maxFileSizeExceeded = $(inputEl).data('max-file-size-message'); - - var sizeExceeded = false; - $.each(files, function() { - if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;} - }); - if (sizeExceeded) { - window.alert(maxFileSizeExceeded); - } else { - $.each(files, function() {addFile(inputEl, this, true);}); - } -} - -function handleFileDropEvent(e) { - - $(this).removeClass('fileover'); - blockEventPropagation(e); - - if ($.inArray('Files', e.dataTransfer.types) > -1) { - uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector')); - } -} - -function dragOverHandler(e) { - $(this).addClass('fileover'); - blockEventPropagation(e); -} - -function dragOutHandler(e) { - $(this).removeClass('fileover'); - blockEventPropagation(e); -} - -function setupFileDrop() { - if (window.File && window.FileList && window.ProgressEvent && window.FormData) { - - $.event.fixHooks.drop = { props: [ 'dataTransfer' ] }; - - $('form div.box').has('input:file').each(function() { - $(this).on({ - dragover: dragOverHandler, - dragleave: dragOutHandler, - drop: handleFileDropEvent - }); - }); - } -} - -$(document).ready(setupFileDrop); +/* Redmine - project management software + Copyright (C) 2006-2013 Jean-Philippe Lang */ + +function postUpMsg(attachmentId) +{ + $.ajax({ + url: '/attachments/renderTag', + type: "GET", + data: { + attachmentId: attachmentId + } + + }) +} +function addFile(inputEl, file, eagerUpload) { + + if ($('#attachments_fields').children().length < 10) { + + var attachmentId = addFile.nextAttachmentId++; + + var fileSpan = $('', { 'id': 'attachments_' + attachmentId, 'class':'attachment' }); + + fileSpan.append( + $('', { 'type': 'text', 'class': 'filename readonly', 'name': 'attachments[' + attachmentId + '][filename]', 'readonly': 'readonly'} ).val(file.name), + $('', { 'type': 'text', 'class': 'description', 'name': 'attachments[' + attachmentId + '][description]', 'maxlength': 254, 'placeholder': $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload), + $('公开:').attr({ 'class': 'ispublic-label' }) , + $('', { 'type': 'checkbox', 'class': 'is_public_checkbox','value':1, 'name': 'attachments[' + attachmentId + '][is_public_checkbox]', checked:'checked' } ).toggle(!eagerUpload), + $(' ').attr({ 'href': "#", 'class': 'remove-upload', 'data-confirm' : "您确定要删除吗?" }).click(removeFile).toggle(!eagerUpload), + $('
    ', { 'class': 'div_attachments', 'name': 'div_'+'attachments_' + attachmentId} ) + ).appendTo('#attachments_fields'); + + if(eagerUpload) { + ajaxUpload(file, attachmentId, fileSpan, inputEl); + + } + return attachmentId; + } + return null; +} + +addFile.nextAttachmentId = 1; + +function ajaxUpload(file, attachmentId, fileSpan, inputEl) { + + function onLoadstart(e) { + fileSpan.removeClass('ajax-waiting'); + fileSpan.addClass('ajax-loading'); + $('input:submit', $(this).parents('form')).attr('disabled', 'disabled'); + } + + function onProgress(e) { + if(e.lengthComputable) { + this.progressbar( 'value', e.loaded * 100 / e.total ); + } + } + + function actualUpload(file, attachmentId, fileSpan, inputEl) { + + ajaxUpload.uploading++; + + uploadBlob(file, $(inputEl).data('upload-path'), attachmentId, { + loadstartEventHandler: onLoadstart.bind(progressSpan), + progressEventHandler: onProgress.bind(progressSpan) + }) + .done(function(result) { + progressSpan.progressbar( 'value', 100 ).remove(); + fileSpan.find('input.description, a').css('display', 'inline-block'); + fileSpan.find('input.is_public_checkbox, a').css('display', 'inline-block'); + }) + .fail(function(result) { + progressSpan.text(result.statusText); + if($("#network_issue")) + { + $("#network_issue").show(); + } + }).always(function() { + ajaxUpload.uploading--; + fileSpan.removeClass('ajax-loading'); + var form = fileSpan.parents('form'); + if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) { + $('input:submit', form).removeAttr('disabled'); + } + form.dequeue('upload'); + }); + + //gcm files count and add delete_all link + + var count=$('#attachments_fields>span').length; + $('#upload_file_count').html("已上传"+""+count+""+"个文件"); + + if(count>=1){ + var add_attachs=$('.add_attachment'); + var delete_all=$('.remove_all'); + if(delete_all.length<1){ + add_attachs.append($(" ").attr({"href":"javascript:void(0)", 'class': 'remove_all',"onclick": "removeAll()"})); + } + } + + //gcm + + } + + var progressSpan = $('
    ').insertAfter(fileSpan.find('input.filename')); + progressSpan.progressbar(); + fileSpan.addClass('ajax-waiting'); + + var maxSyncUpload = $(inputEl).data('max-concurrent-uploads'); + + if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload) + actualUpload(file, attachmentId, fileSpan, inputEl); + else + $(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl)); +} + +ajaxUpload.uploading = 0; + +function removeFile() { + $(this).parent('span').remove(); + return false; +} + +//gcm delete all file +function removeAll(){ + if(confirm("您确定要删除所有文件吗?")){ + $(".remove-upload").removeAttr("data-confirm"); + $(".remove-upload").click(); + } +// return false; +} +//gcm + +function uploadBlob(blob, uploadUrl, attachmentId, options) { + + var actualOptions = $.extend({ + loadstartEventHandler: $.noop, + progressEventHandler: $.noop + }, options); + + uploadUrl = uploadUrl + '?attachment_id=' + attachmentId; + if (blob instanceof window.File) { + uploadUrl += '&filename=' + encodeURIComponent(blob.name); + } + + return $.ajax(uploadUrl, { + type: 'POST', + contentType: 'application/octet-stream', + beforeSend: function(jqXhr) { + jqXhr.setRequestHeader('Accept', 'application/js'); + }, + xhr: function() { + var xhr = $.ajaxSettings.xhr(); + xhr.upload.onloadstart = actualOptions.loadstartEventHandler; + xhr.upload.onprogress = actualOptions.progressEventHandler; + return xhr; + }, + data: blob, + cache: false, + processData: false + }); +} + +function addInputFiles(inputEl) { + // var clearedFileInput = $(inputEl).clone().val(''); + + if (inputEl.files) { + // upload files using ajax + uploadAndAttachFiles(inputEl.files, inputEl); + // $(inputEl).remove(); + } else { + // browser not supporting the file API, upload on form submission + var attachmentId; + var aFilename = inputEl.value.split(/\/|\\/); + attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false); + if (attachmentId) { + $(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId); + } + } + + //clearedFileInput.insertAfter('#attachments_fields'); +} + +function uploadAndAttachFiles(files, inputEl) { + + var maxFileSize = $(inputEl).data('max-file-size'); + var maxFileSizeExceeded = $(inputEl).data('max-file-size-message'); + + var sizeExceeded = false; + $.each(files, function() { + if (this.size && maxFileSize != null && this.size > parseInt(maxFileSize)) {sizeExceeded=true;} + }); + if (sizeExceeded) { + window.alert(maxFileSizeExceeded); + } else { + $.each(files, function() {addFile(inputEl, this, true);}); + } +} + +function handleFileDropEvent(e) { + + $(this).removeClass('fileover'); + blockEventPropagation(e); + + if ($.inArray('Files', e.dataTransfer.types) > -1) { + uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector')); + } +} + +function dragOverHandler(e) { + $(this).addClass('fileover'); + blockEventPropagation(e); +} + +function dragOutHandler(e) { + $(this).removeClass('fileover'); + blockEventPropagation(e); +} + +function setupFileDrop() { + if (window.File && window.FileList && window.ProgressEvent && window.FormData) { + + $.event.fixHooks.drop = { props: [ 'dataTransfer' ] }; + + $('form div.box').has('input:file').each(function() { + $(this).on({ + dragover: dragOverHandler, + dragleave: dragOutHandler, + drop: handleFileDropEvent + }); + }); + } +} + +$(document).ready(setupFileDrop);