diff options
Diffstat (limited to 'app')
66 files changed, 1090 insertions, 732 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 0bccd3358..8b606ea85 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -17,7 +17,7 @@ class AdminController < ApplicationController end # Always give full stack trace for admin interface - def local_request? + def show_rails_exceptions? true end @@ -29,8 +29,7 @@ class AdminController < ApplicationController FileUtils.rm_rf(cache_subpath) # Remove any download zips - download_dir = request_download_zip_dir(info_request) - FileUtils.rm_rf(download_dir) + FileUtils.rm_rf(info_request.download_zip_dir) # Remove the database caches of body / attachment text (the attachment text # one is after privacy rules are applied) diff --git a/app/controllers/admin_general_controller.rb b/app/controllers/admin_general_controller.rb index ec5f95eda..196616ed6 100644 --- a/app/controllers/admin_general_controller.rb +++ b/app/controllers/admin_general_controller.rb @@ -5,7 +5,6 @@ # Email: hello@mysociety.org; WWW: http://www.mysociety.org/ class AdminGeneralController < AdminController - skip_before_filter :authenticate, :only => :admin_js def index # ensure we have a trailing slash @@ -142,9 +141,5 @@ class AdminGeneralController < AdminController @request_env = request.env end - # TODO: Remove this when support for proxy admin interface is removed - def admin_js - render :layout => false, :content_type => "application/javascript" - end end diff --git a/app/controllers/admin_incoming_message_controller.rb b/app/controllers/admin_incoming_message_controller.rb new file mode 100644 index 000000000..6b50d0e36 --- /dev/null +++ b/app/controllers/admin_incoming_message_controller.rb @@ -0,0 +1,80 @@ +class AdminIncomingMessageController < AdminController + + def edit + @incoming_message = IncomingMessage.find(params[:id]) + end + + def update + @incoming_message = IncomingMessage.find(params[:id]) + old_prominence = @incoming_message.prominence + old_prominence_reason = @incoming_message.prominence_reason + @incoming_message.prominence = params[:incoming_message][:prominence] + @incoming_message.prominence_reason = params[:incoming_message][:prominence_reason] + if @incoming_message.save + @incoming_message.info_request.log_event('edit_incoming', + :incoming_message_id => @incoming_message.id, + :editor => admin_current_user(), + :old_prominence => old_prominence, + :prominence => @incoming_message.prominence, + :old_prominence_reason => old_prominence_reason, + :prominence_reason => @incoming_message.prominence_reason) + expire_for_request(@incoming_message.info_request) + flash[:notice] = 'Incoming message successfully updated.' + redirect_to admin_request_show_url(@incoming_message.info_request) + else + render :action => 'edit' + end + end + + def destroy + @incoming_message = IncomingMessage.find(params[:incoming_message_id]) + @info_request = @incoming_message.info_request + incoming_message_id = @incoming_message.id + + @incoming_message.fully_destroy + @incoming_message.info_request.log_event("destroy_incoming", + { :editor => admin_current_user(), :deleted_incoming_message_id => incoming_message_id }) + # expire cached files + expire_for_request(@info_request) + flash[:notice] = 'Incoming message successfully destroyed.' + redirect_to admin_request_show_url(@info_request) + end + + def redeliver + incoming_message = IncomingMessage.find(params[:redeliver_incoming_message_id]) + message_ids = params[:url_title].split(",").each {|x| x.strip} + previous_request = incoming_message.info_request + destination_request = nil + ActiveRecord::Base.transaction do + for m in message_ids + if m.match(/^[0-9]+$/) + destination_request = InfoRequest.find_by_id(m.to_i) + else + destination_request = InfoRequest.find_by_url_title!(m) + end + if destination_request.nil? + flash[:error] = "Failed to find destination request '" + m + "'" + return redirect_to admin_request_show_url(previous_request) + end + + raw_email_data = incoming_message.raw_email.data + mail = MailHandler.mail_from_raw_email(raw_email_data) + destination_request.receive(mail, raw_email_data, true) + + incoming_message_id = incoming_message.id + incoming_message.info_request.log_event("redeliver_incoming", { + :editor => admin_current_user(), + :destination_request => destination_request.id, + :deleted_incoming_message_id => incoming_message_id + }) + + flash[:notice] = "Message has been moved to request(s). Showing the last one:" + end + # expire cached files + expire_for_request(previous_request) + incoming_message.fully_destroy + end + redirect_to admin_request_show_url(destination_request) + end + +end diff --git a/app/controllers/admin_outgoing_message_controller.rb b/app/controllers/admin_outgoing_message_controller.rb new file mode 100644 index 000000000..ec0981677 --- /dev/null +++ b/app/controllers/admin_outgoing_message_controller.rb @@ -0,0 +1,47 @@ +class AdminOutgoingMessageController < AdminController + + def edit + @outgoing_message = OutgoingMessage.find(params[:id]) + end + + def destroy + @outgoing_message = OutgoingMessage.find(params[:outgoing_message_id]) + @info_request = @outgoing_message.info_request + outgoing_message_id = @outgoing_message.id + + @outgoing_message.fully_destroy + @outgoing_message.info_request.log_event("destroy_outgoing", + { :editor => admin_current_user(), :deleted_outgoing_message_id => outgoing_message_id }) + + flash[:notice] = 'Outgoing message successfully destroyed.' + redirect_to admin_request_show_url(@info_request) + end + + def update + @outgoing_message = OutgoingMessage.find(params[:id]) + + old_body = @outgoing_message.body + old_prominence = @outgoing_message.prominence + old_prominence_reason = @outgoing_message.prominence_reason + @outgoing_message.prominence = params[:outgoing_message][:prominence] + @outgoing_message.prominence_reason = params[:outgoing_message][:prominence_reason] + @outgoing_message.body = params[:outgoing_message][:body] + if @outgoing_message.save + @outgoing_message.info_request.log_event("edit_outgoing", + { :outgoing_message_id => @outgoing_message.id, + :editor => admin_current_user(), + :old_body => old_body, + :body => @outgoing_message.body, + :old_prominence => old_prominence, + :old_prominence_reason => old_prominence_reason, + :prominence => @outgoing_message.prominence, + :prominence_reason => @outgoing_message.prominence_reason }) + flash[:notice] = 'Outgoing message successfully updated.' + expire_for_request(@outgoing_message.info_request) + redirect_to admin_request_show_url(@outgoing_message.info_request) + else + render :action => 'edit' + end + end + +end diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index ec2a08dbc..e0da234b0 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -14,6 +14,7 @@ class AdminPublicBodyController < AdminController def _lookup_query_internal @locale = self.locale_from_params() + underscore_locale = @locale.gsub '-', '_' I18n.with_locale(@locale) do @query = params[:query] if @query == "" @@ -23,10 +24,10 @@ class AdminPublicBodyController < AdminController if @page == "" @page = nil end - @public_bodies = PublicBody.joins(:translations).where(@query.nil? ? "public_body_translations.locale = '#{@locale}'" : + @public_bodies = PublicBody.joins(:translations).where(@query.nil? ? "public_body_translations.locale = '#{underscore_locale}'" : ["(lower(public_body_translations.name) like lower('%'||?||'%') or lower(public_body_translations.short_name) like lower('%'||?||'%') or - lower(public_body_translations.request_email) like lower('%'||?||'%' )) AND (public_body_translations.locale = '#{@locale}')", @query, @query, @query]).paginate :order => "public_body_translations.name", :page => @page, :per_page => 100 + lower(public_body_translations.request_email) like lower('%'||?||'%' )) AND (public_body_translations.locale = '#{underscore_locale}')", @query, @query, @query]).paginate :order => "public_body_translations.name", :page => @page, :per_page => 100 end @public_bodies_by_tag = PublicBody.find_by_tag(@query) end diff --git a/app/controllers/admin_request_controller.rb b/app/controllers/admin_request_controller.rb index 40ccfb98c..4d45ced8b 100644 --- a/app/controllers/admin_request_controller.rb +++ b/app/controllers/admin_request_controller.rb @@ -106,39 +106,6 @@ class AdminRequestController < AdminController redirect_to admin_request_list_url end - def edit_outgoing - @outgoing_message = OutgoingMessage.find(params[:id]) - end - - def destroy_outgoing - @outgoing_message = OutgoingMessage.find(params[:outgoing_message_id]) - @info_request = @outgoing_message.info_request - outgoing_message_id = @outgoing_message.id - - @outgoing_message.fully_destroy - @outgoing_message.info_request.log_event("destroy_outgoing", - { :editor => admin_current_user(), :deleted_outgoing_message_id => outgoing_message_id }) - - flash[:notice] = 'Outgoing message successfully destroyed.' - redirect_to admin_request_show_url(@info_request) - end - - def update_outgoing - @outgoing_message = OutgoingMessage.find(params[:id]) - - old_body = @outgoing_message.body - - if @outgoing_message.update_attributes(params[:outgoing_message]) - @outgoing_message.info_request.log_event("edit_outgoing", - { :outgoing_message_id => @outgoing_message.id, :editor => admin_current_user(), - :old_body => old_body, :body => @outgoing_message.body }) - flash[:notice] = 'Outgoing message successfully updated.' - redirect_to admin_request_show_url(@outgoing_message.info_request) - else - render :action => 'edit_outgoing' - end - end - def edit_comment @comment = Comment.find(params[:id]) end @@ -163,58 +130,6 @@ class AdminRequestController < AdminController end end - - def destroy_incoming - @incoming_message = IncomingMessage.find(params[:incoming_message_id]) - @info_request = @incoming_message.info_request - incoming_message_id = @incoming_message.id - - @incoming_message.fully_destroy - @incoming_message.info_request.log_event("destroy_incoming", - { :editor => admin_current_user(), :deleted_incoming_message_id => incoming_message_id }) - # expire cached files - expire_for_request(@info_request) - flash[:notice] = 'Incoming message successfully destroyed.' - redirect_to admin_request_show_url(@info_request) - end - - def redeliver_incoming - incoming_message = IncomingMessage.find(params[:redeliver_incoming_message_id]) - message_ids = params[:url_title].split(",").each {|x| x.strip} - previous_request = incoming_message.info_request - destination_request = nil - ActiveRecord::Base.transaction do - for m in message_ids - if m.match(/^[0-9]+$/) - destination_request = InfoRequest.find_by_id(m.to_i) - else - destination_request = InfoRequest.find_by_url_title!(m) - end - if destination_request.nil? - flash[:error] = "Failed to find destination request '" + m + "'" - return redirect_to admin_request_show_url(previous_request) - end - - raw_email_data = incoming_message.raw_email.data - mail = MailHandler.mail_from_raw_email(raw_email_data) - destination_request.receive(mail, raw_email_data, true) - - incoming_message_id = incoming_message.id - incoming_message.info_request.log_event("redeliver_incoming", { - :editor => admin_current_user(), - :destination_request => destination_request.id, - :deleted_incoming_message_id => incoming_message_id - }) - - flash[:notice] = "Message has been moved to request(s). Showing the last one:" - end - # expire cached files - expire_for_request(previous_request) - incoming_message.fully_destroy - end - redirect_to admin_request_show_url(destination_request) - end - # change user or public body of a request magically def move_request info_request = InfoRequest.find(params[:info_request_id]) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 88b107861..cbdffc441 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -119,12 +119,9 @@ class ApplicationController < ActionController::Base end def render_exception(exception) - - # In development, or the admin interface, or for a local request, let Rails handle the exception - # with its stack trace templates. Local requests in testing are a special case so that we can - # test this method - there we use consider_all_requests_local to control behaviour. - if Rails.application.config.consider_all_requests_local || local_request? || - (request.local? && !Rails.env.test?) + # In development or the admin interface let Rails handle the exception + # with its stack trace templates + if Rails.application.config.consider_all_requests_local || show_rails_exceptions? raise exception end @@ -150,7 +147,7 @@ class ApplicationController < ActionController::Base end end - def local_request? + def show_rails_exceptions? false end @@ -214,19 +211,6 @@ class ApplicationController < ActionController::Base end end - def request_dirs(info_request) - first_three_digits = info_request.id.to_s()[0..2] - File.join(first_three_digits.to_s, info_request.id.to_s) - end - - def request_download_zip_dir(info_request) - File.join(download_zip_dir, "download", request_dirs(info_request)) - end - - def download_zip_dir() - File.join(Rails.root, '/cache/zips/') - end - # get the local locale def locale_from_params(*args) if params[:show_locale] diff --git a/app/controllers/public_body_controller.rb b/app/controllers/public_body_controller.rb index 374866eda..02f0ceb19 100644 --- a/app/controllers/public_body_controller.rb +++ b/app/controllers/public_body_controller.rb @@ -6,6 +6,7 @@ # Email: hello@mysociety.org; WWW: http://www.mysociety.org/ require 'fastercsv' +require 'confidence_intervals' class PublicBodyController < ApplicationController # XXX tidy this up with better error messages, and a more standard infrastructure for the redirect to canonical URL @@ -85,34 +86,45 @@ class PublicBodyController < ApplicationController def list long_cache # XXX move some of these tag SQL queries into has_tag_string.rb - @query = "%#{params[:public_body_query].nil? ? "" : params[:public_body_query]}%" + + like_query = params[:public_body_query] + like_query = "" if like_query.nil? + like_query = "%#{like_query}%" + @tag = params[:tag] - @locale = self.locale_from_params() - default_locale = I18n.default_locale.to_s - locale_condition = "(upper(public_body_translations.name) LIKE upper(?) - OR upper(public_body_translations.notes) LIKE upper (?)) - AND public_body_translations.locale = ? - AND public_bodies.id <> #{PublicBody.internal_admin_body.id}" + + @locale = self.locale_from_params + underscore_locale = @locale.gsub '-', '_' + underscore_default_locale = I18n.default_locale.to_s.gsub '-', '_' + + where_condition = "public_bodies.id <> #{PublicBody.internal_admin_body.id}" + where_parameters = [] + + first_letter = false + + base_tag_condition = " AND (SELECT count(*) FROM has_tag_string_tags" \ + " WHERE has_tag_string_tags.model_id = public_bodies.id" \ + " AND has_tag_string_tags.model = 'PublicBody'" + + # Restrict the public bodies shown according to the tag + # parameter supplied in the URL: if @tag.nil? or @tag == "all" @tag = "all" - conditions = [locale_condition, @query, @query, default_locale] elsif @tag == 'other' category_list = PublicBodyCategories::get().tags().map{|c| "'"+c+"'"}.join(",") - conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id - and has_tag_string_tags.model = \'PublicBody\' - and has_tag_string_tags.name in (' + category_list + ')) = 0', @query, @query, default_locale] + where_condition += base_tag_condition + " AND has_tag_string_tags.name in (#{category_list})) = 0" elsif @tag.size == 1 @tag.upcase! - conditions = [locale_condition + ' AND public_body_translations.first_letter = ?', @query, @query, default_locale, @tag] + # The first letter queries have to be done on + # translations, so just indicate to add that later: + first_letter = true elsif @tag.include?(":") name, value = HasTagString::HasTagStringTag.split_tag_into_name_value(@tag) - conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id - and has_tag_string_tags.model = \'PublicBody\' - and has_tag_string_tags.name = ? and has_tag_string_tags.value = ?) > 0', @query, @query, default_locale, name, value] + where_condition += base_tag_condition + " AND has_tag_string_tags.name = ? AND has_tag_string_tags.value = ?) > 0" + where_parameters.concat [name, value] else - conditions = [locale_condition + ' AND (select count(*) from has_tag_string_tags where has_tag_string_tags.model_id = public_bodies.id - and has_tag_string_tags.model = \'PublicBody\' - and has_tag_string_tags.name = ?) > 0', @query, @query, default_locale, @tag] + where_condition += base_tag_condition + " AND has_tag_string_tags.name = ?) > 0" + where_parameters.concat [@tag] end if @tag == "all" @@ -127,10 +139,45 @@ class PublicBodyController < ApplicationController @description = _("in the category ‘{{category_name}}’", :category_name=>category_name) end end + I18n.with_locale(@locale) do - @public_bodies = PublicBody.where(conditions).joins(:translations).order("public_body_translations.name").paginate( - :page => params[:page], :per_page => 100 - ) + + if AlaveteliConfiguration::public_body_list_fallback_to_default_locale + # Unfortunately, when we might fall back to the + # default locale, this is a rather complex query: + query = %Q{ + SELECT public_bodies.*, COALESCE(current_locale.name, default_locale.name) AS display_name + FROM public_bodies + LEFT OUTER JOIN public_body_translations as current_locale + ON (public_bodies.id = current_locale.public_body_id + AND current_locale.locale = ? AND #{get_public_body_list_translated_condition 'current_locale', first_letter}) + LEFT OUTER JOIN public_body_translations as default_locale + ON (public_bodies.id = default_locale.public_body_id + AND default_locale.locale = ? AND #{get_public_body_list_translated_condition 'default_locale', first_letter}) + WHERE #{where_condition} AND COALESCE(current_locale.name, default_locale.name) IS NOT NULL + ORDER BY display_name} + sql = [query, underscore_locale, like_query, like_query] + sql.push @tag if first_letter + sql += [underscore_default_locale, like_query, like_query] + sql.push @tag if first_letter + sql += where_parameters + @public_bodies = PublicBody.paginate_by_sql( + sql, + :page => params[:page], + :per_page => 100) + else + # The simpler case where we're just searching in the current locale: + where_condition = get_public_body_list_translated_condition('public_body_translations', first_letter, true) + + ' AND ' + where_condition + where_sql = [where_condition, like_query, like_query] + where_sql.push @tag if first_letter + where_sql += [underscore_locale] + where_parameters + @public_bodies = PublicBody.where(where_sql) \ + .joins(:translations) \ + .order("public_body_translations.name") \ + .paginate(:page => params[:page], :per_page => 100) + end + respond_to do |format| format.html { render :template => "public_body/list" } end @@ -149,6 +196,84 @@ class PublicBodyController < ApplicationController :disposition =>'attachment', :encoding => 'utf8') end + def statistics + unless AlaveteliConfiguration::public_body_statistics_page + raise ActiveRecord::RecordNotFound.new("Page not enabled") + end + + per_graph = 8 + minimum_requests = AlaveteliConfiguration::minimum_requests_for_statistics + # Make sure minimum_requests is > 0 to avoid division-by-zero + minimum_requests = [minimum_requests, 1].max + total_column = 'info_requests_count' + + @graph_list = [] + + [[total_column, + [{ + :title => _('Public bodies with the most requests'), + :y_axis => _('Number of requests'), + :highest => true}]], + ['info_requests_successful_count', + [{ + :title => _('Public bodies with the most successful requests'), + :y_axis => _('Percentage of total requests'), + :highest => true}, + { + :title => _('Public bodies with the fewest successful requests'), + :y_axis => _('Percentage of total requests'), + :highest => false}]], + ['info_requests_overdue_count', + [{ + :title => _('Public bodies with most overdue requests'), + :y_axis => _('Percentage of requests that are overdue'), + :highest => true}]], + ['info_requests_not_held_count', + [{ + :title => _('Public bodies that most frequently replied with "Not Held"'), + :y_axis => _('Percentage of total requests'), + :highest => true}]]].each do |column, graphs_properties| + + graphs_properties.each do |graph_properties| + + percentages = (column != total_column) + highest = graph_properties[:highest] + + data = nil + if percentages + data = PublicBody.get_request_percentages(column, + per_graph, + highest, + minimum_requests) + else + data = PublicBody.get_request_totals(per_graph, + highest, + minimum_requests) + end + + data_to_draw = { + 'id' => "#{column}-#{highest ? 'highest' : 'lowest'}", + 'x_axis' => _('Public Bodies'), + 'y_axis' => graph_properties[:y_axis], + 'errorbars' => percentages, + 'title' => graph_properties[:title]} + + if data + data_to_draw.update(data) + data_to_draw['x_values'] = data['public_bodies'].each_with_index.map { |pb, i| i } + data_to_draw['x_ticks'] = data['public_bodies'].each_with_index.map { |pb, i| [i, pb.name] } + end + + @graph_list.push data_to_draw + end + end + + respond_to do |format| + format.html { render :template => "public_body/statistics" } + format.json { render :json => @graph_list } + end + end + # Type ahead search def search_typeahead # Since acts_as_xapian doesn't support the Partial match flag, we work around it @@ -157,5 +282,18 @@ class PublicBodyController < ApplicationController @xapian_requests = perform_search_typeahead(query, PublicBody) render :partial => "public_body/search_ahead" end -end + private + def get_public_body_list_translated_condition(table, first_letter=false, locale=nil) + result = "(upper(#{table}.name) LIKE upper(?)" \ + " OR upper(#{table}.notes) LIKE upper (?))" + if first_letter + result += " AND #{table}.first_letter = ?" + end + if locale + result += " AND #{table}.locale = ?" + end + result + end + +end diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 45d8b7de6..388473b51 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -63,26 +63,24 @@ class RequestController < ApplicationController # Look up by new style text names @info_request = InfoRequest.find_by_url_title!(params[:url_title]) - set_last_request(@info_request) # Test for whole request being hidden if !@info_request.user_can_view?(authenticated_user) return render_hidden end - # Other parameters - @info_request_events = @info_request.info_request_events - @status = @info_request.calculate_status - @collapse_quotes = params[:unfold] ? false : true + set_last_request(@info_request) + # assign variables from request parameters + @collapse_quotes = params[:unfold] ? false : true # Don't allow status update on external requests, otherwise accept param if @info_request.is_external? @update_status = false else @update_status = params[:update_status] ? true : false end - @old_unclassified = @info_request.is_old_unclassified? && !authenticated_user.nil? - @is_owning_user = @info_request.is_owning_user?(authenticated_user) + + assign_variables_for_show_template(@info_request) if @update_status return if !@is_owning_user && !authenticated_as_user?(@info_request.user, @@ -92,11 +90,8 @@ class RequestController < ApplicationController ) end - - @last_info_request_event_id = @info_request.last_event_id_needing_description - @new_responses_count = @info_request.events_needing_description.select {|i| i.event_type == 'response'}.size - # Sidebar stuff + @sidebar = true # ... requests that have similar imporant terms begin limit = 10 @@ -106,13 +101,11 @@ class RequestController < ApplicationController rescue @xapian_similar = nil end - # Track corresponding to this page @track_thing = TrackThing.create_track_for_request(@info_request) @feed_autodetect = [ { :url => do_track_url(@track_thing, 'feed'), :title => @track_thing.params[:title_in_rss], :has_json => true } ] - # For send followup link at bottom - @last_response = @info_request.get_last_response + respond_to do |format| format.html { @has_json = true; render :template => 'request/show'} format.json { render :json => @info_request.json_for_api(true) } @@ -304,7 +297,7 @@ class RequestController < ApplicationController # We don't want the error "Outgoing messages is invalid", as in this # case the list of errors will also contain a more specific error # describing the reason it is invalid. - @info_request.errors.delete("outgoing_messages") + @info_request.errors.delete(:outgoing_messages) render :action => 'new' return @@ -683,9 +676,13 @@ class RequestController < ApplicationController @info_request = incoming_message.info_request # used by view return render_hidden end + if !incoming_message.user_can_view?(authenticated_user) + @incoming_message = incoming_message # used by view + return render_hidden_message + end # Is this a completely public request that we can cache attachments for # to be served up without authentication? - if incoming_message.info_request.all_can_view? + if incoming_message.info_request.all_can_view? && incoming_message.all_can_view? @files_can_be_cached = true end end @@ -871,10 +868,6 @@ class RequestController < ApplicationController @locale = self.locale_from_params() I18n.with_locale(@locale) do @info_request = InfoRequest.find_by_url_title!(params[:url_title]) - # Test for whole request being hidden or requester-only - if !@info_request.all_can_view? - return render_hidden - end if authenticated?( :web => _("To download the zip file"), :email => _("Then you can download a zip file of {{info_request_title}}.", @@ -882,54 +875,17 @@ class RequestController < ApplicationController :email_subject => _("Log in to download a zip file of {{info_request_title}}", :info_request_title=>@info_request.title) ) - updated = Digest::SHA1.hexdigest(@info_request.info_request_events.last.created_at.to_i.to_s + @info_request.updated_at.to_i.to_s) - @url_path = File.join("/download", - request_dirs(@info_request), - updated, - "#{params[:url_title]}.zip") - file_path = File.expand_path(File.join(download_zip_dir(), @url_path)) - if !File.exists?(file_path) - FileUtils.mkdir_p(File.dirname(file_path)) - Zip::ZipFile.open(file_path, Zip::ZipFile::CREATE) { |zipfile| - convert_command = AlaveteliConfiguration::html_to_pdf_command - done = false - if !convert_command.blank? && File.exists?(convert_command) - url = "http://#{AlaveteliConfiguration::domain}#{request_path(@info_request)}?print_stylesheet=1" - tempfile = Tempfile.new('foihtml2pdf') - output = AlaveteliExternalCommand.run(convert_command, url, tempfile.path) - if !output.nil? - zipfile.get_output_stream("correspondence.pdf") { |f| - f.puts(File.open(tempfile.path).read) - } - done = true - else - logger.error("Could not convert info request #{@info_request.id} to PDF with command '#{convert_command} #{url} #{tempfile.path}'") - end - tempfile.close - else - logger.warn("No HTML -> PDF converter found at #{convert_command}") - end - if !done - @info_request_events = @info_request.info_request_events - template = File.read(File.join(File.dirname(__FILE__), "..", "views", "request", "simple_correspondence.html.erb")) - output = ERB.new(template).result(binding) - zipfile.get_output_stream("correspondence.txt") { |f| - f.puts(output) - } - end - for message in @info_request.incoming_messages - attachments = message.get_attachments_for_display - for attachment in attachments - filename = "#{attachment.url_part_number}_#{attachment.display_filename}" - zipfile.get_output_stream(filename) { |f| - f.puts(attachment.body) - } - end - end - } - File.chmod(0644, file_path) + # Test for whole request being hidden or requester-only + if !@info_request.user_can_view?(@user) + return render_hidden + end + cache_file_path = @info_request.make_zip_cache_path(@user) + if !File.exists?(cache_file_path) + FileUtils.mkdir_p(File.dirname(cache_file_path)) + make_request_zip(@info_request, cache_file_path) + File.chmod(0644, cache_file_path) end - redirect_to @url_path + send_file(cache_file_path, :filename => "#{@info_request.url_title}.zip") end end end @@ -938,12 +894,82 @@ class RequestController < ApplicationController def render_hidden respond_to do |format| - response_code = 410 # gone + response_code = 403 # forbidden format.html{ render :template => 'request/hidden', :status => response_code } format.any{ render :nothing => true, :status => response_code } end false end + def render_hidden_message + respond_to do |format| + response_code = 403 # forbidden + format.html{ render :template => 'request/hidden_correspondence', :status => response_code } + format.any{ render :nothing => true, :status => response_code } + end + false + end + + def assign_variables_for_show_template(info_request) + @info_request = info_request + @info_request_events = info_request.info_request_events + @status = info_request.calculate_status + @old_unclassified = info_request.is_old_unclassified? && !authenticated_user.nil? + @is_owning_user = info_request.is_owning_user?(authenticated_user) + @last_info_request_event_id = info_request.last_event_id_needing_description + @new_responses_count = info_request.events_needing_description.select {|i| i.event_type == 'response'}.size + # For send followup link at bottom + @last_response = info_request.get_last_public_response + end + + def make_request_zip(info_request, file_path) + Zip::ZipFile.open(file_path, Zip::ZipFile::CREATE) do |zipfile| + file_info = make_request_summary_file(info_request) + zipfile.get_output_stream(file_info[:filename]) { |f| f.puts(file_info[:data]) } + message_index = 0 + info_request.incoming_messages.each do |message| + next unless message.user_can_view?(authenticated_user) + message_index += 1 + message.get_attachments_for_display.each do |attachment| + filename = "#{message_index}_#{attachment.url_part_number}_#{attachment.display_filename}" + zipfile.get_output_stream(filename) { |f| f.puts(attachment.body) } + end + end + end + end + + def make_request_summary_file(info_request) + done = false + convert_command = AlaveteliConfiguration::html_to_pdf_command + assign_variables_for_show_template(info_request) + if !convert_command.blank? && File.exists?(convert_command) + @render_to_file = true + html_output = render_to_string(:template => 'request/show') + tmp_input = Tempfile.new(['foihtml2pdf-input', '.html']) + tmp_input.write(html_output) + tmp_input.close + tmp_output = Tempfile.new('foihtml2pdf-output') + output = AlaveteliExternalCommand.run(convert_command, tmp_input.path, tmp_output.path) + if !output.nil? + file_info = { :filename => 'correspondence.pdf', + :data => File.open(tmp_output.path).read } + done = true + else + logger.error("Could not convert info request #{info_request.id} to PDF with command '#{convert_command} #{tmp_input.path} #{tmp_output.path}'") + end + tmp_output.close + tmp_input.delete + tmp_output.delete + else + logger.warn("No HTML -> PDF converter found at #{convert_command}") + end + if !done + file_info = { :filename => 'correspondence.txt', + :data => render_to_string(:template => 'request/show.text', + :layout => false) } + end + file_info + end + end diff --git a/app/helpers/link_to_helper.rb b/app/helpers/link_to_helper.rb index 5533402c5..8df28f350 100755 --- a/app/helpers/link_to_helper.rb +++ b/app/helpers/link_to_helper.rb @@ -53,7 +53,7 @@ module LinkToHelper # Respond to request def respond_to_last_url(info_request, options = {}) - last_response = info_request.get_last_response + last_response = info_request.get_last_public_response if last_response.nil? show_response_no_followup_url(options.merge(:id => info_request.id)) else diff --git a/app/mailers/request_mailer.rb b/app/mailers/request_mailer.rb index 4dbce6738..13b3bc4a1 100644 --- a/app/mailers/request_mailer.rb +++ b/app/mailers/request_mailer.rb @@ -347,8 +347,8 @@ class RequestMailer < ApplicationMailer :age_in_days => days_since) for info_request in info_requests - alert_event_id = info_request.get_last_response_event_id - last_response_message = info_request.get_last_response + alert_event_id = info_request.get_last_public_response_event_id + last_response_message = info_request.get_last_public_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 @@ -373,8 +373,8 @@ class RequestMailer < ApplicationMailer def self.alert_not_clarified_request() info_requests = InfoRequest.find(:all, :conditions => [ "awaiting_description = ? and described_state = 'waiting_clarification' and info_requests.updated_at < ?", false, 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 + alert_event_id = info_request.get_last_public_response_event_id + last_response_message = info_request.get_last_public_response if alert_event_id.nil? raise "internal error, no last response while making alert not clarified reminder, request id " + info_request.id.to_s end diff --git a/app/models/censor_rule.rb b/app/models/censor_rule.rb index f0d06e088..3c5c77563 100644 --- a/app/models/censor_rule.rb +++ b/app/models/censor_rule.rb @@ -1,18 +1,17 @@ # == Schema Information -# Schema version: 20120919140404 # # Table name: censor_rules # -# id :integer not null, primary key +# id :integer not null, primary key # info_request_id :integer # user_id :integer # public_body_id :integer -# text :text not null -# replacement :text not null -# last_edit_editor :string(255) not null -# last_edit_comment :text not null -# created_at :datetime not null -# updated_at :datetime not null +# text :text not null +# replacement :text not null +# last_edit_editor :string(255) not null +# last_edit_comment :text not null +# created_at :datetime not null +# updated_at :datetime not null # regexp :boolean # diff --git a/app/models/comment.rb b/app/models/comment.rb index 9527030a9..75d37e04f 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,17 +1,16 @@ # == Schema Information -# Schema version: 114 # # Table name: comments # -# id :integer not null, primary key -# user_id :integer not null -# comment_type :string(255) default("internal_error"), not null +# id :integer not null, primary key +# user_id :integer not null +# comment_type :string(255) default("internal_error"), not null # info_request_id :integer -# body :text not null -# visible :boolean default(TRUE), not null -# created_at :datetime not null -# updated_at :datetime not null -# locale :text default(""), not null +# body :text not null +# visible :boolean default(TRUE), not null +# created_at :datetime not null +# updated_at :datetime not null +# locale :text default(""), not null # # models/comments.rb: diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb index 0340f2b83..914420a2b 100644 --- a/app/models/foi_attachment.rb +++ b/app/models/foi_attachment.rb @@ -1,11 +1,9 @@ # encoding: UTF-8 - # == Schema Information -# Schema version: 114 # # Table name: foi_attachments # -# id :integer not null, primary key +# id :integer not null, primary key # content_type :text # filename :text # charset :text diff --git a/app/models/holiday.rb b/app/models/holiday.rb index 98f73e963..3076cc0fd 100644 --- a/app/models/holiday.rb +++ b/app/models/holiday.rb @@ -1,9 +1,8 @@ # == Schema Information -# Schema version: 114 # # Table name: holidays # -# id :integer not null, primary key +# id :integer not null, primary key # day :date # description :text # diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb index ae3c3b407..8b2aa87e7 100644 --- a/app/models/incoming_message.rb +++ b/app/models/incoming_message.rb @@ -1,15 +1,13 @@ # coding: utf-8 - # == Schema Information -# Schema version: 114 # # Table name: incoming_messages # -# id :integer not null, primary key -# info_request_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# raw_email_id :integer not null +# id :integer not null, primary key +# info_request_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# raw_email_id :integer not null # cached_attachment_text_clipped :text # cached_main_body_text_folded :text # cached_main_body_text_unfolded :text @@ -19,6 +17,9 @@ # last_parsed :datetime # mail_from :text # sent_at :datetime +# prominence :string(255) default("normal"), not null +# prominence_reason :text +# # models/incoming_message.rb: # An (email) message from really anybody to be logged with a request. e.g. A @@ -37,6 +38,7 @@ require 'zip/zip' require 'iconv' unless RUBY_VERSION >= '1.9' class IncomingMessage < ActiveRecord::Base + extend MessageProminence belongs_to :info_request validates_presence_of :info_request @@ -48,6 +50,8 @@ class IncomingMessage < ActiveRecord::Base belongs_to :raw_email + has_prominence + # See binary_mask_stuff function below. It just test for inclusion # in this hash, not the value of the right hand side. DoNotBinaryMask = { @@ -59,6 +63,12 @@ class IncomingMessage < ActiveRecord::Base 'application/zip' => 1, } + # Given that there are in theory many info request events, a convenience method for + # getting the response event + def response_event + self.info_request_events.detect{ |e| e.event_type == 'response' } + end + # Return a cached structured mail object def mail(force = nil) if (!force.nil? || @mail.nil?) && !self.raw_email.nil? @@ -151,14 +161,17 @@ class IncomingMessage < ActiveRecord::Base parse_raw_email! super end + def subject parse_raw_email! super end + def mail_from parse_raw_email! super end + def safe_mail_from if !self.mail_from.nil? mail_from = self.mail_from.dup @@ -166,6 +179,15 @@ class IncomingMessage < ActiveRecord::Base return mail_from end end + + def specific_from_name? + !safe_mail_from.nil? && safe_mail_from.strip != info_request.public_body.name.strip + end + + def from_public_body? + safe_mail_from.nil? || (mail_from_domain == info_request.public_body.request_email_domain) + end + def mail_from_domain parse_raw_email! super diff --git a/app/models/info_request.rb b/app/models/info_request.rb index 14eead6ad..aaced91a2 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -1,26 +1,26 @@ +# encoding: utf-8 # == Schema Information -# Schema version: 20120919140404 # # Table name: info_requests # -# id :integer not null, primary key -# title :text not null +# id :integer not null, primary key +# title :text not null # user_id :integer -# public_body_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# described_state :string(255) not null -# awaiting_description :boolean default(FALSE), not null -# prominence :string(255) default("normal"), not null -# url_title :text not null -# law_used :string(255) default("foi"), not null -# allow_new_responses_from :string(255) default("anybody"), not null -# handle_rejected_responses :string(255) default("bounce"), not null -# idhash :string(255) not null +# public_body_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# described_state :string(255) not null +# awaiting_description :boolean default(FALSE), not null +# prominence :string(255) default("normal"), not null +# url_title :text not null +# law_used :string(255) default("foi"), not null +# allow_new_responses_from :string(255) default("anybody"), not null +# handle_rejected_responses :string(255) default("bounce"), not null +# idhash :string(255) not null # external_user_name :string(255) # external_url :string(255) -# attention_requested :boolean default(FALSE) -# comments_allowed :boolean default(TRUE), not null +# attention_requested :boolean default(FALSE) +# comments_allowed :boolean default(TRUE), not null # require 'digest/sha1' @@ -31,7 +31,10 @@ class InfoRequest < ActiveRecord::Base strip_attributes! validates_presence_of :title, :message => N_("Please enter a summary of your request") - validates_format_of :title, :with => /[a-zA-Z]/, :message => N_("Please write a summary with some text in it"), :if => Proc.new { |info_request| !info_request.title.nil? && !info_request.title.empty? } + # TODO: When we no longer support Ruby 1.8, this can be done with /[[:alpha:]]/ + validates_format_of :title, :with => /[ёЁа-яА-Яa-zA-Zà-üÀ-Ü]/iu, + :message => N_("Please write a summary with some text in it"), + :if => Proc.new { |info_request| !info_request.title.nil? && !info_request.title.empty? } belongs_to :user validate :must_be_internal_or_external @@ -764,28 +767,30 @@ public self.info_request_events.create!(:event_type => type, :params => params) end - def response_events - self.info_request_events.select{|e| e.response?} + def public_response_events + self.info_request_events.select{|e| e.response? && e.incoming_message.all_can_view? } end - # The last response is the default one people might want to reply to - def get_last_response_event_id - get_last_response_event.id if get_last_response_event + # The last public response is the default one people might want to reply to + def get_last_public_response_event_id + get_last_public_response_event.id if get_last_public_response_event end - def get_last_response_event - response_events.last + + def get_last_public_response_event + public_response_events.last end - def get_last_response - get_last_response_event.incoming_message if get_last_response_event + + def get_last_public_response + get_last_public_response_event.incoming_message if get_last_public_response_event end - def outgoing_events - info_request_events.select{|e| e.outgoing? } + def public_outgoing_events + info_request_events.select{|e| e.outgoing? && e.outgoing_message.all_can_view? } end - # The last outgoing message - def get_last_outgoing_event - outgoing_events.last + # The last public outgoing message + def get_last_public_outgoing_event + public_outgoing_events.last end # Text from the the initial request, for use in summary display @@ -836,6 +841,10 @@ public end end + def last_update_hash + Digest::SHA1.hexdigest(info_request_events.last.created_at.to_i.to_s + updated_at.to_i.to_s) + end + # Get previous email sent to def get_previous_email_sent_to(info_request_event) last_email = nil @@ -930,19 +939,29 @@ public end # Used to find when event last changed - def InfoRequest.last_event_time_clause(event_type=nil) + def InfoRequest.last_event_time_clause(event_type=nil, join_table=nil, join_clause=nil) event_type_clause = '' event_type_clause = " AND info_request_events.event_type = '#{event_type}'" if event_type - "(SELECT created_at - FROM info_request_events + tables = ['info_request_events'] + tables << join_table if join_table + join_clause = "AND #{join_clause}" if join_clause + "(SELECT info_request_events.created_at + FROM #{tables.join(', ')} WHERE info_request_events.info_request_id = info_requests.id #{event_type_clause} + #{join_clause} ORDER BY created_at desc LIMIT 1)" end + def InfoRequest.last_public_response_clause() + join_clause = "incoming_messages.id = info_request_events.incoming_message_id + AND incoming_messages.prominence = 'normal'" + last_event_time_clause('response', 'incoming_messages', join_clause) + end + def InfoRequest.old_unclassified_params(extra_params, include_last_response_time=false) - last_response_created_at = last_event_time_clause('response') + last_response_created_at = last_public_response_clause() age = extra_params[:age_in_days] ? extra_params[:age_in_days].days : OLD_AGE_IN_DAYS params = { :conditions => ["awaiting_description = ? AND #{last_response_created_at} < ? @@ -995,9 +1014,39 @@ public find(:all, params) end + def InfoRequest.download_zip_dir() + File.join(Rails.root, "cache", "zips", "#{Rails.env}") + end + + def request_dirs + first_three_digits = id.to_s()[0..2] + File.join(first_three_digits.to_s, id.to_s) + end + + def download_zip_dir + File.join(InfoRequest.download_zip_dir, "download", request_dirs) + end + + def make_zip_cache_path(user) + cache_file_dir = File.join(InfoRequest.download_zip_dir(), + "download", + request_dirs, + last_update_hash) + cache_file_suffix = if all_can_view_all_correspondence? + "" + elsif Ability.can_view_with_prominence?('hidden', self, user) + "_hidden" + elsif Ability.can_view_with_prominence?('requester_only', self, user) + "_requester_only" + else + "" + end + File.join(cache_file_dir, "#{url_title}#{cache_file_suffix}.zip") + end + def is_old_unclassified? - !is_external? && awaiting_description && url_title != 'holding_pen' && get_last_response_event && - Time.now > get_last_response_event.created_at + OLD_AGE_IN_DAYS + !is_external? && awaiting_description && url_title != 'holding_pen' && get_last_public_response_event && + Time.now > get_last_public_response_event.created_at + OLD_AGE_IN_DAYS end # List of incoming messages to followup, by unique email @@ -1010,6 +1059,8 @@ public end incoming_message.safe_mail_from + next if ! incoming_message.all_can_view? + email = OutgoingMailer.email_for_followup(self, incoming_message) name = OutgoingMailer.name_for_followup(self, incoming_message) @@ -1059,13 +1110,7 @@ public end def user_can_view?(user) - if self.prominence == 'hidden' - return User.view_hidden_requests?(user) - end - if self.prominence == 'requester_only' - return self.is_owning_user?(user) - end - return true + Ability.can_view_with_prominence?(self.prominence, self, user) end # Is this request visible to everyone? @@ -1074,6 +1119,12 @@ public return false end + def all_can_view_all_correspondence? + all_can_view? && + incoming_messages.all?{ |message| message.all_can_view? } && + outgoing_messages.all?{ |message| message.all_can_view? } + end + def indexed_by_search? if self.prominence == 'backpage' || self.prominence == 'hidden' || self.prominence == 'requester_only' return false @@ -1135,6 +1186,23 @@ public end end + after_save :update_counter_cache + after_destroy :update_counter_cache + def update_counter_cache + PublicBody.skip_callback(:save, :after, :purge_in_cache) + self.public_body.info_requests_not_held_count = InfoRequest.where( + :public_body_id => self.public_body.id, + :described_state => 'not_held').count + self.public_body.info_requests_successful_count = InfoRequest.where( + :public_body_id => self.public_body.id, + :described_state => ['successful', 'partially_successful']).count + self.public_body.without_revision do + public_body.no_xapian_reindex = true + public_body.save + end + PublicBody.set_callback(:save, :after, :purge_in_cache) + end + def for_admin_column self.class.content_columns.map{|c| c unless %w(title url_title).include?(c.name) }.compact.each do |column| yield(column.human_name, self.send(column.name), column.type.to_s, column.name) diff --git a/app/models/info_request_event.rb b/app/models/info_request_event.rb index 0967e3940..67cdda1b4 100644 --- a/app/models/info_request_event.rb +++ b/app/models/info_request_event.rb @@ -1,20 +1,18 @@ # == Schema Information -# Schema version: 114 # # Table name: info_request_events # -# id :integer not null, primary key -# info_request_id :integer not null -# event_type :text not null -# params_yaml :text not null -# created_at :datetime not null +# id :integer not null, primary key +# info_request_id :integer not null +# event_type :text not null +# params_yaml :text not null +# created_at :datetime not null # described_state :string(255) # calculated_state :string(255) # last_described_at :datetime # incoming_message_id :integer # outgoing_message_id :integer # comment_id :integer -# prominence :string(255) default("normal"), not null # # models/info_request_event.rb: @@ -48,10 +46,10 @@ class InfoRequestEvent < ActiveRecord::Base 'destroy_incoming', # deleted an incoming message (in admin interface) 'destroy_outgoing', # deleted an outgoing message (in admin interface) 'redeliver_incoming', # redelivered an incoming message elsewhere (in admin interface) + 'edit_incoming', # incoming message edited (in admin interface) 'move_request', # changed user or public body (in admin interface) 'hide', # hid a request (in admin interface) 'manual', # you did something in the db by hand - 'response', 'comment', 'status_update' @@ -63,35 +61,12 @@ class InfoRequestEvent < ActiveRecord::Base # user described state (also update in info_request) validate :must_be_valid_state - # whether event is publicly visible - validates_inclusion_of :prominence, :in => [ - 'normal', - 'hidden', - 'requester_only' - ] - def must_be_valid_state if !described_state.nil? and !InfoRequest.enumerate_states.include?(described_state) errors.add(described_state, "is not a valid state") end end - def user_can_view?(user) - unless info_request.user_can_view?(user) - raise "internal error, called user_can_view? on event when there is not permission to view entire request" - end - - case prominence - when 'hidden' - User.view_hidden_requests?(user) - when 'requester_only' - info_request.is_owning_user?(user) - else - true - end - end - - # Full text search indexing acts_as_xapian :texts => [ :search_text_main, :title ], :values => [ @@ -260,6 +235,12 @@ class InfoRequestEvent < ActiveRecord::Base if !self.info_request.indexed_by_search? return false end + if self.event_type == 'response' && !self.incoming_message.indexed_by_search? + return false + end + if ['sent', 'followup_sent'].include?(self.event_type) && !self.outgoing_message.indexed_by_search? + return false + end if self.event_type == 'comment' && !self.comment.visible return false end @@ -268,6 +249,7 @@ class InfoRequestEvent < ActiveRecord::Base return false end end + def variety self.event_type end diff --git a/app/models/mail_server_log.rb b/app/models/mail_server_log.rb index 7f61377ce..0e5b60ff1 100644 --- a/app/models/mail_server_log.rb +++ b/app/models/mail_server_log.rb @@ -1,15 +1,14 @@ # == Schema Information -# Schema version: 20121010214348 # # Table name: mail_server_logs # -# id :integer not null, primary key +# id :integer not null, primary key # mail_server_log_done_id :integer # info_request_id :integer -# order :integer not null -# line :text not null -# created_at :datetime not null -# updated_at :datetime not null +# order :integer not null +# line :text not null +# created_at :datetime not null +# updated_at :datetime not null # # We load log file lines for requests in here, for display in the admin interface. diff --git a/app/models/mail_server_log_done.rb b/app/models/mail_server_log_done.rb index 0e7e9eec3..222b072c5 100644 --- a/app/models/mail_server_log_done.rb +++ b/app/models/mail_server_log_done.rb @@ -1,13 +1,12 @@ # == Schema Information -# Schema version: 20121010214348 # # Table name: mail_server_log_dones # -# id :integer not null, primary key -# filename :text not null -# last_stat :datetime not null -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# filename :text not null +# last_stat :datetime not null +# created_at :datetime not null +# updated_at :datetime not null # # Stores that a particular mail server log file has been loaded in, see mail_server_log.rb diff --git a/app/models/outgoing_message.rb b/app/models/outgoing_message.rb index aedfb9cad..e89c11141 100644 --- a/app/models/outgoing_message.rb +++ b/app/models/outgoing_message.rb @@ -1,18 +1,17 @@ # == Schema Information -# Schema version: 114 # # Table name: outgoing_messages # -# id :integer not null, primary key -# info_request_id :integer not null -# body :text not null -# status :string(255) not null -# message_type :string(255) not null -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# info_request_id :integer not null +# body :text not null +# status :string(255) not null +# message_type :string(255) not null +# created_at :datetime not null +# updated_at :datetime not null # last_sent_at :datetime # incoming_message_followup_id :integer -# what_doing :string(255) not null +# what_doing :string(255) not null # # models/outgoing_message.rb: @@ -23,6 +22,7 @@ # Email: hello@mysociety.org; WWW: http://www.mysociety.org/ class OutgoingMessage < ActiveRecord::Base + extend MessageProminence include Rails.application.routes.url_helpers include LinkToHelper self.default_url_options[:host] = AlaveteliConfiguration::domain @@ -33,6 +33,8 @@ class OutgoingMessage < ActiveRecord::Base strip_attributes! + has_prominence + belongs_to :info_request validates_presence_of :info_request @@ -209,11 +211,11 @@ class OutgoingMessage < ActiveRecord::Base end # Returns text for indexing / text display - def get_text_for_indexing + def get_text_for_indexing(strip_salutation=true) text = self.body.strip # Remove salutation - text.sub!(/Dear .+,/, "") + text.sub!(/Dear .+,/, "") if strip_salutation # Remove email addresses from display/index etc. self.remove_privacy_sensitive_things!(text) @@ -233,6 +235,12 @@ class OutgoingMessage < ActiveRecord::Base return text.html_safe end + # Return body for display as text + def get_body_for_text_display + get_text_for_indexing(strip_salutation=false) + end + + def fully_destroy ActiveRecord::Base.transaction do info_request_event = InfoRequestEvent.find_by_outgoing_message_id(self.id) diff --git a/app/models/post_redirect.rb b/app/models/post_redirect.rb index 409069cb6..5da3d2742 100644 --- a/app/models/post_redirect.rb +++ b/app/models/post_redirect.rb @@ -1,18 +1,17 @@ # == Schema Information -# Schema version: 114 # # Table name: post_redirects # -# id :integer not null, primary key -# token :text not null -# uri :text not null +# id :integer not null, primary key +# token :text not null +# uri :text not null # post_params_yaml :text -# created_at :datetime not null -# updated_at :datetime not null -# email_token :text not null +# created_at :datetime not null +# updated_at :datetime not null +# email_token :text not null # reason_params_yaml :text # user_id :integer -# circumstance :text default("normal"), not null +# circumstance :text default("normal"), not null # # models/post_redirect.rb: diff --git a/app/models/profile_photo.rb b/app/models/profile_photo.rb index 5d542daf1..322ebe53c 100644 --- a/app/models/profile_photo.rb +++ b/app/models/profile_photo.rb @@ -1,12 +1,11 @@ # == Schema Information -# Schema version: 114 # # Table name: profile_photos # -# id :integer not null, primary key -# data :binary not null +# id :integer not null, primary key +# data :binary not null # user_id :integer -# draft :boolean default(FALSE), not null +# draft :boolean default(FALSE), not null # # models/profile_photo.rb: diff --git a/app/models/public_body.rb b/app/models/public_body.rb index a76aeb189..828e8c94a 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -1,27 +1,27 @@ +# -*- coding: utf-8 -*- # == Schema Information -# Schema version: 20120919140404 # # Table name: public_bodies # -# id :integer not null, primary key -# name :text not null -# short_name :text not null -# request_email :text not null -# version :integer not null -# last_edit_editor :string(255) not null -# last_edit_comment :text not null -# created_at :datetime not null -# updated_at :datetime not null -# url_name :text not null -# home_page :text default(""), not null -# notes :text default(""), not null -# first_letter :string(255) not null -# publication_scheme :text default(""), not null -# api_key :string(255) not null -# info_requests_count :integer default(0), not null +# id :integer not null, primary key +# name :text not null +# short_name :text not null +# request_email :text not null +# version :integer not null +# last_edit_editor :string(255) not null +# last_edit_comment :text not null +# created_at :datetime not null +# updated_at :datetime not null +# url_name :text not null +# home_page :text default(""), not null +# notes :text default(""), not null +# first_letter :string(255) not null +# publication_scheme :text default(""), not null +# api_key :string(255) not null +# info_requests_count :integer default(0), not null +# disclosure_log :text default(""), not null # -# -*- coding: utf-8 -*- require 'csv' require 'securerandom' require 'set' @@ -40,6 +40,7 @@ class PublicBody < ActiveRecord::Base has_many :info_requests, :order => 'created_at desc' has_many :track_things, :order => 'created_at desc' has_many :censor_rules, :order => 'created_at desc' + attr_accessor :no_xapian_reindex has_tag_string before_save :set_api_key, :set_default_publication_scheme @@ -60,12 +61,23 @@ class PublicBody < ActiveRecord::Base # XXX - Don't like repeating this! def calculate_cached_fields(t) - t.first_letter = t.name.scan(/^./mu)[0].upcase unless t.name.nil? or t.name.empty? + PublicBody.set_first_letter(t) short_long_name = t.name short_long_name = t.short_name if t.short_name and !t.short_name.empty? t.url_name = MySociety::Format.simplify_url_part(short_long_name, 'body') end + # Set the first letter on a public body or translation + def PublicBody.set_first_letter(instance) + unless instance.name.nil? or instance.name.empty? + # we use a regex to ensure it works with utf-8/multi-byte + first_letter = instance.name.scan(/^./mu)[0].upcase + if first_letter != instance.first_letter + instance.first_letter = first_letter + end + end + end + def translated_versions translations end @@ -130,8 +142,7 @@ class PublicBody < ActiveRecord::Base # Set the first letter, which is used for faster queries before_save(:set_first_letter) def set_first_letter - # we use a regex to ensure it works with utf-8/multi-byte - self.first_letter = self.name.scan(/./mu)[0].upcase + PublicBody.set_first_letter(self) end # If tagged "not_apply", then FOI/EIR no longer applies to authority at all @@ -177,7 +188,11 @@ class PublicBody < ActiveRecord::Base end acts_as_versioned - self.non_versioned_columns << 'created_at' << 'updated_at' << 'first_letter' << 'api_key' << 'info_requests_count' + self.non_versioned_columns << 'created_at' << 'updated_at' << 'first_letter' << 'api_key' + self.non_versioned_columns << 'info_requests_count' << 'info_requests_successful_count' + self.non_versioned_columns << 'info_requests_not_held_count' << 'info_requests_overdue' + self.non_versioned_columns << 'info_requests_overdue_count' + class Version attr_accessor :created_at @@ -231,6 +246,7 @@ class PublicBody < ActiveRecord::Base def reindex_requested_from if self.changes.include?('url_name') for info_request in self.info_requests + for info_request_event in info_request.info_request_events info_request_event.xapian_mark_needs_index end @@ -632,6 +648,65 @@ class PublicBody < ActiveRecord::Base end end + # Return data for the 'n' public bodies with the highest (or + # lowest) number of requests, but only returning data for those + # with at least 'minimum_requests' requests. + def self.get_request_totals(n, highest, minimum_requests) + ordering = "info_requests_count" + ordering += " DESC" if highest + where_clause = "info_requests_count >= #{minimum_requests}" + public_bodies = PublicBody.order(ordering).where(where_clause).limit(n) + public_bodies.reverse! if highest + y_values = public_bodies.map { |pb| pb.info_requests_count } + return { + 'public_bodies' => public_bodies, + 'y_values' => y_values, + 'y_max' => y_values.max} + end + + # Return data for the 'n' public bodies with the highest (or + # lowest) score according to the metric of the value in 'column' + # divided by the total number of requests, expressed as a + # percentage. This only returns data for those public bodies with + # at least 'minimum_requests' requests. + def self.get_request_percentages(column, n, highest, minimum_requests) + total_column = "info_requests_count" + ordering = "y_value" + ordering += " DESC" if highest + y_value_column = "(cast(#{column} as float) / #{total_column})" + where_clause = "#{total_column} >= #{minimum_requests} AND #{column} IS NOT NULL" + public_bodies = PublicBody.select("*, #{y_value_column} AS y_value").order(ordering).where(where_clause).limit(n) + public_bodies.reverse! if highest + y_values = public_bodies.map { |pb| pb.y_value.to_f } + + original_values = public_bodies.map { |pb| pb.send(column) } + # If these are all nil, then probably the values have never + # been set; some have to be set by a rake task. In that case, + # just return nil: + return nil unless original_values.any? { |ov| !ov.nil? } + + original_totals = public_bodies.map { |pb| pb.send(total_column) } + # Calculate confidence intervals, as offsets from the proportion: + cis_below = [] + cis_above = [] + original_totals.each_with_index.map { |total, i| + lower_ci, higher_ci = ci_bounds original_values[i], total, 0.05 + cis_below.push(y_values[i] - lower_ci) + cis_above.push(higher_ci - y_values[i]) + } + # Turn the y values and confidence interval offsets into + # percentages: + [y_values, cis_below, cis_above].each { |l| + l.map! { |v| 100 * v } + } + return { + 'public_bodies' => public_bodies, + 'y_values' => y_values, + 'cis_below' => cis_below, + 'cis_above' => cis_above, + 'y_max' => 100} + end + private def request_email_if_requestable diff --git a/app/models/purge_request.rb b/app/models/purge_request.rb index e48f3cc6f..4e6267bd2 100644 --- a/app/models/purge_request.rb +++ b/app/models/purge_request.rb @@ -1,13 +1,12 @@ # == Schema Information -# Schema version: 114 # # Table name: purge_requests # -# id :integer not null, primary key +# id :integer not null, primary key # url :string(255) -# created_at :datetime not null -# model :string(255) not null -# model_id :integer not null +# created_at :datetime not null +# model :string(255) not null +# model_id :integer not null # # models/purge_request.rb: diff --git a/app/models/raw_email.rb b/app/models/raw_email.rb index 6bf01bc74..21a53f493 100644 --- a/app/models/raw_email.rb +++ b/app/models/raw_email.rb @@ -1,9 +1,8 @@ # == Schema Information -# Schema version: 114 # # Table name: raw_emails # -# id :integer not null, primary key +# id :integer not null, primary key # # models/raw_email.rb: diff --git a/app/models/request_classification.rb b/app/models/request_classification.rb index f5a1b4bee..6873d468b 100644 --- a/app/models/request_classification.rb +++ b/app/models/request_classification.rb @@ -1,9 +1,8 @@ # == Schema Information -# Schema version: 20120919140404 # # Table name: request_classifications # -# id :integer not null, primary key +# id :integer not null, primary key # user_id :integer # info_request_event_id :integer # created_at :datetime diff --git a/app/models/track_thing.rb b/app/models/track_thing.rb index 66b8a5c47..d5e1cdb75 100644 --- a/app/models/track_thing.rb +++ b/app/models/track_thing.rb @@ -1,16 +1,15 @@ # == Schema Information -# Schema version: 114 # # Table name: track_things # -# id :integer not null, primary key -# tracking_user_id :integer not null -# track_query :string(255) not null +# id :integer not null, primary key +# tracking_user_id :integer not null +# track_query :string(255) not null # info_request_id :integer # tracked_user_id :integer # public_body_id :integer -# track_medium :string(255) not null -# track_type :string(255) default("internal_error"), not null +# track_medium :string(255) not null +# track_type :string(255) default("internal_error"), not null # created_at :datetime # updated_at :datetime # diff --git a/app/models/track_things_sent_email.rb b/app/models/track_things_sent_email.rb index a9ea2520e..072d3bdea 100644 --- a/app/models/track_things_sent_email.rb +++ b/app/models/track_things_sent_email.rb @@ -1,10 +1,9 @@ # == Schema Information -# Schema version: 114 # # Table name: track_things_sent_emails # -# id :integer not null, primary key -# track_thing_id :integer not null +# id :integer not null, primary key +# track_thing_id :integer not null # info_request_event_id :integer # user_id :integer # public_body_id :integer diff --git a/app/models/user.rb b/app/models/user.rb index 9da4ad743..d7c1c854e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,26 +1,27 @@ # == Schema Information -# Schema version: 20120919140404 # # Table name: users # -# id :integer not null, primary key -# email :string(255) not null -# name :string(255) not null -# hashed_password :string(255) not null -# salt :string(255) not null -# created_at :datetime not null -# updated_at :datetime not null -# email_confirmed :boolean default(FALSE), not null -# url_name :text not null -# last_daily_track_email :datetime default(Sat Jan 01 00:00:00 UTC 2000) -# admin_level :string(255) default("none"), not null -# ban_text :text default(""), not null -# about_me :text default(""), not null +# id :integer not null, primary key +# email :string(255) not null +# name :string(255) not null +# hashed_password :string(255) not null +# salt :string(255) not null +# created_at :datetime not null +# updated_at :datetime not null +# email_confirmed :boolean default(FALSE), not null +# url_name :text not null +# last_daily_track_email :datetime default(2000-01-01 00:00:00 UTC) +# admin_level :string(255) default("none"), not null +# ban_text :text default(""), not null +# about_me :text default(""), not null # locale :string(255) # email_bounced_at :datetime -# email_bounce_message :text default(""), not null -# no_limit :boolean default(FALSE), not null -# receive_email_alerts :boolean default(TRUE), not null +# email_bounce_message :text default(""), not null +# no_limit :boolean default(FALSE), not null +# receive_email_alerts :boolean default(TRUE), not null +# address :string(255) +# dob :date # require 'digest/sha1' @@ -243,8 +244,8 @@ class User < ActiveRecord::Base !user.nil? && user.owns_every_request? end - # Can the user see every request, even hidden ones? - def User.view_hidden_requests?(user) + # Can the user see every request, response, and outgoing message, even hidden ones? + def User.view_hidden?(user) !user.nil? && user.super? end diff --git a/app/models/user_info_request_sent_alert.rb b/app/models/user_info_request_sent_alert.rb index 449a4c237..098b773f8 100644 --- a/app/models/user_info_request_sent_alert.rb +++ b/app/models/user_info_request_sent_alert.rb @@ -1,12 +1,11 @@ # == Schema Information -# Schema version: 114 # # Table name: user_info_request_sent_alerts # -# id :integer not null, primary key -# user_id :integer not null -# info_request_id :integer not null -# alert_type :string(255) not null +# id :integer not null, primary key +# user_id :integer not null +# info_request_id :integer not null +# alert_type :string(255) not null # info_request_event_id :integer # diff --git a/app/views/admin_general/admin.coffee b/app/views/admin_general/admin.coffee deleted file mode 100644 index 3d39369a4..000000000 --- a/app/views/admin_general/admin.coffee +++ /dev/null @@ -1,24 +0,0 @@ -jQuery -> - $('.locales a:first').tab('show') - $('.accordion-body').on('hidden', -> - $(@).prev().find('i').first().removeClass().addClass('icon-chevron-right') - ) - $('.accordion-body').on('shown', -> - $(@).prev().find('i').first().removeClass().addClass('icon-chevron-down')) - $('.toggle-hidden').live('click', -> - $(@).parents('td').find('div:hidden').show() - false) - $('#request_hidden_user_explanation_reasons input').live('click', -> - $('#request_hidden_user_subject, #request_hidden_user_explanation, #request_hide_button').show() - info_request_id = $('#hide_request_form').attr('data-info-request-id') - reason = $(this).val() - $('#request_hidden_user_explanation_field').attr("value", "[loading default text...]") - $.ajax "/hidden_user_explanation?reason=" + reason + "&info_request_id=" + info_request_id, - type: "GET" - dataType: "text" - error: (data, textStatus, jqXHR) -> - $('#request_hidden_user_explanation_field').attr("value", "Error: #{textStatus}") - success: (data, textStatus, jqXHR) -> - $('#request_hidden_user_explanation_field').attr("value", data) - ) - diff --git a/app/views/admin_general/admin.js b/app/views/admin_general/admin.js deleted file mode 100644 index 9daa51459..000000000 --- a/app/views/admin_general/admin.js +++ /dev/null @@ -1,32 +0,0 @@ -(function() { - jQuery(function() { - $('.locales a:first').tab('show'); - $('.accordion-body').on('hidden', function() { - return $(this).prev().find('i').first().removeClass().addClass('icon-chevron-right'); - }); - $('.accordion-body').on('shown', function() { - return $(this).prev().find('i').first().removeClass().addClass('icon-chevron-down'); - }); - $('.toggle-hidden').live('click', function() { - $(this).parents('td').find('div:hidden').show(); - return false; - }); - return $('#request_hidden_user_explanation_reasons input').live('click', function() { - var info_request_id, reason; - $('#request_hidden_user_subject, #request_hidden_user_explanation, #request_hide_button').show(); - info_request_id = $('#hide_request_form').attr('data-info-request-id'); - reason = $(this).val(); - $('#request_hidden_user_explanation_field').attr("value", "[loading default text...]"); - return $.ajax("/hidden_user_explanation?reason=" + reason + "&info_request_id=" + info_request_id, { - type: "GET", - dataType: "text", - error: function(data, textStatus, jqXHR) { - return $('#request_hidden_user_explanation_field').attr("value", "Error: " + textStatus); - }, - success: function(data, textStatus, jqXHR) { - return $('#request_hidden_user_explanation_field').attr("value", data); - } - }); - }); - }); -}).call(this); diff --git a/app/views/admin_general/admin_js.erb b/app/views/admin_general/admin_js.erb deleted file mode 100644 index c8788a452..000000000 --- a/app/views/admin_general/admin_js.erb +++ /dev/null @@ -1,34 +0,0 @@ -(function() { - - jQuery(function() { - $('.locales a:first').tab('show'); - $('.accordion-body').on('hidden', function() { - return $(this).prev().find('i').first().removeClass().addClass('icon-chevron-right'); - }); - $('.accordion-body').on('shown', function() { - return $(this).prev().find('i').first().removeClass().addClass('icon-chevron-down'); - }); - $('.toggle-hidden').live('click', function() { - $(this).parents('td').find('div:hidden').show(); - return false; - }); - return $('#request_hidden_user_explanation_reasons input').live('click', function() { - var info_request_id, reason; - $('#request_hidden_user_subject, #request_hidden_user_explanation, #request_hide_button').show(); - info_request_id = $('#hide_request_form').attr('data-info-request-id'); - reason = $(this).val(); - $('#request_hidden_user_explanation_field').attr("value", "[loading default text...]"); - return $.ajax("/hidden_user_explanation?reason=" + reason + "&info_request_id=" + info_request_id, { - type: "GET", - dataType: "text", - error: function(data, textStatus, jqXHR) { - return $('#request_hidden_user_explanation_field').attr("value", "Error: " + textStatus); - }, - success: function(data, textStatus, jqXHR) { - return $('#request_hidden_user_explanation_field').attr("value", data); - } - }); - }); - }); - -}).call(this); diff --git a/app/views/admin_general/index.html.erb b/app/views/admin_general/index.html.erb index b239a2b3f..976860fa7 100644 --- a/app/views/admin_general/index.html.erb +++ b/app/views/admin_general/index.html.erb @@ -164,7 +164,7 @@ <%= request_both_links(@request) %> </td> <td class="span2"> - <%=simple_date(@request.get_last_response_event.created_at)%> + <%=simple_date(@request.get_last_public_response_event.created_at)%> </td> </tr> <% end %> diff --git a/app/views/admin_general/timeline.html.erb b/app/views/admin_general/timeline.html.erb index 439ae1e68..c4ea4849b 100644 --- a/app/views/admin_general/timeline.html.erb +++ b/app/views/admin_general/timeline.html.erb @@ -34,7 +34,7 @@ <%= request_both_links(event.info_request) %> <% if event.event_type == 'edit' %> was edited by administrator <strong><%=h event.params[:editor] %></strong>. - <% for p in ['title', 'prominence', 'described_state', 'awaiting_description'] + <% for p in ['title', 'described_state', 'awaiting_description'] if event.params[p.to_sym] != event.params[('old_'+p).to_sym] %> Changed <%=p%> from '<%=h event.params[('old_'+p).to_sym]%>' to '<%=h event.params[p.to_sym] %>'. <% end diff --git a/app/views/admin_incoming_message/_intro.html.erb b/app/views/admin_incoming_message/_intro.html.erb new file mode 100644 index 000000000..1d5585f11 --- /dev/null +++ b/app/views/admin_incoming_message/_intro.html.erb @@ -0,0 +1,3 @@ +<% @title = "Incoming message #{incoming_message.id} of FOI request '#{incoming_message.info_request.title}'" %> +<h1>Incoming message <%= incoming_message.id %></h1> +<p>FOI request: <%= request_both_links(incoming_message.info_request) %></p> diff --git a/app/views/admin_incoming_message/edit.html.erb b/app/views/admin_incoming_message/edit.html.erb new file mode 100644 index 000000000..1088edcab --- /dev/null +++ b/app/views/admin_incoming_message/edit.html.erb @@ -0,0 +1,26 @@ +<%= render :partial => 'intro', :locals => {:incoming_message => @incoming_message } %> +<%= render :partial => 'admin_request/incoming_message_actions', :locals => { :incoming_message => @incoming_message } %> +<fieldset class="form-horizontal"> + <legend>Prominence</legend> + <%= form_tag admin_incoming_update_path(@incoming_message), :class => "form form-inline" do %> + + <div class="control-group"> + <label class="control-label" for="incoming_message_prominence"> Prominence</label> + <div class="controls"> + <%= select('incoming_message', "prominence", IncomingMessage.prominence_states) %> + </div> + </div> + + <div class="control-group"> + <label class="control-label" for="incoming_message_prominence_reason">Reason for prominence</label> + <div class="controls"> + <%= text_area "incoming_message", "prominence_reason", :rows => 5, :class => "span6" %> + </div> + </div> + + <div class="form-actions" > + <%= submit_tag 'Save', :class => "btn" %> + </div> + + <% end %> +</fieldset> diff --git a/app/views/admin_outgoing_message/edit.html.erb b/app/views/admin_outgoing_message/edit.html.erb new file mode 100644 index 000000000..d5f5f43bf --- /dev/null +++ b/app/views/admin_outgoing_message/edit.html.erb @@ -0,0 +1,50 @@ +<h1>Edit outgoing message</h1> + +<%= error_messages_for 'outgoing_message' %> + +<%= form_tag admin_outgoing_update_path(@outgoing_message) do %> + <div class="control-group"> + <label class="control-label" for="outgoing_message_prominence"> Prominence</label> + <div class="controls"> + <%= select('outgoing_message', "prominence", OutgoingMessage.prominence_states) %> + </div> + </div> + + <div class="control-group"> + <label class="control-label" for="outgoing_message_prominence_reason">Reason for prominence</label> + <div class="controls"> + <%= text_area "outgoing_message", "prominence_reason", :rows => 5, :class => "span6" %> + </div> + </div> + + <div class="control-group"> + <label class="control-label" for="outgoing_message_body">Body of message</label> + <div class="controls"> + <%= text_area 'outgoing_message', 'body', :rows => 10, :cols => 60 %> + </div> + + <p><strong>Note:</strong> This is mainly to be used to excise information + that users inadvertently put in their messages, not realising it would be + public. It will already have been sent to the public authority, and their + reply may also include that information and be automatically published on + this site. You could also use this to edit a message before resending it, but + only the edited version will be shown on the public page if you do that.</p> + +<div class="form-actions" > +<%= submit_tag 'Save', :accesskey => 's', :class => 'btn' %> +</div> +<% end %> + +<p> +<%= link_to 'Show', admin_request_show_path(@outgoing_message.info_request) %> | +<%= link_to 'List all', admin_request_list_path %> +</p> + +<%= form_tag admin_outgoing_destroy_path do %> + <div> + <%= hidden_field_tag 'outgoing_message_id', @outgoing_message.id %> + <%= submit_tag "Destroy outgoing message", :class => "btn btn-danger", :confirm => "This is permanent! Are you sure?" %> + </div> +<% end %> + + diff --git a/app/views/admin_request/_incoming_message_actions.html.erb b/app/views/admin_request/_incoming_message_actions.html.erb index 653e73337..4cf099b53 100644 --- a/app/views/admin_request/_incoming_message_actions.html.erb +++ b/app/views/admin_request/_incoming_message_actions.html.erb @@ -1,6 +1,6 @@ <fieldset class="form-horizontal"> <legend>Actions</legend> - <%= form_tag admin_request_redeliver_incoming_path, :class => "form form-inline" do %> + <%= form_tag admin_incoming_redeliver_path, :class => "form form-inline" do %> <div class="control-group"> <label class="control-label" for="url_title_<%= incoming_message.id %>">Redeliver message to one or more other requests</label> <div class="controls"> @@ -22,7 +22,7 @@ </div> </div> - <%= form_tag admin_request_destroy_incoming_path, :class => "form form-inline" do %> + <%= form_tag admin_incoming_destroy_path, :class => "form form-inline" do %> <div class="control-group"> <label class="control-label" for="destroy_message_<%= incoming_message.id %>">Destroy message</label> <div class="controls"> diff --git a/app/views/admin_request/edit_outgoing.html.erb b/app/views/admin_request/edit_outgoing.html.erb deleted file mode 100644 index a0c60520a..000000000 --- a/app/views/admin_request/edit_outgoing.html.erb +++ /dev/null @@ -1,33 +0,0 @@ -<h1>Edit outgoing message</h1> - -<%= error_messages_for 'outgoing_message' %> - -<%= form_tag admin_request_update_outgoing_path(@outgoing_message) do %> - - <p><label for="outgoing_message_body">Body of message</label><br/> - <%= text_area 'outgoing_message', 'body', :rows => 10, :cols => 60 %></p> - - <p><strong>Note:</strong> This is mainly to be used to excise information - that users inadvertently put in their messages, not realising it would be - public. It will already have been sent to the public authority, and their - reply may also include that information and be automatically published on - this site. You could also use this to edit a message before resending it, but - only the edited version will be shown on the public page if you do that.</p> - - <p><%= submit_tag 'Save', :accesskey => 's' %></p> -<% end %> - -<p> -<%= link_to 'Show', admin_request_show_path(@outgoing_message.info_request) %> | -<%= link_to 'List all', admin_request_list_path %> -</p> - -<%= form_tag admin_request_destroy_outgoing_path do %> - <div> - <%= hidden_field_tag 'outgoing_message_id', @outgoing_message.id %> - Warning, this is permanent! ---> - <%= submit_tag "Destroy outgoing message" %> - </div> -<% end %> - - diff --git a/app/views/admin_request/show.html.erb b/app/views/admin_request/show.html.erb index e18e319be..83d9c3764 100644 --- a/app/views/admin_request/show.html.erb +++ b/app/views/admin_request/show.html.erb @@ -233,7 +233,7 @@ <div class="accordion-group"> <div class="accordion-heading"> <a href="#outgoing_<%=outgoing_message.id%>" data-toggle="collapse" data-parent="#outgoing_messages"><%= chevron_right %></a> - <%= link_to admin_request_edit_outgoing_path(outgoing_message) do %> + <%= link_to admin_outgoing_edit_path(outgoing_message) do %> #<%= outgoing_message.id %> -- <%= outgoing_message.status.humanize %> <%= outgoing_message.message_type.humanize %> <% end %> <blockquote> @@ -275,11 +275,16 @@ <hr> <h2>Incoming messages</h2> <div class="accordion" id="incoming_messages"> - <% for incoming_message in @info_request.incoming_messages.find(:all, :order => 'created_at') %> + <% for incoming_message in @info_request.incoming_messages %> <div class="accordion-group"> <div class="accordion-heading"> <a href="#incoming_<%=incoming_message.id%>" data-toggle="collapse" data-parent="#incoming_messages"><%= chevron_right %></a> - <%=incoming_message.id%> -- <%= h(incoming_message.mail_from) %> <%=_("at")%> <%=admin_value(incoming_message.sent_at)%> + <%= link_to admin_incoming_edit_path(incoming_message) do %> + <%=incoming_message.id%> + -- + <%= h(incoming_message.mail_from) %> + <%=_("at")%> <%=admin_value(incoming_message.sent_at)%> + <% end %> <blockquote class="incoming-message"> <% if !incoming_message.cached_main_body_text_folded.nil? %> <%= truncate(incoming_message.cached_main_body_text_folded.gsub('FOLDED_QUOTED_SECTION', ''), :length => 400) %> diff --git a/app/views/admin_request/show_raw_email.html.erb b/app/views/admin_request/show_raw_email.html.erb index 72c782ad6..da22b6069 100644 --- a/app/views/admin_request/show_raw_email.html.erb +++ b/app/views/admin_request/show_raw_email.html.erb @@ -1,9 +1,5 @@ -<% @title = "Incoming message #{@raw_email.incoming_message.id} of FOI request '#{@raw_email.incoming_message.info_request.title}'" %> +<%= render :partial => 'admin_incoming_message/intro', :locals => { :incoming_message => @raw_email.incoming_message } %> -<h1>Incoming message <%=@raw_email.incoming_message.id %></h1> - -<p> - FOI request: <%= request_both_links(@raw_email.incoming_message.info_request) %> <% if @holding_pen %> <br>This is in the holding pen because: <strong><%= @rejected_reason %></strong> <% if @public_bodies.size > 0 %> diff --git a/app/views/comment/_single_comment.html.erb b/app/views/comment/_single_comment.html.erb index 421a9d4ba..af1de0649 100644 --- a/app/views/comment/_single_comment.html.erb +++ b/app/views/comment/_single_comment.html.erb @@ -1,5 +1,5 @@ <div class="comment_in_request" id="comment-<%=comment.id.to_s%>"> - <% if comment.user && comment.user.profile_photo %> + <% if comment.user && comment.user.profile_photo && !@render_to_file %> <div class="user_photo_on_comment"> <img src="<%= get_profile_photo_url(:url_name => comment.user.url_name) %>" alt=""> </div> diff --git a/app/views/comment/_single_comment.text.erb b/app/views/comment/_single_comment.text.erb new file mode 100644 index 000000000..925e8b688 --- /dev/null +++ b/app/views/comment/_single_comment.text.erb @@ -0,0 +1,2 @@ +<%= _("{{username}} left an annotation:", :username =>comment.user.name) %> (<%= simple_date(comment.created_at || Time.now) %>) +<%= comment.body.strip %> diff --git a/app/views/general/_stylesheet_includes.html.erb b/app/views/general/_stylesheet_includes.html.erb index 9dd1f357d..416ddb825 100644 --- a/app/views/general/_stylesheet_includes.html.erb +++ b/app/views/general/_stylesheet_includes.html.erb @@ -1,16 +1,23 @@ - <%= stylesheet_link_tag 'main', :title => "Main", :rel => "stylesheet", :media => "all" %> - <%= stylesheet_link_tag 'fonts', :rel => "stylesheet", :media => "all" %> - <%= stylesheet_link_tag 'print', :rel => "stylesheet", :media => "print" %> - <% if !params[:print_stylesheet].nil? %> - <%= stylesheet_link_tag 'print', :rel => "stylesheet", :media => "all" %> - <% end %> - <%= stylesheet_link_tag 'admin-theme/jquery-ui-1.8.15.custom.css', :rel => 'stylesheet'%> - <!--[if LT IE 7]> - <style type="text/css">@import url("/stylesheets/ie6.css");</style> - <![endif]--> - <!--[if LT IE 8]> - <style type="text/css">@import url("/stylesheets/ie7.css");</style> - <![endif]--> - <% if AlaveteliConfiguration::force_registration_on_new_request %> - <%= stylesheet_link_tag 'jquery.fancybox-1.3.4', :rel => "stylesheet" %> - <% end %> +<%- if @render_to_file %> + <style> + <%= raw File.read(Rails.root.join('public', 'stylesheets', 'main.css')) %> + <%= raw File.read(Rails.root.join('public', 'stylesheets', 'print.css')) %> + </style> +<%- else %> + <%= stylesheet_link_tag 'main', :title => "Main", :rel => "stylesheet", :media => "all" %> + <%= stylesheet_link_tag 'fonts', :rel => "stylesheet", :media => "all" %> + <%= stylesheet_link_tag 'print', :rel => "stylesheet", :media => "print" %> + <% if !params[:print_stylesheet].nil? %> + <%= stylesheet_link_tag 'print', :rel => "stylesheet", :media => "all" %> + <% end %> + <%= stylesheet_link_tag 'admin-theme/jquery-ui-1.8.15.custom.css', :rel => 'stylesheet'%> + <!--[if LT IE 7]> + <style type="text/css">@import url("/stylesheets/ie6.css");</style> + <![endif]--> + <!--[if LT IE 8]> + <style type="text/css">@import url("/stylesheets/ie7.css");</style> + <![endif]--> + <% if AlaveteliConfiguration::force_registration_on_new_request %> + <%= stylesheet_link_tag 'jquery.fancybox-1.3.4', :rel => "stylesheet" %> + <% end %> +<% end %> diff --git a/app/views/layouts/_favicon.html.erb b/app/views/layouts/_favicon.html.erb new file mode 100644 index 000000000..4f3859d6c --- /dev/null +++ b/app/views/layouts/_favicon.html.erb @@ -0,0 +1 @@ +<link rel="shortcut icon" href="/favicon.ico"> diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index a58913892..7722efad4 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb @@ -4,7 +4,7 @@ <meta http-equiv="content-type" content="text/html;charset=UTF-8" > <title><%= site_name %> admin<%= @title ? ":" : "" %> <%=@title%></title> - <%= javascript_include_tag '/javascripts/jquery.js', '/admin/javascripts/jquery-ui.min.js', '/admin/javascripts/bootstrap-collapse', '/admin/javascripts/bootstrap-tab', '/admin/javascripts/admin' %> + <%= javascript_include_tag '/javascripts/jquery.js', '/admin/javascripts/jquery-ui.min.js', '/admin/javascripts/bootstrap-collapse', '/admin/javascripts/bootstrap-tab', '/admin/javascripts/admin', '/javascripts/jquery_ujs' %> <%= stylesheet_link_tag 'admin-theme/jquery-ui-1.8.15.custom.css', :rel => 'stylesheet'%> <%= stylesheet_link_tag "/admin/stylesheets/admin", :title => "Main", :rel => "stylesheet" %> diff --git a/app/views/layouts/default.html.erb b/app/views/layouts/default.html.erb index 472fa8ec1..5895becf7 100644 --- a/app/views/layouts/default.html.erb +++ b/app/views/layouts/default.html.erb @@ -10,7 +10,7 @@ <% end %> </title> - <link rel="shortcut icon" href="/favicon.ico"> + <%= render :partial => 'layouts/favicon' %> <%= render :partial => 'general/stylesheet_includes' %> <% if is_admin? %> diff --git a/app/views/public_body/statistics.html.erb b/app/views/public_body/statistics.html.erb new file mode 100644 index 000000000..840af0c10 --- /dev/null +++ b/app/views/public_body/statistics.html.erb @@ -0,0 +1,75 @@ +<% @title = _("Public Body Statistics") %> +<div id="main_content"> + <h1>Public Body Statistics</h1> + + <p><%= _("This page of public body statistics is currently \ +experimental, so there are some caveats that should be borne \ +in mind:") %></p> + + <ul> + + <li><%= _("The percentages are calculated with respect to \ +the total number of requests, which includes invalid \ +requests; this is a known problem that will be fixed in a \ +later release.") %></li> + + <li><%= _("The classification of requests (e.g. to say \ +whether they were successful or not) is done manually by users \ +and administrators of the site, which means that they are \ +subject to error.") %></li> + + <li><%= _("Requests are considered successful if they were \ +classified as either 'Successful' or 'Partially Successful'.") %></li> + + <li><%= _("Requests are considered overdue if they are in \ +the 'Overdue' or 'Very Overdue' states.") %></li> + + <li><%= _("The error bars shown are 95% confidence intervals \ +for the hypothesized underlying proportion (i.e. that which \ +you would obtain by making an infinite number of requests \ +through this site to that authority). In other words, the \ +population being sampled is all the current and future \ +requests to the authority through this site, rather than, \ +say, all requests that have been made to the public body by \ +any means.") %></li> + + </ul> + + <p><%= _("These graphs were partly inspired by \ +<a href=\"http://mark.goodge.co.uk/2011/08/number-crunching-whatdotheyknow/\">some \ +statistics that Mark Goodge produced for WhatDoTheyKnow</a>, so thanks \ +are due to him.") %></p> + + <% @graph_list.each do |graph_data| %> + <h3 class="public-body-ranking-title"><%= graph_data['title']%></h3> + <div class="public-body-ranking" id="<%= graph_data['id'] %>"> + <% if graph_data['x_values'] %> + <table border=0> + <thead> + <tr> + <th>Public Body</th> + <th><%= graph_data['y_axis'] %></th> + </tr> + </thead> + <tbody> + <% graph_data['x_ticks'].each_with_index do |pb_and_index, i| %> + <tr> + <td><%= pb_and_index[1] %></td> + <td class="statistic"><%= graph_data['y_values'][i].round %></td> + </tr> + <% end %> + </tbody> + </table> + <% else %> + <%= _("There was no data calculated for this graph yet.") %> + <% end %> + </div> + <% end %> + +<script type="text/javascript"> + var graphs_data = <%= @graph_list.to_json.html_safe %>; +</script> +<!--[if lte IE 8]><%= javascript_include_tag 'excanvas.min.js' %><![endif]--> +<%= javascript_include_tag 'jquery.flot.min.js', 'jquery.flot.errorbars.min.js', 'jquery.flot.axislabels.js', 'stats-graphs.js' %> + +</div> diff --git a/app/views/request/_after_actions.html.erb b/app/views/request/_after_actions.html.erb index b54a8f5fb..f780e3a37 100644 --- a/app/views/request/_after_actions.html.erb +++ b/app/views/request/_after_actions.html.erb @@ -15,11 +15,9 @@ <%= link_to _('Update the status of this request'), '#describe_state_form_1' %> </li> <% end %> - <% if @info_request.all_can_view? %> <li> <%= link_to _("Download a zip file of all correspondence"), download_entire_request_path(:url_title => @info_request.url_title) %> </li> - <% end %> </ul> </div> <% if ! @info_request.is_external? %> diff --git a/app/views/request/_correspondence.html.erb b/app/views/request/_correspondence.html.erb index 68711b259..872761749 100644 --- a/app/views/request/_correspondence.html.erb +++ b/app/views/request/_correspondence.html.erb @@ -1,80 +1,12 @@ <div class="ff-print-fix"></div> -<% -if !info_request_event.nil? && info_request_event.event_type == 'response' - incoming_message = info_request_event.incoming_message -end - -if not incoming_message.nil? -%> - <div class="incoming correspondence" id="incoming-<%=incoming_message.id.to_s%>"> - <h2> - <% if !incoming_message.safe_mail_from.nil? && incoming_message.safe_mail_from.strip != @info_request.public_body.name.strip %> - <%= _("From:") %> <%=h incoming_message.safe_mail_from %><br> - <% end %> - <% if incoming_message.safe_mail_from.nil? || (incoming_message.mail_from_domain == @info_request.public_body.request_email_domain) %> - <%=h @info_request.public_body.name %><br> - <% end %> - <br><%= simple_date(incoming_message.sent_at) %> - </h2> - - <%= render :partial => 'bubble', :locals => { :incoming_message => incoming_message, :body => incoming_message.get_body_for_html_display(@collapse_quotes), :attachments => incoming_message.get_attachments_for_display } %> - - <p class="event_actions"> - <% if !@user.nil? && @user.admin_page_links? %> - <%= link_to "Admin", admin_request_show_raw_email_path(incoming_message.raw_email_id) %> | - <% end %> - <%= link_to _("Link to this"), incoming_message_path(incoming_message), :class => "link_to_this" %> - </p> - </div> -<% -elsif [ 'sent', 'followup_sent' ].include?(info_request_event.event_type) - outgoing_message = info_request_event.outgoing_message - %> - <div class="outgoing correspondence" id="outgoing-<%=outgoing_message.id.to_s%>"> - - <h2> - <%= _("From:") %> <%=h @info_request.user_name %><br> - <br><%= simple_date(info_request_event.created_at) %> - </h2> - - <%= render :partial => 'bubble', :locals => { :body => outgoing_message.get_body_for_html_display(), :attachments => nil } %> - - <p class="event_actions"> - <% if outgoing_message.status == 'ready' && !@info_request.is_external? %> - <strong>Warning:</strong> This message has <strong>not yet been sent</strong> for an unknown reason. - <% end %> - - <!-- Can use this to get name of who followup was too, if say you - play with proper from display, but not sure needed - <% if outgoing_message.message_type == 'followup' && !outgoing_message.incoming_message_followup.nil? && !outgoing_message.incoming_message_followup.safe_mail_from.nil? %> - Follow up sent to: <%=h outgoing_message.incoming_message_followup.safe_mail_from %> - <% end %> - --> - - <%= link_to _("Link to this"), outgoing_message_path(outgoing_message), :class => "link_to_this" %> - </p> - </div> -<% elsif [ 'resent', 'followup_resent' ].include?(info_request_event.event_type) %> - <div class="outgoing correspondence" id="outgoing-<%=info_request_event.outgoing_message.id.to_s%>"> - <h2> - <%= simple_date(info_request_event.created_at) %> - </h2> - <p class="event_plain"> - Sent - <% if info_request_event.outgoing_message.message_type == 'initial_request' %> - request - <% elsif info_request_event.outgoing_message.message_type == 'followup' %> - a follow up - <% else %> - <% raise "unknown message_type" %> - <% end %> - - to <%= public_body_link(@info_request.public_body) %> again<% if not info_request_event.same_email_as_previous_send? %>, using a new contact address<% end %>. - </p> - </div> -<% elsif info_request_event.event_type == 'comment' - comment = info_request_event.comment -%> - <%= render :partial => 'comment/single_comment', :locals => { :comment => comment } %> +<% case info_request_event.event_type %> +<% when 'response' %> + <%= render :partial => 'request/incoming_correspondence', :locals => { :incoming_message => info_request_event.incoming_message } %> +<% when 'sent', 'followup_sent' %> + <%= render :partial => 'request/outgoing_correspondence', :locals => { :outgoing_message => info_request_event.outgoing_message, :info_request_event => info_request_event }%> +<% when 'resent', 'followup_resent' %> + <%= render :partial => 'request/resent_outgoing_correspondence', :locals => { outgoing_message => info_request_event.outgoing_message, :info_request_event => info_request_event }%> +<% when 'comment' %> + <%= render :partial => 'comment/single_comment', :locals => { :comment => info_request_event.comment } %> <% end %> diff --git a/app/views/request/_hidden_correspondence.html.erb b/app/views/request/_hidden_correspondence.html.erb index 4c06f1f48..153164278 100644 --- a/app/views/request/_hidden_correspondence.html.erb +++ b/app/views/request/_hidden_correspondence.html.erb @@ -1,33 +1,13 @@ -<% if info_request_event.prominence == 'requester_only' %> - <% - if !info_request_event.nil? && info_request_event.event_type == 'response' - incoming_message = info_request_event.incoming_message - end - if not incoming_message.nil? - %> - <div class="correspondence" id="incoming-<%=incoming_message.id.to_s%>"> - <p> - <%= _('This response has been hidden. See annotations to find out why. - If you are the requester, then you may <a href="{{url}}">sign in</a> to view the response.', :url => signin_url(:r => request.fullpath).html_safe) %> - </p> - </div> - <% elsif [ 'sent', 'followup_sent', 'resent', 'followup_resent' ].include?(info_request_event.event_type) %> - <div class="correspondence" id="outgoing-<%=outgoing_message.id.to_s%>"> - <p> - <%= _('This outgoing message has been hidden. See annotations to - find out why. If you are the requester, then you may <a href="{{url}}">sign in</a> to view the response.', :url => signin_url(:r => request.fullpath).html_safe) %> - </p> - </div> - <% elsif info_request_event.event_type == 'comment' %> - <div class="comment_in_request" id="comment-<%=comment.id.to_s%>"> - <p><%= _('This comment has been hidden. See annotations to - find out why. If you are the requester, then you may <a href="{{url}}">sign in</a> to view the response.', :url => signin_url(:r => request.fullpath).html_safe) %> - </p> - </div> - <% end %> - -<% elsif info_request_event.prominence == 'hidden' %> - <% # show nothing when hidden %> -<% else %> - <% raise _("unexpected prominence on request event") %> -<% end %> +<p id="hidden_message"> + <%- if !message.prominence_reason.blank? %> + <%= _('This message has been hidden.') %> + <%= message.prominence_reason %> + <%= _('Please <a href="{{url}}">contact us</a> if you have any questions.', :url => help_contact_path.html_safe) %> + <%- else %> + <%= _("This message has been hidden. There are various reasons why we might have done this, sorry we can't be more specific here.") %> + <%= _('Please <a href="{{url}}">contact us</a> if you have any questions.', :url => help_contact_path.html_safe) %> + <%- end %> + <% if message.prominence == 'requester_only' %> + <%= _('If you are the requester, then you may <a href="{{url}}">sign in</a> to view the message.', :url => signin_url(:r => request.fullpath).html_safe) %> + <% end %> +</p> diff --git a/app/views/request/_hidden_correspondence.text.erb b/app/views/request/_hidden_correspondence.text.erb new file mode 100644 index 000000000..010b6b66d --- /dev/null +++ b/app/views/request/_hidden_correspondence.text.erb @@ -0,0 +1,5 @@ +<%- if !message.prominence_reason.blank? %> + <%= _('This message has been hidden.') %> <%= message.prominence_reason %> +<%- else %> + <%= _("This message has been hidden. There are various reasons why we might have done this, sorry we can't be more specific here.") %> +<%- end %> diff --git a/app/views/request/_incoming_correspondence.html.erb b/app/views/request/_incoming_correspondence.html.erb new file mode 100644 index 000000000..f39d650d8 --- /dev/null +++ b/app/views/request/_incoming_correspondence.html.erb @@ -0,0 +1,26 @@ +<div class="incoming correspondence <%= incoming_message.prominence %>" id="incoming-<%=incoming_message.id.to_s%>"> + <%- if not incoming_message.user_can_view?(@user) %> + <%= render :partial => 'request/hidden_correspondence', :locals => { :message => incoming_message }%> + <%- else %> + <%= render :partial => 'request/restricted_correspondence', :locals => {:message => incoming_message } %> + <h2> + <% if incoming_message.specific_from_name? %> + <%= _("From:") %> <%= incoming_message.safe_mail_from %><br> + <% end %> + <% if incoming_message.from_public_body? %> + <%= @info_request.public_body.name %><br> + <% end %> + <br><%= simple_date(incoming_message.sent_at) %> + </h2> + + <%= render :partial => 'bubble', :locals => { :incoming_message => incoming_message, :body => incoming_message.get_body_for_html_display(@collapse_quotes), :attachments => incoming_message.get_attachments_for_display } %> + + <p class="event_actions"> + <% if !@user.nil? && @user.admin_page_links? %> + <%= link_to "Admin", admin_incoming_edit_path(incoming_message.id) %> | + <% end %> + <%= link_to _("Link to this"), incoming_message_path(incoming_message), :class => "link_to_this" %> + </p> + <%- end %> +</div> + diff --git a/app/views/request/_incoming_correspondence.text.erb b/app/views/request/_incoming_correspondence.text.erb new file mode 100644 index 000000000..33ddad926 --- /dev/null +++ b/app/views/request/_incoming_correspondence.text.erb @@ -0,0 +1,12 @@ +<%- if not incoming_message.user_can_view?(@user) %> + <%= render :partial => 'request/hidden_correspondence.text', :locals => { :message => incoming_message }%> +<%- else %> +<%= _('From:') %><% if incoming_message.specific_from_name? %> <%= incoming_message.safe_mail_from %><% end %><% if incoming_message.from_public_body? %>, <%= @info_request.public_body.name %><% end %> +<%= _('To:') %> <% if @info_request.user_name %><%= @info_request.user_name %><% else %><%= "[#{_('An anonymous user')}]"%><% end %> +<%= _('Date:') %> <%= simple_date(incoming_message.sent_at) %> + + <%= incoming_message.get_body_for_quoting %> + <% incoming_message.get_attachments_for_display.each do |a| %> +<%= _('Attachment:') %> <%= a.display_filename %> (<%= a.display_size %>) + <% end %> +<% end %> diff --git a/app/views/request/_outgoing_correspondence.html.erb b/app/views/request/_outgoing_correspondence.html.erb new file mode 100644 index 000000000..dced5c94c --- /dev/null +++ b/app/views/request/_outgoing_correspondence.html.erb @@ -0,0 +1,18 @@ +<div class="outgoing correspondence" id="outgoing-<%=outgoing_message.id.to_s%>"> + <%- if not outgoing_message.user_can_view?(@user) %> + <%= render :partial => 'request/hidden_correspondence', :locals => { :message => outgoing_message }%> + <%- else %> + <%= render :partial => 'request/restricted_correspondence', :locals => {:message => outgoing_message } %> + <h2> + <%= _("From:") %> <%= @info_request.user_name %><br> + <br><%= simple_date(info_request_event.created_at) %> + </h2> + <%= render :partial => 'bubble', :locals => { :body => outgoing_message.get_body_for_html_display(), :attachments => nil } %> + <p class="event_actions"> + <% if outgoing_message.status == 'ready' && !@info_request.is_external? %> + <strong>Warning:</strong> This message has <strong>not yet been sent</strong> for an unknown reason. + <% end %> + <%= link_to _("Link to this"), outgoing_message_path(outgoing_message), :class => "link_to_this" %> + </p> + <%- end %> +</div> diff --git a/app/views/request/_outgoing_correspondence.text.erb b/app/views/request/_outgoing_correspondence.text.erb new file mode 100644 index 000000000..80c71cc01 --- /dev/null +++ b/app/views/request/_outgoing_correspondence.text.erb @@ -0,0 +1,8 @@ +<%- if not outgoing_message.user_can_view?(@user) %> + <%= render :partial => 'request/hidden_correspondence.text', :locals => { :message => outgoing_message }%> +<%- else %> + <%= _('From:') %> <% if @info_request.user_name %><%= @info_request.user_name %><% else %><%= "[#{_('An anonymous user')}]"%><% end %> + <%= _('To:') %> <%= @info_request.public_body.name %> + <%= _('Date:') %> <%= simple_date(info_request_event.created_at) %> + <%= outgoing_message.get_body_for_text_display %> +<%- end %> diff --git a/app/views/request/_resent_outgoing_correspondence.html.erb b/app/views/request/_resent_outgoing_correspondence.html.erb new file mode 100644 index 000000000..17b6b635b --- /dev/null +++ b/app/views/request/_resent_outgoing_correspondence.html.erb @@ -0,0 +1,16 @@ +<div class="outgoing correspondence" id="outgoing-<%=outgoing_message.id.to_s%>"> + <h2> + <%= simple_date(info_request_event.created_at) %> + </h2> + <p class="event_plain"> + Sent + <% if outgoing_message.message_type == 'initial_request' %> + request + <% elsif outgoing_message.message_type == 'followup' %> + a follow up + <% else %> + <% raise "unknown message_type" %> + <% end %> + to <%= public_body_link(@info_request.public_body) %> again<% if not info_request_event.same_email_as_previous_send? %>, using a new contact address<% end %>. + </p> +</div> diff --git a/app/views/request/_resent_outgoing_correspondence.text.erb b/app/views/request/_resent_outgoing_correspondence.text.erb new file mode 100644 index 000000000..d645e9488 --- /dev/null +++ b/app/views/request/_resent_outgoing_correspondence.text.erb @@ -0,0 +1,2 @@ +<%= _('Date:') %> <%= simple_date(info_request_event.created_at) %> +Sent <% if outgoing_message.message_type == 'initial_request' %> request <% elsif outgoing_message.message_type == 'followup' %> a follow up <% else %> <% raise "unknown message_type" %><% end %> to <%= public_body_link(@info_request.public_body) %> again<% if not info_request_event.same_email_as_previous_send? %>, using a new contact address<% end %>. diff --git a/app/views/request/_restricted_correspondence.html.erb b/app/views/request/_restricted_correspondence.html.erb new file mode 100644 index 000000000..745c4ff0e --- /dev/null +++ b/app/views/request/_restricted_correspondence.html.erb @@ -0,0 +1,18 @@ +<% if message.prominence == 'hidden' %> + <p id="hidden_message"> + <%- if !message.prominence_reason.blank? %> + <%= _('This message has prominence \'hidden\'. {{reason}} You can only see it because you are logged in as a super user.', :reason => message.prominence_reason) %> + <%- else %> + <%= _('This message has prominence \'hidden\'. You can only see it because you are logged in as a super user.') %> + <%- end %> + </p> +<% end %> +<% if message.prominence == 'requester_only' %> + <p id="hidden_message"> + <%- if !message.prominence_reason.blank? %> + <%= _('This message is hidden, so that only you, the requester, can see it. {{reason}}', :reason => message.prominence_reason) %> + <%- else %> + <%= _('This message is hidden, so that only you, the requester, can see it. Please <a href="{{url}}">contact us</a> if you are not sure why.', :url => help_requesting_path.html_safe) %> + <%- end %> + </p> +<% end %> diff --git a/app/views/request/hidden_correspondence.html.erb b/app/views/request/hidden_correspondence.html.erb new file mode 100644 index 000000000..46bf3ee37 --- /dev/null +++ b/app/views/request/hidden_correspondence.html.erb @@ -0,0 +1,4 @@ +<% @title = _("Message has been removed") %> + +<h1><%=@title%></h1> +<%= render :partial => 'request/hidden_correspondence', :locals => { :message => @incoming_message } %> diff --git a/app/views/request/show.html.erb b/app/views/request/show.html.erb index 1d5b9977f..c520ce40c 100644 --- a/app/views/request/show.html.erb +++ b/app/views/request/show.html.erb @@ -25,8 +25,7 @@ <div id="left_column"> <h1><%=h(@info_request.title)%></h1> - - <% if !@info_request.is_external? && @info_request.user.profile_photo %> + <% if !@info_request.is_external? && @info_request.user.profile_photo && !@render_to_file %> <p class="user_photo_on_request"> <img src="<%= get_profile_photo_url(:url_name => @info_request.user.url_name) %>" alt=""> </p> @@ -49,7 +48,7 @@ <p id="request_status" class="request_icon_line icon_<%= @info_request.calculate_status %>"> <% if @info_request.awaiting_description %> - <% if @is_owning_user && !@info_request.is_external? %> + <% if @is_owning_user && !@info_request.is_external? && !@render_to_file %> <%= _('Please <strong>answer the question above</strong> so we know whether the ')%> <%= MySociety::Format.fancy_pluralize(@new_responses_count, 'recent response contains', 'recent responses contain') %> <%= _('useful information.') %> <% else %> @@ -147,4 +146,4 @@ <%= render :partial => 'after_actions' %> </div> -<%= render :partial => 'sidebar' %> +<%- if @sidebar %><%= render :partial => 'sidebar' %><% end %> diff --git a/app/views/request/show.text.erb b/app/views/request/show.text.erb new file mode 100644 index 000000000..29ac2987f --- /dev/null +++ b/app/views/request/show.text.erb @@ -0,0 +1,17 @@ +<%= _('This is a plain-text version of the Freedom of Information request "{{request_title}}". The latest, full version is available online at {{full_url}}', :request_title => @info_request.title, :full_url => "http://#{AlaveteliConfiguration::domain}#{show_request_path(:url_title=>@info_request.url_title)}") %>. + +<% @info_request_events.each do |info_request_event| %> + <% if info_request_event.visible %> + <% case info_request_event.event_type %> + <% when 'response' %> + <%= render :partial => 'request/incoming_correspondence.text', :locals => { :incoming_message => info_request_event.incoming_message } %> + <% when 'sent', 'followup_sent' %> + <%= render :partial => 'request/outgoing_correspondence.text', :locals => { :outgoing_message => info_request_event.outgoing_message, :info_request_event => info_request_event }%> + <% when 'resent', 'followup_resent' %> + <%= render :partial => 'request/resent_outgoing_correspondence.text', :locals => { outgoing_message => info_request_event.outgoing_message, :info_request_event => info_request_event }%> + <% when 'comment' %> + <%= render :partial => 'comment/single_comment.text', :locals => { :comment => info_request_event.comment } %> + <% end %> +------------------------------- + <% end %> +<% end %> diff --git a/app/views/request/show_response.html.erb b/app/views/request/show_response.html.erb index a61359679..ace86cf4c 100644 --- a/app/views/request/show_response.html.erb +++ b/app/views/request/show_response.html.erb @@ -36,7 +36,7 @@ <dd> <%= _('To do that please send a private email to ') %><%=h(@postal_email_name)%> <<%=link_to h(@postal_email), "mailto:" + @postal_email%>> - <%= _('containing your postal address, and asking them to reply to this request. + <%= _('containing your postal address, and asking them to reply to this request. Or you could phone them.') %> <%= _('When you receive the paper response, please help @@ -63,16 +63,16 @@ <% end %> <% else %> <% if @incoming_message.recently_arrived %> - <h2><%= _('New response to {{law_used_short}} request',:law_used_short => h(@info_request.law_used_short))%> '<%= request_link @info_request %>'</h2> + <h2><%= _('New response to {{law_used_short}} request',:law_used_short => h(@info_request.law_used_short))%> '<%= request_link @info_request %>'</h2> <% else %> <h2>Response to <%=h(@info_request.law_used_short)%> request '<%= request_link @info_request %>'</h2> <% end %> <% end %> <% if @incoming_message.nil? %> - <%= render :partial => 'correspondence', :locals => { :info_request_event => @info_request.get_last_outgoing_event, :incoming_message => nil } %> + <%= render :partial => 'correspondence', :locals => { :info_request_event => @info_request.get_last_outgoing_event } %> <% else %> - <%= render :partial => 'correspondence', :locals => { :info_request_event => nil, :incoming_message => @incoming_message } %> + <%= render :partial => 'correspondence', :locals => { :info_request_event => @incoming_message.response_event } %> <% end %> <% end %> diff --git a/app/views/request/simple_correspondence.html.erb b/app/views/request/simple_correspondence.html.erb deleted file mode 100644 index 461fa3912..000000000 --- a/app/views/request/simple_correspondence.html.erb +++ /dev/null @@ -1,45 +0,0 @@ -<%= _('This is a plain-text version of the Freedom of Information request "{{request_title}}". The latest, full version is available online at {{full_url}}', :request_title => @info_request.title, :full_url => "http://#{AlaveteliConfiguration::domain}#{show_request_path(:url_title=>@info_request.url_title)}") %>. - -<% for info_request_event in @info_request_events %> -<% - incoming_message = nil - if info_request_event.visible - if !info_request_event.nil? && info_request_event.event_type == 'response' - incoming_message = info_request_event.incoming_message - end - - - if not incoming_message.nil? - if !incoming_message.safe_mail_from.nil? && incoming_message.safe_mail_from.strip != @info_request.public_body.name.strip %> -<%= _('From:') %> <%= incoming_message.safe_mail_from %><% end - if incoming_message.safe_mail_from.nil? || (incoming_message.mail_from_domain == @info_request.public_body.request_email_domain) %>, <%= @info_request.public_body.name %><% end %> -<%= _('To:') %> <% if @info_request.user_name %><%= @info_request.user_name %><% else %><%= "[#{_('An anonymous user')}]"%><% end %> -<%= _('Date:') %> <%= simple_date(incoming_message.sent_at) %> - -<%= incoming_message.get_body_for_quoting %> -<% incoming_message.get_attachments_for_display.each do |a| %> - <%= _('Attachment:') %> <%= a.display_filename %> (<%= a.display_size %>) - <% end %> -<% -elsif [ 'sent', 'followup_sent' ].include?(info_request_event.event_type) - outgoing_message = info_request_event.outgoing_message - %> -<%= _('From:') %> <% if @info_request.user_name %><%= @info_request.user_name %><% else %><%= "[#{_('An anonymous user')}]"%><% end %> -<%= _('To:') %> <%= @info_request.public_body.name %> -<%= _('Date:') %> <%= simple_date(info_request_event.created_at) %> -<% - text = outgoing_message.body.strip - outgoing_message.remove_privacy_sensitive_things!(text) %> - -<%= text %> -<% elsif [ 'resent', 'followup_resent' ].include?(info_request_event.event_type) %> -<%= _('Date:') %> <%= simple_date(info_request_event.created_at) %> -Sent <% if info_request_event.outgoing_message.message_type == 'initial_request' %> request <% elsif info_request_event.outgoing_message.message_type == 'followup' %> a follow up <% else %> <% raise "unknown message_type" %><% end %> to <%= public_body_link(@info_request.public_body) %> again<% if not info_request_event.same_email_as_previous_send? %>, using a new contact address<% end %>. - -<% elsif info_request_event.event_type == 'comment' - comment = info_request_event.comment -%> -<%= _("{{username}} left an annotation:", :username =>comment.user.name) %> (<%= simple_date(comment.created_at || Time.now) %>) -<%= comment.body.strip %> -<% end %> --------------------------------<% end %><% end %> |