aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/admin_censor_rule_controller.rb72
-rw-r--r--app/controllers/request_controller.rb12
-rw-r--r--app/models/censor_rule.rb33
-rw-r--r--app/models/incoming_message.rb25
-rw-r--r--app/models/info_request.rb3
-rw-r--r--app/views/admin_censor_rule/_form.rhtml14
-rw-r--r--app/views/admin_censor_rule/_show.rhtml27
-rw-r--r--app/views/admin_censor_rule/edit.rhtml16
-rw-r--r--app/views/admin_censor_rule/new.rhtml9
-rw-r--r--app/views/admin_request/show.rhtml2
-rw-r--r--config/routes.rb3
-rw-r--r--db/migrate/068_add_censor_table.rb29
-rw-r--r--db/schema.rb14
-rw-r--r--todo.txt13
14 files changed, 254 insertions, 18 deletions
diff --git a/app/controllers/admin_censor_rule_controller.rb b/app/controllers/admin_censor_rule_controller.rb
new file mode 100644
index 000000000..36c700cbb
--- /dev/null
+++ b/app/controllers/admin_censor_rule_controller.rb
@@ -0,0 +1,72 @@
+# app/controllers/admin_censor_rule_controller.rb:
+# For modifying requests.
+#
+# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
+# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+#
+# $Id: admin_censor_rule_controller.rb,v 1.1 2008-10-27 18:18:30 francis Exp $
+
+class AdminCensorRuleController < ApplicationController
+ layout "admin"
+ before_filter :assign_http_auth_user
+
+ def new
+ @info_request = InfoRequest.find(params[:info_request_id])
+ end
+
+ def create
+ params[:censor_rule][:last_edit_editor] = admin_http_auth_user()
+ @censor_rule = CensorRule.new(params[:censor_rule])
+ if @censor_rule.save
+ expire_for_request(@censor_rule.info_request)
+ flash[:notice] = 'CensorRule was successfully created.'
+ redirect_to admin_url('request/show/' + @censor_rule.info_request.id.to_s)
+ else
+ render :action => 'new'
+ end
+ end
+
+ def edit
+ @censor_rule = CensorRule.find(params[:id])
+ end
+
+ def update
+ params[:censor_rule][:last_edit_editor] = admin_http_auth_user()
+ @censor_rule = CensorRule.find(params[:id])
+ if @censor_rule.update_attributes(params[:censor_rule])
+ expire_for_request(@censor_rule.info_request)
+ flash[:notice] = 'CensorRule was successfully updated.'
+ redirect_to admin_url('request/show/' + @censor_rule.info_request.id.to_s)
+ else
+ render :action => 'edit'
+ end
+ end
+
+ def destroy
+ censor_rule = CensorRule.find(params[:censor_rule_id])
+ info_request = censor_rule.info_request
+
+ censor_rule.destroy
+ expire_for_request(info_request)
+
+ flash[:notice] = "CensorRule was successfully destroyed."
+
+ redirect_to admin_url('request/show/' + info_request.id.to_s)
+ end
+
+
+ def expire_for_request(info_request)
+ # clear out cached entries
+ for incoming_message in info_request.incoming_messages
+ for attachment in incoming_message.get_attachments_for_display
+ expire_page :controller => 'request', :action => "get_attachment", :id => info_request.id,
+ :incoming_message_id => incoming_message.id,
+ :part => attachment.url_part_number, :file_name => attachment.display_filename
+ end
+ end
+ end
+
+ private
+
+end
+
diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb
index afb980c87..bb0d7f9bd 100644
--- a/app/controllers/request_controller.rb
+++ b/app/controllers/request_controller.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_controller.rb,v 1.129 2008-10-25 12:01:06 francis Exp $
+# $Id: request_controller.rb,v 1.130 2008-10-27 18:18:30 francis Exp $
class RequestController < ApplicationController
@@ -406,6 +406,10 @@ class RequestController < ApplicationController
get_attachment_internal
html = @attachment.body_as_html
+ # Mask any more emails that have now been exposed (e.g. in PDFs - ones in
+ # .doc will have been got in get_attachment_internal below)
+ html = @incoming_message.binary_mask_stuff(html)
+
view_html_stylesheet = render_to_string :partial => "request/view_html_stylesheet"
html.sub!(/<head>/i, "<head>" + view_html_stylesheet)
html.sub!(/<body[^>]*>/i, '<body><prefix-here><div id="wrapper"><div id="view_html_content">' + view_html_stylesheet)
@@ -414,10 +418,6 @@ class RequestController < ApplicationController
view_html_prefix = render_to_string :partial => "request/view_html_prefix"
html.sub!("<prefix-here>", view_html_prefix)
- # Mask any more emails that have now been exposed (e.g. in PDFs - ones in
- # .doc will have been got in get_attachment_internal below)
- html = IncomingMessage.binary_mask_all_emails(html)
-
response.content_type = 'text/html'
render :text => html
end
@@ -436,7 +436,7 @@ class RequestController < ApplicationController
# Prevent spam to magic request address.
# XXX Bit dodgy modifying a binary like this but hey. Maybe only do for some mime types?
- @attachment.body = IncomingMessage.binary_mask_all_emails(@attachment.body)
+ @attachment.body = @incoming_message.binary_mask_stuff(@attachment.body)
end
# FOI officers can upload a response
diff --git a/app/models/censor_rule.rb b/app/models/censor_rule.rb
new file mode 100644
index 000000000..acc4349e6
--- /dev/null
+++ b/app/models/censor_rule.rb
@@ -0,0 +1,33 @@
+# models/censor_rule.rb:
+# Stores alterations to remove specific data from requests.
+#
+# Copyright (c) 2008 UK Citizens Online Democracy. All rights reserved.
+# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
+#
+# $Id: censor_rule.rb,v 1.1 2008-10-27 18:18:30 francis Exp $
+
+class CensorRule < ActiveRecord::Base
+ belongs_to :info_request
+ belongs_to :user
+ belongs_to :public_body
+
+ def apply_to_text(text)
+ text.gsub!(self.text, self.replacement)
+ return text
+ end
+ def apply_to_binary(binary)
+ replacement = self.text.gsub(/./, 'x')
+ binary.gsub!(self.text, replacement)
+ return binary
+ end
+
+
+ def validate
+ if self.info_request.nil? && self.user.nil? && self.public_body.nil?
+ errors.add("Censor must apply to an info request a user or a body; ")
+ end
+ end
+end
+
+
+
diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb
index a6ca692c8..eb63ee6fa 100644
--- a/app/models/incoming_message.rb
+++ b/app/models/incoming_message.rb
@@ -19,7 +19,7 @@
# Copyright (c) 2007 UK Citizens Online Democracy. All rights reserved.
# Email: francis@mysociety.org; WWW: http://www.mysociety.org/
#
-# $Id: incoming_message.rb,v 1.154 2008-10-17 20:43:25 francis Exp $
+# $Id: incoming_message.rb,v 1.155 2008-10-27 18:18:30 francis Exp $
# TODO
# Move some of the (e.g. quoting) functions here into rblib, as they feel
@@ -288,7 +288,8 @@ class IncomingMessage < ActiveRecord::Base
end
# Replaces all email addresses in (possibly binary data) with equal length alternative ones.
- def IncomingMessage.binary_mask_all_emails(text)
+ # Also replaces censor items
+ def binary_mask_stuff(text)
orig_size = text.size
# Replace ASCII email addresses...
@@ -311,7 +312,12 @@ class IncomingMessage < ActiveRecord::Base
text.gsub!(email, mask)
end
- raise "internal error in binary_mask_all_emails" if text.size != orig_size
+ # Replace censor items
+ for censor_rule in self.info_request.censor_rules
+ text = censor_rule.apply_to_binary(text)
+ end
+
+ raise "internal error in binary_mask_stuff" if text.size != orig_size
return text
end
@@ -337,7 +343,7 @@ class IncomingMessage < ActiveRecord::Base
end
# Remove emails, mobile phones and other details FOI officers ask us to remove.
- def self.remove_privacy_sensitive_things(text)
+ def remove_privacy_sensitive_things(text)
text = text.dup
# Remove any email addresses - we don't want bounce messages to leak out
@@ -362,6 +368,11 @@ class IncomingMessage < ActiveRecord::Base
# Remove WhatDoTheyKnow signup links
text.gsub!(/http:\/\/www.whatdotheyknow.com\/c\/[^\s]+/, "[WDTK login link]")
+ # Remove things from censor rules
+ for censor_rule in self.info_request.censor_rules
+ text = censor_rule.apply_to_text(text)
+ end
+
return text
end
@@ -704,7 +715,7 @@ class IncomingMessage < ActiveRecord::Base
# Find the body text and remove emails for privacy/anti-spam reasons
text = get_main_body_text
text = self.mask_special_emails(text)
- text = IncomingMessage.remove_privacy_sensitive_things(text)
+ text = self.remove_privacy_sensitive_things(text)
# Remove quoted sections, adding HTML. XXX The FOLDED_QUOTED_SECTION is
# a nasty hack so we can escape other HTML before adding the unfold
@@ -745,7 +756,7 @@ class IncomingMessage < ActiveRecord::Base
# Find the body text and remove emails for privacy/anti-spam reasons
text = get_main_body_text
text = self.mask_special_emails(text)
- text = IncomingMessage.remove_privacy_sensitive_things(text)
+ text = self.remove_privacy_sensitive_things(text)
# Remove existing quoted sections
text = self.remove_lotus_quoting(text, '')
@@ -763,7 +774,7 @@ class IncomingMessage < ActiveRecord::Base
# Remove any privacy things
text = self.cached_attachment_text
text = self.mask_special_emails(text)
- text = IncomingMessage.remove_privacy_sensitive_things(text)
+ text = self.remove_privacy_sensitive_things(text)
return text
end
def IncomingMessage.get_attachment_text_internal_one_file(content_type, body)
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 0c99dadbf..ebf06913c 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -23,7 +23,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.146 2008-10-14 12:48:49 francis Exp $
+# $Id: info_request.rb,v 1.147 2008-10-27 18:18:30 francis Exp $
require 'digest/sha1'
require File.join(File.dirname(__FILE__),'../../vendor/plugins/acts_as_xapian/lib/acts_as_xapian')
@@ -44,6 +44,7 @@ class InfoRequest < ActiveRecord::Base
has_many :user_info_request_sent_alerts
has_many :track_things, :order => 'created_at desc'
has_many :comments, :order => 'created_at'
+ has_many :censor_rules, :order => 'created_at desc'
# user described state (also update in info_request_event, admin_request/edit.rhtml)
validates_inclusion_of :described_state, :in => [
diff --git a/app/views/admin_censor_rule/_form.rhtml b/app/views/admin_censor_rule/_form.rhtml
new file mode 100644
index 000000000..4034e9859
--- /dev/null
+++ b/app/views/admin_censor_rule/_form.rhtml
@@ -0,0 +1,14 @@
+<%= error_messages_for 'censor_rule' %>
+
+<p><label for="censor_rule_text">Text</label> (that you want to remove)<br/>
+<%= text_field 'censor_rule', 'text', :size => 60 %></p>
+
+<p><label for="censor_rule_replacement">Replacement</label> (put is in <strong>[square brackets]</strong>, e.g. [personal information removed]. applies only to text in emails; binaries must stay the same length and the replacement is just a bunch of 'x's)<br/>
+<%= text_field 'censor_rule', 'replacement', :size => 60 %></p>
+
+<p><label for="censor_rule_last_edit_comment">Comment for this edit</label> (put purpose of the rule, and why the change)<br/>
+<%= text_area 'censor_rule', 'last_edit_comment', :rows => 2, :cols => 60 %></p>
+
+<p>Rule is for request '<%=request_link(info_request)%>'
+ <%= hidden_field 'censor_rule', 'info_request_id', { :value => info_request.id } %>
+</p>
diff --git a/app/views/admin_censor_rule/_show.rhtml b/app/views/admin_censor_rule/_show.rhtml
new file mode 100644
index 000000000..4d6432a9e
--- /dev/null
+++ b/app/views/admin_censor_rule/_show.rhtml
@@ -0,0 +1,27 @@
+
+<table>
+ <tr>
+ <th>Id</th>
+ <% for column in CensorRule.content_columns %>
+ <th><%= column.human_name %></th>
+ <% end %>
+ <th>Actions</th>
+ </tr>
+
+<% for censor_rule in censor_rules %>
+ <tr class="<%= cycle('odd', 'even') %>">
+ <td><%=h censor_rule.id %></td>
+ <% for column in CensorRule.content_columns.map { |c| c.name } %>
+ <td><%=h censor_rule.send(column) %></td>
+ <% end %>
+ <td>
+ <%= link_to "Edit", '../../censor/edit/' + censor_rule.id.to_s %>
+ </td>
+ </tr>
+<% end %>
+</table>
+
+<p>
+ <%= link_to "New censor rule", '../../censor/new?info_request_id=' + info_request.id.to_s %>
+</p>
+
diff --git a/app/views/admin_censor_rule/edit.rhtml b/app/views/admin_censor_rule/edit.rhtml
new file mode 100644
index 000000000..c22a61021
--- /dev/null
+++ b/app/views/admin_censor_rule/edit.rhtml
@@ -0,0 +1,16 @@
+<% @title = 'Edit censor rule' %>
+
+<h1><%=@title%></h1>
+
+<% form_tag '../update/' + @censor_rule.id.to_s do %>
+ <%= render :partial => 'form', :locals => { :info_request => @censor_rule.info_request } %>
+ <p><%= submit_tag 'Save', :accesskey => 's' %></p>
+<% end %>
+
+<% form_tag('../destroy/' + @censor_rule.id.to_s) do %>
+ <p>
+ <%= hidden_field_tag(:censor_rule_id, @censor_rule.id) %>
+ Permanent! --&gt; <%= submit_tag "Destroy rule" %>
+ </p>
+<% end %>
+
diff --git a/app/views/admin_censor_rule/new.rhtml b/app/views/admin_censor_rule/new.rhtml
new file mode 100644
index 000000000..36de5f0f1
--- /dev/null
+++ b/app/views/admin_censor_rule/new.rhtml
@@ -0,0 +1,9 @@
+<% @title = 'New censor rule' %>
+
+<h1><%=@title%></h1>
+
+<% form_tag 'create' do %>
+ <%= render :partial => 'form', :locals => { :info_request => @info_request } %>
+ <p><%= submit_tag "Create" %></p>
+<% end %>
+
diff --git a/app/views/admin_request/show.rhtml b/app/views/admin_request/show.rhtml
index 7a5deb7d7..4efd90b11 100644
--- a/app/views/admin_request/show.rhtml
+++ b/app/views/admin_request/show.rhtml
@@ -128,4 +128,6 @@
<% end %>
</table>
+<h2>Censor rules</h2>
+<%= render :partial => 'admin_censor_rule/show', :locals => { :censor_rules => @info_request.censor_rules, :info_request => @info_request } %>
diff --git a/config/routes.rb b/config/routes.rb
index 6d27b2dd7..1f70bee8e 100644
--- a/config/routes.rb
+++ b/config/routes.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: routes.rb,v 1.76 2008-10-17 20:32:43 francis Exp $
+# $Id: routes.rb,v 1.77 2008-10-27 18:18:31 francis Exp $
ActionController::Routing::Routes.draw do |map|
@@ -96,6 +96,7 @@ ActionController::Routing::Routes.draw do |map|
map.connect '/admin/request/:action/:id', :controller => 'admin_request'
map.connect '/admin/user/:action/:id', :controller => 'admin_user'
map.connect '/admin/track/:action/:id', :controller => 'admin_track'
+ map.connect '/admin/censor/:action/:id', :controller => 'admin_censor_rule'
# Sample of named route:
# map.purchase 'products/:id/purchase', :controller => 'catalog', :action => 'purchase'
diff --git a/db/migrate/068_add_censor_table.rb b/db/migrate/068_add_censor_table.rb
new file mode 100644
index 000000000..92a17d2bc
--- /dev/null
+++ b/db/migrate/068_add_censor_table.rb
@@ -0,0 +1,29 @@
+class AddCensorTable < ActiveRecord::Migration
+ def self.up
+ create_table :censor_rules do |t|
+ t.column :info_request_id, :integer
+ t.column :user_id, :integer
+ t.column :public_body_id, :integer
+
+ t.column :text, :text, :null => false
+ t.column :replacement, :text, :null => false
+
+ t.column :last_edit_editor, :string, :null => false
+ t.column :last_edit_comment, :text, :null => false
+
+ t.column :created_at, :datetime, :null => false
+ t.column :updated_at, :datetime, :null => false
+ end
+
+ if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
+ execute "ALTER TABLE censor_rules ADD CONSTRAINT fk_censor_rules_info_request FOREIGN KEY (info_request_id) REFERENCES info_requests(id)"
+ execute "ALTER TABLE censor_rules ADD CONSTRAINT fk_censor_rules_user FOREIGN KEY (user_id) REFERENCES users(id)"
+ execute "ALTER TABLE censor_rules ADD CONSTRAINT fk_censor_rules_public_body FOREIGN KEY (public_body_id) REFERENCES public_bodies(id)"
+ end
+ end
+
+ def self.down
+ drop_table :censor_rules
+ end
+end
+
diff --git a/db/schema.rb b/db/schema.rb
index 6939d7c41..e33f36c38 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 => 67) do
+ActiveRecord::Schema.define(:version => 68) do
create_table "acts_as_xapian_jobs", :force => true do |t|
t.string "model", :null => false
@@ -19,6 +19,18 @@ ActiveRecord::Schema.define(:version => 67) do
add_index "acts_as_xapian_jobs", ["model", "model_id"], :name => "index_acts_as_xapian_jobs_on_model_and_model_id", :unique => true
+ create_table "censor_rules", :force => true do |t|
+ t.integer "info_request_id"
+ t.integer "user_id"
+ t.integer "public_body_id"
+ t.text "text", :null => false
+ t.text "replacement", :null => false
+ t.string "last_edit_editor", :null => false
+ t.text "last_edit_comment", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
create_table "comments", :force => true do |t|
t.integer "user_id", :null => false
t.string "comment_type", :default => "internal_error", :null => false
diff --git a/todo.txt b/todo.txt
index 0195b0d14..d95b881ee 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,3 +1,14 @@
+Test data for Tony
+
+Censor stuff
+============
+
+Thing about case insensitivity
+Add rules for users / bodies?
+
+Internal review
+===============
+
Where to offer button to enter internal review state:
- always offer option on request to have internal review, except when in waiting_response
earlier than 20 days, and except when in waiting_clarification (call button "make clarification"!)
@@ -24,8 +35,6 @@ might want to go back to internal review, not to general awaiting response?
When you select "waiting_response" might want to convert to
internal_review in case where current state is already internal_review.
-Test data for Tony
-
Next
====