diff options
author | francis <francis> | 2008-03-24 09:35:23 +0000 |
---|---|---|
committer | francis <francis> | 2008-03-24 09:35:23 +0000 |
commit | 5dccf065dbff50587d2c235eeac28ed98e87d53e (patch) | |
tree | e59e09fa4f4628b03cbfe169a0a0d27dc8b17453 | |
parent | 788ddd480c7c131a5c04d0923ccb354a545c39b1 (diff) |
Send email to remind people to classify their response.
-rw-r--r-- | app/models/info_request.rb | 18 | ||||
-rw-r--r-- | app/models/info_request_event.rb | 32 | ||||
-rw-r--r-- | app/models/request_mailer.rb | 51 | ||||
-rw-r--r-- | app/models/user_info_request_sent_alert.rb | 5 | ||||
-rw-r--r-- | app/views/admin/index.rhtml | 3 | ||||
-rw-r--r-- | app/views/request/_describe_state.rhtml | 34 | ||||
-rw-r--r-- | app/views/request/describe_state.rhtml | 4 | ||||
-rw-r--r-- | app/views/request/show.rhtml | 4 | ||||
-rw-r--r-- | app/views/request_mailer/new_response.rhtml | 5 | ||||
-rw-r--r-- | app/views/request_mailer/new_response_reminder_alert.rhtml | 13 | ||||
-rw-r--r-- | config/crontab.ugly | 3 | ||||
-rw-r--r-- | db/migrate/046_add_last_event_id_to_alert_table.rb | 13 | ||||
-rw-r--r-- | db/schema.rb | 11 | ||||
-rwxr-xr-x | script/alert-new-response-reminders | 7 | ||||
-rw-r--r-- | spec/controllers/request_controller_spec.rb | 37 | ||||
-rw-r--r-- | todo.txt | 2 |
16 files changed, 196 insertions, 46 deletions
diff --git a/app/models/info_request.rb b/app/models/info_request.rb index 3c0e97107..ef6f4bc4d 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -22,7 +22,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: info_request.rb,v 1.71 2008-03-21 14:45:38 francis Exp $ +# $Id: info_request.rb,v 1.72 2008-03-24 09:35:23 francis Exp $ require 'digest/sha1' @@ -356,17 +356,27 @@ public end # The last response is the default one people might want to reply to - def get_last_response + def get_last_response_event_id events = self.info_request_events.find(:all, :order => "created_at") events.reverse.each do |e| if e.event_type == 'response' - id = e.params[:incoming_message_id].to_i - return IncomingMessage.find(id) + return e.id end end return nil end + # The last response is the default one people might want to reply to + def get_last_response + event_id = self.get_last_response_event_id + if event_id.nil? + return nil + end + e = self.info_request_events.find(event_id) + incoming_message_id = e.params[:incoming_message_id].to_i + return IncomingMessage.find(incoming_message_id) + end + # The last outgoing message def get_last_outgoing_event events = self.info_request_events.find(:all, :order => "created_at") diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index fc4588596..a6f67c4fd 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -16,12 +16,14 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: info_request_event.rb,v 1.24 2008-03-21 14:45:38 francis Exp $ +# $Id: info_request_event.rb,v 1.25 2008-03-24 09:35:23 francis Exp $ class InfoRequestEvent < ActiveRecord::Base belongs_to :info_request validates_presence_of :info_request + belongs_to :info_request_event_id + validates_presence_of :event_type validates_inclusion_of :event_type, :in => [ 'sent', @@ -53,6 +55,34 @@ class InfoRequestEvent < ActiveRecord::Base YAML.load(self.params_yaml) end + # Find related incoming message + # XXX search for the find below and call this function more instead + def incoming_message + if not ['response'].include?(self.event_type) + raise "only call incoming_message for response events" + end + + if not self.params[:incoming_message_id] + raise "internal error, no incoming message id for response event" + end + + return IncomingMessage.find(self.params[:incoming_message_id].to_i) + end + + # Find related outgoing message + # XXX search for the find below and call this function more instead + def outgoing_message + if not [ 'edit_outgoing', 'sent', 'resent', 'followup_sent' ].include?(self.event_type) + raise "only call outgoing_message for appropriate event types" + end + + if not self.params[:outgoing_message_id] + raise "internal error, no outgoing message id for event type which expected one" + end + + return OutgoingMessage.find(self.params[:outgoing_message_id].to_i) + end + end diff --git a/app/models/request_mailer.rb b/app/models/request_mailer.rb index 8300422bb..58209e3b3 100644 --- a/app/models/request_mailer.rb +++ b/app/models/request_mailer.rb @@ -4,7 +4,7 @@ # Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: request_mailer.rb,v 1.27 2008-03-21 14:04:29 francis Exp $ +# $Id: request_mailer.rb,v 1.28 2008-03-24 09:35:23 francis Exp $ class RequestMailer < ApplicationMailer @@ -87,6 +87,21 @@ class RequestMailer < ApplicationMailer @body = { :info_request => info_request, :url => url } end + # Tell the requester that they need to say if the new response + # contains info or not + def new_response_reminder_alert(info_request, incoming_message) + post_redirect = PostRedirect.new( + :uri => describe_state_url(:id => info_request.id), + :user_id => info_request.user.id) + post_redirect.save! + url = confirm_url(:email_token => post_redirect.email_token) + + @from = contact_from_name_and_email + @recipients = info_request.user.name_and_email + @subject = "Did your recent FOI response contain information? - " + info_request.title + @body = { :incoming_message => incoming_message, :info_request => info_request, :url => url } + end + # Class function, called by script/mailin with all incoming responses. # [ This is a copy (Monkeypatch!) of function from action_mailer/base.rb, @@ -121,7 +136,7 @@ class RequestMailer < ApplicationMailer # Send email alerts for overdue requests def self.alert_overdue_requests() - #puts "alert_overdue_requests" + #STDERR.puts "alert_overdue_requests" info_requests = InfoRequest.find(:all, :conditions => [ "described_state = 'waiting_response' and not awaiting_description" ], :include => [ :user ] ) for info_request in info_requests # Only overdue requests @@ -130,19 +145,47 @@ class RequestMailer < ApplicationMailer sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = 'overdue_1' and user_id = ? and info_request_id = ?", info_request.user_id, info_request.id]) if sent_already.nil? # Alert not yet sent for this user - puts "sending overdue alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s + STDERR.puts "sending overdue alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s store_sent = UserInfoRequestSentAlert.new store_sent.info_request = info_request store_sent.user = info_request.user store_sent.alert_type = 'overdue_1' RequestMailer.deliver_overdue_alert(info_request, info_request.user) store_sent.save! - #puts "sent " + info_request.user.email + #STDERR.puts "sent " + info_request.user.email end end end + end + # Send email alerts for new responses which haven't been + # classified. Goes out 3 days after last update of event. + def self.alert_new_response_reminders() + #STDERR.puts "alert_new_response_reminders" + info_requests = InfoRequest.find(:all, :conditions => [ "awaiting_description and info_requests.updated_at < ?", Time.now() - 3.days ], :include => [ :user ], :order => "info_requests.id" ) + for info_request in info_requests + alert_event_id = info_request.get_last_response_event_id + last_response_message = info_request.get_last_response + if alert_event_id.nil? + raise "internal error, no last response while making alert new response reminder, request id " + info_request.id.to_s + end + # To the user who created the request + sent_already = UserInfoRequestSentAlert.find(:first, :conditions => [ "alert_type = 'new_response_reminder_1' and user_id = ? and info_request_id = ? and info_request_event_id = ?", info_request.user_id, info_request.id, alert_event_id]) + if sent_already.nil? + # Alert not yet sent for this user + STDERR.puts "sending new response reminder alert to info_request " + info_request.id.to_s + " user " + info_request.user_id.to_s + " event " + alert_event_id.to_s + store_sent = UserInfoRequestSentAlert.new + store_sent.info_request = info_request + store_sent.user = info_request.user + store_sent.alert_type = 'new_response_reminder_1' + store_sent.info_request_event_id = alert_event_id + RequestMailer.deliver_new_response_reminder_alert(info_request, last_response_message) + store_sent.save! + #STDERR.puts "sent " + info_request.user.email + end + end end + end diff --git a/app/models/user_info_request_sent_alert.rb b/app/models/user_info_request_sent_alert.rb index f58f6a58c..da4aeb94b 100644 --- a/app/models/user_info_request_sent_alert.rb +++ b/app/models/user_info_request_sent_alert.rb @@ -16,14 +16,15 @@ # Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org; WWW: http://www.mysociety.org/ # -# $Id: user_info_request_sent_alert.rb,v 1.7 2008-03-21 14:45:38 francis Exp $ +# $Id: user_info_request_sent_alert.rb,v 1.8 2008-03-24 09:35:23 francis Exp $ class UserInfoRequestSentAlert < ActiveRecord::Base belongs_to :user belongs_to :info_request validates_inclusion_of :alert_type, :in => [ - 'overdue_1' # tell user that info request has become overdue + 'overdue_1', # tell user that info request has become overdue + 'new_response_reminder_1' # reminder user to classify the recent response ] end diff --git a/app/views/admin/index.rhtml b/app/views/admin/index.rhtml index 9d330784c..116d38500 100644 --- a/app/views/admin/index.rhtml +++ b/app/views/admin/index.rhtml @@ -71,7 +71,7 @@ Missing outgoing message, internal error. <% end %> <% elsif event.event_type == 'response' %> - <% incoming_message = IncomingMessage.find(event.params[:incoming_message_id]) %> + <% incoming_message = event.incoming_message %> received <%= link_to 'a response', main_url(show_response_url(:id => incoming_message.info_request.id, :incoming_message_id => incoming_message.id, :only_path => true)) %> @@ -82,7 +82,6 @@ <% elsif event.event_type == 'resent' %> had the request resent to <%=h event.params[:email]%> at <%=h event.info_request.public_body.name %>. <% elsif event.event_type == 'followup_sent' %> - <% outgoing_messages = OutgoingMessage.find(:all, event.params[:outgoing_message_id].to_i) %> had a follow up message sent to <%=h event.info_request.public_body.name %>. <% else %> had '<%=event.event_type%>' done to it, parameters <%=h event.params_yaml%>. diff --git a/app/views/request/_describe_state.rhtml b/app/views/request/_describe_state.rhtml index 1dd789998..d05ea531b 100644 --- a/app/views/request/_describe_state.rhtml +++ b/app/views/request/_describe_state.rhtml @@ -2,33 +2,35 @@ <% form_for(:incoming_message, @info_request, :url => describe_state_url(:id => @info_request.id)) do |f| %> <h2>What is the status of this request now?</h2> <p> - <%= radio_button "incoming_message", "described_state", "waiting_response" %> - <label for="incoming_message_described_state_waiting_response">I'm still <strong>waiting</strong> for my information / a rejection (e.g. if the new response was just an acknowledgement)</label> + <%= radio_button "incoming_message", "described_state", "waiting_response", :id => 'waiting_response' + id_suffix %> + <label for="waiting_response<%=id_suffix%>">I'm still <strong>waiting</strong> for my information / a rejection (e.g. if the new response was just an acknowledgement)</label> <br> - <%= radio_button "incoming_message", "described_state", "waiting_clarification" %> - <label for="incoming_message_described_state_waiting_clarification">I'm about to <strong>clarify</strong> my request</label> + <%= radio_button "incoming_message", "described_state", "waiting_clarification", :id => 'waiting_clarification' + id_suffix %> + <label for="waiting_clarification<%=id_suffix%>">I'm about to <strong>clarify</strong> my request</label> <br> - <%= radio_button "incoming_message", "described_state", "not_held" %> - <label for="incoming_message_described_state_not_held">The authority <strong>does not have</strong> the information (perhaps they suggest making the request elsewhere)</label> + <%= radio_button "incoming_message", "described_state", "not_held", :id => 'not_held' + id_suffix %> + <label for="not_held<%=id_suffix%>">The authority <strong>does not have</strong> the information (perhaps they suggest making the request elsewhere)</label> <br> - <%= radio_button "incoming_message", "described_state", "rejected" %> - <label for="incoming_message_described_state_rejected">My request has been <strong>rejected</strong></label> + <%= radio_button "incoming_message", "described_state", "rejected", :id => 'rejected' + id_suffix %> + <label for="rejected<%=id_suffix%>">My request has been <strong>rejected</strong></label> <br> - <%= radio_button "incoming_message", "described_state", "successful" %> - <label for="incoming_message_described_state_successful">I've received <strong>all the information</strong> (or equivalents) that I asked for</label> + <%= radio_button "incoming_message", "described_state", "successful", :id => 'successful' + id_suffix %> + <label for="successful<%=id_suffix%>">I've received <strong>all the information</strong> (or equivalents) that I asked for</label> <br> - <%= radio_button "incoming_message", "described_state", "partially_successful" %> - <label for="incoming_message_described_state_partially_successful">I've received <strong>some of the information</strong> that I asked for</label> + <%= radio_button "incoming_message", "described_state", "partially_successful", :id => 'partially_successful' + id_suffix %> + <label for="partially_successful<%=id_suffix%>">I've received <strong>some of the information</strong> that I asked for</label> <br> - <%= radio_button "incoming_message", "described_state", "requires_admin" %> - <label for="incoming_message_described_state_requires_admin"><strong>None</strong> of the above - e.g. add a new option here</label> + <%= radio_button "incoming_message", "described_state", "requires_admin", :id => 'requires_admin' + id_suffix %> + <label for="requires_admin<%=id_suffix%>"><strong>None</strong> of the above - e.g. add a new option here</label> </p> <p>Filling this in each time you get a new response helps us track the progress of your request. </p> - <%= hidden_field_tag 'last_info_request_event_id', @last_info_request_event_id %> - <%= hidden_field_tag 'submitted_describe_state', 1 %> + <p> + <%= hidden_field_tag 'last_info_request_event_id', @last_info_request_event_id, :id => 'last_info_request_event_id' + id_suffix %> + <%= hidden_field_tag 'submitted_describe_state', 1, :id => 'submitted_describe_state' + id_suffix %> <%= submit_tag "Next" %> + </p> <% end %> <% else %> We don't know whether the most recent response to this request contains diff --git a/app/views/request/describe_state.rhtml b/app/views/request/describe_state.rhtml index 354cab447..e65823e3e 100644 --- a/app/views/request/describe_state.rhtml +++ b/app/views/request/describe_state.rhtml @@ -4,7 +4,7 @@ <%= foi_error_messages_for :incoming_message, :outgoing_message %> <div class="describe_state_form"> - <%= render :partial => 'describe_state' %> + <%= render :partial => 'describe_state', :locals => { :id_suffix => "1" } %> </div> <div id="show_response_view"> @@ -17,6 +17,6 @@ </div> <div class="describe_state_form"> - <%= render :partial => 'describe_state' %> + <%= render :partial => 'describe_state', :locals => { :id_suffix => "2" } %> </div> diff --git a/app/views/request/show.rhtml b/app/views/request/show.rhtml index 9627d5d29..8e5ac5f4f 100644 --- a/app/views/request/show.rhtml +++ b/app/views/request/show.rhtml @@ -2,7 +2,7 @@ <% if @info_request.awaiting_description %> <div class="describe_state_form"> - <%= render :partial => 'describe_state' %> + <%= render :partial => 'describe_state', :locals => { :id_suffix => "1" } %> </div> <% end %> @@ -84,7 +84,7 @@ <% if @info_request.awaiting_description %> <div class="describe_state_form"> - <%= render :partial => 'describe_state' %> + <%= render :partial => 'describe_state', :locals => { :id_suffix => "2" } %> </div> <% end %> diff --git a/app/views/request_mailer/new_response.rhtml b/app/views/request_mailer/new_response.rhtml index 947558c4d..c55289b04 100644 --- a/app/views/request_mailer/new_response.rhtml +++ b/app/views/request_mailer/new_response.rhtml @@ -1,5 +1,6 @@ -You have a new response to the FOI request '<%= @info_request.title %>' -that you made to <%= @info_request.public_body.name %>. +You have a new response to the Freedom of Information request +'<%= @info_request.title %>' that you made to +<%= @info_request.public_body.name %>. To view the response, click on the link below. diff --git a/app/views/request_mailer/new_response_reminder_alert.rhtml b/app/views/request_mailer/new_response_reminder_alert.rhtml new file mode 100644 index 000000000..fe1bf2d40 --- /dev/null +++ b/app/views/request_mailer/new_response_reminder_alert.rhtml @@ -0,0 +1,13 @@ +Please let us know whether there was information in the recent +response to your Freedom of Information request. To do this, +click on the link below. + +<%=@url%> + +Thanks very much - this will help others find useful stuff. We'll +also, if you need it, give advice on what to do next about your +request. + +-- the WhatDoTheyKnow team + + diff --git a/config/crontab.ugly b/config/crontab.ugly index a7e0571bd..4f6e4d4ab 100644 --- a/config/crontab.ugly +++ b/config/crontab.ugly @@ -4,7 +4,7 @@ # Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved. # Email: francis@mysociety.org. WWW: http://www.mysociety.org/ # -# $Id: crontab.ugly,v 1.7 2008-03-11 08:06:05 francis Exp $ +# $Id: crontab.ugly,v 1.8 2008-03-24 09:35:24 francis Exp $ PATH=/usr/local/bin:/usr/bin:/bin MAILTO=team@whatdotheyknow.com @@ -17,4 +17,5 @@ MAILTO=team@whatdotheyknow.com # Once a day, early morning 23 4 * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/delete-old-sessions.lock /data/vhost/!!(*= $vhost *)!!/mysociety/foi/script/delete-old-sessions || echo "stalled?" +0 8 * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/alert-new-response-reminders.lock /data/vhost/!!(*= $vhost *)!!/mysociety/foi/script/alert-new-response-reminders || echo "stalled?" diff --git a/db/migrate/046_add_last_event_id_to_alert_table.rb b/db/migrate/046_add_last_event_id_to_alert_table.rb new file mode 100644 index 000000000..4e67fee5b --- /dev/null +++ b/db/migrate/046_add_last_event_id_to_alert_table.rb @@ -0,0 +1,13 @@ +class AddLastEventIdToAlertTable < ActiveRecord::Migration + def self.up + add_column :user_info_request_sent_alerts, :info_request_event_id, :integer, :default => nil + execute "ALTER TABLE user_info_request_sent_alerts ADD CONSTRAINT fk_user_info_request_sent_alert_info_request_event FOREIGN KEY (info_request_event_id) REFERENCES info_request_events(id)" + # The coalesce is because null values are considred not equal in SQL, and we want them + # to be considered equal for the purposes of this index. + execute "create unique index user_info_request_sent_alerts_unique_index on user_info_request_sent_alerts (user_id, info_request_id, alert_type, coalesce(info_request_event_id, -1))" + end + + def self.down + remove_column :user_info_request_sent_alerts, :info_request_event_id + end +end diff --git a/db/schema.rb b/db/schema.rb index d057a9a10..dbdc7f4fd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 45) do +ActiveRecord::Schema.define(:version => 46) do create_table "incoming_messages", :force => true do |t| t.integer "info_request_id", :null => false @@ -116,11 +116,14 @@ ActiveRecord::Schema.define(:version => 45) do add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at" create_table "user_info_request_sent_alerts", :force => true do |t| - t.integer "user_id", :null => false - t.integer "info_request_id", :null => false - t.string "alert_type", :null => false + t.integer "user_id", :null => false + t.integer "info_request_id", :null => false + t.string "alert_type", :null => false + t.integer "info_request_event_id" end + add_index "user_info_request_sent_alerts", ["user_id", "info_request_id", "alert_type"], :name => "user_info_request_sent_alerts_unique_index", :unique => true + create_table "users", :force => true do |t| t.string "email", :null => false t.string "name", :null => false diff --git a/script/alert-new-response-reminders b/script/alert-new-response-reminders new file mode 100755 index 000000000..89ea117ab --- /dev/null +++ b/script/alert-new-response-reminders @@ -0,0 +1,7 @@ +#!/bin/bash + +LOC=`dirname $0` + +$LOC/runner 'RequestMailer.alert_new_response_reminders' + + diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index dd74829d4..746ae5f13 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -56,9 +56,9 @@ describe RequestController, "when showing one request" do ir = info_requests(:fancy_dog_request) receive_incoming_mail('incoming-request-plain.email', ir.incoming_email) deliveries = ActionMailer::Base.deliveries - deliveries.size.should == 1 + deliveries.size.should == 1 mail = deliveries[0] - mail.body.should =~ /You have a new response to the FOI request/ + mail.body.should =~ /You have a new response to the Freedom of Information request/ get :show, :url_title => 'why_do_you_have_such_a_fancy_dog' (assigns[:info_request_events].size - size_before).should == 1 @@ -149,7 +149,7 @@ describe RequestController, "when creating a new request" do om.body.should == "This is a silly letter. It is too short to be interesting." deliveries = ActionMailer::Base.deliveries - deliveries.size.should == 1 + deliveries.size.should == 1 mail = deliveries[0] mail.body.should =~ /This is a silly letter. It is too short to be interesting./ @@ -259,7 +259,7 @@ describe RequestController, "when sending a followup message" do post :show_response, :outgoing_message => { :body => "What a useless response! You suck." }, :id => info_requests(:fancy_dog_request).id, :incoming_message_id => incoming_messages(:useless_incoming_message), :submitted_followup => 1 deliveries = ActionMailer::Base.deliveries - deliveries.size.should == 1 + deliveries.size.should == 1 mail = deliveries[0] mail.body.should =~ /What a useless response! You suck./ mail.to_addrs.to_s.should == "FOI Person <foiperson@localhost>" @@ -278,7 +278,7 @@ describe RequestController, "sending overdue request alerts" do RequestMailer.alert_overdue_requests deliveries = ActionMailer::Base.deliveries - deliveries.size.should == 1 + deliveries.size.should == 1 mail = deliveries[0] mail.body.should =~ /20 working days/ mail.to_addrs.to_s.should == info_requests(:naughty_chicken_request).user.name_and_email @@ -297,5 +297,32 @@ describe RequestController, "sending overdue request alerts" do end +describe RequestController, "sending unclassified new response reminder alerts" do + integrate_views + fixtures :info_requests, :info_request_events, :public_bodies, :users, :incoming_messages, :outgoing_messages # all needed as integrating views + + it "should send an alert" do + RequestMailer.alert_new_response_reminders + + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + mail = deliveries[0] + mail.body.should =~ /this will help others/ + mail.to_addrs.to_s.should == info_requests(:fancy_dog_request).user.name_and_email + mail.body =~ /(http:\/\/.*\/c\/(.*))/ + mail_url = $1 + mail_token = $2 + + session[:user_id].should be_nil + controller.test_code_redirect_by_email_token(mail_token, self) # XXX hack to avoid having to call User controller for email link + session[:user_id].should == info_requests(:fancy_dog_request).user.id + + response.should render_template('describe_state') + assigns[:info_request].should == info_requests(:fancy_dog_request) + end + +end + + @@ -27,7 +27,6 @@ BAILII - relationship with law courts, robots.txt ? Next ==== -Send email to remind people to classify Send email to tell admins something isn't classified Send email to remind people to clarify @@ -81,6 +80,7 @@ Tell application developer if working days table not up to date, and needs updating Response overdue alerts are only sent first time a request goes into that state :( + Store id in alert of last event which resets the due date Get deploying of Lucene search working |