diff options
Diffstat (limited to 'app')
23 files changed, 260 insertions, 154 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 7bd794d23..30a43bb81 100644 --- a/app/controllers/admin_public_body_controller.rb +++ b/app/controllers/admin_public_body_controller.rb @@ -142,13 +142,7 @@ class AdminPublicBodyController < AdminController @notes = "" @errors = "" if request.post? - 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 + dry_run_only = (params['commit'] == 'Upload' ? false : true) # Read file from params if params[:csv_file] csv_contents = params[:csv_file].read diff --git a/app/controllers/admin_request_controller.rb b/app/controllers/admin_request_controller.rb index ae4bb511a..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/application_controller.rb b/app/controllers/application_controller.rb index 11f21025c..ce18e6ef5 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -134,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 @@ -157,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 @@ -206,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}" @@ -382,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) 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 01332c5ab..16e37277b 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,20 +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? - request.external_user_name || _("Anonymous user") + 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.user_name + " (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") @@ -111,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) @@ -118,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") @@ -125,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 @@ -199,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/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/info_request.rb b/app/models/info_request.rb index dfaa524b2..6f472c290 100644 --- a/app/models/info_request.rb +++ b/app/models/info_request.rb @@ -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 @@ -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 @@ -1036,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/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/views/admin_public_body/import_csv.rhtml b/app/views/admin_public_body/import_csv.rhtml index 4eb83cc7e..4a03d0665 100644 --- a/app/views/admin_public_body/import_csv.rhtml +++ b/app/views/admin_public_body/import_csv.rhtml @@ -44,7 +44,7 @@ <blockquote> <p> - #id,name,request_email,name.es,tag_string<br/> + #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> 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/comment/new.rhtml b/app/views/comment/new.rhtml index 55155c8a2..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,7 +67,7 @@ </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> diff --git a/app/views/request/_after_actions.rhtml b/app/views/request/_after_actions.rhtml index 02ed7c849..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 36257991b..bcfc93657 100644 --- a/app/views/request/_correspondence.rhtml +++ b/app/views/request/_correspondence.rhtml @@ -40,7 +40,7 @@ elsif [ 'sent', 'followup_sent' ].include?(info_request_event.event_type) <%= 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/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 a7760ab19..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> @@ -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=>@info_request.user.nil? ? @info_request.user_name : 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_for_request(@info_request) %> <%= _('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_for_request(@info_request)) %> - <%= 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/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 0de96c5f3..697ff99aa 100644 --- a/app/views/request/upload_response.rhtml +++ b/app/views/request/upload_response.rhtml @@ -27,17 +27,17 @@ <h2><%= _('Respond using the web')%></h2> - <p><%= _('Enter your response below. You may attach one file (use email, or + <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> + <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> + <label class="form_label" for="file_1"><% _('Attachment (optional):')%></label> <%= file_field_tag :file_1, :size => 35 %> </p> |