diff options
Diffstat (limited to 'app')
42 files changed, 675 insertions, 403 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index d8fda9c01..08528f8a8 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -36,7 +36,7 @@ class AdminController < ApplicationController # also force a search reindexing (so changed text reflected in search) info_request.reindex_request_events - # and remove from varnsi + # and remove from varnish info_request.purge_in_cache end diff --git a/app/controllers/admin_public_body_controller.rb b/app/controllers/admin_public_body_controller.rb index 285523e11..30a43bb81 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -139,48 +139,80 @@ class AdminPublicBodyController < AdminController end def import_csv - if params['commit'] == 'Dry run' - dry_run_only = true - elsif params['commit'] == 'Upload' - dry_run_only = false - else - raise "internal error, unknown button label" - end - if params[:csv_file] - csv_contents = params[:csv_file].read - else - csv_contents = session.delete(:previous_csv) - end - if !csv_contents.nil? - # Try with dry run first - en = PublicBody.import_csv(csv_contents, params[:tag], params[:tag_behaviour], true, admin_http_auth_user(), I18n.available_locales) - errors = en[0] - notes = en[1] - - if errors.size == 0 - if dry_run_only - notes.push("Dry run was successful, real run would do as above.") - session[:previous_csv] = csv_contents - else - # And if OK, with real run - en = PublicBody.import_csv(csv_contents, params[:tag], params[:tag_behaviour], false, admin_http_auth_user(), I18n.available_locales) - errors = en[0] - notes = en[1] - if errors.size != 0 - raise "dry run mismatched real run" + @notes = "" + @errors = "" + if request.post? + dry_run_only = (params['commit'] == 'Upload' ? false : true) + # Read file from params + if params[:csv_file] + csv_contents = params[:csv_file].read + @original_csv_file = params[:csv_file].original_filename + # or from previous dry-run temporary file + elsif params[:temporary_csv_file] && params[:original_csv_file] + csv_contents = retrieve_csv_data(params[:temporary_csv_file]) + @original_csv_file = params[:original_csv_file] + end + + if !csv_contents.nil? + # Try with dry run first + errors, notes = PublicBody.import_csv(csv_contents, + params[:tag], + params[:tag_behaviour], + true, + admin_http_auth_user(), + I18n.available_locales) + + if errors.size == 0 + if dry_run_only + notes.push("Dry run was successful, real run would do as above.") + # Store the csv file for ease of performing the real run + @temporary_csv_file = store_csv_data(csv_contents) + else + # And if OK, with real run + errors, notes = PublicBody.import_csv(csv_contents, + params[:tag], + params[:tag_behaviour], + false, + admin_http_auth_user(), + I18n.available_locales) + if errors.size != 0 + raise "dry run mismatched real run" + end + notes.push("Import was successful.") end - notes.push("Import was successful.") end + @errors = errors.join("\n") + @notes = notes.join("\n") end - @errors = errors.join("\n") - @notes = notes.join("\n") - else - @errors = "" - @notes = "" end - end private + # Save the contents to a temporary file - not using Tempfile as we need + # the file to persist between requests. Return the name of the file. + def store_csv_data(csv_contents) + tempfile_name = "csv_upload-#{Time.now.strftime("%Y%m%d")}-#{SecureRandom.random_number(10000)}" + tempfile = File.new(File.join(Dir::tmpdir, tempfile_name), 'w') + tempfile.write(csv_contents) + tempfile.close + return tempfile_name + end + + # Get csv contents from the file whose name is passed, as long as the + # name is of the expected form. + # Delete the file, return the contents. + def retrieve_csv_data(tempfile_name) + if not /csv_upload-\d{8}-\d{1,5}/.match(tempfile_name) + raise "Invalid filename in upload_csv: #{tempfile_name}" + end + tempfile_path = File.join(Dir::tmpdir, tempfile_name) + if ! File.exist?(tempfile_path) + raise "Missing file in upload_csv: #{tempfile_name}" + end + csv_contents = File.read(tempfile_path) + File.delete(tempfile_path) + return csv_contents + end + end diff --git a/app/controllers/admin_request_controller.rb b/app/controllers/admin_request_controller.rb index fd1405319..c5abf8769 100644 --- a/app/controllers/admin_request_controller.rb +++ b/app/controllers/admin_request_controller.rb @@ -28,8 +28,8 @@ class AdminRequestController < AdminController @info_request = InfoRequest.find(params[:id]) # XXX is this *really* the only way to render a template to a # variable, rather than to the response? - vars = OpenStruct.new(:name_to => @info_request.user.name, - :name_from => MySociety::Config.get("CONTACT_NAME", 'Alaveteli'), + vars = OpenStruct.new(:name_to => @info_request.user_name, + :name_from => MySociety::Config.get("CONTACT_NAME", 'Alaveteli'), :info_request => @info_request, :reason => params[:reason], :info_request_url => 'http://' + MySociety::Config.get('DOMAIN') + request_url(@info_request), :site_name => site_name) @@ -81,6 +81,8 @@ class AdminRequestController < AdminController :old_handle_rejected_responses => old_handle_rejected_responses, :handle_rejected_responses => @info_request.handle_rejected_responses, :old_tag_string => old_tag_string, :tag_string => @info_request.tag_string }) + # expire cached files + expire_for_request(@info_request) flash[:notice] = 'Request successfully updated.' redirect_to request_admin_url(@info_request) else @@ -95,7 +97,8 @@ class AdminRequestController < AdminController url_title = @info_request.url_title @info_request.fully_destroy - + # expire cached files + expire_for_request(@info_request) flash[:notice] = "Request #{url_title} has been completely destroyed. Email of user who made request: " + user.email redirect_to admin_url('request/list') end @@ -166,7 +169,8 @@ class AdminRequestController < AdminController @incoming_message.fully_destroy @incoming_message.info_request.log_event("destroy_incoming", { :editor => admin_http_auth_user(), :deleted_incoming_message_id => incoming_message_id }) - + # expire cached files + expire_for_request(@info_request) flash[:notice] = 'Incoming message successfully destroyed.' redirect_to request_admin_url(@info_request) end @@ -174,17 +178,18 @@ class AdminRequestController < AdminController 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) + destination_request = InfoRequest.find_by_url_title!(m) end if destination_request.nil? flash[:error] = "Failed to find destination request '" + m + "'" - return redirect_to request_admin_url(incoming_message.info_request) + return redirect_to request_admin_url(previous_request) end raw_email_data = incoming_message.raw_email.data @@ -201,6 +206,8 @@ class AdminRequestController < AdminController 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 request_admin_url(destination_request) @@ -344,23 +351,29 @@ class AdminRequestController < AdminController explanation = params[:explanation] info_request = InfoRequest.find(params[:id]) info_request.prominence = "requester_only" - + info_request.log_event("hide", { :editor => admin_http_auth_user(), :reason => params[:reason], :subject => subject, :explanation => explanation }) - + info_request.set_described_state(params[:reason]) info_request.save! - ContactMailer.deliver_from_admin_message( - info_request.user, - subject, - params[:explanation] - ) - flash[:notice] = _("Your message to {{recipient_user_name}} has been sent",:recipient_user_name=>CGI.escapeHTML(info_request.user.name)) + if ! info_request.is_external? + ContactMailer.deliver_from_admin_message( + info_request.user, + subject, + params[:explanation] + ) + flash[:notice] = _("Your message to {{recipient_user_name}} has been sent",:recipient_user_name=>CGI.escapeHTML(info_request.user.name)) + else + flash[:notice] = _("This external request has been hidden") + end + # expire cached files + expire_for_request(info_request) redirect_to request_admin_url(info_request) end end diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 26950aaf3..6c98ebeba 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -158,8 +158,61 @@ class ApiController < ApplicationController mail = RequestMailer.create_external_response(request, body, sent_at, attachment_hashes) request.receive(mail, mail.encoded, true) end - - head :no_content + render :json => { + 'url' => make_url("request", request.url_title), + } + end + + def body_request_events + feed_type = params[:feed_type] + raise PermissionDenied.new("#{@public_body.id} != #{params[:id]}") if @public_body.id != params[:id].to_i + + @events = InfoRequestEvent.find_by_sql([ + %(select info_request_events.* + from info_requests + join info_request_events on info_requests.id = info_request_events.info_request_id + where info_requests.public_body_id = ? + and info_request_events.event_type in ( + 'sent', 'followup_sent', 'resent', 'followup_resent' + ) + order by info_request_events.created_at desc + ), @public_body.id + ]) + if feed_type == "atom" + render :template => "api/request_events.atom", :layout => false + elsif feed_type == "json" + # For the JSON feed, we take a "since" parameter that allows the client + # to restrict to events more recent than a certain other event + if params[:since_event_id] + @since_event_id = params[:since_event_id].to_i + end + @event_data = [] + @events.each do |event| + break if event.id == @since_event_id + + request = event.info_request + this_event = { + :request_id => request.id, + :event_id => event.id, + :created_at => event.created_at.iso8601, + :event_type => event.event_type, + :request_url => main_url(request_url(request)), + :request_email => request.incoming_email, + :title => request.title, + :body => event.outgoing_message.body, + + :user_name => request.user_name, + } + if request.user + this_event[:user_url] = main_url(user_url(request.user)) + end + + @event_data.push(this_event) + end + render :json => @event_data + else + raise ActiveRecord::RecordNotFound.new("Unrecognised feed type: #{feed_type}") + end end protected diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 41adf1848..ce18e6ef5 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -27,6 +27,7 @@ class ApplicationController < ActionController::Base before_filter :check_in_post_redirect before_filter :session_remember_me before_filter :set_vary_header + before_filter :set_popup_banner # scrub sensitive parameters from the logs filter_parameter_logging :password @@ -133,6 +134,10 @@ class ApplicationController < ActionController::Base # Make sure expiry time for session is set (before_filters are # otherwise missed by this override) session_remember_me + + # Make sure the locale is set correctly too + set_gettext_locale + case exception when ActiveRecord::RecordNotFound, ActionController::UnknownAction, ActionController::RoutingError @status = 404 @@ -156,6 +161,9 @@ class ApplicationController < ActionController::Base # otherwise missed by this override) session_remember_me + # Make sure the locale is set correctly too + set_gettext_locale + # Display default, detailed error for developers original_rescue_action_locally(exception) end @@ -205,13 +213,16 @@ class ApplicationController < ActionController::Base foi_cache_path = File.expand_path(File.join(File.dirname(__FILE__), '../../cache')) return File.join(foi_cache_path, path) end + def foi_fragment_cache_exists?(key_path) return File.exists?(key_path) end + def foi_fragment_cache_read(key_path) logger.info "Reading from fragment cache #{key_path}" return File.read(key_path) end + def foi_fragment_cache_write(key_path, content) FileUtils.mkdir_p(File.dirname(key_path)) logger.info "Writing to fragment cache #{key_path}" @@ -381,8 +392,11 @@ class ApplicationController < ActionController::Base # might fail later if the database has subsequently been reopened. return result end + def get_search_page_from_params - return (params[:page] || "1").to_i + page = (params[:page] || "1").to_i + page = 1 if page < 1 + return page end def perform_search_typeahead(query, model) @@ -553,6 +567,9 @@ class ApplicationController < ActionController::Base return country end + def set_popup_banner + @popup_banner = render_to_string(:partial => "general/popup_banner").strip + end # URL generating functions are needed by all controllers (for redirects), # views (for links) and mailers (for use in emails), so include them into # all of all. diff --git a/app/controllers/comment_controller.rb b/app/controllers/comment_controller.rb index d9cd002dd..1552017c2 100644 --- a/app/controllers/comment_controller.rb +++ b/app/controllers/comment_controller.rb @@ -12,7 +12,7 @@ class CommentController < ApplicationController def new if params[:type] == 'request' - @info_request = InfoRequest.find_by_url_title(params[:url_title]) + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) @track_thing = TrackThing.create_track_for_request(@info_request) if params[:comment] @comment = Comment.new(params[:comment].merge({ diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index e3b77271e..c7affd57c 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -15,7 +15,7 @@ class HelpController < ApplicationController def unhappy @info_request = nil if params[:url_title] - @info_request = InfoRequest.find_by_url_title(params[:url_title]) + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) end end diff --git a/app/controllers/request_controller.rb b/app/controllers/request_controller.rb index 7f42eeb7e..6e983a014 100644 --- a/app/controllers/request_controller.rb +++ b/app/controllers/request_controller.rb @@ -64,10 +64,7 @@ class RequestController < ApplicationController end # Look up by new style text names - @info_request = InfoRequest.find_by_url_title(params[:url_title]) - if @info_request.nil? - raise ActiveRecord::RecordNotFound.new("Request not found") - end + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) set_last_request(@info_request) # Test for whole request being hidden @@ -80,7 +77,13 @@ class RequestController < ApplicationController @info_request_events = @info_request.info_request_events @status = @info_request.calculate_status @collapse_quotes = params[:unfold] ? false : true - @update_status = params[:update_status] ? true : false + + # 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) @@ -125,14 +128,10 @@ class RequestController < ApplicationController # Extra info about a request, such as event history def details long_cache - @info_request = InfoRequest.find_by_url_title(params[:url_title]) - if @info_request.nil? - raise ActiveRecord::RecordNotFound.new("Request not found") - else - if !@info_request.user_can_view?(authenticated_user) - render :template => 'request/hidden', :status => 410 # gone - return - end + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) + if !@info_request.user_can_view?(authenticated_user) + render :template => 'request/hidden', :status => 410 # gone + return end @columns = ['id', 'event_type', 'created_at', 'described_state', 'last_described_at', 'calculated_state' ] end @@ -142,7 +141,7 @@ class RequestController < ApplicationController short_cache @per_page = 25 @page = (params[:page] || "1").to_i - @info_request = InfoRequest.find_by_url_title(params[:url_title]) + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) raise ActiveRecord::RecordNotFound.new("Request not found") if @info_request.nil? if !@info_request.user_can_view?(authenticated_user) @@ -313,7 +312,7 @@ class RequestController < ApplicationController # case the list of errors will also contain a more specific error # describing the reason it is invalid. @info_request.errors.delete("outgoing_messages") - + render :action => 'new' return end @@ -385,6 +384,13 @@ class RequestController < ApplicationController return end + # If this is an external request, go to the request page - we don't allow + # state change from the front end interface. + if @info_request.is_external? + redirect_to request_url(@info_request) + return + end + @is_owning_user = @info_request.is_owning_user?(authenticated_user) @last_info_request_event_id = @info_request.last_event_id_needing_description @old_unclassified = @info_request.is_old_unclassified? && !authenticated_user.nil? @@ -431,7 +437,7 @@ class RequestController < ApplicationController }) # Don't give advice on what to do next, as it isn't their request - RequestMailer.deliver_old_unclassified_updated(@info_request) + RequestMailer.deliver_old_unclassified_updated(@info_request) if !@info_request.is_external? if session[:request_game] flash[:notice] = _('Thank you for updating the status of the request \'<a href="{{url}}">{{info_request_title}}</a>\'. There are some more requests below for you to classify.',:info_request_title=>CGI.escapeHTML(@info_request.title), :url=>CGI.escapeHTML(request_url(@info_request))) redirect_to play_url @@ -592,6 +598,13 @@ class RequestController < ApplicationController return end + # Test for external request + if @info_request.is_external? + @reason = 'external' + render :action => 'followup_bad' + return + end + # Force login early - this is really the "send followup" form. We want # to make sure they're the right user first, before they start writing a # message and wasting their time if they are not the requester. @@ -659,16 +672,21 @@ class RequestController < ApplicationController @info_request = incoming_message.info_request # used by view render :template => 'request/hidden', :status => 410 # gone 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? + @files_can_be_cached = true + end end def report_request - info_request = InfoRequest.find_by_url_title(params[:url_title]) + info_request = InfoRequest.find_by_url_title!(params[:url_title]) return if !authenticated?( :web => _("To report this FOI request"), :email => _("Then you can report the request '{{title}}'", :title => info_request.title), :email_subject => _("Report an offensive or unsuitable request") ) - + if !info_request.attention_requested info_request.set_described_state('attention_requested', @user) info_request.attention_requested = true # tells us if attention has ever been requested @@ -689,6 +707,7 @@ class RequestController < ApplicationController key = params.merge(:only_path => true) key_path = foi_fragment_cache_path(key) if foi_fragment_cache_exists?(key_path) + logger.info("Reading cache for #{key_path}") raise PermissionDenied.new("Directory listing not allowed") if File.directory?(key_path) cached = foi_fragment_cache_read(key_path) response.content_type = AlaveteliFileTypes.filename_to_mimetype(params[:file_name].join("/")) || 'application/octet-stream' @@ -703,7 +722,10 @@ class RequestController < ApplicationController # various fragment cache functions using Ruby Marshall to write the file # which adds a header, so isnt compatible with images that have been # extracted elsewhere from PDFs) - foi_fragment_cache_write(key_path, response.body) + if @files_can_be_cached == true + logger.info("Writing cache for #{key_path}") + foi_fragment_cache_write(key_path, response.body) + end end end end @@ -784,7 +806,7 @@ class RequestController < ApplicationController def upload_response @locale = self.locale_from_params() PublicBody.with_locale(@locale) do - @info_request = InfoRequest.find_by_url_title(params[:url_title]) + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) @reason_params = { :web => _("To upload a response, you must be logged in using an email address from ") + CGI.escapeHTML(@info_request.public_body.name), @@ -841,10 +863,7 @@ class RequestController < ApplicationController def download_entire_request @locale = self.locale_from_params() PublicBody.with_locale(@locale) do - info_request = InfoRequest.find_by_url_title(params[:url_title]) - if info_request.nil? - raise ActiveRecord::RecordNotFound.new("Request not found") - end + info_request = InfoRequest.find_by_url_title!(params[:url_title]) if authenticated?( :web => _("To download the zip file"), :email => _("Then you can download a zip file of {{info_request_title}}.",:info_request_title=>info_request.title), diff --git a/app/controllers/services_controller.rb b/app/controllers/services_controller.rb index 00c0e61bd..40e0faaf7 100644 --- a/app/controllers/services_controller.rb +++ b/app/controllers/services_controller.rb @@ -3,36 +3,43 @@ require 'open-uri' class ServicesController < ApplicationController + def other_country_message text = "" iso_country_code = MySociety::Config.get('ISO_COUNTRY_CODE').downcase if country_from_ip.downcase != iso_country_code found_country = WorldFOIWebsites.by_code(country_from_ip) found_country_name = !found_country.nil? && found_country[:country_name] - old_locale = FastGettext.locale - FastGettext.locale = FastGettext.best_locale_in(request.env['HTTP_ACCEPT_LANGUAGE']) - if found_country_name - text = _("Hello! You can make Freedom of Information requests within {{country_name}} at {{link_to_website}}", :country_name => found_country_name, :link_to_website => "<a href=\"#{found_country[:url]}\">#{found_country[:name]}</a>") - else - current_country = WorldFOIWebsites.by_code(iso_country_code)[:country_name] - text = _("Hello! We have an <a href=\"/help/alaveteli?country_name=#{CGI.escape(current_country)}\">important message</a> for visitors outside {{country_name}}", :country_name => current_country) + + old_fgt_locale = FastGettext.locale + begin + FastGettext.locale = FastGettext.best_locale_in(request.env['HTTP_ACCEPT_LANGUAGE']) + if found_country_name + text = _("Hello! You can make Freedom of Information requests within {{country_name}} at {{link_to_website}}", :country_name => found_country_name, :link_to_website => "<a href=\"#{found_country[:url]}\">#{found_country[:name]}</a>") + else + current_country = WorldFOIWebsites.by_code(iso_country_code)[:country_name] + text = _("Hello! We have an <a href=\"/help/alaveteli?country_name=#{CGI.escape(current_country)}\">important message</a> for visitors outside {{country_name}}", :country_name => current_country) + end + ensure + FastGettext.locale = old_fgt_locale end - FastGettext.locale = old_locale end if !text.empty? text += ' <span class="close-button">X</span>' end render :text => text, :content_type => "text/plain" # XXX workaround the HTML validation in test suite end + def hidden_user_explanation info_request = InfoRequest.find(params[:info_request_id]) - render :template => "admin_request/hidden_user_explanation", + render :template => "admin_request/hidden_user_explanation", :content_type => "text/plain", :layout => false, - :locals => {:name_to => info_request.user.name, - :name_from => MySociety::Config.get("CONTACT_NAME", 'Alaveteli'), + :locals => {:name_to => info_request.user_name, + :name_from => MySociety::Config.get("CONTACT_NAME", 'Alaveteli'), :info_request => info_request, :reason => params[:reason], :info_request_url => 'http://' + MySociety::Config.get('DOMAIN') + request_url(info_request), :site_name => site_name} end + end diff --git a/app/controllers/track_controller.rb b/app/controllers/track_controller.rb index 07e807451..1a21491b1 100644 --- a/app/controllers/track_controller.rb +++ b/app/controllers/track_controller.rb @@ -15,7 +15,7 @@ class TrackController < ApplicationController # Track all updates to a particular request def track_request - @info_request = InfoRequest.find_by_url_title(params[:url_title]) + @info_request = InfoRequest.find_by_url_title!(params[:url_title]) @track_thing = TrackThing.create_track_for_request(@info_request) return atom_feed_internal if params[:feed] == 'feed' diff --git a/app/helpers/link_to_helper.rb b/app/helpers/link_to_helper.rb index 1a86333b6..cae17ebd3 100755 --- a/app/helpers/link_to_helper.rb +++ b/app/helpers/link_to_helper.rb @@ -45,9 +45,11 @@ module LinkToHelper def incoming_message_url(incoming_message) return request_url(incoming_message.info_request)+"#incoming-"+incoming_message.id.to_s end + def outgoing_message_url(outgoing_message) return request_url(outgoing_message.info_request)+"#outgoing-"+outgoing_message.id.to_s end + def comment_url(comment) return request_url(comment.info_request)+"#comment-"+comment.id.to_s end @@ -67,21 +69,27 @@ module LinkToHelper def public_body_url(public_body) public_body.url_name.nil? ? '' : show_public_body_url(:url_name => public_body.url_name, :only_path => true) end + def public_body_link_short(public_body) link_to h(public_body.short_or_long_name), public_body_url(public_body) end + def public_body_link(public_body, cls=nil) link_to h(public_body.name), public_body_url(public_body), :class => cls end + def public_body_link_absolute(public_body) # e.g. for in RSS link_to h(public_body.name), main_url(public_body_url(public_body)) end + def public_body_admin_url(public_body) return admin_url('body/show/' + public_body.id.to_s) end + def public_body_both_links(public_body) link_to(h(public_body.name), main_url(public_body_url(public_body))) + " (" + link_to("admin", public_body_admin_url(public_body)) + ")" end + def list_public_bodies_default list_public_bodies_url(:tag => 'all') end @@ -90,12 +98,37 @@ module LinkToHelper def user_url(user) return show_user_url(:url_name => user.url_name, :only_path => true) end + def user_link(user, cls=nil) link_to h(user.name), user_url(user), :class => cls end + + def user_link_for_request(request, cls=nil) + if request.is_external? + user_name = request.external_user_name || _("Anonymous user") + if !request.external_url.nil? + link_to h(user_name), request.external_url + else + user_name + end + else + link_to h(request.user.name), user_url(request.user), :class => cls + end + end + + def user_admin_link_for_request(request, external_text=nil, internal_text=nil) + if request.is_external? + text = external_text ? external_text : (request.external_user_name || _("Anonymous user")) + " (external)" + else + text = internal_text ? internal_text : request.user.name + link_to(h(text), user_admin_url(request.user)) + end + end + def user_link_absolute(user) link_to h(user.name), main_url(user_url(user)) end + def request_user_link_absolute(request) if request.is_external? request.external_user_name || _("Anonymous user") @@ -103,6 +136,7 @@ module LinkToHelper user_link_absolute(request.user) end end + def user_or_you_link(user) if @user && user == @user link_to h("you"), user_url(user) @@ -110,6 +144,7 @@ module LinkToHelper link_to h(user.name), user_url(user) end end + def user_or_you_capital(user) if @user && user == @user return h("You") @@ -117,15 +152,19 @@ module LinkToHelper return h(user.name) end end + def user_or_you_capital_link(user) link_to user_or_you_capital(user), user_url(user) end + def user_admin_url(user) return admin_url('user/show/' + user.id.to_s) end + def user_admin_link(user, name="admin", cls=nil) link_to name, user_admin_url(user), :class => cls end + def user_both_links(user) link_to(h(user.name), main_url(user_url(user))) + " (" + link_to("admin", user_admin_url(user)) + ")" end @@ -191,6 +230,7 @@ module LinkToHelper def about_url return help_general_url(:action => 'about') end + def unhappy_url(info_request = nil) if info_request.nil? return help_general_url(:action => 'unhappy') diff --git a/app/models/censor_rule.rb b/app/models/censor_rule.rb index a477d2568..da3f49760 100644 --- a/app/models/censor_rule.rb +++ b/app/models/censor_rule.rb @@ -9,6 +9,7 @@ # public_body_id :integer # text :text not null # replacement :text not null +# regexp :boolean # last_edit_editor :string(255) not null # last_edit_comment :text not null # created_at :datetime not null @@ -28,33 +29,59 @@ class CensorRule < ActiveRecord::Base belongs_to :user belongs_to :public_body - def binary_replacement - self.text.gsub(/./, 'x') + # a flag to allow the require_user_request_or_public_body validation to be skipped + attr_accessor :allow_global + validate :require_user_request_or_public_body, :unless => proc{ |rule| rule.allow_global == true } + validate :require_valid_regexp, :if => proc{ |rule| rule.regexp? == true } + validates_presence_of :text + + named_scope :global, {:conditions => {:info_request_id => nil, + :user_id => nil, + :public_body_id => nil}} + + def require_user_request_or_public_body + if self.info_request.nil? && self.user.nil? && self.public_body.nil? + errors.add("Censor must apply to an info request a user or a body; ") + end + end + + def require_valid_regexp + begin + self.make_regexp() + rescue RegexpError => e + errors.add(:text, e.message) + end + end + + def make_regexp + return Regexp.new(self.text, Regexp::MULTILINE) end def apply_to_text!(text) if text.nil? return nil end - text.gsub!(self.text, self.replacement) + to_replace = regexp? ? self.make_regexp() : self.text + text.gsub!(to_replace, self.replacement) end + def apply_to_binary!(binary) if binary.nil? return nil end - binary.gsub!(self.text, self.binary_replacement) + to_replace = regexp? ? self.make_regexp() : self.text + binary.gsub!(to_replace){ |match| match.gsub(/./, 'x') } end - - def validate - if self.info_request.nil? && self.user.nil? && self.public_body.nil? - errors.add("Censor must apply to an info request a user or a body; ") + def for_admin_column + self.class.content_columns.each do |column| + yield(column.human_name, self.send(column.name), column.type.to_s, column.name) end end - def for_admin_column - self.class.content_columns.each do |column| - yield(column.human_name, self.send(column.name), column.type.to_s, column.name) + def is_global? + return true if (info_request_id.nil? && user_id.nil? && public_body_id.nil?) + return false end - end + end diff --git a/app/models/exim_log.rb b/app/models/exim_log.rb index 60faa7f0b..82000efa1 100644 --- a/app/models/exim_log.rb +++ b/app/models/exim_log.rb @@ -94,7 +94,7 @@ class EximLog < ActiveRecord::Base # Get all requests sent for from 2 to 10 days ago. The 2 day gap is # because we load exim log lines via cron at best an hour after they # are made) - irs = InfoRequest.find(:all, :conditions => [ "created_at < ? and created_at > ?", Time.now() - 2.day, Time.now() - 10.days ] ) + irs = InfoRequest.find(:all, :conditions => [ "created_at < ? and created_at > ? and user_id is not null", Time.now() - 2.day, Time.now() - 10.days ] ) # Go through each request and check it ok = true diff --git a/app/models/foi_attachment.rb b/app/models/foi_attachment.rb index 9bbf0988f..a40898aef 100644 --- a/app/models/foi_attachment.rb +++ b/app/models/foi_attachment.rb @@ -1,3 +1,5 @@ +# encoding: UTF-8 + # == Schema Information # Schema version: 114 # @@ -14,8 +16,6 @@ # hexdigest :string(32) # -# encoding: UTF-8 - # models/foi_attachment.rb: # An attachment to an email (IncomingMessage) # @@ -315,14 +315,21 @@ class FoiAttachment < ActiveRecord::Base tempfile.print self.body tempfile.flush + html = nil if self.content_type == 'application/pdf' - html = AlaveteliExternalCommand.run("pdftohtml", "-nodrm", "-zoom", "1.0", "-stdout", "-enc", "UTF-8", "-noframes", tempfile.path) + # We set a timeout here, because pdftohtml can spiral out of control + # on some PDF files and we don’t want to crash the whole server. + html = AlaveteliExternalCommand.run("pdftohtml", "-nodrm", "-zoom", "1.0", "-stdout", "-enc", "UTF-8", "-noframes", tempfile.path, :timeout => 30) elsif self.content_type == 'application/rtf' - html = AlaveteliExternalCommand.run("unrtf", "--html", tempfile.path) - elsif self.has_google_docs_viewer? - html = '' # force error and using Google docs viewer - else - raise "No HTML conversion available for type " + self.content_type + html = AlaveteliExternalCommand.run("unrtf", "--html", tempfile.path, :timeout => 120) + end + + if html.nil? + if self.has_google_docs_viewer? + html = '' # force error and using Google docs viewer + else + raise "No HTML conversion available for type " + self.content_type + end end tempfile.close diff --git a/app/models/incoming_message.rb b/app/models/incoming_message.rb index 593590fb8..13fc316cd 100644 --- a/app/models/incoming_message.rb +++ b/app/models/incoming_message.rb @@ -375,25 +375,10 @@ class IncomingMessage < ActiveRecord::Base # http://www.whatdotheyknow.com/request/common_purpose_training_graduate#incoming-774 text.gsub!(/(Mobile|Mob)([\s\/]*(Fax|Tel))*\s*:?[\s\d]*\d/, "[mobile number]") - # Specific removals # XXX remove these and turn them into censor rules in database - # http://www.whatdotheyknow.com/request/total_number_of_objects_in_the_n_6 - text.gsub!(/\*\*\*+\nPolly Tucker.*/ms, "") - # http://www.whatdotheyknow.com/request/cctv_data_retention_and_use - text.gsub!(/Andy 079.*/, "Andy [mobile number]") - # http://www.whatdotheyknow.com/request/how_do_the_pct_deal_with_retirin_113 - text.gsub!(/(Complaints and Corporate Affairs Officer)\s+Westminster Primary Care Trust.+/ms, "\\1") - # Remove WhatDoTheyKnow signup links domain = MySociety::Config.get('DOMAIN') text.gsub!(/http:\/\/#{domain}\/c\/[^\s]+/, "[WDTK login link]") - # Remove Home Office survey links - # e.g. http://www.whatdotheyknow.com/request/serious_crime_act_2007_section_7#incoming-12650 - if self.info_request.public_body.url_name == 'home_office' - text.gsub!(/Your password:-\s+[^\s]+/, '[password]') - text.gsub!(/Password=[^\s]+/, '[password]') - end - # Remove things from censor rules self.info_request.apply_censor_rules_to_text!(text) end @@ -599,7 +584,6 @@ class IncomingMessage < ActiveRecord::Base # Remove existing quoted sections folded_quoted_text = self.remove_lotus_quoting(text, 'FOLDED_QUOTED_SECTION') folded_quoted_text = IncomingMessage.remove_quoted_sections(text, "FOLDED_QUOTED_SECTION") - self.cached_main_body_text_unfolded = text self.cached_main_body_text_folded = folded_quoted_text self.save! diff --git a/app/models/info_request.rb b/app/models/info_request.rb index d09acbcf6..6f472c290 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -1,11 +1,10 @@ # == Schema Information -# Schema version: 114 # # Table name: info_requests # # id :integer not null, primary key # title :text not null -# user_id :integer not null +# user_id :integer # public_body_id :integer not null # created_at :datetime not null # updated_at :datetime not null @@ -17,10 +16,11 @@ # 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) # - require 'digest/sha1' class InfoRequest < ActiveRecord::Base @@ -104,7 +104,7 @@ class InfoRequest < ActiveRecord::Base errors.add(:described_state, "is not a valid state") if !InfoRequest.enumerate_states.include? described_state end - + # The request must either be internal, in which case it has # a foreign key reference to a User object and no external_url or external_user_name, # or else be external in which case it has no user_id but does have an external_url, @@ -120,15 +120,15 @@ class InfoRequest < ActiveRecord::Base errors.add(:external_url, "must be null for an internal request") if !external_url.nil? end end - + def is_external? !external_url.nil? end - + def user_name is_external? ? external_user_name : user.name end - + def user_name_slug if is_external? if external_user_name.nil? @@ -136,7 +136,7 @@ class InfoRequest < ActiveRecord::Base else fake_slug = external_user_name.parameterize end - public_body.url_name + "_"+fake_slug + (public_body.url_name || "") + "_" + fake_slug else user.url_name end @@ -223,7 +223,7 @@ class InfoRequest < ActiveRecord::Base incoming_message.clear_in_database_caches! end end - + # For debugging def InfoRequest.profile_search(query) t = Time.now.usec @@ -246,7 +246,9 @@ public # For request with same title as others, add on arbitary numeric identifier unique_url_title = url_title suffix_num = 2 # as there's already one without numeric suffix - while not InfoRequest.find_by_url_title(unique_url_title, :conditions => self.id.nil? ? nil : ["id <> ?", self.id] ).nil? + while not InfoRequest.find_by_url_title(unique_url_title, + :conditions => self.id.nil? ? nil : ["id <> ?", self.id] + ).nil? unique_url_title = url_title + "_" + suffix_num.to_s suffix_num = suffix_num + 1 end @@ -456,7 +458,7 @@ public if !allow if self.handle_rejected_responses == 'bounce' - RequestMailer.deliver_stopped_responses(self, email, raw_email_data) + RequestMailer.deliver_stopped_responses(self, email, raw_email_data) if !is_external? elsif self.handle_rejected_responses == 'holding_pen' InfoRequest.holding_pen_request.receive(email, raw_email_data, false, reason) elsif self.handle_rejected_responses == 'blackhole' @@ -566,7 +568,10 @@ public self.calculate_event_states if self.requires_admin? - RequestMailer.deliver_requires_admin(self, set_by) + # Check there is someone to send the message "from" + if !set_by.nil? || !self.user.nil? + RequestMailer.deliver_requires_admin(self, set_by) + end end end @@ -708,10 +713,10 @@ public return self.public_body.is_followupable? end def recipient_name_and_email - return TMail::Address.address_from_name_and_email( - _("{{law_used}} requests at {{public_body}}", - :law_used => self.law_used_short, - :public_body => self.public_body.short_or_long_name), + return TMail::Address.address_from_name_and_email( + _("{{law_used}} requests at {{public_body}}", + :law_used => self.law_used_short, + :public_body => self.public_body.short_or_long_name), self.recipient_email).to_s end @@ -942,7 +947,7 @@ public last_response_created_at = last_event_time_clause('response') age = extra_params[:age_in_days] ? extra_params[:age_in_days].days : OLD_AGE_IN_DAYS params = {:select => "*, #{last_response_created_at} as last_response_time", - :conditions => ["awaiting_description = ? and #{last_response_created_at} < ? and url_title != 'holding_pen'", + :conditions => ["awaiting_description = ? and #{last_response_created_at} < ? and url_title != 'holding_pen' and user_id is not null", true, Time.now() - age], :order => "last_response_time"} params[:limit] = extra_params[:limit] if extra_params[:limit] @@ -960,6 +965,7 @@ public end def is_old_unclassified? + return false if is_external? return false if !awaiting_description return false if url_title == 'holding_pen' last_response_event = get_last_response_event @@ -995,27 +1001,28 @@ public return ret.reverse end + # Get the list of censor rules that apply to this request + def applicable_censor_rules + applicable_rules = [self.censor_rules, self.public_body.censor_rules, CensorRule.global.all] + if self.user && !self.user.censor_rules.empty? + applicable_rules << self.user.censor_rules + end + return applicable_rules.flatten + end + # Call groups of censor rules def apply_censor_rules_to_text!(text) - for censor_rule in self.censor_rules + self.applicable_censor_rules.each do |censor_rule| censor_rule.apply_to_text!(text) end - if self.user # requests during construction have no user - for censor_rule in self.user.censor_rules - censor_rule.apply_to_text!(text) - end - end + return text end def apply_censor_rules_to_binary!(binary) - for censor_rule in self.censor_rules + self.applicable_censor_rules.each do |censor_rule| censor_rule.apply_to_binary!(binary) end - if self.user # requests during construction have no user - for censor_rule in self.user.censor_rules - censor_rule.apply_to_binary!(binary) - end - end + return binary end def is_owning_user?(user) @@ -1035,6 +1042,12 @@ public return true end + # Is this request visible to everyone? + def all_can_view? + return true if ['normal', 'backpage'].include?(self.prominence) + return false + end + def indexed_by_search? if self.prominence == 'backpage' || self.prominence == 'hidden' || self.prominence == 'requester_only' return false diff --git a/app/models/public_body.rb b/app/models/public_body.rb index bc8f084bb..fb30da234 100644 --- a/app/models/public_body.rb +++ b/app/models/public_body.rb @@ -1,5 +1,5 @@ +# -*- coding: utf-8 -*- # == Schema Information -# Schema version: 114 # # Table name: public_bodies # @@ -19,7 +19,6 @@ # publication_scheme :text default(""), not null # api_key :string(255) not null # - # models/public_body.rb: # A public body, from which information can be requested. # @@ -43,6 +42,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' has_tag_string @@ -93,8 +93,9 @@ class PublicBody < ActiveRecord::Base # Make sure publication_scheme gets the correct default value. # (This would work automatically, were publication_scheme not a translated attribute) self.publication_scheme = "" if self.publication_scheme.nil? - - # Set an API key if there isn’t one + end + + def before_save self.api_key = SecureRandom.base64(33) if self.api_key.nil? end @@ -103,7 +104,7 @@ class PublicBody < ActiveRecord::Base locale = self.locale || I18n.locale PublicBody.with_locale(locale) do found = PublicBody.find(:all, - :conditions => ["public_body_translations.url_name='#{name}'"], + :conditions => ["public_body_translations.url_name=?", name], :joins => :translations, :readonly => false) # If many bodies are found (usually because the url_name is the same across @@ -583,5 +584,3 @@ class PublicBody < ActiveRecord::Base end end - - diff --git a/app/models/request_mailer.rb b/app/models/request_mailer.rb index 03d26f237..ba9285fc6 100644 --- a/app/models/request_mailer.rb +++ b/app/models/request_mailer.rb @@ -28,17 +28,17 @@ class RequestMailer < ApplicationMailer :filename => attachment_name end end - + # Used when a response is uploaded using the API def external_response(info_request, body, sent_at, attachments) @from = blackhole_email @recipients = info_request.incoming_name_and_email @body = { :body => body } - + # ActionMailer only works properly when the time is in the local timezone: # see https://rails.lighthouseapp.com/projects/8994/tickets/3113-actionmailer-only-works-correctly-with-sent_on-times-that-are-in-the-local-time-zone @sent_on = sent_at.dup.localtime - + attachments.each do |attachment_hash| attachment attachment_hash end @@ -392,6 +392,7 @@ class RequestMailer < ApplicationMailer ) for info_request in info_requests + next if info_request.is_external? # Count number of new comments to alert on earliest_unalerted_comment_event = nil last_comment_event = nil diff --git a/app/models/user.rb b/app/models/user.rb index a21676f68..657ea2a4a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,4 @@ # == Schema Information -# Schema version: 114 # # Table name: users # @@ -21,9 +20,7 @@ # email_bounce_message :text default(""), not null # no_limit :boolean default(FALSE), not null # receive_email_alerts :boolean default(TRUE), not null -# user_similarity_id :integer # - # models/user.rb: # Model of people who use the site to file requests, make comments etc. # diff --git a/app/views/admin_censor_rule/_form.rhtml b/app/views/admin_censor_rule/_form.rhtml index d077afd9a..ac43de704 100644 --- a/app/views/admin_censor_rule/_form.rhtml +++ b/app/views/admin_censor_rule/_form.rhtml @@ -11,6 +11,9 @@ <% end %> </p> +<p><label for="censor_rule_regexp">Is it regexp replacement?</label> (Leave unchecked if you are not sure about this)<br/> +<%= check_box 'censor_rule', 'regexp' %></p> + <p><label for="censor_rule_text">Text</label> (that you want to remove, case sensitive)<br/> <%= text_field 'censor_rule', 'text', :size => 60 %></p> @@ -21,9 +24,9 @@ <%= text_area 'censor_rule', 'last_edit_comment', :rows => 2, :cols => 60 %></p> <p><strong>Warning and notes:</strong> This does replace text in binary files, but for -most formats only in a naive way. It works well on surprisingly many Word documents. Notably -it doesn't even do UCS-2 (unicode sometimes used in Word). There is also special code -which works on some PDFs. Please <strong>carefully check</strong> all attachments have +most formats only in a naive way. It works well on surprisingly many Word documents. Notably +it doesn't even do UCS-2 (unicode sometimes used in Word). There is also special code +which works on some PDFs. Please <strong>carefully check</strong> all attachments have changed in the way you expect, and haven't become corrupted. </p> @@ -32,4 +35,6 @@ things by individual request or by user by adding the censor rule from the appropriate page. If you need to redact across a whole authority, it will be easy enough to make code changes to add it, so do ask. </p> +<p><strong>Regexp rules that are hard to process will really slow down request display.</strong> Please only use regexps if you really need to. +</p> diff --git a/app/views/admin_public_body/import_csv.rhtml b/app/views/admin_public_body/import_csv.rhtml index d5717de23..4a03d0665 100644 --- a/app/views/admin_public_body/import_csv.rhtml +++ b/app/views/admin_public_body/import_csv.rhtml @@ -9,48 +9,57 @@ <pre id="error"><%=@errors %></pre> <% end %> - <% form_tag 'import_csv', :multipart => true do %> <p> - <label for="csv_file">CSV file:</label> - <%= file_field_tag :csv_file, :size => 40 %> + <% if @original_csv_file && @temporary_csv_file %> + CSV file: + <%= @original_csv_file %> + <%= hidden_field_tag :original_csv_file, @original_csv_file %> + <%= hidden_field_tag :temporary_csv_file, @temporary_csv_file %> + <%= link_to 'Clear current file', 'import_csv', :class => "btn btn-warning" %> + <% else %> + <label for="csv_file">CSV file:</label> + <%= file_field_tag :csv_file, :size => 40 %> + <% end %> </p> - + <p> <label for="tag">Optional: Tag to add entries to / alter entries for:</label> <%= text_field_tag 'tag', params[:tag] %> </p> - + <p> <label for="tag_behaviour">What to do with existing tags?</label> - <%= select_tag 'tag_behaviour', + <%= select_tag 'tag_behaviour', "<option value='add' selected>Add new tags to existing ones</option> - <option value='replace'>Replace existing tags with new ones</option>" + <option value='replace'>Replace existing tags with new ones</option>" %> </p> - <p><strong>CSV file format:</strong> A first row with the list of fields, + <p><strong>CSV file format:</strong> A first row with the list of fields, starting with '#', is optional but highly recommended. The fields 'name' and 'request_email' are required; additionally, translated values are supported by adding the locale name to the field name, e.g. 'name.es', 'name.de'... Example: </p> - + <blockquote> - #id,name,request_email,name.es,tag_string<br/> - 1,An Authority,a@example.com,Un organismo,a_tag another_tag<br/> - 2,Another One,another@example.com,Otro organismo,a_tag<br/> + <p> + #id,name,request_email,name.es,tag_string<br/> + 1,An Authority,a@example.com,Un organismo,a_tag another_tag<br/> + 2,Another One,another@example.com,Otro organismo,a_tag<br/> + <p> </blockquote> - <p>Supported fields: name (i18n), short_name (i18n), request_email (i18n), notes (i18n), + <p>Supported fields: name (i18n), short_name (i18n), request_email (i18n), notes (i18n), publication_scheme (i18n), home_page, tag_string (tags separated by spaces).</p> - + <p><strong>Note:</strong> Choose <strong>dry run</strong> to test, without actually altering the database. Choose <strong>upload</strong> to actually make the changes. In either case, you will be shown any errors, or details of the changes. When uploading, any changes since last import will be overwritten - e.g. email addresses changed back. </p> - + <p><strong>Note:</strong> The import tag will also be added to the imported bodies if no tags are provided in the CSV file or if the import mode is set to "Add new tags to existing ones". @@ -61,7 +70,7 @@ <hr> -<p>Standard tags: +<p>Standard tags: <% for category, description in PublicBodyCategories::get().by_tag() %> <% if category != "other" %> <strong><%= category %></strong>=<%= description %>; diff --git a/app/views/admin_request/edit.rhtml b/app/views/admin_request/edit.rhtml index 4026ee712..808028b47 100644 --- a/app/views/admin_request/edit.rhtml +++ b/app/views/admin_request/edit.rhtml @@ -7,21 +7,21 @@ <p><label for="info_request_title"><strong>Title</strong></label> (warning: editing this will break URLs right now)<br/> <%= text_field 'info_request', 'title', :size => 50 %></p> - <p><label for="info_request_prominence"><strong>Prominence</strong></label> + <p><label for="info_request_prominence"><strong>Prominence</strong></label> <%= select( 'info_request', "prominence", [ "normal", "backpage", "requester_only", "hidden" ]) %> (backpage means hidden from lists/search; hidden means completely hidden; super users can see anything) </p> <p> - <label for="info_request_allow_new_responses_from"><strong>Allow new responses</strong> from</label> + <label for="info_request_allow_new_responses_from"><strong>Allow new responses</strong> from</label> <%= select( 'info_request', "allow_new_responses_from", [ "anybody", "authority_only", "nobody" ] ) %>; - <label for="info_request_handle_rejected_responses"><strong>Handle rejected responses</strong> with</label> + <label for="info_request_handle_rejected_responses"><strong>Handle rejected responses</strong> with</label> <%= select( 'info_request', "handle_rejected_responses", [ "bounce", "holding_pen", "blackhole" ] ) %> <br> ('authority_only' means email From: domain of authority request email or any domain that has previously sent a response; 'nobody' also stops requester making followups; take care when using 'blackhole' which just drops mail) </p> - <p><label for="info_request_described_state"><strong>Described state</strong></label> + <p><label for="info_request_described_state"><strong>Described state</strong></label> <%= select( 'info_request', "described_state", InfoRequest.enumerate_states ) %>; <label for="info_request_awaiting_description"><strong>Awaiting description</strong></label> <%= select('info_request', "awaiting_description", [["Yes - needs state updating",true],["No - state is up to date",false]]) %> @@ -49,7 +49,7 @@ <% form_tag '../destroy/' + @info_request.id.to_s do %> <p> - <strong>This is permanent and irreversible!</strong> <%= submit_tag 'Destory request entirely' %> + <strong>This is permanent and irreversible!</strong> <%= submit_tag 'Destroy request entirely' %> <br>Use it mainly if someone posts private information, e.g. made a Data Protection request. It destroys all responses and tracks as well. </p> diff --git a/app/views/admin_request/show.rhtml b/app/views/admin_request/show.rhtml index aac68ad2e..9d939eb35 100644 --- a/app/views/admin_request/show.rhtml +++ b/app/views/admin_request/show.rhtml @@ -11,14 +11,20 @@ <% if column.name == 'described_state' %> <strong>Calculated status:</strong> <%= @info_request.calculate_status %> <br/><strong>Initial request last sent at:</strong> <%=@info_request.date_initial_request_last_sent_at.to_date %> - <strong>Date response required by:</strong> <%= @info_request.date_response_required_by %> + <strong>Date response required by:</strong> <%= @info_request.date_response_required_by %> <strong>Very overdue after:</strong> <%= @info_request.date_very_overdue_after %> <% end %> <% if ![ 'allow_new_responses_from' ].include?(column.name) %> <br/> <% end %> <% end %> - <strong>Created by:</strong> <%= user_both_links(@info_request.user) %> + <strong>Created by:</strong> + <% if @info_request.is_external? %> + <%= @info_request.public_body.name %> on behalf of <%= (@info_request.user_name || _('an anonymous user'))%> (using API) + <% else %> + <%= user_both_links(@info_request.user) %> + <% end %> + <span> <span> (<%= link_to_function("move...", "$(this).up(1).childElements().invoke('toggle')") %>) @@ -30,7 +36,7 @@ </span> </span> <br> -<strong>Public authority:</strong> <%= public_body_both_links(@info_request.public_body) %> +<strong>Public authority:</strong> <%= public_body_both_links(@info_request.public_body) %> <span> <span> (<%= link_to_function("move...", "$(this).up(1).childElements().invoke('toggle')") %>) @@ -63,7 +69,7 @@ <% end %> <th>Actions</th> </tr> - + <% for info_request_event in @info_request.info_request_events.find(:all, :order => "created_at, id") %> <tr class="<%= cycle('odd', 'even') %>"> <td><%=h info_request_event.id %></td> @@ -102,7 +108,7 @@ <% end %> <th>Actions</th> </tr> - + <% for outgoing_message in @info_request.outgoing_messages.find(:all, :order => 'created_at') %> <tr class="<%= cycle('odd', 'even') %>"> <td><%=h outgoing_message.id %></td> @@ -110,8 +116,8 @@ <% if column == 'body' %> <td> - <div><%= simple_format( truncate(outgoing_message.body, :length => 400, - :omission => link_to_function("...", "$(this).up('td').childElements().invoke('toggle')") + <div><%= simple_format( truncate(outgoing_message.body, :length => 400, + :omission => link_to_function("...", "$(this).up('td').childElements().invoke('toggle')") )) %></div> <div style="display:none;"><%= simple_format( outgoing_message.body ) %></div> </td> @@ -143,15 +149,15 @@ <% end %> <th>Actions</th> </tr> - + <% for incoming_message in @info_request.incoming_messages.find(:all, :order => 'created_at') %> <tr class="<%= cycle('odd', 'even') %>" id="incoming-<%=incoming_message.id.to_s%>"> <td><%=h incoming_message.id %></td> <% for column in IncomingMessage.content_columns.map { |c| c.name } %> <% if column =~ /^cached_.*?$/ %> <td> - <div><%= simple_format( truncate(incoming_message.send(column), :length => 400, - :omission => link_to_function("...", "$(this).up('td').childElements().invoke('toggle')") + <div><%= simple_format( truncate(incoming_message.send(column), :length => 400, + :omission => link_to_function("...", "$(this).up('td').childElements().invoke('toggle')") )) %></div> <div style="display:none;"><%= simple_format( incoming_message.send(column) ) %></div> </td> @@ -183,7 +189,7 @@ <% end %> <th>Actions</th> </tr> - + <% for comment in @info_request.comments %> <tr class="<%= cycle('odd', 'even') %>"> <td><%=h comment.id %></td> diff --git a/app/views/api/request_events.atom.builder b/app/views/api/request_events.atom.builder new file mode 100644 index 000000000..4f0133051 --- /dev/null +++ b/app/views/api/request_events.atom.builder @@ -0,0 +1,25 @@ +atom_feed("xmlns:alaveteli" => "http://www.alaveteli.org/API/v2/RequestEvents/Atom") do |feed| + feed.title("Events relating to #{@public_body.name}") + feed.updated(@events.first.created_at) + + for event in @events + feed.entry(event) do |entry| + request = event.info_request + + entry.published(event.created_at) + entry.tag!("alaveteli:event_type", event.event_type) + entry.tag!("alaveteli:request_url", main_url(request_url(request))) + entry.title(request.title) + + entry.content(event.outgoing_message.body, :type => 'text') + + entry.author do |author| + author.name(request.user_name) + if !request.user.nil? + author.uri(main_url(user_url(request.user))) + end + author.email(request.incoming_email) + end + end + end +end diff --git a/app/views/comment/new.rhtml b/app/views/comment/new.rhtml index cf9367b88..aa5b6051c 100644 --- a/app/views/comment/new.rhtml +++ b/app/views/comment/new.rhtml @@ -33,7 +33,7 @@ <% if [ 'successful', 'partially_successful' ].include?(@info_request.described_state) %> <li><%= _(' <strong>Summarise</strong> the content of any information returned. ')%></li> <li><%= _(' Say how you\'ve <strong>used the information</strong>, with links if possible.')%> </li> - <li> <%= _('<strong>Thank</strong> the public authority or ')%><%=h @info_request.user.name %>. </li> + <li> <%= _('<strong>Thank</strong> the public authority or ')%><%=h (@info_request.user_name ? @info_request.user_name : _('the requester')) %>. </li> <% end %> <% if [ 'partially_successful' ].include?(@info_request.described_state) %> <li> <%= _('Suggest how the requester can find the <strong>rest of the information</strong>.')%></li> @@ -67,8 +67,11 @@ </ul> <p> - <big><%= _('Annotations will be posted publicly here, and are + <big><%= _('Annotations will be posted publicly here, and are <strong>not</strong> sent to {{public_body_name}}.',:public_body_name=>h(@info_request.public_body.name)) %></big> + <% if @info_request.is_external? %> + <big><%= _('Note that the requester will not be notified about your annotation, because the request was published by {{public_body_name}} on their behalf.', :public_body_name => @info_request.public_body.name) %></big> + <% end %> </p> <%= render :partial => 'comment/comment_form', :locals => { :track_thing => @track_thing } %> diff --git a/app/views/general/_popup_banner.rhtml b/app/views/general/_popup_banner.rhtml new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/app/views/general/_popup_banner.rhtml @@ -0,0 +1 @@ + diff --git a/app/views/general/_stylesheet_includes.rhtml b/app/views/general/_stylesheet_includes.rhtml new file mode 100644 index 000000000..2ffa5dadf --- /dev/null +++ b/app/views/general/_stylesheet_includes.rhtml @@ -0,0 +1,21 @@ + <%= 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 7]> + <style type="text/css">@import url("/stylesheets/ie6-custom.css");</style> + <![endif]--> + <!--[if LT IE 8]> + <style type="text/css">@import url("/stylesheets/ie7.css");</style> + <![endif]--> + <!-- the following method for customising CSS is deprecated; see `doc/THEMES.md` for detail --> + <%= stylesheet_link_tag 'custom', :title => "Main", :rel => "stylesheet" %> + <% if force_registration_on_new_request %> + <%= stylesheet_link_tag 'jquery.fancybox-1.3.4', :rel => "stylesheet" %> + <% end %> diff --git a/app/views/layouts/default.rhtml b/app/views/layouts/default.rhtml index 5c3499c93..e4022661f 100644 --- a/app/views/layouts/default.rhtml +++ b/app/views/layouts/default.rhtml @@ -10,40 +10,19 @@ </title> <link rel="shortcut icon" href="/favicon.ico"> - <%= 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 %> - <% if is_admin? %> + <%= render :partial => 'general/stylesheet_includes' %> + <% if is_admin? %> <%= stylesheet_link_tag "/adminbootstraptheme/stylesheets/admin", :title => "Main", :rel => "stylesheet" %> - <% end %> - <%= javascript_include_tag 'jquery.js', 'jquery-ui.min','jquery.cookie.js', 'general.js' %> + <% end %> + <%= javascript_include_tag 'jquery.js', 'jquery-ui.min','jquery.cookie.js', 'general.js' %> <% if @profile_photo_javascript %> <script type="text/javascript" src="/javascripts/jquery.Jcrop.js"></script> <script type="text/javascript" src="/javascripts/profile_photo.js"></script> <link rel="stylesheet" href="/stylesheets/jquery.Jcrop.css" type="text/css" > <% 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 7]> - <style type="text/css">@import url("/stylesheets/ie6-custom.css");</style> - <![endif]--> - <!--[if LT IE 8]> - <style type="text/css">@import url("/stylesheets/ie7.css");</style> - <![endif]--> - <!-- the following method for customising CSS is deprecated; see `doc/THEMES.md` for detail --> - <%= stylesheet_link_tag 'custom', :title => "Main", :rel => "stylesheet" %> - <% if force_registration_on_new_request %> - <%= stylesheet_link_tag 'jquery.fancybox-1.3.4', :rel => "stylesheet" %> - <% end %> - <% if @feed_autodetect %> <% for feed in @feed_autodetect %> <link rel="alternate" type="application/atom+xml" title="<%=h feed[:title] %>" href="<%=h feed[:url]%>"> @@ -63,7 +42,6 @@ <%= render :partial => 'general/before_head_end' %> </head> <body class="<%= 'admin' if is_admin? %> <%= 'front' if params[:action] == 'frontpage' %>"> - <!-- XXX: move to a separate file --> <% if force_registration_on_new_request && !@user %> <%= javascript_include_tag 'jquery.fancybox-1.3.4.pack' %> <script type="text/javascript"> @@ -79,7 +57,7 @@ if (typeof modal_signin_successful != 'undefined' ) { window.location.href = '<%= select_authority_url %>'; } - } + } }); }); </script> @@ -89,20 +67,19 @@ <%= render :partial => 'admin_general/admin_navbar' %> <% end %> -<% # code for popup advert for a campaign etc. -=begin - <div id="everypage" class="jshide"> - <p style="float:right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;">Close</a></p> - [ message goes here ] - <p style="text-align: right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;">Close</a></p> - </div> -=end -%> +<% if !@popup_banner.blank? %> +<div id="everypage" class="jshide"> + <p style="float:right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;"><%= _('Close') %></a></p> + <%= @popup_banner %> + <p style="text-align: right"><a href="#top" onclick="$.cookie('seen_foi2', 1, { expires: 7, path: '/' }); $('#everypage').hide('slow'); return false;"><%= _('Close') %></a></p> +</div> +<% end %> + <div class="entirebody"> <div id="banner"> <div id="banner_inner"> <div class="lang"><%= render :partial => 'general/locale_switcher' %></div> - + <% if not (controller.action_name == 'signin' or controller.action_name == 'signup') %> <div id="logged_in_bar"> <% if @user %> @@ -120,19 +97,19 @@ <%= link_to _("Sign in or sign up"), signin_url(:r => request.request_uri) %> <% end %> </div> - <% end %> + <% end %> <div id="navigation_search"> <% form_tag({:controller => "general", :action => "search_redirect"}, {:id => "navigation_search_form"}) do %> <p> <%= text_field_tag 'query', params[:query], { :size => 40, :id => "navigation_search_query" } %> - <%= image_submit_tag('search-button.png') %> + <%= submit_tag 'search', :id => "navigation_search_button" %> </p> <% end %> </div> - + <%= render :partial => 'general/orglink' %> - + <%= render :partial => 'general/topnav' %> </div> </div> @@ -163,7 +140,7 @@ </div> <% ga_code = MySociety::Config.get('GA_CODE', '') - + unless ga_code.empty? %> <script> var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www."); @@ -173,10 +150,9 @@ var pageTracker = _gat._getTracker("<%=ga_code%>"); pageTracker._trackPageview(); </script> - + <% end %> <%= render :partial => 'general/before_body_end' %> </body> </html> - diff --git a/app/views/request/_after_actions.rhtml b/app/views/request/_after_actions.rhtml index 205b738de..15ca6302e 100644 --- a/app/views/request/_after_actions.rhtml +++ b/app/views/request/_after_actions.rhtml @@ -1,51 +1,52 @@ <div id="after_actions"> - + <h2><%= _('Things to do with this request') %></h2> <div id="anyone_actions"> <strong><%= _('Anyone:') %></strong> <ul> <li> - <%= _('<a href="%s">Add an annotation</a> (to help the requester or others)') % [new_comment_url(:url_title => @info_request.url_title)] %> + <%= _('<a href="%s">Add an annotation</a> (to help the requester or others)') % [new_comment_url(:url_title => @info_request.url_title)] %> </li> - <% if @old_unclassified %> + <% if @old_unclassified %> <li> <%= link_to _('Update the status of this request'), '#describe_state_form_1' %> </li> <% end %> <li> - <%= link_to _("Download a zip file of all correspondence"), download_entire_request_url(:url_title => @info_request.url_title) %> + <%= link_to _("Download a zip file of all correspondence"), download_entire_request_url(:url_title => @info_request.url_title) %> </li> </ul> </div> + <% if ! @info_request.is_external? %> + <div id="owner_actions"> + <strong><%= _('{{info_request_user_name}} only:',:info_request_user_name=>h(@info_request.user_name)) %></strong> + <ul> + + <li> + <% if @last_response.nil? %> + <%= link_to _("Send a followup"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "#followup" %> + <% else %> + <%= link_to _("Write a reply"), show_response_url(:id => @info_request.id, :incoming_message_id => @last_response.id) + "#followup" %> + <% end %> + </li> + <% if !@old_unclassified %> + <li> + <%= link_to _("Update the status of this request"), request_url(@info_request, :update_status => 1) %> + </li> + <% end %> + <li> + <%= link_to _("Request an internal review"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "?internal_review=1#followup" %> + </li> + </ul> + </div> + <% end %> - <div id="owner_actions"> - <strong><%= _('{{info_request_user_name}} only:',:info_request_user_name=>h(@info_request.user.name)) %></strong> - <ul> - - <li> - <% if @last_response.nil? %> - <%= link_to _("Send a followup"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "#followup" %> - <% else %> - <%= link_to _("Write a reply"), show_response_url(:id => @info_request.id, :incoming_message_id => @last_response.id) + "#followup" %> - <% end %> - </li> - <% if !@old_unclassified %> - <li> - <%= link_to _("Update the status of this request"), request_url(@info_request, :update_status => 1) %> - </li> - <% end %> - <li> - <%= link_to _("Request an internal review"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "?internal_review=1#followup" %> - </li> - </ul> - </div> - <div id="public_body_actions"> - <strong><%= _('{{public_body_name}} only:',:public_body_name=>h(@info_request.public_body.name) ) %> </strong> + <strong><%= _('{{public_body_name}} only:',:public_body_name=>h(@info_request.public_body.name) ) %> </strong> <ul> <li> - <%= link_to _("Respond to request"), upload_response_url(:url_title => @info_request.url_title) %> + <%= link_to _("Respond to request"), upload_response_url(:url_title => @info_request.url_title) %> </li> </ul> </div> diff --git a/app/views/request/_correspondence.rhtml b/app/views/request/_correspondence.rhtml index 9a198ad7d..bcfc93657 100644 --- a/app/views/request/_correspondence.rhtml +++ b/app/views/request/_correspondence.rhtml @@ -33,14 +33,14 @@ elsif [ 'sent', 'followup_sent' ].include?(info_request_event.event_type) <div class="outgoing correspondence" id="outgoing-<%=outgoing_message.id.to_s%>"> <h2> - <%= _("From:") %> <%=h @info_request.user.name %><br> + <%= _("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' %> + <% 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 %> diff --git a/app/views/request/_describe_state.rhtml b/app/views/request/_describe_state.rhtml index 71699835c..5b6004e81 100644 --- a/app/views/request/_describe_state.rhtml +++ b/app/views/request/_describe_state.rhtml @@ -104,9 +104,11 @@ <% elsif @old_unclassified %> <%= render :partial => 'other_describe_state', :locals => {:id_suffix => id_suffix } %> <% else %> -<%= _('We don\'t know whether the most recent response to this request contains + <% if !@info_request.is_external? %> + <%= _('We don\'t know whether the most recent response to this request contains information or not – if you are {{user_link}} please <a href="{{url}}">sign in</a> and let everyone know.',:user_link=>user_link(@info_request.user), :url=>signin_url(:r => request.request_uri)) %> + <% end %> <% end %> diff --git a/app/views/request/followup_bad.rhtml b/app/views/request/followup_bad.rhtml index 306eddd10..7efa3f826 100644 --- a/app/views/request/followup_bad.rhtml +++ b/app/views/request/followup_bad.rhtml @@ -25,6 +25,9 @@ one on their website, or by phoning them up and asking. If you manage to find one, then please <a href="%s">send it to us</a>.') % [help_contact_path] %> </p> +<% elsif @reason == 'external' %> + <p><%= _("Followups cannot be sent for this request, as it was made externally, and published here by {{public_body_name}} on the requester's behalf.", :public_body_name => h(@info_request.public_body.name)) %> + </p> <% else %> <% raise _("unknown reason ") + @reason %> <% end %> diff --git a/app/views/request/show.rhtml b/app/views/request/show.rhtml index 27ad0700e..cf1f971d9 100644 --- a/app/views/request/show.rhtml +++ b/app/views/request/show.rhtml @@ -16,7 +16,7 @@ <% end %> -<% if @update_status || @info_request.awaiting_description %> +<% if ( @update_status || @info_request.awaiting_description ) && ! @info_request.is_external? %> <div class="describe_state_form" id="describe_state_form_1"> <%= render :partial => 'describe_state', :locals => { :id_suffix => "1" } %> </div> @@ -27,7 +27,7 @@ <div id="left_column"> <h1><%=h(@info_request.title)%></h1> - <% if @info_request.user.profile_photo %> + <% if !@info_request.is_external? && @info_request.user.profile_photo %> <p class="user_photo_on_request"> <img src="<%= get_profile_photo_url(:url_name => @info_request.user.url_name) %>" alt=""> </p> @@ -35,60 +35,62 @@ <p class="subtitle"> <% if !@user.nil? && @user.admin_page_links? %> - <%= _('{{user}} (<a href="{{user_admin_url}}">admin</a>) made this {{law_used_full}} request (<a href="{{request_admin_url}}">admin</a>) to {{public_body_link}} (<a href="{{public_body_admin_url}}">admin</a>)', - :user => user_link(@info_request.user), + <%= _('{{user}} ({{user_admin_link}}) made this {{law_used_full}} request (<a href="{{request_admin_url}}">admin</a>) to {{public_body_link}} (<a href="{{public_body_admin_url}}">admin</a>)', + :user => @info_request.is_external? ? (@info_request.user_name || _('An anonymous user')) : user_link(@info_request.user), :law_used_full => h(@info_request.law_used_full), - :user_admin_url => user_admin_url(@info_request.user), + :user_admin_link => user_admin_link_for_request(@info_request, _('external'), _('admin')), :request_admin_url => request_admin_url(@info_request), :public_body_link => public_body_link(@info_request.public_body), :public_body_admin_url => public_body_admin_url(@info_request.public_body)) %> <% else %> - <%= _('{{user}} made this {{law_used_full}} request',:user=>user_link(@info_request.user), :law_used_full=>h(@info_request.law_used_full)) %> - <%= _('to {{public_body}}',:public_body=>public_body_link(@info_request.public_body)) %> + <%= _('{{user}} made this {{law_used_full}} request',:user=>@info_request.is_external? ? (@info_request.user_name || _('An anonymous user')) : user_link(@info_request.user), :law_used_full=>h(@info_request.law_used_full)) %> + <%= _('to {{public_body}}',:public_body=>public_body_link(@info_request.public_body)) %> <% end %> </p> <p id="request_status" class="request_icon_line icon_<%= @info_request.calculate_status %>"> <% if @info_request.awaiting_description %> - <% if @is_owning_user %> - <%= _('Please <strong>answer the question above</strong> so we know whether the ')%> + <% if @is_owning_user && !@info_request.is_external? %> + <%= _('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 %> <%= _('This request has an <strong>unknown status</strong>.') %> <% if @old_unclassified %> - <%= _('We\'re waiting for someone to read') %> + <%= _('We\'re waiting for someone to read') %> <%= MySociety::Format.fancy_pluralize(@new_responses_count, 'a recent response', 'recent responses') %> <%= _('and update the status accordingly. Perhaps <strong>you</strong> might like to help out by doing that?') %> <% else %> <%= _('We\'re waiting for') %> - <%= user_link(@info_request.user) %> <%= _('to read') %> - <%= MySociety::Format.fancy_pluralize(@new_responses_count, 'a recent response', 'recent responses') %> + <%= user_link_for_request(@info_request) %> <%= _('to read') %> + <%= MySociety::Format.fancy_pluralize(@new_responses_count, 'a recent response', 'recent responses') %> <%= _('and update the status.') %> <% end %> <% end %> <% elsif @status == 'waiting_response' %> - <%= _('Currently <strong>waiting for a response</strong> from {{public_body_link}}, they must respond promptly and', :public_body_link=> public_body_link(@info_request.public_body)) %> + <%= _('Currently <strong>waiting for a response</strong> from {{public_body_link}}, they must respond promptly and', :public_body_link=> public_body_link(@info_request.public_body)) %> <% if @info_request.public_body.is_school? %> <%= _('in term time') %> <% else %> - <%= _('normally') %> + <%= _('normally') %> <% end %> <%= _('no later than') %> <strong><%= simple_date(@info_request.date_response_required_by) %></strong> (<%= link_to _("details"), "/help/requesting#quickly_response" %>). <% elsif @status == 'waiting_response_overdue' %> <%= _('Response to this request is <strong>delayed</strong>.') %> - <%= _('By law, {{public_body_link}} should normally have responded <strong>promptly</strong> and',:public_body_link=>public_body_link(@info_request.public_body)) %> + <%= _('By law, {{public_body_link}} should normally have responded <strong>promptly</strong> and',:public_body_link=>public_body_link(@info_request.public_body)) %> <% if @info_request.public_body.is_school? %> - <%= _('in term time') %> + <%= _('in term time') %> <% end %> <%= _('by') %> <strong><%= simple_date(@info_request.date_response_required_by) %></strong> - (<%= _('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response'] %>) + (<%= _('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response'] %>) <% elsif @status == 'waiting_response_very_overdue' %> - <%= _('Response to this request is <strong>long overdue</strong>.') %> - <%= _('By law, under all circumstances, {{public_body_link}} should have responded by now',:public_body_link => public_body_link(@info_request.public_body)) %> + <%= _('Response to this request is <strong>long overdue</strong>.') %> + <%= _('By law, under all circumstances, {{public_body_link}} should have responded by now',:public_body_link => public_body_link(@info_request.public_body)) %> (<%= _('<a href="%s">details</a>') % [help_requesting_path + '#quickly_response'] %>). - <%= _('You can <strong>complain</strong> by') %> - <%= link_to _("requesting an internal review"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "?internal_review=1#followup" %>. + <% if !@info_request.is_external? %> + <%= _('You can <strong>complain</strong> by') %> + <%= link_to _("requesting an internal review"), show_response_no_followup_url(:id => @info_request.id, :incoming_message_id => nil) + "?internal_review=1#followup" %>. + <% end %> <% elsif @status == 'not_held' %> <%= public_body_link(@info_request.public_body) %> <%= _('<strong>did not have</strong> the information requested.') %> <% elsif @status == 'rejected' %> @@ -98,26 +100,28 @@ <% elsif @status == 'partially_successful' %> <%= _('The request was <strong>partially successful</strong>.') %> <% elsif @status == 'waiting_clarification' %> - <% if @is_owning_user %> - <%=h @info_request.public_body.name %> <%= _('is <strong>waiting for your clarification</strong>.') %> + <% if @is_owning_user && !@info_request.is_external? %> + <%=h @info_request.public_body.name %> <%= _('is <strong>waiting for your clarification</strong>.') %> <%= _('Please') %> <%= link_to _("send a follow up message"), respond_to_last_url(@info_request) + '#followup' %>. <% else %> - <%= _('The request is <strong>waiting for clarification</strong>.') %> - <%= _('If you are {{user_link}}, please',:user_link=>user_link(@info_request.user)) %> - <%= link_to _("sign in"), signin_url(:r => request.request_uri) %> <%= _('to send a follow up message.') %> + <%= _('The request is <strong>waiting for clarification</strong>.') %> + <% if !@info_request.is_external? %> + <%= _('If you are {{user_link}}, please',:user_link=>user_link_for_request(@info_request)) %> + <%= link_to _("sign in"), signin_url(:r => request.request_uri) %> <%= _('to send a follow up message.') %> + <% end %> <% end %> <% elsif @status == 'gone_postal' %> <%= _('The authority would like to / has <strong>responded by post</strong> to this request.') %> <% elsif @status == 'internal_review' %> - <%= _('Waiting for an <strong>internal review</strong> by {{public_body_link}} of their handling of this request.',:public_body_link=>public_body_link(@info_request.public_body)) %> + <%= _('Waiting for an <strong>internal review</strong> by {{public_body_link}} of their handling of this request.',:public_body_link=>public_body_link(@info_request.public_body)) %> <% elsif @status == 'error_message' %> <%= _('There was a <strong>delivery error</strong> or similar, which needs fixing by the {{site_name}} team.', :site_name=>site_name) %> <% elsif @status == 'requires_admin' %> <%= _('This request has had an unusual response, and <strong>requires attention</strong> from the {{site_name}} team.', :site_name=>site_name) %> <% elsif @status == 'user_withdrawn' %> - <%= _('This request has been <strong>withdrawn</strong> by the person who made it. - There may be an explanation in the correspondence below.') %> + <%= _('This request has been <strong>withdrawn</strong> by the person who made it. + There may be an explanation in the correspondence below.') %> <% elsif @status == 'attention_requested' %> <%= _('This request has been <strong>reported</strong> as needing administrator attention (perhaps because it is vexatious, or a request for personal information)') %> <% elsif @status == 'vexatious' %> @@ -135,7 +139,7 @@ <% end %> <% end %> - <% if @info_request.awaiting_description %> + <% if @info_request.awaiting_description && ! @info_request.is_external? %> <div class="describe_state_form" id="describe_state_form_2"> <%= render :partial => 'describe_state', :locals => { :id_suffix => "2" } %> </div> diff --git a/app/views/request/show_response.rhtml b/app/views/request/show_response.rhtml index d8647d1ec..c40b37c3b 100644 --- a/app/views/request/show_response.rhtml +++ b/app/views/request/show_response.rhtml @@ -1,9 +1,9 @@ <% if @incoming_message.nil? %> - <% @title = "Send follow up to '" + h(@info_request.title) + "'" %> + <% @title = _("Send follow up to '{{title}}'", :title => h(@info_request.title)) %> <% elsif @incoming_message.recently_arrived %> - <% @title = "New response to '" + h(@info_request.title) + "'" %> + <% @title = _("New response to '{{title}}'", :title => h(@info_request.title)) %> <% else %> - <% @title = "Response to '" + h(@info_request.title) + "'" %> + <% @title = _("Response to '{{title}}'", :title => h(@info_request.title)) %> <% end %> <%= foi_error_messages_for :incoming_message, :outgoing_message %> @@ -34,11 +34,11 @@ <%= _('You want to <strong>give your postal address</strong> to the authority in private.') %> </dt> <dd> - <%= _('To do that please send a private email to ') %><%=h(@postal_email_name)%> + <%= _('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. Or you could phone them.') %> - + <%= _('When you receive the paper response, please help others find out what it says:') %> <ul> @@ -68,7 +68,7 @@ <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 } %> <% else %> diff --git a/app/views/request/simple_correspondence.rhtml b/app/views/request/simple_correspondence.rhtml index 45b90b84b..bcbc795e7 100644 --- a/app/views/request/simple_correspondence.rhtml +++ b/app/views/request/simple_correspondence.rhtml @@ -4,16 +4,16 @@ <% 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 !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:') %> <%= @info_request.user.name %> +<%= _('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 %> @@ -24,7 +24,7 @@ elsif [ 'sent', 'followup_sent' ].include?(info_request_event.event_type) outgoing_message = info_request_event.outgoing_message %> -<%= _('From:') %> <%= @info_request.user.name %> +<%= _('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) %> <% @@ -36,7 +36,7 @@ elsif [ 'sent', 'followup_sent' ].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' +<% 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) %>) diff --git a/app/views/request/upload_response.rhtml b/app/views/request/upload_response.rhtml index 38c3db268..697ff99aa 100644 --- a/app/views/request/upload_response.rhtml +++ b/app/views/request/upload_response.rhtml @@ -1,45 +1,52 @@ -<% @title = "Respond to the FOI request '" + h(@info_request.title) + "' made by " + h(@info_request.user.name) %> +<% @title = "Respond to the FOI request '" + h(@info_request.title) + "' made by " + h(@info_request.user_name) %> -<%= foi_error_messages_for :comment %> +<% if @info_request.is_external? %> -<h1><%= _('Respond to the FOI request')%> '<%=request_link(@info_request)%>'<% _(' made by ')%><%=user_link(@info_request.user) %></h1> + <h1><%= _('This request was not made via {{site_name}}', :site_name => site_name) %></h1> + <p><%= _('Sorry - you cannot respond to this request via {{site_name}}, because this is a copy of the request originally at {{link_to_original_request}}.', :site_name => site_name, :link_to_original_request => link_to(@info_request.external_url, @info_request.external_url)) %></p> -<p> - <%= _('Your response will <strong>appear on the Internet</strong>, <a href="%s">read why</a> and answers to other questions.')% [help_officers_path] %> -</p> +<% else %> -<h2><%= _('Respond by email')%></h2> + <%= foi_error_messages_for :comment %> -<p><%= _('You should have received a copy of the request by email, and you can respond -by <strong>simply replying</strong> to that email. For your convenience, here is the address:')%> -<a href="mailto:<%=h @info_request.incoming_email%>"><%=h @info_request.incoming_email%></a>. -<%= _('You may <strong>include attachments</strong>. If you would like to attach a -file too large for email, use the form below.')%> -</p> + <h1><%= _('Respond to the FOI request')%> '<%=request_link(@info_request)%>'<% _(' made by ')%><%=user_link(@info_request.user) %></h1> + <p> + <%= _('Your response will <strong>appear on the Internet</strong>, <a href="%s">read why</a> and answers to other questions.')% [help_officers_path] %> + </p> -<h2><%= _('Respond using the web')%></h2> + <h2><%= _('Respond by email')%></h2> -<p><%= _('Enter your response below. You may attach one file (use email, or -<a href="%s">contact us</a> if you need more).')% [help_contact_path] %></p> + <p><%= _('You should have received a copy of the request by email, and you can respond + by <strong>simply replying</strong> to that email. For your convenience, here is the address:')%> + <a href="mailto:<%=h @info_request.incoming_email%>"><%=h @info_request.incoming_email%></a>. + <%= _('You may <strong>include attachments</strong>. If you would like to attach a + file too large for email, use the form below.')%> + </p> -<% form_tag '', :id => 'upload_response_form', :multipart => true do %> - <p> - <label class="form_label" for="body"><% _('Response:')%></label> - <%= text_area_tag :body, "", :rows => 10, :cols => 55 %> - </p> - <p> - <label class="form_label" for="file_1"><% _('Attachment (optional):')%></label> - <%= file_field_tag :file_1, :size => 35 %> - </p> + <h2><%= _('Respond using the web')%></h2> - <p> - <%= hidden_field_tag 'submitted_upload_response', 1 %> - <%= submit_tag "Upload FOI response" %> - <%= _(' (<strong>patience</strong>, especially for large files, it may take a while!)')%> - </p> + <p><%= _('Enter your response below. You may attach one file (use email, or + <a href="%s">contact us</a> if you need more).')% [help_contact_path] %></p> + <% form_tag '', :id => 'upload_response_form', :multipart => true do %> + <p> + <label class="form_label" for="body"><% _('Response:')%></label> + <%= text_area_tag :body, "", :rows => 10, :cols => 55 %> + </p> + + <p> + <label class="form_label" for="file_1"><% _('Attachment (optional):')%></label> + <%= file_field_tag :file_1, :size => 35 %> + </p> + + <p> + <%= hidden_field_tag 'submitted_upload_response', 1 %> + <%= submit_tag "Upload FOI response" %> + <%= _(' (<strong>patience</strong>, especially for large files, it may take a while!)')%> + </p> + <% end %> <% end %> diff --git a/app/views/track_mailer/event_digest.rhtml b/app/views/track_mailer/event_digest.rhtml index 089b778f8..2c2e3c957 100644 --- a/app/views/track_mailer/event_digest.rhtml +++ b/app/views/track_mailer/event_digest.rhtml @@ -18,14 +18,14 @@ # e.g. Julian Burgess sent a request to Royal Mail Group (15 May 2008) if event.event_type == 'response' url = main_url(incoming_message_url(event.incoming_message)) - main_text += _("{{public_body}} sent a response to {{user_name}}", :public_body => event.info_request.public_body.name, :user_name => event.info_request.user.name) + main_text += _("{{public_body}} sent a response to {{user_name}}", :public_body => event.info_request.public_body.name, :user_name => event.info_request.user_name) elsif event.event_type == 'followup_sent' url = main_url(outgoing_message_url(event.outgoing_message)) - main_text += _("{{user_name}} sent a follow up message to {{public_body}}", :user_name => event.info_request.user.name, :public_body => event.info_request.public_body.name) + main_text += _("{{user_name}} sent a follow up message to {{public_body}}", :user_name => event.info_request.user_name, :public_body => event.info_request.public_body.name) elsif event.event_type == 'sent' # this is unlikely to happen in real life, but happens in the test code url = main_url(outgoing_message_url(event.outgoing_message)) - main_text += _("{{user_name}} sent a request to {{public_body}}", :user_name => event.info_request.user.name, :public_body => event.info_request.public_body.name) + main_text += _("{{user_name}} sent a request to {{public_body}}", :user_name => event.info_request.user_name, :public_body => event.info_request.public_body.name) elsif event.event_type == 'comment' url = main_url(comment_url(event.comment)) main_text += _("{{user_name}} added an annotation", :user_name => event.comment.user.name) diff --git a/app/views/user/_show_user_info.rhtml b/app/views/user/_show_user_info.rhtml new file mode 100644 index 000000000..5dfecee1e --- /dev/null +++ b/app/views/user/_show_user_info.rhtml @@ -0,0 +1,20 @@ + + <% if !@display_user.get_about_me_for_html_display.empty? || @is_you %> + <div class="user_about_me"> + <img class="comment_quote" src="/images/quote.png" alt=""> + <%= @display_user.get_about_me_for_html_display %> + <% if @is_you %> + (<%= link_to _("edit text about you"), set_profile_about_me_url() %>) + <% end %> + </div> + <% end %> + + <% if @is_you %> + <p id="user_change_password_email"> + <% if @display_user.profile_photo %> + <%= link_to _('Change profile photo'), set_profile_photo_url() %> | + <% end %> + <%= link_to _('Change your password'), signchangepassword_url() %> | + <%= link_to _('Change your email'), signchangeemail_url() %> + </p> + <% end %> diff --git a/app/views/user/contact.rhtml b/app/views/user/contact.rhtml index 4bbb15789..333b72334 100644 --- a/app/views/user/contact.rhtml +++ b/app/views/user/contact.rhtml @@ -9,21 +9,21 @@ <% form_for :contact do |f| %> <div class="form_note"> - <h1>Contact <%=h @recipient_user.name%></h1> + <h1><%= _("Contact {{recipient}}", :recipient => h(@recipient_user.name)) %></h1> </div> <p> - <label class="form_label">From:</label> + <label class="form_label"><%= _("From") %>:</label> <%= h(@user.name_and_email) %> </p> <p> - <label class="form_label" for="contact_subject">Subject:</label> + <label class="form_label" for="contact_subject"><%= _("Subject") %>:</label> <%= f.text_field :subject, :size => 50 %> </p> <p> - <label class="form_label" for="contact_message">Message:</label> + <label class="form_label" for="contact_message"><%= _("Message") %>:</label> <%= f.text_area :message, :rows => 10, :cols => 50 %> </p> @@ -39,9 +39,7 @@ <div class="form_button"> <%= hidden_field_tag(:submitted_contact_form, { :value => 1 } ) %> - <%= submit_tag "Send message" %> + <%= submit_tag _("Send message") %> </div> <% end %> - - diff --git a/app/views/user/set_crop_profile_photo.rhtml b/app/views/user/set_crop_profile_photo.rhtml index db18d10a1..eed0304d2 100644 --- a/app/views/user/set_crop_profile_photo.rhtml +++ b/app/views/user/set_crop_profile_photo.rhtml @@ -20,7 +20,7 @@ <div style="width:96px;height:96px;overflow:hidden;"> <img src="<%= get_draft_profile_photo_url(:id => @draft_profile_photo.id) %>" id="profile_photo_preview" /> </div> - + </td> </tr> </table> @@ -32,12 +32,12 @@ <%= hidden_field_tag 'draft_profile_photo_id', @draft_profile_photo.id %> - <p><%= _('<strong>Privacy note:</strong> Your photo will be shown in public on the Internet, + <p><%= _('<strong>Privacy note:</strong> Your photo will be shown in public on the Internet, wherever you do something on {{site_name}}.', :site_name=>site_name)%> <p> <%= hidden_field_tag 'submitted_crop_profile_photo', 1 %> - <%= submit_tag "Done >>" %> + <%= submit_tag _("Done") + " >>" %> </p> <% end %> diff --git a/app/views/user/set_draft_profile_photo.rhtml b/app/views/user/set_draft_profile_photo.rhtml index 90be49600..b3faba7fc 100644 --- a/app/views/user/set_draft_profile_photo.rhtml +++ b/app/views/user/set_draft_profile_photo.rhtml @@ -10,12 +10,12 @@ <% form_tag 'set_photo', :id => 'set_draft_profile_photo_form', :multipart => true do %> <p> - <label class="form_label" for="file_1"><%= _('Photo of you:')%></label> + <label class="form_label" for="file_1"><%= _('Photo of you:')%></label> <%= file_field_tag :file, :size => 35, :id => 'file_1' %> </p> <ul> - <li><%= _('Your photo will be shown in public <strong>on the Internet</strong>, + <li><%= _('Your photo will be shown in public <strong>on the Internet</strong>, wherever you do something on {{site_name}}.', :site_name=>site_name)%> </li> @@ -36,7 +36,7 @@ <noscript> <div> <%= hidden_field_tag 'automatically_crop', 1 %> - <%= submit_tag "Done >>" %> + <%= submit_tag _("Done >>") %> </div> </noscript> <% end %> @@ -46,7 +46,7 @@ <h2><%= _('OR remove the existing photo')%></h2> <% form_tag 'clear_photo', :id => 'clear_profile_photo_form', :multipart => true do %> - <%= submit_tag "Clear photo" %> + <%= submit_tag _("Clear photo") %> <% end %> <% end %> diff --git a/app/views/user/show.rhtml b/app/views/user/show.rhtml index d723196d3..12a9d3f74 100644 --- a/app/views/user/show.rhtml +++ b/app/views/user/show.rhtml @@ -1,14 +1,14 @@ <% if @show_requests %> - <% @title = h(@display_user.name) + _(" - Freedom of Information requests") %> + <% @title = _("{{user_name}} - Freedom of Information requests", :user_name => h(@display_user.name)) %> <% else %> - <% @title = h(@display_user.name) + _(" - user profile") %> + <% @title = _("{{user_name}} - user profile", :user_name => h(@display_user.name)) %> <% end %> <% if (@same_name_users.size >= 1) %> - <p><%= _('There is <strong>more than one person</strong> who uses this site and has this name. + <p><%= _('There is <strong>more than one person</strong> who uses this site and has this name. One of them is shown below, you may mean a different one:')%> <% for @same_name_user in @same_name_users %> <%= user_link(@same_name_user) %> - <% end %> + <% end %> <% end%> <% if @show_profile && @is_you && @undescribed_requests.size > 0 %> @@ -40,11 +40,11 @@ <a href="#foi_requests"><%= _('FOI requests')%></a> <br><a href="#annotations"><%= _('Annotations')%></a> <% end %> - </div> + </div> <div class="header_left"> <p id="user_photo_on_profile"> - <% if @display_user.profile_photo %> + <% if @display_user.profile_photo %> <% if @is_you %> <a href="<%= set_profile_photo_url() %>"> <% end %> @@ -93,25 +93,7 @@ </div> <% end %> - <% if !@display_user.get_about_me_for_html_display.empty? || @is_you %> - <div class="user_about_me"> - <img class="comment_quote" src="/images/quote.png" alt=""> - <%= @display_user.get_about_me_for_html_display %> - <% if @is_you %> - (<%= link_to _("edit text about you"), set_profile_about_me_url() %>) - <% end %> - </div> - <% end %> - - <% if @is_you %> - <p id="user_change_password_email"> - <% if @display_user.profile_photo %> - <%= link_to _('Change profile photo'), set_profile_photo_url() %> | - <% end %> - <%= link_to _('Change your password'), signchangepassword_url() %> | - <%= link_to _('Change your email'), signchangeemail_url() %> - </p> - <% end %> + <%= render :partial => 'user/show_user_info' %> <% if not @is_you %> <p id="user_not_logged_in"> @@ -127,7 +109,7 @@ <div id="user_profile_search"> <% form_tag(show_user_url, :method => "get", :id=>"search_form") do %> <div> - <%= text_field_tag(:user_query, params[:user_query]) %> + <%= text_field_tag(:user_query, params[:user_query]) %> <% if @is_you %> <%= submit_tag(_("Search your contributions")) %> <% else %> @@ -146,7 +128,7 @@ <% end %> <% else %> <h2 class="foi_results" id="foi_requests"> - <%= @is_you ? n_('Your %d Freedom of Information request', 'Your %d Freedom of Information requests', @xapian_requests.matches_estimated.to_s) % @xapian_requests.matches_estimated.to_s : n_('This person\'s %d Freedom of Information request', 'This person\'s %d Freedom of Information requests', @xapian_requests.matches_estimated.to_s) % @xapian_requests.matches_estimated %> + <%= @is_you ? n_('Your %d Freedom of Information request', 'Your %d Freedom of Information requests', @xapian_requests.matches_estimated) % @xapian_requests.matches_estimated.to_s : n_('This person\'s %d Freedom of Information request', 'This person\'s %d Freedom of Information requests', @xapian_requests.matches_estimated) % @xapian_requests.matches_estimated %> <!-- matches_estimated <%=@xapian_requests.matches_estimated%> --> <%= @match_phrase %> <%= @page_desc %> @@ -159,12 +141,12 @@ <%= will_paginate WillPaginate::Collection.new(@page, @per_page, @display_user.info_requests.size) %> <% end %> - <% else %> + <% else %> <% if @show_requests %> <h2 class="foi_results" id="foi_requests"><%= @is_you ? _('Freedom of Information requests made by you') : _('Freedom of Information requests made by this person') %> </h2> <p><%= _('The search index is currently offline, so we can\'t show the Freedom of Information requests this person has made.')%></p> <% end %> - <% end %> + <% end %> <% if !@xapian_comments.nil? %> <% if @xapian_comments.results.empty? %> @@ -221,7 +203,7 @@ <%= hidden_field_tag 'r', request.request_uri %> <% if track_things.size > 1 %> <%= submit_tag _('unsubscribe all')%> - <% end %> + <% end %> </h3> <% end %> <% end %> @@ -231,7 +213,7 @@ <li> <% form_tag({:controller => 'track', :action => 'update', :track_id => track_thing.id}, :class => "feed_form") do %> <div> - <%= track_thing.params[:list_description] %> + <%= track_thing.params[:list_description] %> <%= hidden_field_tag 'track_medium', "delete", { :id => 'track_medium_' + track_thing.id.to_s } %> <%= hidden_field_tag 'r', request.request_uri, { :id => 'r_' + track_thing.id.to_s } %> <%= submit_tag _('unsubscribe') %> |