From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from pigeon.gentoo.org ([208.92.234.80] helo=lists.gentoo.org) by finch.gentoo.org with esmtp (Exim 4.60) (envelope-from ) id 1QV4rW-0004Um-AA for garchives@archives.gentoo.org; Fri, 10 Jun 2011 16:47:10 +0000 Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 638281C07C; Fri, 10 Jun 2011 16:46:38 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by pigeon.gentoo.org (Postfix) with ESMTP id 116FD1C07C for ; Fri, 10 Jun 2011 16:46:37 +0000 (UTC) Received: from pelican.gentoo.org (unknown [66.219.59.40]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 7F13B1B4036 for ; Fri, 10 Jun 2011 16:46:37 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by pelican.gentoo.org (Postfix) with ESMTP id CE6B98003E for ; Fri, 10 Jun 2011 16:46:36 +0000 (UTC) From: "Petteri Räty" To: gentoo-commits@lists.gentoo.org Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Petteri Räty" Message-ID: Subject: [gentoo-commits] proj/council-webapp:master commit in: site/config/environments/, site/spec/support/, site/db/, ... X-VCS-Repository: proj/council-webapp X-VCS-Files: site/Gemfile site/Gemfile.lock site/app/mailers/user_mailer.rb site/app/models/agenda.rb site/app/views/user_mailer/meeting_reminder.erb site/config/environments/test.rb site/config/initializers/custom_configs.rb site/db/schema.rb site/doc/sample_configs/reminders.yml site/script/delayed_job site/spec/models/agenda_spec.rb site/spec/models/user_mailer_spec.rb site/spec/spec_helper.rb site/spec/support/delayed_should_receive.rb site/spec/support/should_have_text.rb X-VCS-Directories: site/config/environments/ site/spec/support/ site/db/ site/app/views/user_mailer/ site/app/mailers/ site/ site/doc/sample_configs/ site/config/initializers/ site/app/models/ site/spec/models/ site/spec/ site/script/ X-VCS-Committer: betelgeuse X-VCS-Committer-Name: Petteri Räty X-VCS-Revision: a79293f652cedf63f9f3cd88107e98b9b4da99f3 Date: Fri, 10 Jun 2011 16:46:36 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: quoted-printable X-Archives-Salt: X-Archives-Hash: b5b044c3794f6db9880599dbbdf43075 commit: a79293f652cedf63f9f3cd88107e98b9b4da99f3 Author: Joachim Filip Ignacy Bartosik gmail com= > AuthorDate: Mon Jun 6 18:50:58 2011 +0000 Commit: Petteri R=C3=A4ty gentoo org> CommitDate: Fri Jun 10 16:11:42 2011 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=3Dproj/council-webap= p.git;a=3Dcommit;h=3Da79293f6 Send email reminders about meetings using delayed_job --- site/Gemfile | 2 + site/Gemfile.lock | 8 ++++ site/app/mailers/user_mailer.rb | 6 +++ site/app/models/agenda.rb | 43 +++++++++++++++++= ++++-- site/app/views/user_mailer/meeting_reminder.erb | 5 +++ site/config/environments/test.rb | 2 + site/config/initializers/custom_configs.rb | 4 ++- site/db/schema.rb | 21 ++++++++++- site/doc/sample_configs/reminders.yml | 1 + site/script/delayed_job | 5 +++ site/spec/models/agenda_spec.rb | 41 +++++++++++++++++= ++++ site/spec/models/user_mailer_spec.rb | 14 +++++++ site/spec/spec_helper.rb | 5 +++ site/spec/support/delayed_should_receive.rb | 11 ++++++ site/spec/support/should_have_text.rb | 8 ++++ 15 files changed, 170 insertions(+), 6 deletions(-) diff --git a/site/Gemfile b/site/Gemfile index fa841ac..a95faa0 100644 --- a/site/Gemfile +++ b/site/Gemfile @@ -3,11 +3,13 @@ gem 'rails', '3.0.3' gem 'sqlite3-ruby', :require =3D> 'sqlite3' gem 'devise' gem 'hobo_devise', '>=3D0.0.2' +gem 'delayed_job' =20 group :development, :test do gem 'ruby-debug' gem 'rspec-rails' gem 'shoulda' + gem 'email_spec' =20 gem 'cucumber-rails' gem 'capybara' diff --git a/site/Gemfile.lock b/site/Gemfile.lock index 4313a4a..aca3ead 100644 --- a/site/Gemfile.lock +++ b/site/Gemfile.lock @@ -57,7 +57,11 @@ GEM nokogiri (>=3D 1.4.4) rack-test (>=3D 0.5.7) culerity (0.2.15) + daemons (1.1.0) database_cleaner (0.6.6) + delayed_job (2.1.2) + activesupport (~> 3.0) + daemons devise (1.3.4) bcrypt-ruby (~> 2.1.2) orm_adapter (~> 0.0.3) @@ -69,6 +73,8 @@ GEM dryml (1.3.0.pre28) actionpack (>=3D 3.0.0) hobo_support (=3D 1.3.0.pre28) + email_spec (1.1.1) + rspec (~> 2.0) erubis (2.6.6) abstract (>=3D 1.0.0) factory_girl (1.3.3) @@ -207,7 +213,9 @@ DEPENDENCIES capybara cucumber-rails database_cleaner + delayed_job devise + email_spec factory_girl fuubar-cucumber hobo (>=3D 1.3.0.pre28) diff --git a/site/app/mailers/user_mailer.rb b/site/app/mailers/user_mail= er.rb index c5c18f8..d9515f3 100644 --- a/site/app/mailers/user_mailer.rb +++ b/site/app/mailers/user_mailer.rb @@ -7,4 +7,10 @@ class UserMailer < ActionMailer::Base :to =3D> user.email ) end =20 + def meeting_reminder(user, agenda) + @user =3D user + @agenda =3D agenda + mail(:subject =3D> "Upcoming meeting reminder - #{agenda.meeting_tim= e.to_s}", + :to =3D> user.email) + end end diff --git a/site/app/models/agenda.rb b/site/app/models/agenda.rb index 22414d7..ea58041 100644 --- a/site/app/models/agenda.rb +++ b/site/app/models/agenda.rb @@ -3,7 +3,8 @@ class Agenda < ActiveRecord::Base hobo_model # Don't put anything above this =20 fields do - meeting_time :datetime + meeting_time :datetime + email_reminder_sent :boolean, :null =3D> false, :default =3D> false timestamps end =20 @@ -101,7 +102,12 @@ class Agenda < ActiveRecord::Base end end =20 - def self.voters + def time_for_reminders + offset =3D CustomConfig['Reminders']['hours_before_meeting_to_send_e= mail_reminders'].hours + meeting_time - offset + end + + def self.voters_users # It's possible to rewrite this as SQL, but # * this method is rarely called # * it fetches little data @@ -109,7 +115,38 @@ class Agenda < ActiveRecord::Base # Joachim council =3D ::User.council_member_is(true) proxies =3D Agenda.current.proxies - [council - proxies.*.council_member + proxies.*.proxy].flatten.*.irc= _nick + [council - proxies.*.council_member + proxies.*.proxy].flatten + end + + def self.voters + Agenda.voters_users.*.irc_nick + end + + def self.send_current_agenda_reminders + agenda =3D Agenda.current + + return if agenda.email_reminder_sent? + return if Time.now < agenda.time_for_reminders + + for user in Agenda.voters_users + UserMailer.delay.deliver_meeting_reminder(user, agenda) + end + + agenda.email_reminder_sent =3D true + agenda.save! + end + + before_save do |a| + return true if a.new_record? + return true unless a.meeting_time_changed? + a.email_reminder_sent =3D false + true + end + + after_save do |a| + if a.new_record? or a.meeting_time_changed? + Agenda.delay(:run_at =3D> a.time_for_reminders).send_current_agend= a_reminders + end end =20 protected diff --git a/site/app/views/user_mailer/meeting_reminder.erb b/site/app/v= iews/user_mailer/meeting_reminder.erb new file mode 100644 index 0000000..b49e7e6 --- /dev/null +++ b/site/app/views/user_mailer/meeting_reminder.erb @@ -0,0 +1,5 @@ +<%=3D @user %>, + +meeting will take place on <%=3D @agenda.meeting_time.to_s %>. You can v= iew agenda for the meeting on: + + <%=3D agenda_url(@agenda) %> diff --git a/site/config/environments/test.rb b/site/config/environments/= test.rb index c2fc237..944a63f 100644 --- a/site/config/environments/test.rb +++ b/site/config/environments/test.rb @@ -32,4 +32,6 @@ Council::Application.configure do =20 # Print deprecation notices to the stderr config.active_support.deprecation =3D :stderr + + config.action_mailer.default_url_options =3D { :host =3D> 'localhost',= :port =3D> '3000' } end diff --git a/site/config/initializers/custom_configs.rb b/site/config/ini= tializers/custom_configs.rb index 599646f..dca866f 100644 --- a/site/config/initializers/custom_configs.rb +++ b/site/config/initializers/custom_configs.rb @@ -1,2 +1,4 @@ CustomConfig =3D {} -CustomConfig['Bot'] =3D YAML.load open('config/bot.yml').read +for conf in ['bot', 'reminders'] + CustomConfig[conf.camelize] =3D YAML.load open("config/#{conf}.yml").r= ead +end diff --git a/site/db/schema.rb b/site/db/schema.rb index fec65de..071ff84 100644 --- a/site/db/schema.rb +++ b/site/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control= system. =20 -ActiveRecord::Schema.define(:version =3D> 20110603133359) do +ActiveRecord::Schema.define(:version =3D> 20110606170332) do =20 create_table "agenda_items", :force =3D> true do |t| t.string "title" @@ -30,12 +30,29 @@ ActiveRecord::Schema.define(:version =3D> 20110603133= 359) do t.datetime "meeting_time" t.datetime "created_at" t.datetime "updated_at" - t.string "state", :default =3D> "open" + t.string "state", :default =3D> "open" t.datetime "key_timestamp" + t.boolean "email_reminder_sent", :default =3D> false, :null =3D> f= alse end =20 add_index "agendas", ["state"], :name =3D> "index_agendas_on_state" =20 + create_table "delayed_jobs", :force =3D> true do |t| + t.integer "priority", :default =3D> 0 + t.integer "attempts", :default =3D> 0 + t.text "handler" + t.text "last_error" + t.datetime "run_at" + t.datetime "locked_at" + t.datetime "failed_at" + t.string "locked_by" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "delayed_jobs", ["locked_by"], :name =3D> "delayed_jobs_lock= ed_by" + add_index "delayed_jobs", ["priority", "run_at"], :name =3D> "delayed_= jobs_priority" + create_table "participations", :force =3D> true do |t| t.string "irc_nick" t.datetime "created_at" diff --git a/site/doc/sample_configs/reminders.yml b/site/doc/sample_conf= igs/reminders.yml new file mode 100644 index 0000000..edf937a --- /dev/null +++ b/site/doc/sample_configs/reminders.yml @@ -0,0 +1 @@ +hours_before_meeting_to_send_email_reminders: 24 diff --git a/site/script/delayed_job b/site/script/delayed_job new file mode 100755 index 0000000..edf1959 --- /dev/null +++ b/site/script/delayed_job @@ -0,0 +1,5 @@ +#!/usr/bin/env ruby + +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config= ', 'environment')) +require 'delayed/command' +Delayed::Command.new(ARGV).daemonize diff --git a/site/spec/models/agenda_spec.rb b/site/spec/models/agenda_sp= ec.rb index 2a08210..83b31a3 100644 --- a/site/spec/models/agenda_spec.rb +++ b/site/spec/models/agenda_spec.rb @@ -147,4 +147,45 @@ describe Agenda do (voters - nicks).should be_empty (nicks - voters).should be_empty end + + it 'should add Agenda.send_current_agenda_reminders to delayed jobs wh= en created' do + Agenda.should_receive_delayed(:send_current_agenda_reminders) + Factory(:agenda) + end + + it 'should add Agenda.send_current_agenda_reminders to delayed jobs wh= en meeting time changes' do + a =3D Factory(:agenda) + Agenda.should_receive_delayed(:send_current_agenda_reminders) + a.meeting_time =3D Time.now + 24.hours + a.save! + end + + it 'should set email_reminder_sent to false when time changes' do + a =3D Factory(:agenda, :email_reminder_sent =3D> true) + lambda { + a.meeting_time =3D Time.now + 24.hours + a.save! + }.should change(a, :email_reminder_sent?).from(true).to(false) + end + + it 'should send reminders properly with send_current_agenda_reminders = using delayed jobs' do + agenda =3D Factory(:agenda) + users =3D users_factory([:user] * 2) + council =3D users_factory([:council] * 2) + Factory(:proxy, :proxy =3D> users.first, :council_member =3D> counci= l.first, :agenda =3D> agenda) + UserMailer.should_receive_delayed(:deliver_meeting_reminder, council= .last, agenda) + UserMailer.should_receive_delayed(:deliver_meeting_reminder, users.f= irst, agenda) + + Agenda.send_current_agenda_reminders + + agenda.reload + agenda.email_reminder_sent.should be_true + end + + it 'should not send reminders with send_current_agenda_reminders if Ag= enda.current.email_reminder_sent is true' do + a =3D Factory(:agenda, :email_reminder_sent =3D> true) + users =3D users_factory([:user] * 2) + UserMailer.should_not_receive(:delay) + Agenda.send_current_agenda_reminders + end end diff --git a/site/spec/models/user_mailer_spec.rb b/site/spec/models/user= _mailer_spec.rb new file mode 100644 index 0000000..ea2c2bc --- /dev/null +++ b/site/spec/models/user_mailer_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' +describe UserMailer do + it 'should send proper meeting reminders' do + user =3D Factory(:user) + agenda =3D Factory(:agenda) + reminder =3D UserMailer.meeting_reminder(user, agenda) + reminder.should deliver_to(user.email) + reminder.should deliver_from("no-reply@localhost") + reminder.should have_text(/meeting will take place on #{agenda.meeti= ng_time.to_s}./) + reminder.should have_text(/You can view agenda for the meeting on:/) + reminder.should have_text(/http:\/\/localhost:3000\/agendas\/#{agend= a.id}/) + reminder.should have_subject("Upcoming meeting reminder - #{agenda.m= eeting_time.to_s}") + end +end diff --git a/site/spec/spec_helper.rb b/site/spec/spec_helper.rb index a8b8aea..47ed37e 100644 --- a/site/spec/spec_helper.rb +++ b/site/spec/spec_helper.rb @@ -15,3 +15,8 @@ RSpec.configure do |config| config.mock_with :rspec config.use_transactional_fixtures =3D true end + +RSpec.configure do |config| + config.include(EmailSpec::Helpers) + config.include(EmailSpec::Matchers) +end diff --git a/site/spec/support/delayed_should_receive.rb b/site/spec/supp= ort/delayed_should_receive.rb new file mode 100644 index 0000000..0fbbe27 --- /dev/null +++ b/site/spec/support/delayed_should_receive.rb @@ -0,0 +1,11 @@ +class Object + def should_receive_delayed(method, *args) + m =3D RSpec::Mocks::Mock.new('proxy') + if args.empty? + m.should_receive(method) + else + m.should_receive(method).with(*args) + end + self.should_receive(:delay).and_return(m) + end +end diff --git a/site/spec/support/should_have_text.rb b/site/spec/support/sh= ould_have_text.rb new file mode 100644 index 0000000..3016c13 --- /dev/null +++ b/site/spec/support/should_have_text.rb @@ -0,0 +1,8 @@ +module Mail + class Message + # emailspec doesn't add this, so we have to + def has_text?(text) + not body.to_s.match(text).nil? + end + end +end