From f01d164295ea186cf827a4e551baed20b9b0ed61 Mon Sep 17 00:00:00 2001 From: alan <547533434@qq.com> Date: Wed, 21 Jan 2015 12:01:02 +0800 Subject: [PATCH 1/8] Signed-off-by: alan <547533434@qq.com> --- app/helpers/courses_helper.rb | 2 +- app/models/mailer.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb index 95b049dc2..22eb9bfae 100644 --- a/app/helpers/courses_helper.rb +++ b/app/helpers/courses_helper.rb @@ -112,7 +112,7 @@ module CoursesHelper # end #获取课程所有成员 - def course_member course + def course_all_member course course.members end # 学生人数计算 diff --git a/app/models/mailer.rb b/app/models/mailer.rb index a2e742ee3..2cd069175 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -62,7 +62,7 @@ class Mailer < ActionMailer::Base course = journals_for_message.jour @author = journals_for_message.user #课程的教师 - @members = course_member journals_for_message.jour + @members = course_all_member journals_for_message.jour #收件人邮箱 @recipients ||= [] @members.each do |teacher| From 54c8ee9d4d29ab264c3baa3deebd345ca0aabe3a Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Wed, 21 Jan 2015 17:51:12 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=A6=E7=94=9F?= =?UTF-8?q?=E7=AD=94=E5=AE=8C=E9=97=AE=E5=8D=B7=E4=B9=8B=E5=90=8E=E3=80=82?= =?UTF-8?q?=E8=83=BD=E7=9C=8B=E5=88=B0=E8=87=AA=E5=B7=B1=E7=AD=94=E9=A2=98?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/poll_controller.rb | 12 +++++-- app/helpers/poll_helper.rb | 2 +- app/views/poll/_poll.html.erb | 11 +++---- app/views/poll/_show_MCQ_result.html.erb | 26 +++++++++++++++ app/views/poll/_show_MC_result.html.erb | 27 ++++++++++++++++ app/views/poll/_show_mulit_result.html.erb | 20 ++++++++++++ app/views/poll/_show_single_result.html.erb | 18 +++++++++++ app/views/poll/poll_result.html.erb | 36 +++++++++++++++++++++ config/routes.rb | 1 + 9 files changed, 144 insertions(+), 9 deletions(-) create mode 100644 app/views/poll/_show_MCQ_result.html.erb create mode 100644 app/views/poll/_show_MC_result.html.erb create mode 100644 app/views/poll/_show_mulit_result.html.erb create mode 100644 app/views/poll/_show_single_result.html.erb create mode 100644 app/views/poll/poll_result.html.erb diff --git a/app/controllers/poll_controller.rb b/app/controllers/poll_controller.rb index 42ab98e10..4abddaa5e 100644 --- a/app/controllers/poll_controller.rb +++ b/app/controllers/poll_controller.rb @@ -1,7 +1,7 @@ class PollController < ApplicationController - before_filter :find_poll_and_course, :only => [:edit,:update,:destroy,:show,:statistics_result,:create_poll_question,:commit_poll,:commit_answer,:publish_poll,:republish_poll] + before_filter :find_poll_and_course, :only => [:edit,:update,:destroy,:show,:statistics_result,:create_poll_question,:commit_poll,:commit_answer,:publish_poll,:republish_poll,:poll_result] before_filter :find_container, :only => [:new,:create, :index] - before_filter :is_member_of_course, :only => [:index,:show] + before_filter :is_member_of_course, :only => [:index,:show,:poll_result] before_filter :is_course_teacher, :only => [:new,:create,:edit,:update,:destroy,:publish_poll,:republish_poll] include PollHelper def index @@ -330,6 +330,14 @@ class PollController < ApplicationController end end + #显示某个学生某份问卷的填写结果 + def poll_result + @poll_questions = paginateHelper @poll.poll_questions,5 + respond_to do |format| + format.html{render :layout => 'base_courses'} + end + end + private def find_poll_and_course @poll = Poll.find params[:id] diff --git a/app/helpers/poll_helper.rb b/app/helpers/poll_helper.rb index 17ef02a36..60d82c096 100644 --- a/app/helpers/poll_helper.rb +++ b/app/helpers/poll_helper.rb @@ -73,5 +73,5 @@ module PollHelper "多行主观题" end end - + end \ No newline at end of file diff --git a/app/views/poll/_poll.html.erb b/app/views/poll/_poll.html.erb index 3290ff2dc..c53f09361 100644 --- a/app/views/poll/_poll.html.erb +++ b/app/views/poll/_poll.html.erb @@ -1,20 +1,19 @@ <% has_commit = has_commit_poll?(poll.id ,User.current)%> +<% poll_name = poll.polls_name.empty? ? l(:label_poll_new) : poll.polls_name%>
  • <% if @is_teacher %> <% if has_commit %> - <%= poll.polls_name.empty? ? l(:label_poll_new) : poll.polls_name%> + <%= link_to poll_name, poll_result_poll_path(poll.id), :class => "polls_title polls_title_w fl", :style => "max-width: 550px;width: 550px;" %> <% else %> - <%= link_to (poll.polls_name.empty? ? l(:label_poll_new) : poll.polls_name), poll_path(poll.id), :class => "polls_title polls_title_w fl" %> + <%= link_to poll_name, poll_path(poll.id), :class => "polls_title polls_title_w fl" %> <% end %> <% else %> <% if has_commit && poll.polls_status == 2 %> - - <%= poll.polls_name.empty? ? l(:label_poll_new) : poll.polls_name %> - + <%= link_to poll_name, poll_result_poll_path(poll.id), :class => "polls_title polls_title_w fl", :style => "max-width: 500px;width: auto;" %> <% elsif !has_commit && poll.polls_status == 2 %> - <%= link_to (poll.polls_name.empty? ? l(:label_poll_new) : poll.polls_name), poll_path(poll.id), :class => "polls_title polls_title_w fl", :style => "max-width: 550px;width: 550px;" %> + <%= link_to poll_name, poll_path(poll.id), :class => "polls_title polls_title_w fl", :style => "max-width: 550px;width: 550px;" %> <% end %> <% end %>
  • diff --git a/app/views/poll/_show_MCQ_result.html.erb b/app/views/poll/_show_MCQ_result.html.erb new file mode 100644 index 000000000..f46882881 --- /dev/null +++ b/app/views/poll/_show_MCQ_result.html.erb @@ -0,0 +1,26 @@ +
  • +
    + + 第<%= poll_question.question_number%>题: + + <%= poll_question.question_title %> + [多选题] + <%if poll_question.is_necessary == 1%> + * + <%end%> +
    +
    +
    + + + <% poll_question.poll_votes.where("user_id = #{User.current.id}").each do |answer|%> + + + + <% end%> + +
    + <%= answer.poll_answer.answer_text %> +
    +
    +
  • \ No newline at end of file diff --git a/app/views/poll/_show_MC_result.html.erb b/app/views/poll/_show_MC_result.html.erb new file mode 100644 index 000000000..7f2cbbd83 --- /dev/null +++ b/app/views/poll/_show_MC_result.html.erb @@ -0,0 +1,27 @@ +
  • +
    + + 第<%= poll_question.question_number%>题: + + <%= poll_question.question_title %> + [单选题] + <%if poll_question.is_necessary == 1%> + * + <%end%> +
    +
    +
    + + + <% poll_question.poll_votes.where("user_id = #{User.current.id}").each do |answer|%> + + + + <% end%> + + +
    + <%= answer.poll_answer.answer_text %> +
    +
    +
  • \ No newline at end of file diff --git a/app/views/poll/_show_mulit_result.html.erb b/app/views/poll/_show_mulit_result.html.erb new file mode 100644 index 000000000..e54cca505 --- /dev/null +++ b/app/views/poll/_show_mulit_result.html.erb @@ -0,0 +1,20 @@ +
  • +
    +
    + + 第<%= poll_question.question_number%>题: + + <%= poll_question.question_title %> + [多行主观] + <%if poll_question.is_necessary == 1%> + * + <%end%> +
    +
    +
    +

    + <%= get_anwser_vote_text poll_question.id,User.current.id%> +

    +
    +
    +
  • \ No newline at end of file diff --git a/app/views/poll/_show_single_result.html.erb b/app/views/poll/_show_single_result.html.erb new file mode 100644 index 000000000..07559773d --- /dev/null +++ b/app/views/poll/_show_single_result.html.erb @@ -0,0 +1,18 @@ +
  • +
    + + 第<%= poll_question.question_number%>题: + + <%= poll_question.question_title %> + [单行主观] + <%if poll_question.is_necessary == 1%> + * + <%end%> +
    +
    +
    +

    + <%= get_anwser_vote_text poll_question.id,User.current.id%> +

    +
    +
  • \ No newline at end of file diff --git a/app/views/poll/poll_result.html.erb b/app/views/poll/poll_result.html.erb new file mode 100644 index 000000000..a7cb415b3 --- /dev/null +++ b/app/views/poll/poll_result.html.erb @@ -0,0 +1,36 @@ +<%= stylesheet_link_tag 'polls', :media => 'all' %> +
    +
    +

    + <%= @poll.polls_name.empty? ? l(:label_poll_new) : @poll.polls_name %> +

    +

    + <%= @poll.polls_description%> +

    +
    +
    +
      + <% @poll_questions.each do |poll_question|%> + <% if poll_question.question_type == 1%> + <%= render :partial => 'show_MC_result', :locals => {:poll_question => poll_question} %> + <% elsif poll_question.question_type == 2%> + <%= render :partial => 'show_MCQ_result', :locals => {:poll_question => poll_question} %> + <% elsif poll_question.question_type == 3%> + <%= render :partial => 'show_single_result', :locals => {:poll_question => poll_question} %> + <% elsif poll_question.question_type == 4%> + <%= render :partial => 'show_mulit_result', :locals => {:poll_question => poll_question} %> + <% end%> + <% end%> +
    +
    +
    + + +
    + +
    +
    +
    + diff --git a/config/routes.rb b/config/routes.rb index 67b0118b0..524373378 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -66,6 +66,7 @@ RedmineApp::Application.routes.draw do post 'commit_poll' get 'publish_poll' get 'republish_poll' + get 'poll_result' end collection do delete 'delete_poll_question' From e72ed1054e8fc36119eb3ccca726e4f7643375f5 Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Thu, 22 Jan 2015 09:39:04 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=97=AE=E5=8D=B7?= =?UTF-8?q?=E8=B0=83=E6=9F=A5=E6=8C=89=E9=92=AE=E7=9A=84=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/layouts/base_courses.html.erb | 17 +++++++++++++---- public/stylesheets/polls.css | 6 +++--- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/views/layouts/base_courses.html.erb b/app/views/layouts/base_courses.html.erb index f0204f7ee..466e711c2 100644 --- a/app/views/layouts/base_courses.html.erb +++ b/app/views/layouts/base_courses.html.erb @@ -300,13 +300,22 @@
    +
    - <%= link_to l(:label_poll), poll_index_path(:polls_type => "Course", :polls_group_id => @course.id)%> +
    +

    N

    +
    +
    diff --git a/public/stylesheets/polls.css b/public/stylesheets/polls.css index e601d231d..863ee5864 100644 --- a/public/stylesheets/polls.css +++ b/public/stylesheets/polls.css @@ -14,9 +14,9 @@ div,html,img,ul,li,p,body,h1,h2,h3,h4,p,a,table,tr,td,fieldset,input,span{ margi #polls .fr{ float:right;} /*问卷按钮*/ -.polls_btn{ height:33px;border-top:1px solid #15bed1; border-bottom:1px solid #15bed1;border-right:1px solid #cee6e6; width:225px; padding:7px 0 0 15px; } -.polls_btn a{font-size:14px; color:#444444;font-weight:bold;} -.polls_btn span{ color:#15bed1; font-size:12px; font-weight:normal;} +/*.polls_btn{ height:33px;border-top:1px solid #15bed1; border-bottom:1px solid #15bed1;border-right:1px solid #cee6e6; width:225px; padding:7px 0 0 15px; }*/ +/*.polls_btn a{font-size:14px; color:#444444;font-weight:bold;}*/ +/*.polls_btn span{ color:#15bed1; font-size:12px; font-weight:normal;}*/ /*问卷列表*/ .polls_content{ width:615px;padding-left: 6px;} From 683625066ea24bde979ff44705024dd424634d79 Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Thu, 22 Jan 2015 15:16:15 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=E6=9C=AA=E6=89=B9=E5=88=97=E8=A1=A8=E4=BF=AE=E6=94=B9=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E5=90=8E=EF=BC=8C=E8=80=81=E5=B8=88=E8=BF=9B=E8=A1=8C?= =?UTF-8?q?=E8=AF=84=E5=88=86=E4=B9=8B=E5=90=8E=E6=8E=92=E5=BA=8F=E4=BC=9A?= =?UTF-8?q?=E5=9B=9E=E5=88=B0=E9=BB=98=E8=AE=A4=E6=8E=92=E5=BA=8F=E9=A2=9D?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/homework_attach_controller.rb | 5 +++-- app/views/homework_attach/_addjour.html.erb | 2 +- app/views/homework_attach/_homework.html.erb | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/controllers/homework_attach_controller.rb b/app/controllers/homework_attach_controller.rb index 8b9bf9099..8e69d1d72 100644 --- a/app/controllers/homework_attach_controller.rb +++ b/app/controllers/homework_attach_controller.rb @@ -26,6 +26,7 @@ class HomeworkAttachController < ApplicationController get_not_batch_homework_list sort,direction, @bid.id @cur_page = params[:page] || 1 @cur_type = 1 + @cur_sort,@cur_direction = params[:sort] || "s_socre", params[:direction] || "desc" @direction = direction == 'asc'? 'desc' : 'asc' respond_to do |format| format.js @@ -433,7 +434,7 @@ class HomeworkAttachController < ApplicationController #添加留言 def addjours @is_teacher,@is_anonymous_comments,@m_score = params[:is_teacher]=="true",params[:is_anonymous_comments]=="true",params[:stars_value] - @cur_page,@cur_type = params[:cur_page] || 1,params[:cur_type] || 5 + @cur_page,@cur_type = params[:page] || 1,params[:cur_type] || 5 @homework = HomeworkAttach.find(params[:homework_id]) @stars_reates = @homework.rates(:quality) homework = @homework @@ -479,7 +480,7 @@ class HomeworkAttachController < ApplicationController if @cur_type == "1" #如果当前是老师未批列表,需要刷新整个作业列表界面 @bid = @homework.bid - get_not_batch_homework_list "s_socre","desc",@homework.bid_id + get_not_batch_homework_list params[:cur_sort] || "s_socre",params[:cur_direction] || "desc",@homework.bid_id elsif @cur_type == "2" #老师已批列表 @result_homework = HomeworkAttach.find_by_sql("SELECT homework_attaches.*, (SELECT stars FROM seems_rateable_rates WHERE rateable_type = 'HomeworkAttach' AND rateable_id = homework_attaches.id AND is_teacher_score = 1 AND stars IS NOT NULL ORDER BY updated_at DESC limit 0,1) AS t_score, diff --git a/app/views/homework_attach/_addjour.html.erb b/app/views/homework_attach/_addjour.html.erb index 48beebdf8..78514daca 100644 --- a/app/views/homework_attach/_addjour.html.erb +++ b/app/views/homework_attach/_addjour.html.erb @@ -31,7 +31,7 @@ :url => {:controller => 'homework_attach', :action => 'addjours', :homework_id => homework_attach.id, - :cur_page => cur_page, + :page => cur_page, :cur_type => cur_type, :is_anonymous_comments => @is_anonymous_comments, :is_teacher => @is_teacher diff --git a/app/views/homework_attach/_homework.html.erb b/app/views/homework_attach/_homework.html.erb index c2b87832c..fca25e8ee 100644 --- a/app/views/homework_attach/_homework.html.erb +++ b/app/views/homework_attach/_homework.html.erb @@ -19,7 +19,7 @@ <% else %> <% homework_filename = homework.name %> <% end %> - <%= link_to homework_filename , homework_attach_path(homework,:cur_page => @cur_page,:cur_type => @cur_type), :title => homework_filename, :remote => true%> + <%= link_to homework_filename , homework_attach_path(homework,:cur_page => @cur_page,:cur_type => @cur_type,:cur_sort => @cur_sort, :cur_direction => @cur_direction), :title => homework_filename, :remote => true%> 提交时间: <%= format_time homework.created_at%> @@ -46,7 +46,7 @@ <% if is_teacher %>
  • - <%= link_to l(:label_work_rating),homework_attach_path(homework,:cur_page => @cur_page,:cur_type => @cur_type),:remote => true %> + <%= link_to l(:label_work_rating),homework_attach_path(homework,:cur_page => @cur_page,:cur_type => @cur_type,:cur_sort => @cur_sort, :cur_direction => @cur_direction),:remote => true %> <% if Time.parse(bid.deadline.to_s).strftime("%Y-%m-%d") < Time.parse(homework.created_at.to_s).strftime("%Y-%m-%d") %>   迟交! <% end %> From 432e3a05f2be310b92d0577a37d36e8d707ddafd Mon Sep 17 00:00:00 2001 From: alan <547533434@qq.com> Date: Thu, 22 Jan 2015 16:30:21 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=B4=B4=E5=90=A7?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=EF=BC=8C=E5=8F=91=E5=B8=96=E6=97=B6=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=82=AE=E4=BB=B6=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E3=80=8A=E9=82=AE=E4=BB=B6=E9=87=8D=E5=8F=91=E5=A4=9A?= =?UTF-8?q?=E6=AC=A1=E3=80=8Bbug=20Signed-off-by:=20alan=20<547533434@qq.c?= =?UTF-8?q?om>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/forums_controller.rb | 13 +- app/models/forum.rb | 7 +- app/models/forum_observer.rb | 8 ++ app/models/mailer.rb | 130 ++++++++++++++---- app/models/memo.rb | 8 +- app/models/memo_observer.rb | 8 ++ app/models/project.rb | 2 +- app/views/mailer/forum_add.html.erb | 4 + app/views/mailer/forum_add.text.erb | 4 + app/views/mailer/forum_message_added.html.erb | 4 + app/views/mailer/forum_message_added.text.erb | 5 + app/views/mailer/message_posted.html.erb | 8 +- config/locales/en.yml | 2 + config/locales/zh.yml | 2 + lib/redmine/notifiable.rb | 2 + spec/models/forum_observer_spec.rb | 5 + spec/models/memo_observer_spec.rb | 5 + 17 files changed, 178 insertions(+), 39 deletions(-) create mode 100644 app/models/forum_observer.rb create mode 100644 app/models/memo_observer.rb create mode 100644 app/views/mailer/forum_add.html.erb create mode 100644 app/views/mailer/forum_add.text.erb create mode 100644 app/views/mailer/forum_message_added.html.erb create mode 100644 app/views/mailer/forum_message_added.text.erb create mode 100644 spec/models/forum_observer_spec.rb create mode 100644 spec/models/memo_observer_spec.rb diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb index 03d1454ef..54b8c6305 100644 --- a/app/controllers/forums_controller.rb +++ b/app/controllers/forums_controller.rb @@ -160,12 +160,15 @@ class ForumsController < ApplicationController def create @forum = Forum.new(params[:forum]) @forum.creator_id = User.current.id + if @forum.save + respond_to do |format| - respond_to do |format| - if @forum.save - format.html { redirect_to @forum, notice: l(:label_forum_create_succ) } - format.json { render json: @forum, status: :created, location: @forum } - else + format.html { redirect_to @forum, notice: l(:label_forum_create_succ) } + format.json { render json: @forum, status: :created, location: @forum } + end + + else + respond_to do |format| flash.now[:error] = "#{l :label_forum_create_fail}: #{@forum.errors.full_messages[0]}" format.html { render action: "new" } format.json { render json: @forum.errors, status: :unprocessable_entity } diff --git a/app/models/forum.rb b/app/models/forum.rb index 61ba528a0..eb8bb19d2 100644 --- a/app/models/forum.rb +++ b/app/models/forum.rb @@ -18,7 +18,7 @@ class Forum < ActiveRecord::Base acts_as_taggable scope :by_join_date, order("created_at DESC") - + after_create :send_email def reset_counters! self.class.reset_counters!(id) end @@ -33,6 +33,11 @@ class Forum < ActiveRecord::Base self.creator == user || user.admin? end + def send_email + Thread.start do + Mailer.forum_add(self).deliver if Setting.notified_events.include?('forum_add') + end + end # Updates topic_count, memo_count and last_memo_id attributes for +board_id+ def self.reset_counters!(forum_id) forum_id = forum_id.to_i diff --git a/app/models/forum_observer.rb b/app/models/forum_observer.rb new file mode 100644 index 000000000..1c514d6ab --- /dev/null +++ b/app/models/forum_observer.rb @@ -0,0 +1,8 @@ +class ForumObserver < ActiveRecord::Observer + def after_create(forum) + Thread.start do + Mailer.forum_add(forum).deliver if Setting.notified_events.include?('forum_add') + end + + end +end diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 2cd069175..02684a187 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -26,7 +26,37 @@ class Mailer < ActionMailer::Base def self.default_url_options { :host => Setting.host_name, :protocol => Setting.protocol } end - + + # 贴吧新建贴吧发送邮件 + # example Mailer.forum(forum).deliver + def forum_add(forum) + + redmine_headers 'Forum' => forum.id + @forum = forum + @author = forum.creator + recipients = forum.creator.mail + # cc = wiki_content.page.wiki.watcher_recipients - recipients + + @forum_url = url_for(:controller => 'forums', :action => 'show', :id => forum.id) + mail :to => recipients,:subject => "[ #{l(:label_forum)} : #{forum.name} #{l(:notice_successful_create)}]" + + end + + def forum_message_added(memo) + @memo = memo + redmine_headers 'Memo' => memo.id + @forum = memo.forum + @author = memo.author + recipients ||= [] + mems = memo.self_and_siblings + mems.each do |mem| + recipients << mem.author.mail unless recipients.include? mem.author.mail + end + # cc = wiki_content.page.wiki.watcher_recipients - recipients + + @memo_url = url_for(forum_memo_url(@forum, (@memo.parent_id.nil? ? @memo : @memo.parent_id))) + mail :to => recipients,:subject => "[ #{l(:label_message_plural)} : #{memo.subject} #{l(:label_memo_create_succ)}]" + end # Builds a Mail::Message object used to email recipients of the added journals for message. # 留言分为直接留言,和对留言人留言的回复 @@ -282,7 +312,7 @@ class Mailer < ActionMailer::Base recipients = container.notified_users.select { |user| user.allowed_to?(:view_files, container) }.collect { |u| u.mail } when 'Course' added_to_url = url_for(:controller => 'files', :action => 'index', :course_id => container) - added_to = "#{l(:label_course)}: #{container}" + added_to = "#{l(:label_course)}: #{container.name}" recipients = container.notified_users.select { |user| user.allowed_to?(:view_files, container) }.collect { |u| u.mail } when 'Version' added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project) @@ -323,13 +353,25 @@ class Mailer < ActionMailer::Base # news_added(news) => Mail::Message object # Mailer.news_added(news).deliver => sends an email to the news' project recipients def news_added(news) - redmine_headers 'Project' => news.project.identifier - @author = news.author - message_id news - @news = news - @news_url = url_for(:controller => 'news', :action => 'show', :id => news) - mail :to => news.recipients, - :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}" + + if news.project + redmine_headers 'Project' => news.project.identifier + @author = news.author + message_id news + @news = news + @news_url = url_for(:controller => 'news', :action => 'show', :id => news) + mail :to => news.recipients, + :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}" + elsif news.course + redmine_headers 'Course' => news.course.id + @author = news.author + message_id news + @news = news + recipients = news.course.notified_users.select { |user| user.allowed_to?(:view_files, news.course) }.collect { |u| u.mail } + @news_url = url_for(:controller => 'news', :action => 'show', :id => news) + mail :to => recipients, + :subject => "[#{news.course.name}] #{l(:label_news)}: #{news.title}" + end end # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added. @@ -339,15 +381,28 @@ class Mailer < ActionMailer::Base # Mailer.news_comment_added(comment) => sends an email to the news' project recipients def news_comment_added(comment) news = comment.commented - redmine_headers 'Project' => news.project.identifier - @author = comment.author - message_id comment - @news = news - @comment = comment - @news_url = url_for(:controller => 'news', :action => 'show', :id => news) - mail :to => news.recipients, - :cc => news.watcher_recipients, - :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}" + if news.project + redmine_headers 'Project' => news.project.identifier + @author = comment.author + message_id comment + @news = news + @comment = comment + @news_url = url_for(:controller => 'news', :action => 'show', :id => news) + mail :to => news.recipients, + :cc => news.watcher_recipients, + :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}" + elsif news.course + redmine_headers 'Course' => news.course.id + @author = comment.author + message_id comment + @news = news + @comment = comment + @news_url = url_for(:controller => 'news', :action => 'show', :id => news) + recipients = news.course.notified_users.select { |user| user.allowed_to?(:view_files, news.course) }.collect { |u| u.mail } + + mail :to => recipients, + :subject => "[#{news.course.name}] #{l(:label_news)}: #{news.title}" + end end # Builds a Mail::Message object used to email the recipients of the specified message that was posted. @@ -356,18 +411,33 @@ class Mailer < ActionMailer::Base # message_posted(message) => Mail::Message object # Mailer.message_posted(message).deliver => sends an email to the recipients def message_posted(message) - redmine_headers 'Project' => message.project.identifier, - 'Topic-Id' => (message.parent_id || message.id) - @author = message.author - message_id message - references message.parent unless message.parent.nil? - recipients = message.recipients - cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients) - @message = message - @message_url = url_for(message.event_url) - mail :to => recipients, - :cc => cc, - :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}" + if message.project + redmine_headers 'Project' => message.project.identifier, + 'Topic-Id' => (message.parent_id || message.id) + @author = message.author + message_id message + references message.parent unless message.parent.nil? + recipients = message.recipients + cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients) + @message = message + @message_url = url_for(message.event_url) + mail :to => recipients, + :cc => cc, + :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}" + elsif message.course + redmine_headers 'Course' => message.course.id, + 'Topic-Id' => (message.parent_id || message.id) + @author = message.author + message_id message + references message.parent unless message.parent.nil? + recipients = message.course.notified_users.select { |user| user.allowed_to?(:view_files, message.course) }.collect { |u| u.mail } + cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients) + @message = message + @message_url = url_for(message.event_url) + mail :to => recipients, + :cc => cc, + :subject => "[#{message.board.course.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}" + end end # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added. diff --git a/app/models/memo.rb b/app/models/memo.rb index cfc509923..f9482911a 100644 --- a/app/models/memo.rb +++ b/app/models/memo.rb @@ -43,7 +43,7 @@ class Memo < ActiveRecord::Base "parent_id", "replies_count" - after_create :add_author_as_watcher, :reset_counters!#,:be_user_score -- 公共区发帖暂不计入得分 + after_create :add_author_as_watcher, :reset_counters!, :sendmail#,:be_user_score -- 公共区发帖暂不计入得分 # after_update :update_memos_forum after_destroy :reset_counters!#,:down_user_score -- 公共区发帖暂不计入得分 # after_create :send_notification @@ -54,6 +54,12 @@ class Memo < ActiveRecord::Base # includes(:forum => ).where() # } + def sendmail + thread1=Thread.new do + Mailer.forum_message_added(self).deliver if Setting.notified_events.include?('forum_message_added') + end + end + def cannot_reply_to_locked_topic errors.add :base, l(:label_memo_locked) if root.locked? && self != root end diff --git a/app/models/memo_observer.rb b/app/models/memo_observer.rb new file mode 100644 index 000000000..66cabe923 --- /dev/null +++ b/app/models/memo_observer.rb @@ -0,0 +1,8 @@ +class MemoObserver < ActiveRecord::Observer + def after_create(memo) + + thread1=Thread.new do + Mailer.forum_message_added(memo).deliver if Setting.notified_events.include?('forum_message_added') + end + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 14763347f..01e6cd91c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -600,7 +600,7 @@ class Project < ActiveRecord::Base # Returns the users that should be notified on project events def notified_users # TODO: User part should be extracted to User#notify_about? - members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal} + members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all' || m.principal.mail_notification == 'only_my_events' ||m.principal.mail_notification == 'selected')}.collect {|m| m.principal} end # Returns an array of all custom fields enabled for project issues diff --git a/app/views/mailer/forum_add.html.erb b/app/views/mailer/forum_add.html.erb new file mode 100644 index 000000000..8da8b7891 --- /dev/null +++ b/app/views/mailer/forum_add.html.erb @@ -0,0 +1,4 @@ +

    <%= link_to(h(@forum.name), @forum_url) %>

    +<%=h @forum.creator.name %> + +<%= @forum.description.html_safe %> \ No newline at end of file diff --git a/app/views/mailer/forum_add.text.erb b/app/views/mailer/forum_add.text.erb new file mode 100644 index 000000000..ba7246a49 --- /dev/null +++ b/app/views/mailer/forum_add.text.erb @@ -0,0 +1,4 @@ +<%= @forum_url %> +<%= @author.name %> + +<%= @forum.description %> diff --git a/app/views/mailer/forum_message_added.html.erb b/app/views/mailer/forum_message_added.html.erb new file mode 100644 index 000000000..743c06ae7 --- /dev/null +++ b/app/views/mailer/forum_message_added.html.erb @@ -0,0 +1,4 @@ +

    <%= link_to(h(@memo.subject), @memo_url) %>

    +<%=h @memo.author.name %> + +<%= @memo.content.html_safe %> \ No newline at end of file diff --git a/app/views/mailer/forum_message_added.text.erb b/app/views/mailer/forum_message_added.text.erb new file mode 100644 index 000000000..bd084cd40 --- /dev/null +++ b/app/views/mailer/forum_message_added.text.erb @@ -0,0 +1,5 @@ +<%= @memo_url %> +<%= @author.name %> + +<%= @memo.subject %> +<%= @memo.content %> diff --git a/app/views/mailer/message_posted.html.erb b/app/views/mailer/message_posted.html.erb index f43a8cf0f..4bb487405 100644 --- a/app/views/mailer/message_posted.html.erb +++ b/app/views/mailer/message_posted.html.erb @@ -1,4 +1,10 @@ -

    <%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %>

    +

    + <% if @message.project %> + <%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %> + <% elsif @message.course %> + <%=h @message.board.course.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %> + <% end %> +

    <%=h @message.author %> <%= textilizable(@message, :content, :only_path => false) %> diff --git a/config/locales/en.yml b/config/locales/en.yml index d25ba6ae2..ab248a062 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -568,6 +568,8 @@ en: label_document_new: New document label_document_plural: Documents label_document_added: Document added + label_forum_message_added: Message added + label_forum_add: Forum added label_document_public_info: "If you don't choose public, only the project's members can see the document." label_role: Role label_role_plural: Roles diff --git a/config/locales/zh.yml b/config/locales/zh.yml index bd6c6dc22..815dd6fa1 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -581,6 +581,8 @@ zh: label_document_new: 新建文档 label_document_plural: 文档 label_document_added: 文档已添加 + label_forum_message_added: 发帖成功 + label_forum_add: 贴吧创建成功 label_document_public_info: (打钩为公开,不打钩则不公开,若不公开,仅项目成员可见该文档。) label_role: 角色 label_role_plural: 角色 diff --git a/lib/redmine/notifiable.rb b/lib/redmine/notifiable.rb index 88ca9d776..42a81980f 100644 --- a/lib/redmine/notifiable.rb +++ b/lib/redmine/notifiable.rb @@ -20,6 +20,8 @@ module Redmine notifications << Notifiable.new('message_posted') notifications << Notifiable.new('wiki_content_added') notifications << Notifiable.new('wiki_content_updated') + notifications << Notifiable.new('forum_add') + notifications << Notifiable.new('forum_message_added', 'forum_add') notifications end end diff --git a/spec/models/forum_observer_spec.rb b/spec/models/forum_observer_spec.rb new file mode 100644 index 000000000..76d68fafa --- /dev/null +++ b/spec/models/forum_observer_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe ForumObserver do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/memo_observer_spec.rb b/spec/models/memo_observer_spec.rb new file mode 100644 index 000000000..82603ba7a --- /dev/null +++ b/spec/models/memo_observer_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe MemoObserver do + pending "add some examples to (or delete) #{__FILE__}" +end From 90a81ee1f17d204bf5afc9da8d4c7bc3c102cf21 Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Thu, 22 Jan 2015 17:03:01 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BD=91=E7=AB=99?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=A6=96=E9=A1=B5=E5=8A=A0=E5=85=A5=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/projects_controller.rb | 10 ++- app/views/projects/_join_project.html.erb | 83 +++++++++++++++++++++++ app/views/projects/join_project.js.erb | 9 +++ app/views/welcome/index.html.erb | 3 + config/locales/zh.yml | 1 + config/routes.rb | 4 ++ 6 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 app/views/projects/_join_project.html.erb create mode 100644 app/views/projects/join_project.js.erb diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 24a3ff19f..a2e793a10 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -35,7 +35,7 @@ class ProjectsController < ApplicationController # edit before_filter :authorize1, :only => [:show] # - before_filter :find_project, :except => [ :index, :search,:list, :new, :create, :copy, :statistics, :new_join, :course, :enterprise_course, :course_enterprise,:view_homework_attaches] + before_filter :find_project, :except => [ :index, :search,:list, :new, :create, :copy, :statistics, :new_join, :course, :enterprise_course, :course_enterprise,:view_homework_attaches,:join_project] # before_filter :authorize, :except => [:new_join, :new_homework, :homework, :statistics, :search, :watcherlist, :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy, :member, :focus, :file, # :statistics, :feedback, :course, :enterprise_course, :course_enterprise, :project_respond, :share, # :show_projects_score, :issue_score_index, :news_score_index, :file_score_index, :code_submit_score_index, :projects_topic_score_index] @@ -917,6 +917,14 @@ class ProjectsController < ApplicationController end end end + + #加入私有项目 + def join_project + respond_to do |format| + format.js + end + end + private def memberAccess diff --git a/app/views/projects/_join_project.html.erb b/app/views/projects/_join_project.html.erb new file mode 100644 index 000000000..c7ce29dae --- /dev/null +++ b/app/views/projects/_join_project.html.erb @@ -0,0 +1,83 @@ + + + + + 快速进入项目通道 + + + + + +
    +
    +
    +

    快速进入项目通道

    +

    只要持有项目的ID,就可快速申请加入所在项目。项目页面搜索不到的私有项目只能从此通道进入哦!

    +
    +
    + <%= form_tag({:controller => 'applied_project', + :action => 'applied_join_project'}, + :remote => true, + :method => :post, + :id => 'new-watcher-form') do %> + + <% end%> +
    +
    +
    + + + diff --git a/app/views/projects/join_project.js.erb b/app/views/projects/join_project.js.erb new file mode 100644 index 000000000..f3bdfb50a --- /dev/null +++ b/app/views/projects/join_project.js.erb @@ -0,0 +1,9 @@ +$('#ajax-modal').html('<%= escape_javascript(render :partial => 'projects/join_project') %>'); +showModal('ajax-modal', '510px'); +$('#ajax-modal').css('height','260px'); +$('#ajax-modal').siblings().remove(); +$('#ajax-modal').before("" + + ""); +$('#ajax-modal').parent().removeClass("alert_praise"); +$('#ajax-modal').parent().css("top","").css("left",""); +$('#ajax-modal').parent().addClass("alert_box"); diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb index 0dc62c6a3..3e341bd27 100644 --- a/app/views/welcome/index.html.erb +++ b/app/views/welcome/index.html.erb @@ -66,6 +66,9 @@ :course => 0, :project_type =>( @project_type||=0)}, :class => 'icon icon-add') if User.current.allowed_to?(:add_project, nil, :global => true) %> +      + <%= link_to l(:label_join_project), join_project_projects_path ,:remote => true, :class => 'icon icon-add' %> +      <% end %>
    diff --git a/config/locales/zh.yml b/config/locales/zh.yml index bd6c6dc22..fbdee1d1f 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -2282,4 +2282,5 @@ zh: label_answer: 答案: label_poll_answer_valid_result: 以上为有效问答题答案! label_answer_total: 总计: + label_join_project: 加入项目 diff --git a/config/routes.rb b/config/routes.rb index 524373378..65498e4ec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -377,6 +377,10 @@ RedmineApp::Application.routes.draw do match 'copy', :via => [:get, :post] end + collection do + match 'join_project', :via => [:get, :post] + end + #by young match '/member', :to => 'projects#member', :as => 'member', :via => :get match '/file', :to => 'projects#file', :as => 'file', :via => :get From 8f1249390a46a1804fc8bd659cdbc451f070a741 Mon Sep 17 00:00:00 2001 From: alan <547533434@qq.com> Date: Thu, 22 Jan 2015 17:31:34 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E3=80=8A=E5=8F=91?= =?UTF-8?q?=E9=80=81=E5=A4=9A=E5=B0=81=E7=9B=B8=E5=90=8C=E9=82=AE=E4=BB=B6?= =?UTF-8?q?=E3=80=8B=20Signed-off-by:=20alan=20<547533434@qq.com>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/mailer.rb | 11 ++++++++--- app/models/project.rb | 2 +- app/views/mailer/issue_edit.html.erb | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 02684a187..23ac36054 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -147,8 +147,10 @@ class Mailer < ActionMailer::Base @project_url = url_for(:controller => 'projects', :action => 'show', :id => issue.project_id, :token => @token.value) @user_url = url_for(my_account_url(user,:token => @token.value)) - - cc = issue.watcher_recipients - issue.recipients + cc = nil + if recipients == issue.recipients[0] + cc = issue.watcher_recipients - issue.recipients + end subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue_id}] (#{issue.status.name}) #{issue.subject}" mail(:to => recipients, :cc => cc, @@ -197,8 +199,11 @@ class Mailer < ActionMailer::Base # Watchers in cc + cc = nil + if recipients == journal.recipients[0] + cc = journal.watcher_recipients - journal.recipients + end - cc = journal.watcher_recipients - journal.recipients s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue_id}] " s << "(#{issue.status.name}) " if journal.new_value_for('status_id') s << issue.subject diff --git a/app/models/project.rb b/app/models/project.rb index 01e6cd91c..14763347f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -600,7 +600,7 @@ class Project < ActiveRecord::Base # Returns the users that should be notified on project events def notified_users # TODO: User part should be extracted to User#notify_about? - members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all' || m.principal.mail_notification == 'only_my_events' ||m.principal.mail_notification == 'selected')}.collect {|m| m.principal} + members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal} end # Returns an array of all custom fields enabled for project issues diff --git a/app/views/mailer/issue_edit.html.erb b/app/views/mailer/issue_edit.html.erb index 6fcb0ddb5..af167cff5 100644 --- a/app/views/mailer/issue_edit.html.erb +++ b/app/views/mailer/issue_edit.html.erb @@ -12,7 +12,7 @@ <%= l(:field_content)%>:<%= @journal.notes %>
    -
    + <%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url } %>
    <%= link_to( l(:mail_issue_footer), @user_url) %>
    From 84bfd30fc510ec57dd044ef2bad5664ba1142261 Mon Sep 17 00:00:00 2001 From: huang Date: Thu, 22 Jan 2015 17:46:12 +0800 Subject: [PATCH 8/8] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=8F=8D=E9=A6=88=E5=BC=B9=E6=A1=86=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/layouts/_base_feedback.html.erb | 289 ++++++++++++---------- config/locales/zh.yml | 3 +- public/images/blue_line.png | Bin 0 -> 2819 bytes public/images/sidebar_bg.png | Bin 0 -> 9419 bytes 4 files changed, 164 insertions(+), 128 deletions(-) create mode 100644 public/images/blue_line.png create mode 100644 public/images/sidebar_bg.png diff --git a/app/views/layouts/_base_feedback.html.erb b/app/views/layouts/_base_feedback.html.erb index 52006e94d..ae85d9479 100644 --- a/app/views/layouts/_base_feedback.html.erb +++ b/app/views/layouts/_base_feedback.html.erb @@ -1,49 +1,122 @@ - - - - -意见反馈浮窗 + - + + + + +意见反馈 + + + - - -
    -
    - - <% get_memo %> - <%= form_for(@new_memo, :url => create_feedback_forum_path(@public_forum)) do |f| %> -
    -

    - <%= f.text_area :subject, :class => "opnionText",:placeholder => "有什么想说的,尽管来咆哮吧~~"%> -

    -

    - <%= f.hidden_field :content, :required => true ,:value=>'该贴来自用户反馈!'%> -

    - <%#= f.submit :value => l(:label_memo_create), :class => "opnionButton", :id => "button1" %> - 提  交 - <% end %> -
    - - - -
    + + +
    +
    +
    + +
    +
    + <% get_memo %> + <%= form_for(@new_memo, :url => create_feedback_forum_path(@public_forum)) do |f| %> + <%= f.text_area :subject, :class => "opnionText",:placeholder => "有什么想说的,尽管来咆哮吧~~"%> + <%= f.hidden_field :content, :required => true ,:value=>'该贴来自用户反馈!'%> + <%#= f.submit :value => l(:label_memo_create), :class => "opnionButton", :id => "button1" %> + 提  交 + <% end %> +
    + +
    +
    +
    +
    +
    提交
    - -
    -
    技术支持:
    -

    <%= l(:label_course_adcolick) %>黄井泉
    - <%= l(:label_course_adcolick) %>白羽

    -
    - -
    + + - - - + \ No newline at end of file diff --git a/config/locales/zh.yml b/config/locales/zh.yml index bd6c6dc22..fad70aabd 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -2282,4 +2282,5 @@ zh: label_answer: 答案: label_poll_answer_valid_result: 以上为有效问答题答案! label_answer_total: 总计: - + label_technical_support: 技术支持: + label_feedback: 意见反馈 diff --git a/public/images/blue_line.png b/public/images/blue_line.png new file mode 100644 index 0000000000000000000000000000000000000000..4ae87f34320f80b3839409e80f275f205369f5e8 GIT binary patch literal 2819 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 V1*1Is;UEA2002ovPDHLkV1lWASCaq$ literal 0 HcmV?d00001 diff --git a/public/images/sidebar_bg.png b/public/images/sidebar_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..e41ea789d541cffeab9bdeed534fd1ffb17830da GIT binary patch literal 9419 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