diff --git a/app/api/mobile/entities/issue.rb b/app/api/mobile/entities/issue.rb index 1a23bb464..cd0cbb0ce 100644 --- a/app/api/mobile/entities/issue.rb +++ b/app/api/mobile/entities/issue.rb @@ -9,7 +9,11 @@ module Mobile issue[f] elsif issue.is_a?(::Issue) if issue.respond_to?(f) - issue.send(f) + if f == :created_on + format_time(issue.send(f)) + else + issue.send(f) + end else case f when :issue_priority @@ -27,9 +31,15 @@ module Mobile expose :description expose :author, using: Mobile::Entities::User expose :done_ratio + issue_expose :created_on issue_expose :issue_priority issue_expose :issue_assigned_to issue_expose :issue_status + expose :issue_journals, using: Mobile::Entities::Journal do |f, opt| + if f.is_a?(::Issue) + f.journals + end + end end end end \ No newline at end of file diff --git a/app/api/mobile/entities/journal.rb b/app/api/mobile/entities/journal.rb new file mode 100644 index 000000000..a2c54248e --- /dev/null +++ b/app/api/mobile/entities/journal.rb @@ -0,0 +1,37 @@ +module Mobile +module Entities + class Journal [], :deleted => []} + if detail.old_value + values_by_field[field_id][:deleted] << detail.old_value + end + if detail.value + values_by_field[field_id][:added] << detail.value + end + next + end + end + strings << jshow_detail(detail, no_html, options) + + end + values_by_field.each do |field_id, changes| + detail = JournalDetail.new(:property => 'cf', :prop_key => field_id) + if changes[:added].any? + detail.value = changes[:added] + strings << jshow_detail(detail, no_html, options) + elsif changes[:deleted].any? + detail.old_value = changes[:deleted] + strings << jshow_detail(detail, no_html, options) + end + end + strings + end + + # Returns the textual representation of a single journal detail + def jshow_detail(detail, no_html=false, options={}) + multiple = false + case detail.property + when 'attr' + field = detail.prop_key.to_s.gsub(/\_id$/, "") + label = l(("field_" + field).to_sym) + case detail.prop_key + when 'due_date', 'start_date' + value = format_date(detail.value.to_date) if detail.value + old_value = format_date(detail.old_value.to_date) if detail.old_value + + when 'project_id', 'status_id', 'tracker_id', 'assigned_to_id', + 'priority_id', 'category_id', 'fixed_version_id' + value = find_name_by_reflection(field, detail.value) + old_value = find_name_by_reflection(field, detail.old_value) + + when 'estimated_hours' + value = "%0.02f" % detail.value.to_f unless detail.value.blank? + old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank? + + when 'parent_id' + label = l(:field_parent_issue) + value = "##{detail.value}" unless detail.value.blank? + old_value = "##{detail.old_value}" unless detail.old_value.blank? + + when 'is_private' + value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? + old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? + end + when 'cf' + custom_field = CustomField.find_by_id(detail.prop_key) + if custom_field + multiple = custom_field.multiple? + label = custom_field.name + value = format_value(detail.value, custom_field.field_format) if detail.value + old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value + end + when 'attachment' + label = l(:label_attachment) + end + call_hook(:helper_issues_show_detail_after_setting, + {:detail => detail, :label => label, :value => value, :old_value => old_value }) + + label ||= detail.prop_key + value ||= detail.value + old_value ||= detail.old_value + + unless no_html + label = content_tag('strong', label) + old_value = content_tag("i", old_value) if detail.old_value + old_value = content_tag("del", old_value) if detail.old_value and detail.value.blank? + if detail.property == 'attachment' && !value.blank? && atta = Attachment.find_by_id(detail.prop_key) + # Link to the attachment if it has not been removed + if options[:token].nil? + value = atta.filename + else + value = atta.filename + end + # 放大镜搜索功能 + # if options[:only_path] != false && atta.is_text? + # value += link_to( + # image_tag('magnifier.png'), + # :controller => 'attachments', :action => 'show', + # :id => atta, :filename => atta.filename + # ) + # end + else + value = content_tag("i", value) if value + end + end + # 缺陷更新结果在消息中显示样式 + if no_html == "message" + label = content_tag(:span, label, :class => "issue_update_message") + old_value = content_tag("span", old_value) if detail.old_value + old_value = content_tag("del", old_value) if detail.old_value and detail.value.blank? + if detail.property == 'attachment' && !value.blank? && atta = Attachment.find_by_id(detail.prop_key) + # Link to the attachment if it has not been removed + if options[:token].nil? + value = atta.filename + else + value = atta.filename + end + else + value = content_tag(:span, value, :class => "issue_update_message_value") if value + end + end + + if detail.property == 'attr' && detail.prop_key == 'description' + s = l(:text_journal_changed_no_detail, :label => label) + unless no_html + diff_link = link_to l(:label_diff), + {:controller => 'journals', :action => 'diff', :id => detail.journal_id, + :detail_id => detail.id, :only_path => options[:only_path]}, + :title => l(:label_view_diff) + s << " (#{ diff_link })" + end + s.html_safe + elsif detail.value.present? + case detail.property + when 'attr', 'cf' + if detail.old_value.present? + l(:text_journal_changed, :label => label, :old => old_value, :new => value).html_safe + elsif multiple + l(:text_journal_added, :label => label, :value => value).html_safe + else + l(:text_journal_set_to, :label => label, :value => value).html_safe + end + when 'attachment' + l(:text_journal_added, :label => label, :value => value).html_safe + end + else + l(:text_journal_deleted, :label => label, :old => old_value).html_safe + end + end end \ No newline at end of file diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 4ad3cb49d..bef6b580c 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -19,7 +19,7 @@ module IssuesHelper include ApplicationHelper - + include TagsHelper def issue_list(issues, &block) ancestors = [] issues.each do |issue| diff --git a/app/models/blog_comment.rb b/app/models/blog_comment.rb index 2b31af604..3775523b3 100644 --- a/app/models/blog_comment.rb +++ b/app/models/blog_comment.rb @@ -1,5 +1,7 @@ class BlogComment < ActiveRecord::Base # attr_accessible :title, :body + require 'net/http' + require 'json' include Redmine::SafeAttributes belongs_to :blog belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' @@ -18,7 +20,7 @@ class BlogComment < ActiveRecord::Base after_save :add_user_activity after_update :update_activity - after_create :update_parent_time + after_create :update_parent_time, :blog_wechat_message before_destroy :destroy_user_activity scope :like, lambda {|arg| @@ -72,4 +74,50 @@ class BlogComment < ActiveRecord::Base end def project end + + #博客回复微信模板消息 + def blog_wechat_message + unless self.parent_id == nil + uw = UserWechat.where(user_id: self.parent.author_id).first + #unless uw.nil? && self.parent.author_id != User.current.id + unless uw.nil? + data = { + touser:uw.openid, + template_id:"A_3f5v90-zK73V9Kijm-paDkl9S-NuM8Cf-1UJi92_c", + url:"http://weixin.qq.com/download", + topcolor:"#FF0000", + data:{ + first: { + value:"您的博客有新回复了", + color:"#173177" + }, + keyword1:{ + value:self.author.try(:realname), + color:"#173177" + }, + keyword2:{ + value:self.created_at, + color:"#173177" + }, + keyword3:{ + value:h(truncate(" - #{self.content.html_safe}", length:50, omission: '...')), + color:"#173177" + }, + remark:{ + value:"具体内容请点击详情查看网站", + color:"#173177" + } + } + } + uri = URI("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=1234567") + body = data.to_json + res = Net::HTTP.new(uri.host, uri.port).start do |client| + request = Net::HTTP::Post.new(uri.path) + request.body = body + request["Content-Type"] = "application/json" + client.request(request) + end + end + end + end end diff --git a/app/models/homework_common.rb b/app/models/homework_common.rb index f8e222b0f..e1f4766de 100644 --- a/app/models/homework_common.rb +++ b/app/models/homework_common.rb @@ -2,6 +2,8 @@ #homework_type: 0:普通作业;1:匿评作业;2:编程作业 class HomeworkCommon < ActiveRecord::Base # attr_accessible :name, :user_id, :description, :publish_time, :end_time, :homework_type, :late_penalty, :course_id + require 'net/http' + require 'json' include Redmine::SafeAttributes include ApplicationHelper @@ -26,7 +28,7 @@ class HomeworkCommon < ActiveRecord::Base :author => :author, :url => Proc.new {|o| {:controller => 'student_work', :action => 'index', :homework => o.id}} after_create :act_as_activity, :send_mail, :act_as_course_message - after_update :update_activity + after_update :update_activity, :wechat_message after_save :act_as_course_activity after_destroy :delete_kindeditor_assets @@ -98,6 +100,51 @@ class HomeworkCommon < ActiveRecord::Base jfm end + #修改作业后发送微信模板消息 + def wechat_message + self.course.members.each do |member| + uw = UserWechat.where("user_id=?", member.user_id).first + unless uw.nil? + data = { + touser:uw.openid, + template_id:"3e5Dj2GIx8MOcMyRKpTUEQnM7Tg0ASSCNc01NS9HCGI", + url:"http://weixin.qq.com/download", + topcolor:"#FF0000", + data:{ + first: { + value:"您的作业已被修改", + color:"#173177" + }, + keyword1:{ + value:self.course.name, + color:"#173177" + }, + keyword2:{ + value:self.name, + color:"#173177" + }, + keyword3:{ + value:self.end_time.to_s + "23:59:59", + color:"#173177" + }, + remark:{ + value:"具体内容请点击详情查看网站", + color:"#173177" + } + } + } + uri = URI("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=1234567") + body = data.to_json + res = Net::HTTP.new(uri.host, uri.port).start do |client| + request = Net::HTTP::Post.new(uri.path) + request.body = body + request["Content-Type"] = "application/json" + client.request(request) + end + end + end + end + delegate :language_name, :language, :to => :homework_detail_programing end diff --git a/app/models/journal.rb b/app/models/journal.rb index fd67e8a62..2432f1db1 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -16,6 +16,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Journal < ActiveRecord::Base + require 'net/http' + require 'json' include UserScoreHelper belongs_to :journalized, :polymorphic => true,:touch => true # added as a quick fix to allow eager loading of the polymorphic association @@ -52,7 +54,7 @@ class Journal < ActiveRecord::Base # fq after_save :act_as_activity,:be_user_score, :act_as_forge_message, act_as_at_message(:notes, :user_id) - after_create :update_issue_time + after_create :update_issue_timeissue, :issue_wechat_message # end #after_destroy :down_user_score #before_save :be_user_score @@ -233,4 +235,50 @@ class Journal < ActiveRecord::Base forge_activity.update_attribute(:created_at, self.created_on) unless forge_activity.nil? end end + + #缺陷回复微信模板消息 + def issue_wechat_message + unless self.parent_id == nil + uw = UserWechat.where(user_id: self.issue.author_id).first + #unless uw.nil? && self.issue.author_id != User.current.id + unless uw.nil? + data = { + touser:uw.openid, + template_id:"A_3f5v90-zK73V9Kijm-paDkl9S-NuM8Cf-1UJi92_c", + url:"http://weixin.qq.com/download", + topcolor:"#FF0000", + data:{ + first: { + value:"您的缺陷有新回复了", + color:"#173177" + }, + keyword1:{ + value:self.author.try(:realname), + color:"#173177" + }, + keyword2:{ + value:self.created_on, + color:"#173177" + }, + keyword3:{ + value:h(truncate(" - #{self.description.html_safe}", length:50, omission: '...')), + color:"#173177" + }, + remark:{ + value:"具体内容请点击详情查看网站", + color:"#173177" + } + } + } + uri = URI("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=1234567") + body = data.to_json + res = Net::HTTP.new(uri.host, uri.port).start do |client| + request = Net::HTTP::Post.new(uri.path) + request.body = body + request["Content-Type"] = "application/json" + client.request(request) + end + end + end + end end diff --git a/app/models/journals_for_message.rb b/app/models/journals_for_message.rb index fa5beb813..33dcc78af 100644 --- a/app/models/journals_for_message.rb +++ b/app/models/journals_for_message.rb @@ -2,6 +2,8 @@ # 数据库字段中带有m前缀和is_readed是二次开发添加,之前的字段基本复用 # 注意reply_id 是提到人的id,不是留言id, Base中叫做 at_user class JournalsForMessage < ActiveRecord::Base + require 'net/http' + require 'json' include Redmine::SafeAttributes include UserScoreHelper include ApplicationHelper @@ -253,6 +255,9 @@ class JournalsForMessage < ActiveRecord::Base self.course_messages << CourseMessage.new(:user_id => r, :course_id => self.jour.id, :viewed => false) end end + if self.jour_type == 'HomeworkCommon' + journal_wechat_message '您的作业有新回复了' + end end @@ -264,6 +269,7 @@ class JournalsForMessage < ActiveRecord::Base if self.reply_id == 0 if self.user_id != self.jour_id # 过滤自己给自己的留言消息 receivers << self.jour + journal_wechat_message "您有新留言了" end else # 留言回复 reply_to = User.find(self.reply_id) @@ -273,6 +279,7 @@ class JournalsForMessage < ActiveRecord::Base if self.user_id != self.parent.jour_id && self.reply_id != self.parent.jour_id # 给东家发信息,如果回复的对象是东家则不发 receivers << self.parent.jour end + journal_wechat_message "您的留言有新回复了" end receivers.each do |r| self.user_feedback_messages << UserFeedbackMessage.new(:user_id => r.id, :journals_for_message_id => self.id, :journals_for_message_type => "Principal", :viewed => false) @@ -299,4 +306,48 @@ class JournalsForMessage < ActiveRecord::Base end end + #微信模板消息 + def journal_wechat_message type + uw = UserWechat.where(user_id: self.reply_id).first + #unless uw.nil? && self.reply_id != User.current.id + unless uw.nil? + data = { + touser:uw.openid, + template_id:"3e5Dj2GIx8MOcMyRKpTUEQnM7Tg0ASSCNc01NS9HCGI", + url:"http://weixin.qq.com/download", + topcolor:"#FF0000", + data:{ + first: { + value:type, + color:"#173177" + }, + keyword1:{ + value:self.user.try(:realname), + color:"#173177" + }, + keyword2:{ + value:self.created_on, + color:"#173177" + }, + keyword3:{ + value:h(truncate(" - #{self.notes.html_safe}", length:50, omission: '...')), + color:"#173177" + }, + remark:{ + value:"具体内容请点击详情查看网站", + color:"#173177" + } + } + } + uri = URI("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=1234567") + body = data.to_json + res = Net::HTTP.new(uri.host, uri.port).start do |client| + request = Net::HTTP::Post.new(uri.path) + request.body = body + request["Content-Type"] = "application/json" + client.request(request) + end + end + end + end diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 05b0349ec..98ed4ee1f 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -16,6 +16,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Mailer < ActionMailer::Base + require 'net/http' + require 'json' layout 'mailer' helper :application helper :issues @@ -638,6 +640,9 @@ class Mailer < ActionMailer::Base mail :to => recipients, :subject => "[ #{l(:label_user_homework)} : #{homework_common.name} #{l(:label_memo_create_succ)}]", :filter => true + @homework_common.course.members.each do |member| + mail_wechat_message member.user_id, "3e5Dj2GIx8MOcMyRKpTUEQnM7Tg0ASSCNc01NS9HCGI", "您的课程有新作业了", @homework_common.course.name, @homework_common.name, @homework_common.end_time.to_s + " 23:59:59" + end end # Builds a Mail::Message object used to email recipients of a news' project when a news item is added. @@ -703,6 +708,8 @@ class Mailer < ActionMailer::Base mail :to => recipients, :subject => "[#{news.course.name}] #{l(:label_news)}: #{news.title}", :filter => true + + mail_wechat_message news.author_id, "3e5Dj2GIx8MOcMyRKpTUEQnM7Tg0ASSCNc01NS9HCGI", "您的课程通知有新回复了", @author.try(:realname), comment.created_on, comment.comments.html_safe end end @@ -727,6 +734,13 @@ class Mailer < ActionMailer::Base :cc => cc, :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}", :filter => true + if message.parent_id == nil + message.project.members.each do |member| + mail_wechat_message member.user_id, "oKzFCdk7bsIHnGbscA__N8LPQrBkUShvpjV3-kuwWDQ", "项目讨论区有新帖子发布了", message.subject, @author.try(:realname), message.created_on + end + else + mail_wechat_message member.parent.author_id, "A_3f5v90-zK73V9Kijm-paDkl9S-NuM8Cf-1UJi92_c", "您的帖子有新回复了", @author.try(:realname), message.created_on, message.content.html_safe + end elsif message.course redmine_headers 'Course' => message.course.id, 'Topic-Id' => (message.parent_id || message.id) @@ -742,6 +756,13 @@ class Mailer < ActionMailer::Base :cc => cc, :subject => "[#{message.board.course.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}", :filter => true + if message.parent_id == nil + message.course.members.each do |member| + mail_wechat_message member.user_id, "oKzFCdk7bsIHnGbscA__N8LPQrBkUShvpjV3-kuwWDQ", "课程问答区有新帖子发布了", message.subject, @author.try(:realname), message.created_on + end + else + mail_wechat_message member.parent.author_id, "A_3f5v90-zK73V9Kijm-paDkl9S-NuM8Cf-1UJi92_c", "您的帖子有新回复了", @author.try(:realname), message.created_on, message.content.html_safe + end end end @@ -1097,4 +1118,46 @@ class Mailer < ActionMailer::Base return newpass end + #微信模板消息 + def mail_wechat_message user_id, template_id, first, key1, key2, key3, remark="具体内容请点击详情查看网站" + uw = UserWechat.where(user_id: user_id).first + unless uw.nil? + data = { + touser:uw.openid, + template_id:template_id, + url:"http://weixin.qq.com/download", + topcolor:"#FF0000", + data:{ + first: { + value:first, + color:"#173177" + }, + keyword1:{ + value:key1, + color:"#173177" + }, + keyword2:{ + value:key2, + color:"#173177" + }, + keyword3:{ + value:h(truncate(" - #{key3}", length:50, omission: '...')), + color:"#173177" + }, + remark:{ + value:remark, + color:"#173177" + } + } + } + uri = URI("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=1234567") + body = data.to_json + res = Net::HTTP.new(uri.host, uri.port).start do |client| + request = Net::HTTP::Post.new(uri.path) + request.body = body + request["Content-Type"] = "application/json" + client.request(request) + end + end + end end