From ce6746f7a9317fed56cec1979e3adb95bf3fd5a4 Mon Sep 17 00:00:00 2001 From: "konstantin.grabar" Date: Mon, 26 Dec 2011 19:48:57 +0400 Subject: [PATCH] [refs #54] Add subscribes and notifications --- app/controllers/subscribes_controller.rb | 31 +++++++++++++++ app/helpers/subscribes_helper.rb | 2 + app/mailers/user_mailer.rb | 26 ++++++++++++- app/models/comment.rb | 16 ++++++++ app/models/issue.rb | 39 +++++++++++++++++++ app/models/relation.rb | 1 + app/models/subscribe.rb | 4 ++ app/views/issues/show.html.haml | 8 ++++ .../issue_assign_notification.haml | 7 ++++ .../user_mailer/new_comment_notification.haml | 7 ++++ .../user_mailer/new_issue_notification.haml | 7 ++++ config/locales/ru.yml | 9 +++++ config/routes.rb | 3 ++ .../20111226141947_create_subscribes.rb | 14 +++++++ db/schema.rb | 21 ++++++---- .../controllers/subscribes_controller_spec.rb | 5 +++ spec/factories/subscribes.rb | 6 +++ spec/helpers/subscribes_helper_spec.rb | 15 +++++++ spec/models/subscribe_spec.rb | 5 +++ 19 files changed, 218 insertions(+), 8 deletions(-) create mode 100644 app/controllers/subscribes_controller.rb create mode 100644 app/helpers/subscribes_helper.rb create mode 100644 app/models/subscribe.rb create mode 100644 app/views/user_mailer/issue_assign_notification.haml create mode 100644 app/views/user_mailer/new_comment_notification.haml create mode 100644 app/views/user_mailer/new_issue_notification.haml create mode 100644 db/migrate/20111226141947_create_subscribes.rb create mode 100644 spec/controllers/subscribes_controller_spec.rb create mode 100644 spec/factories/subscribes.rb create mode 100644 spec/helpers/subscribes_helper_spec.rb create mode 100644 spec/models/subscribe_spec.rb diff --git a/app/controllers/subscribes_controller.rb b/app/controllers/subscribes_controller.rb new file mode 100644 index 000000000..4bb51be46 --- /dev/null +++ b/app/controllers/subscribes_controller.rb @@ -0,0 +1,31 @@ +class SubscribesController < ApplicationController + def create + @subscribe = @subscribeable.subscribes.build(:user_id => current_user.id) + if @subscribe.save + flash[:notice] = I18n.t("flash.subscribe.saved") + redirect_to :back + else + flash[:error] = I18n.t("flash.subscribe.saved_error") + redirect_to :back + end + end + + def destroy + @subscribe = Subscribe.find(params[:id]) + @subscribe.destroy + + flash[:notice] = t("flash.subscribe.destroyed") + redirect_to :back + end + + private + + def find_subscribeable + params.each do |name, value| + if name =~ /(.+)_id$/ + return $1.classify.constantize.find(value) + end + end + nil + end +end diff --git a/app/helpers/subscribes_helper.rb b/app/helpers/subscribes_helper.rb new file mode 100644 index 000000000..dc1b490ec --- /dev/null +++ b/app/helpers/subscribes_helper.rb @@ -0,0 +1,2 @@ +module SubscribesHelper +end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 3137b0dff..2c43482e1 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -5,7 +5,31 @@ class UserMailer < ActionMailer::Base def new_user_notification(user) @user = user - mail(:to => user.email, :subject => "Регистрация на проекте «#{APP_CONFIG['project_name']}»") do |format| + mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_user_notification", :project_name => APP_CONFIG['project_name'])) do |format| + format.html + end + end + + def new_comment_notification(comment, user) + @user = user + @comment = comment + mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_comment_notification")) do |format| + format.html + end + end + + def new_issue_notification(issue, user) + @user = user + @issue = issue + mail(:to => user.email, :subject => I18n.t("notifications.subjects.new_issue_notification")) do |format| + format.html + end + end + + def issue_assign_notification(issue, user) + @user = user + @issue = issue + mail(:to => user.email, :subject => I18n.t("notifications.subjects.issue_assign_notification")) do |format| format.html end end diff --git a/app/models/comment.rb b/app/models/comment.rb index 4c15a8b66..36e14c412 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -3,4 +3,20 @@ class Comment < ActiveRecord::Base belongs_to :user validates :body, :user_id, :commentable_id, :commentable_type, :presence => true + + after_create :deliver_new_comment_notification + + protected + + def deliver_new_comment_notification + #UserMailer.new_comment_notification(self, self.commentable.user).deliver + #UserMailer.new_comment_notification(self, self.commentable.project.owner).deliver + recipients = self.commentable.project.relations.by_role('admin').where(:object_type => 'User').map { |rel| rel.read_attribute(:object_id) } + recipients = recipients | [self.commentable.user_id] + recipients = recipients | [self.commentable.project.owner_id] if self.commentable.project.owner_type == 'User' + recipients.each do |recipient_id| + recipient = User.find(recipient_id) + UserMailer.new_comment_notification(self, recipient).deliver + end + end end diff --git a/app/models/issue.rb b/app/models/issue.rb index ad6f57468..586175b89 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -5,12 +5,17 @@ class Issue < ActiveRecord::Base belongs_to :user has_many :comments, :as => :commentable + has_many :subscribes, :as => :subscribeable validates :title, :body, :project_id, :user_id, :presence => true #attr_readonly :serial_id after_create :set_serial_id + after_create :subscribe_users + after_create :deliver_new_issue_notification + after_create :deliver_issue_assign_notification + after_update :deliver_issue_assign_notification protected @@ -18,4 +23,38 @@ class Issue < ActiveRecord::Base self.serial_id = self.project.issues.count self.save! end + + def deliver_new_issue_notification + #UserMailer.new_issue_notification(self, self.project.owner).deliver + #self.project.relations.by_role('admin').each do |rel| + # admin = User.find(rel.object_id) + # UserMailer.new_issue_notification(self, admin).deliver + #end + + recipients = collect_recipient_ids + recipients.each do |recipient_id| + recipient = User.find(recipient_id) + UserMailer.new_issue_notification(self, recipient).deliver + end + end + + def deliver_issue_assign_notification + UserMailer.issue_assign_notification(self, self.user).deliver if self.user_id_was != self.user_id + end + + def subscribe_users + recipients = collect_recipient_ids + recipients.each do |recipient_id| + ss = self.subscribes.build(:user_id => recipient_id) + ss.save! + end + end + + def collect_recipient_ids + recipients = self.project.relations.by_role('admin').where(:object_type => 'User').map { |rel| rel.read_attribute(:object_id) } + recipients = recipients | [self.user_id] + recipients = recipients | [self.project.owner_id] if self.project.owner_type == 'User' + recipients + end + end diff --git a/app/models/relation.rb b/app/models/relation.rb index 822687dca..a08ddf6a9 100644 --- a/app/models/relation.rb +++ b/app/models/relation.rb @@ -10,6 +10,7 @@ class Relation < ActiveRecord::Base scope :by_object, lambda {|obj| {:conditions => ['object_id = ? AND object_type = ?', obj.id, obj.class.to_s]}} scope :by_target, lambda {|tar| {:conditions => ['target_id = ? AND target_type = ?', tar.id, tar.class.to_s]}} + scope :by_role, lambda {|role| {:conditions => ['role = ?', role]}} def self.create_with_role(object, target, role) r = new diff --git a/app/models/subscribe.rb b/app/models/subscribe.rb new file mode 100644 index 000000000..0c3a52698 --- /dev/null +++ b/app/models/subscribe.rb @@ -0,0 +1,4 @@ +class Subscribe < ActiveRecord::Base + belongs_to :subscribeable, :polymorphic => true + belongs_to :user +end diff --git a/app/views/issues/show.html.haml b/app/views/issues/show.html.haml index 51c080e4a..69c2be747 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -20,6 +20,14 @@ = t('activerecord.attributes.issue.status') \: = @issue.status + %p + %b + = t('layout.issues.subscribe') + \: + - if @issue.subscribes.exists? :user_id => current_user.id + = link_to t('layout.issues.unsubscribe_btn'), unsubscribe_issue(@issue), :method => :post + - else + = link_to t('layout.issues.subscribe_btn'), subscribe_issue(@issue), :method => :delete %a{ :name => "comments" } .block diff --git a/app/views/user_mailer/issue_assign_notification.haml b/app/views/user_mailer/issue_assign_notification.haml new file mode 100644 index 000000000..72e99e7df --- /dev/null +++ b/app/views/user_mailer/issue_assign_notification.haml @@ -0,0 +1,7 @@ +%p== Здравствуйте, #{@user.name}. + + +%p Вам была назначена задача #{ link_to @issue.title, show_issue_path(@issue.project, @issue.serial_id) } + + +%p== Команда поддержки «ROSA Build System» diff --git a/app/views/user_mailer/new_comment_notification.haml b/app/views/user_mailer/new_comment_notification.haml new file mode 100644 index 000000000..0e57ff415 --- /dev/null +++ b/app/views/user_mailer/new_comment_notification.haml @@ -0,0 +1,7 @@ +%p== Здравствуйте, #{@user.name}. + + +%p К задаче #{ link_to @comment.commentable.title, show_issue_path(@comment.commentable.project, @comment.commentable.serial_id) } был добавлен новый комментарий. + + +%p== Команда поддержки «ROSA Build System» diff --git a/app/views/user_mailer/new_issue_notification.haml b/app/views/user_mailer/new_issue_notification.haml new file mode 100644 index 000000000..e98f32f45 --- /dev/null +++ b/app/views/user_mailer/new_issue_notification.haml @@ -0,0 +1,7 @@ +%p== Здравствуйте, #{@user.name}. + + +%p К проекту #{ link_to @issue.project.name, project_path(@issue.project) } была добавлена задача #{ link_to @issue.title, show_issue_path(@issue.project, @issue.serial_id) } + + +%p== Команда поддержки «ROSA Build System» diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 97eea839c..563ffdea7 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -106,6 +106,9 @@ ru: open: Открытые closed: Закрытые any: Все + subscribe: Подписка на уведомления + subscribe_btn: Подписаться + unsubscribe_btn: Отписаться comments: confirm_delete: Вы уверены, что хотите удалить комментарий? @@ -653,3 +656,9 @@ ru: distro: Дистрибутив platform: Архитектура counter: Закачки + notifications: + subjects: + new_comment_notification: Новый комментарий к Вашей задаче + new_issue_notification: Новая задача добавлена к проекту + new_user_notification: Регистрация на проекте «%{ project_name }» + issue_assign_notification: Вам назначили задачу diff --git a/config/routes.rb b/config/routes.rb index 4a0227e63..e71991c55 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -78,6 +78,9 @@ Rosa::Application.routes.draw do resources :categories, :only => [:index, :show] end + match "issues/:issue_id/subscribe" => 'subscribes#create', :as => :subscribe_issue, :via => :post + match "issues/:issue_id/unsubscribe" => 'subscribes#destroy', :as => :unsubscribe_issue, :via => :delete + match "projects/:project_id/issues/:serial_id" => 'issues#show', :serial_id => /\d+/, :as => :show_issue, :via => :get match "projects/:project_id/issues/:serial_id/edit" => 'issues#edit', :serial_id => /\d+/, :as => :edit_issue, :via => :get resources :projects do diff --git a/db/migrate/20111226141947_create_subscribes.rb b/db/migrate/20111226141947_create_subscribes.rb new file mode 100644 index 000000000..631e09f09 --- /dev/null +++ b/db/migrate/20111226141947_create_subscribes.rb @@ -0,0 +1,14 @@ +class CreateSubscribes < ActiveRecord::Migration + def self.up + create_table :subscribes do |t| + t.integer :subscribeable_id + t.string :subscribeable_type + t.integer :user_id + t.timestamps + end + end + + def self.down + drop_table :subscribes + end +end diff --git a/db/schema.rb b/db/schema.rb index 55f94564c..1aece65f1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20111221194422) do +ActiveRecord::Schema.define(:version => 20111226141947) do create_table "arches", :force => true do |t| t.string "name", :null => false @@ -245,7 +245,6 @@ ActiveRecord::Schema.define(:version => 20111221194422) do t.string "object_type" t.integer "target_id" t.string "target_type" - t.integer "role_id" t.datetime "created_at" t.datetime "updated_at" t.string "role" @@ -272,18 +271,26 @@ ActiveRecord::Schema.define(:version => 20111221194422) do add_index "rpms", ["project_id", "arch_id"], :name => "index_rpms_on_project_id_and_arch_id" add_index "rpms", ["project_id"], :name => "index_rpms_on_project_id" + create_table "subscribes", :force => true do |t| + t.integer "subscribeable_id" + t.string "subscribeable_type" + t.integer "user_id" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "users", :force => true do |t| t.string "name" - t.string "email", :default => "", :null => false - t.string "encrypted_password", :limit => 128, :default => "", :null => false + t.string "email", :default => "", :null => false + t.string "encrypted_password", :limit => 128, :default => "", :null => false + t.string "password_salt", :default => "", :null => false t.string "reset_password_token" - t.datetime "reset_password_sent_at" + t.string "remember_token" t.datetime "remember_created_at" t.datetime "created_at" t.datetime "updated_at" - t.string "uname" t.text "ssh_key" - t.integer "role_id" + t.string "uname" t.string "role" end diff --git a/spec/controllers/subscribes_controller_spec.rb b/spec/controllers/subscribes_controller_spec.rb new file mode 100644 index 000000000..e1c466cb3 --- /dev/null +++ b/spec/controllers/subscribes_controller_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe SubscribesController do + +end diff --git a/spec/factories/subscribes.rb b/spec/factories/subscribes.rb new file mode 100644 index 000000000..f0644816f --- /dev/null +++ b/spec/factories/subscribes.rb @@ -0,0 +1,6 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :subscribe do + end +end \ No newline at end of file diff --git a/spec/helpers/subscribes_helper_spec.rb b/spec/helpers/subscribes_helper_spec.rb new file mode 100644 index 000000000..c72869cf9 --- /dev/null +++ b/spec/helpers/subscribes_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the SubscribesHelper. For example: +# +# describe SubscribesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe SubscribesHelper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/subscribe_spec.rb b/spec/models/subscribe_spec.rb new file mode 100644 index 000000000..0df4fbb42 --- /dev/null +++ b/spec/models/subscribe_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Subscribe do + pending "add some examples to (or delete) #{__FILE__}" +end