diff options
26 files changed, 706 insertions, 121 deletions
| diff --git a/app/controllers/admin_spam_addresses_controller.rb b/app/controllers/admin_spam_addresses_controller.rb new file mode 100644 index 000000000..f5c7e93da --- /dev/null +++ b/app/controllers/admin_spam_addresses_controller.rb @@ -0,0 +1,27 @@ +class AdminSpamAddressesController < AdminController + +    def index +        @spam_addresses = SpamAddress.all +        @spam_address = SpamAddress.new +    end + +    def create +        @spam_address = SpamAddress.new(params[:spam_address]) + +        if @spam_address.save +            notice = "#{ @spam_address.email } has been added to the spam addresses list" +            redirect_to spam_addresses_path, :notice => notice +        else +            @spam_addresses = SpamAddress.all +            render :index +        end +    end + +    def destroy +        @spam_address = SpamAddress.find(params[:id]) +        @spam_address.destroy +        notice = "#{ @spam_address.email } has been removed from the spam addresses list" +        redirect_to spam_addresses_path, :notice => notice +    end + +end diff --git a/app/controllers/track_controller.rb b/app/controllers/track_controller.rb index 83e05ebbc..dccc52efc 100644 --- a/app/controllers/track_controller.rb +++ b/app/controllers/track_controller.rb @@ -118,7 +118,7 @@ class TrackController < ApplicationController          if @user              @existing_track = TrackThing.find_existing(@user, @track_thing)              if @existing_track -                flash[:notice] = _("You are already following updates about {{track_description}}", :track_description => @track_thing.params[:list_description]) +                flash[:notice] = view_context.already_subscribed_notice(@track_thing)                  return true              end          end @@ -130,11 +130,7 @@ class TrackController < ApplicationController          @track_thing.track_medium = 'email_daily'          @track_thing.tracking_user_id = @user.id          @track_thing.save! -        if @user.receive_email_alerts -            flash[:notice] = _('You will now be emailed updates about {{track_description}}. <a href="{{change_email_alerts_url}}">Prefer not to receive emails?</a>', :track_description =>  @track_thing.params[:list_description], :change_email_alerts_url => url_for(:controller => "user", :action => "wall", :url_name => @user.url_name)) -        else -            flash[:notice] = _('You are now <a href="{{wall_url_user}}">following</a> updates about {{track_description}}', :track_description => @track_thing.params[:list_description], :wall_url_user => url_for(:controller => "user", :action => "wall", :url_name => @user.url_name)) -        end +        flash[:notice] = render_to_string(:partial => 'track_set').html_safe          return true      end @@ -183,16 +179,8 @@ class TrackController < ApplicationController          new_medium = params[:track_medium]          if new_medium == 'delete'              track_thing.destroy -            flash[:notice] = _("You are no longer following {{track_description}}.", :track_description => track_thing.params[:list_description]) +            flash[:notice] = view_context.unsubscribe_notice(track_thing)              redirect_to URI.parse(params[:r]).path - -        # Reuse code like this if we let medium change again. -        #elsif new_medium == 'email_daily' -        #    track_thing.track_medium = new_medium -        #    track_thing.created_at = Time.now() # as created_at is used to limit the alerts to start with -        #    track_thing.save! -        #    flash[:notice] = "You are now tracking " + track_thing.params[:list_description] + " by email daily" -        #    redirect_to user_url(track_thing.tracking_user)          else              raise "new medium not handled " + new_medium          end @@ -217,7 +205,6 @@ class TrackController < ApplicationController          for track_thing in TrackThing.find(:all, :conditions => [ "track_type = ? and tracking_user_id = ?", track_type, user_id ])              track_thing.destroy          end -        flash[:notice] += "</ul>"          redirect_to params[:r]      end diff --git a/app/helpers/link_to_helper.rb b/app/helpers/link_to_helper.rb index 594296e77..dd6ffa805 100755 --- a/app/helpers/link_to_helper.rb +++ b/app/helpers/link_to_helper.rb @@ -18,8 +18,8 @@ module LinkToHelper          request_url(info_request, {:only_path => true}.merge(options))      end -    def request_link(info_request, cls=nil ) -        link_to h(info_request.title), request_path(info_request), :class => cls +    def request_link(info_request, cls=nil) +        link_to info_request.title, request_path(info_request), :class => cls      end      def request_details_path(info_request) @@ -96,19 +96,19 @@ module LinkToHelper      end      def user_link(user, cls=nil) -        link_to h(user.name), user_path(user), :class => cls +        link_to user.name, user_path(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 +                link_to user_name, request.external_url              else                  user_name              end          else -            link_to h(request.user.name), user_path(request.user), :class => cls +            link_to request.user.name, user_path(request.user), :class => cls          end      end @@ -116,7 +116,7 @@ module LinkToHelper          if request.is_external?              external_text || (request.external_user_name || _("Anonymous user")) + " (external)"          else -            link_to(h(internal_text || request.user.name), admin_user_show_url(request.user)) +            link_to(internal_text || request.user.name, admin_user_show_url(request.user))          end      end diff --git a/app/helpers/track_helper.rb b/app/helpers/track_helper.rb new file mode 100644 index 000000000..7bd0fa55d --- /dev/null +++ b/app/helpers/track_helper.rb @@ -0,0 +1,122 @@ +module TrackHelper + +    def already_subscribed_notice(track_thing) +        case track_thing.track_type +        when 'request_updates' +            _("You are already subscribed to '{{link_to_request}}', a request", +                :link_to_request => request_link(track_thing.info_request)) +        when 'all_new_requests' +            _('You are already subscribed to any <a href="{{new_requests_url}}">new requests</a>', +                :new_requests_url => request_list_path) +        when 'all_successful_requests' +            _('You are already subscribed to any <a href="{{successful_requests_url}}">successful requests</a>', +                :successful_requests_url => request_list_successful_path ) +        when 'public_body_updates' +            _("You are already subscribed to '{{link_to_authority}}', a public authority", +                :link_to_authority => public_body_link(track_thing.public_body)) +        when 'user_updates' +            _("You are already subscribed to '{{link_to_user}}', a person", +                :link_to_user => user_link(track_thing.tracked_user)) +        when 'search_query' +            _('You are already subscribed to <a href="{{search_url}}">this search</a>', +                :search_url => search_path([track_thing.track_query, 'newest', 'advanced'])) +        end +    end + +    def subscribe_email_notice(track_thing) +        case track_thing.track_type +        when 'request_updates' +            _("You will now be emailed updates about '{{link_to_request}}', a request", +                :link_to_request => request_link(track_thing.info_request)) +        when 'all_new_requests' +            _('You will now be emailed updates about any <a href="{{new_requests_url}}">new requests</a>', +                :new_requests_url => request_list_path) +        when 'all_successful_requests' +            _('You will now be emailed updates about <a href="{{successful_requests_url}}">successful requests</a>', +                :successful_requests_url => request_list_successful_path ) +        when 'public_body_updates' +            _("You will now be emailed updates about '{{link_to_authority}}', a public authority", +                :link_to_authority => public_body_link(track_thing.public_body)) +        when 'user_updates' +            _("You will now be emailed updates about '{{link_to_user}}', a person", +                :link_to_user => user_link(track_thing.tracked_user)) +        when 'search_query' +            _("You will now be emailed updates about <a href=\"{{search_url}}\">this search</a>", +                :search_url => search_path([track_thing.track_query, 'newest', 'advanced'])) +        end +    end + +    def subscribe_follow_notice(track_thing) +        wall_url_user = show_user_wall_path(:url_name => track_thing.tracking_user.url_name) +        case track_thing.track_type +        when 'request_updates' +            _('You are now <a href="{{wall_url_user}}">following</a> updates about \'{{link_to_request}}\', a request', +                :link_to_request => request_link(track_thing.info_request), +                :wall_url_user => wall_url_user) +        when 'all_new_requests' +            _('You are now <a href="{{wall_url_user}}">following</a> updates about <a href="{{new_requests_url}}">new requests</a>', +                :new_requests_url => request_list_path, +                :wall_url_user => wall_url_user) +        when 'all_successful_requests' +            _('You are now <a href="{{wall_url_user}}">following</a> updates about <a href="{{successful_requests_url}}">successful requests</a>', +                :successful_requests_url => request_list_successful_path, +                :wall_url_user => wall_url_user) +        when 'public_body_updates' +            _('You are now <a href="{{wall_url_user}}">following</a> updates about \'{{link_to_authority}}\', a public authority', +                :wall_url_user => wall_url_user, +                :link_to_authority => public_body_link(track_thing.public_body)) +        when 'user_updates' +            _('You are now <a href="{{wall_url_user}}">following</a> updates about \'{{link_to_user}}\', a person', +                :wall_url_user => wall_url_user, +                :link_to_user => user_link(track_thing.tracked_user)) +        when 'search_query' +            _('You are now <a href="{{wall_url_user}}">following</a> updates about <a href="{{search_url}}">this search</a>', +                :wall_url_user => wall_url_user, +                :search_url => search_path([track_thing.track_query, 'newest', 'advanced'])) +        end +    end + +    def unsubscribe_notice(track_thing) +        case track_thing.track_type +        when 'request_updates' +            _("You are no longer following '{{link_to_request}}', a request", +                :link_to_request => request_link(track_thing.info_request)) +        when 'all_new_requests' +            _('You are no longer following <a href="{{new_requests_url}}">new requests</a>', +                :new_requests_url => request_list_path) +        when 'all_successful_requests' +            _('You are no longer following <a href="{{successful_requests_url}}">successful requests</a>', +                :successful_requests_url => request_list_successful_path ) +        when 'public_body_updates' +            _("You are no longer following '{{link_to_authority}}', a public authority", +                :link_to_authority => public_body_link(track_thing.public_body)) +        when 'user_updates' +            _("You are no longer following '{{link_to_user}}', a person", +                :link_to_user => user_link(track_thing.tracked_user)) +        when 'search_query' +            _('You are no longer following <a href="{{search_url}}">this search</a>', +                :search_url => search_path([track_thing.track_query, 'newest', 'advanced'])) +        end +    end + +    def track_description(track_thing) +        case track_thing.track_type +        when 'request_updates' +            _("'{{link_to_request}}', a request", +                :link_to_request => request_link(track_thing.info_request)) +        when 'all_new_requests' +            link_to(_('new requests'), request_list_path) +        when 'all_successful_requests' +            link_to(_('successful requests'), request_list_successful_path) +        when 'public_body_updates' +            _("'{{link_to_authority}}', a public authority", +                :link_to_authority => public_body_link(track_thing.public_body)) +        when 'user_updates' +            _("'{{link_to_user}}', a person", +                :link_to_user => user_link(track_thing.tracked_user)) +        when 'search_query' +            link_to(track_thing.track_query_description, +                    search_path([track_thing.track_query, 'newest', 'advanced'])) +        end +    end +end diff --git a/app/mailers/request_mailer.rb b/app/mailers/request_mailer.rb index af1a75df9..1fd5b9ba7 100644 --- a/app/mailers/request_mailer.rb +++ b/app/mailers/request_mailer.rb @@ -250,7 +250,7 @@ class RequestMailer < ApplicationMailer          if reply_info_requests.size == 0              reason = _("Could not identify the request from the email address")              request = InfoRequest.holding_pen_request -            request.receive(email, raw_email, false, reason) +            request.receive(email, raw_email, false, reason) unless SpamAddress.spam?(email.to)              return          end diff --git a/app/models/spam_address.rb b/app/models/spam_address.rb new file mode 100644 index 000000000..15c9d1ab8 --- /dev/null +++ b/app/models/spam_address.rb @@ -0,0 +1,11 @@ +class SpamAddress < ActiveRecord::Base +    attr_accessible :email + +    validates_presence_of :email, :message => _('Please enter the email address to mark as spam') +    validates_uniqueness_of :email, :message => _('This address is already marked as spam') + +    def self.spam?(email_address) +        exists?(:email => email_address) +    end + +end diff --git a/app/models/track_thing.rb b/app/models/track_thing.rb index d5dda7bb5..13b6f78dd 100644 --- a/app/models/track_thing.rb +++ b/app/models/track_thing.rb @@ -69,66 +69,30 @@ class TrackThing < ActiveRecord::Base      end      def track_query_description -        # XXX this is very brittle... we should probably ask users -        # simply to name their tracks when they make them? -        original_text = parsed_text = self.track_query.gsub(/([()]|OR)/, "") -        filters = parsed_text.scan /\b\S+:\S+\b/ -        varieties = Set.new -        date = "" -        statuses = Set.new -        for filter in filters -            parsed_text = parsed_text.sub(filter, "") -            if filter =~ /variety:user/ -                varieties << _("users") -            end -            if filter =~ /variety:comment/ -                varieties << _("comments") -            end -            if filter =~ /variety:authority/ -                varieties << _("authorities") -            end -            if filter =~ /(variety:(sent|followup_sent|response)|latest_status)/ -                varieties << _("requests") -            end -            if filter =~ /[0-9\/]+\.\.[0-9\/]+/ -                date = _("between two dates") -            end -            if filter =~ /(rejected|not_held)/ -                statuses << _("unsuccessful") -            end -            if filter =~ /(:successful|:partially_successful)/ -                statuses << _("successful") -            end -            if filter =~ /waiting/ -                statuses << _("awaiting a response") -            end -        end -        if filters.empty? -            parsed_text = original_text -        end -        descriptions = [] -        if varieties.include? _("requests") -            if statuses.empty? -                # HACK: Relies on the 'descriptions.sort' below to luckily put this first -                descriptions << _("all requests") +        filter_description = query_filter_description('(variety:sent OR variety:followup_sent OR variety:response OR variety:comment)', +                                    :no_query => N_("all requests or comments"), +                                    :query => N_("all requests or comments matching text '{{query}}'")) +        return filter_description if filter_description +        filter_description = query_filter_description('(latest_status:successful OR latest_status:partially_successful)', +                                    :no_query => N_("requests which are successful"), +                                    :query => N_("requests which are successful matching text '{{query}}'")) +        return filter_description if filter_description +        return _("anything matching text '{{query}}'", :query => track_query) +    end + +    # Return a readable query description for queries involving commonly used filter clauses +    def query_filter_description(string, options) +        parsed_query = track_query.gsub(string, '') +        if parsed_query != track_query +            parsed_query.strip! +            if parsed_query.empty? +                _(options[:no_query])              else -                descriptions << _("requests which are {{list_of_statuses}}", :list_of_statuses => Array(statuses).sort.join(_(' or '))) +                _(options[:query], :query => parsed_query)              end -            varieties -= [_("requests")]          end -        if descriptions.empty? and varieties.empty? -            varieties << _("anything") -        end -        descriptions += Array(varieties) -        parsed_text = parsed_text.strip -        descriptions = descriptions.sort.join(_(" or ")) -        if !parsed_text.empty? -            descriptions += _("{{list_of_things}} matching text '{{search_query}}'", :list_of_things => "", :search_query => parsed_text) -        end -        return descriptions      end -      def TrackThing.create_track_for_request(info_request)          track_thing = TrackThing.new          track_thing.track_type = 'request_updates' @@ -194,30 +158,32 @@ class TrackThing < ActiveRecord::Base      end      # Return hash of text parameters describing the request etc. -    include LinkToHelper      def params          if @params.nil?              if self.track_type == 'request_updates'                  @params = {                      # Website -                    :list_description => _("'{{link_to_request}}', a request", -                                        :link_to_request => ("<a href=\"/request/" + CGI.escapeHTML(self.info_request.url_title) + "\">" + CGI.escapeHTML(self.info_request.title) + "</a>").html_safe), # XXX yeuch, sometimes I just want to call view helpers from the model, sorry! can't work out how +                      :verb_on_page => _("Follow this request"),                      :verb_on_page_already => _("You are already following this request"),                      # Email -                    :title_in_email => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title.html_safe), -                                         :title_in_rss => _("New updates for the request '{{request_title}}'", :request_title => self.info_request.title), +                    :title_in_email => _("New updates for the request '{{request_title}}'", +                                        :request_title => self.info_request.title.html_safe), +                    :title_in_rss => _("New updates for the request '{{request_title}}'", +                                        :request_title => self.info_request.title),                      # Authentication -                    :web => _("To follow the request '{{request_title}}'", :request_title => CGI.escapeHTML(self.info_request.title)), -                    :email => _("Then you will be updated whenever the request '{{request_title}}' is updated.", :request_title => CGI.escapeHTML(self.info_request.title)), -                    :email_subject => _("Confirm you want to follow the request '{{request_title}}'", :request_title => self.info_request.title), +                    :web => _("To follow the request '{{request_title}}'", +                                :request_title => self.info_request.title), +                    :email => _("Then you will be updated whenever the request '{{request_title}}' is updated.", +                                :request_title => self.info_request.title), +                    :email_subject => _("Confirm you want to follow the request '{{request_title}}'", +                                :request_title => self.info_request.title),                      # RSS sorting                      :feed_sortby => 'newest'                  }              elsif self.track_type == 'all_new_requests'                  @params = {                      # Website -                    :list_description => _("any <a href=\"/list\">new requests</a>"),                      :verb_on_page => _("Follow all new requests"),                      :verb_on_page_already => _("You are already following new requests"),                      # Email @@ -233,7 +199,6 @@ class TrackThing < ActiveRecord::Base              elsif self.track_type == 'all_successful_requests'                  @params = {                      # Website -                    :list_description => _("any <a href=\"/list/successful\">successful requests</a>"),                      :verb_on_page => _("Follow new successful responses"),                      :verb_on_page_already => _("You are following all new successful responses"),                      # Email @@ -252,39 +217,51 @@ class TrackThing < ActiveRecord::Base              elsif self.track_type == 'public_body_updates'                  @params = {                      # Website -                    :list_description => _("'{{link_to_authority}}', a public authority", :link_to_authority => ("<a href=\"/body/" + CGI.escapeHTML(self.public_body.url_name) + "\">" + CGI.escapeHTML(self.public_body.name) + "</a>").html_safe), # XXX yeuch, sometimes I just want to call view helpers from the model, sorry! can't work out how -                    :verb_on_page => _("Follow requests to {{public_body_name}}",:public_body_name=>CGI.escapeHTML(self.public_body.name)), -                    :verb_on_page_already => _("You are already following requests to {{public_body_name}}", :public_body_name=>CGI.escapeHTML(self.public_body.name)), +                    :verb_on_page => _("Follow requests to {{public_body_name}}", +                                        :public_body_name => self.public_body.name), +                    :verb_on_page_already => _("You are already following requests to {{public_body_name}}", +                                        :public_body_name => self.public_body.name),                      # Email -                    :title_in_email => self.public_body.law_only_short + " requests to '" + self.public_body.name + "'", -                    :title_in_rss => self.public_body.law_only_short + " requests to '" + self.public_body.name + "'", +                    :title_in_email => _("{{foi_law}} requests to '{{public_body_name}}'", +                                        :foi_law => self.public_body.law_only_short, +                                        :public_body_name => self.public_body.name), +                    :title_in_rss => _("{{foi_law}} requests to '{{public_body_name}}'", +                                        :foi_law => self.public_body.law_only_short, +                                        :public_body_name => self.public_body.name),                      # Authentication -                    :web => _("To follow requests made using {{site_name}} to the public authority '{{public_body_name}}'", :site_name=>AlaveteliConfiguration::site_name, :public_body_name=>CGI.escapeHTML(self.public_body.name)), -                    :email => _("Then you will be notified whenever someone requests something or gets a response from '{{public_body_name}}'.", :public_body_name=>CGI.escapeHTML(self.public_body.name)), -                    :email_subject => _("Confirm you want to follow requests to '{{public_body_name}}'", :public_body_name=>self.public_body.name), +                    :web => _("To follow requests made using {{site_name}} to the public authority '{{public_body_name}}'", +                                :site_name => AlaveteliConfiguration::site_name, +                                :public_body_name => self.public_body.name), +                    :email => _("Then you will be notified whenever someone requests something or gets a response from '{{public_body_name}}'.", +                                :public_body_name => self.public_body.name), +                    :email_subject => _("Confirm you want to follow requests to '{{public_body_name}}'", +                                :public_body_name => self.public_body.name),                      # RSS sorting                      :feed_sortby => 'newest'                  }              elsif self.track_type == 'user_updates'                  @params = {                      # Website -                    :list_description => _("'{{link_to_user}}', a person", :link_to_user => ("<a href=\"/user/" + CGI.escapeHTML(self.tracked_user.url_name) + "\">" + CGI.escapeHTML(self.tracked_user.name) + "</a>").html_safe), # XXX yeuch, sometimes I just want to call view helpers from the model, sorry! can't work out how                      :verb_on_page => _("Follow this person"),                      :verb_on_page_already => _("You are already following this person"),                      # Email -                    :title_in_email => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name.html_safe), -                    :title_in_rss => _("FOI requests by '{{user_name}}'", :user_name=>self.tracked_user.name), +                    :title_in_email => _("FOI requests by '{{user_name}}'", +                                        :user_name => self.tracked_user.name.html_safe), +                    :title_in_rss => _("FOI requests by '{{user_name}}'", +                                        :user_name => self.tracked_user.name),                      # Authentication -                    :web => _("To follow requests by '{{user_name}}'", :user_name=>CGI.escapeHTML(self.tracked_user.name)), -                    :email => _("Then you will be notified whenever '{{user_name}}' requests something or gets a response.", :user_name=>CGI.escapeHTML(self.tracked_user.name)), -                    :email_subject => _("Confirm you want to follow requests by '{{user_name}}'", :user_name=>self.tracked_user.name), +                    :web => _("To follow requests by '{{user_name}}'", +                                :user_name=> self.tracked_user.name), +                    :email => _("Then you will be notified whenever '{{user_name}}' requests something or gets a response.", +                                :user_name => self.tracked_user.name), +                    :email_subject => _("Confirm you want to follow requests by '{{user_name}}'", +                                :user_name => self.tracked_user.name),                      # RSS sorting                      :feed_sortby => 'newest'                  }              elsif self.track_type == 'search_query'                  @params = {                      # Website -                    :list_description => ("<a href=\"/search/" + CGI.escapeHTML(self.track_query) + "/newest/advanced\">" + CGI.escapeHTML(self.track_query_description) + "</a>").html_safe, # XXX yeuch, sometimes I just want to call view helpers from the model, sorry! can't work out how                      :verb_on_page => _("Follow things matching this search"),                      :verb_on_page_already => _("You are already following things matching this search"),                      # Email diff --git a/app/views/admin_request/_incoming_message_actions.html.erb b/app/views/admin_request/_incoming_message_actions.html.erb index 4cf099b53..dd50eb047 100644 --- a/app/views/admin_request/_incoming_message_actions.html.erb +++ b/app/views/admin_request/_incoming_message_actions.html.erb @@ -22,6 +22,13 @@    </div>   </div> +  <div class="control-group"> +    <label class="control-label">Mark <code>To:</code> address as spam</label> +    <div class="controls"> +      <%= link_to 'Spam Addresses', spam_addresses_path %> +    </div> +  </div> +   <%= form_tag admin_incoming_destroy_path, :class => "form form-inline" do %>    <div class="control-group">     <label class="control-label" for="destroy_message_<%= incoming_message.id %>">Destroy message</label> diff --git a/app/views/admin_spam_addresses/index.html.erb b/app/views/admin_spam_addresses/index.html.erb new file mode 100644 index 000000000..9846bc017 --- /dev/null +++ b/app/views/admin_spam_addresses/index.html.erb @@ -0,0 +1,51 @@ +<% @title = 'Spam Addresses' %> + +<h1><%= @title %></h1> + +<div class="row"> +    <div class="span12"> +        <p> +            Incoming mail that gets redirected to the holding pen will be +            rejected if it is sent <code>To:</code> an address on this +            list. +        </p> +    </div> +</div> + +<hr /> + +<div class="row"> +    <div class="span12"> +        <%= form_for(@spam_address, :html => { :class => 'form-inline' }) do |f| -%> +            <%= error_messages_for @spam_address %> +            <%= f.text_field :email, :class => 'input-xxlarge', :placeholder => 'Enter email' %> +            <%= f.submit 'Add Spam Address', :class => 'btn btn-warning' %> +        <% end -%> +    </div> +</div> + +<hr /> + +<% if @spam_addresses.any? %> +    <div class="row"> +        <table class="table table-hover span12"> +            <thead> +                <tr> +                    <th>Email</th> +                    <th></th> +                </tr> +            </thead> +            <tbody> +                <% @spam_addresses.each do |spam| %> +                    <tr> +                        <td><%= spam.email %></td> +                        <td><%= link_to 'Remove', spam, +                                    :method => :delete, +                                    :confirm => 'This is permanent! Are you sure?', +                                    :class => 'btn btn-mini btn-danger' %></td> +                    </tr> +                <% end %> +            </tbody> +        </table> +    </div> +<% end %> diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index c1f9335b1..2147f22e1 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb @@ -2,6 +2,8 @@  <html lang="en-gb">      <head>        <meta http-equiv="content-type" content="text/html;charset=UTF-8" > +      <%= csrf_meta_tags %> +        <title><%= site_name %> admin<%= @title ? ":" : "" %> <%=@title%></title>        <%= javascript_include_tag "admin" %> diff --git a/app/views/layouts/default.html.erb b/app/views/layouts/default.html.erb index 79d7b9c93..93b3c3698 100644 --- a/app/views/layouts/default.html.erb +++ b/app/views/layouts/default.html.erb @@ -2,6 +2,8 @@  <html lang="<%= I18n.locale %>">      <head>          <meta charset="utf-8"> +        <%= csrf_meta_tags %> +          <title>          <% if @title %>              <%=@title%> - <%= site_name %> diff --git a/app/views/layouts/no_chrome.html.erb b/app/views/layouts/no_chrome.html.erb index e613b8ca2..a4278ab24 100644 --- a/app/views/layouts/no_chrome.html.erb +++ b/app/views/layouts/no_chrome.html.erb @@ -2,6 +2,8 @@  <html lang="<%= I18n.locale %>">      <head>          <meta charset="utf-8"> +        <%= csrf_meta_tags %> +          <title>          <% if @title %>              <%=@title%> - <%= site_name %> diff --git a/app/views/track/_track_set.erb b/app/views/track/_track_set.erb new file mode 100644 index 000000000..c7665312d --- /dev/null +++ b/app/views/track/_track_set.erb @@ -0,0 +1,6 @@ +<% if @user.receive_email_alerts %> +  <%= subscribe_email_notice(@track_thing) %> +  <%= link_to(_('Prefer not to receive emails?'), show_user_wall_path(:url_name => @user.url_name)) %> +<% else %> +  <%= subscribe_follow_notice(@track_thing) %> +<% end %> diff --git a/app/views/user/show.html.erb b/app/views/user/show.html.erb index 1ccb1d649..8dd8c6b88 100644 --- a/app/views/user/show.html.erb +++ b/app/views/user/show.html.erb @@ -224,7 +224,7 @@                  <li>                      <%= form_tag({:controller => 'track', :action => 'update', :track_id => track_thing.id}, :class => "feed_form") do %>                          <div> -                            <%= track_thing.params[:list_description] %> +                            <%= track_description(track_thing) %>                              <%= hidden_field_tag 'track_medium', "delete", { :id => 'track_medium_' + track_thing.id.to_s } %>                              <%= hidden_field_tag 'r', request.fullpath, { :id => 'r_' + track_thing.id.to_s }  %>                              <%= submit_tag _('unsubscribe') %> diff --git a/config/crontab-example b/config/crontab-example index 64d0c45c9..8fe13151b 100644 --- a/config/crontab-example +++ b/config/crontab-example @@ -12,7 +12,7 @@ MAILTO=cron-!!(*= $site *)!!@mysociety.org  # Every 10 minutes  5,15,25,35,45,55 * * * * !!(*= $user *)!! /etc/init.d/foi-alert-tracks check  5,15,25,35,45,55 * * * * !!(*= $user *)!! /etc/init.d/foi-purge-varnish check -0,10,20,30,40,50 * * * * !!(*= $user *)!! run-with-lockfile -n /data/vhost/!!(*= $vhost *)!!/send-batch-requests.lock /data/vhost/!!(*= $vhost *)!!/!!(*= $vcspath *)!!/script/send-batch-requests || echo "stalled?" +0,10,20,30,40,50 * * * * !!(*= $user *)!! run-with-lockfile -n !!(*= $vhost_dir *)!!/send-batch-requests.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/send-batch-requests || echo "stalled?"  # Once an hour  09 * * * * !!(*= $user *)!! run-with-lockfile -n !!(*= $vhost_dir *)!!/alert-comment-on-request.lock !!(*= $vhost_dir *)!!/!!(*= $vcspath *)!!/script/alert-comment-on-request || echo "stalled?" diff --git a/config/routes.rb b/config/routes.rb index 1079fbe14..d9d21f0bd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -248,6 +248,14 @@ Alaveteli::Application.routes.draw do      match '/admin/censor/destroy/:censor_rule_id' => 'admin_censor_rule#destroy', :as => :admin_rule_destroy      #### +    #### AdminSpamAddresses controller +    scope '/admin' do +        resources :spam_addresses, +                  :controller => 'admin_spam_addresses', +                  :only => [:index, :create, :destroy] +    end +    #### +      #### Api controller      match '/api/v2/request.json' => 'api#create_request', :as => :api_create_request, :via => :post diff --git a/db/migrate/20140325120619_create_spam_addresses.rb b/db/migrate/20140325120619_create_spam_addresses.rb new file mode 100644 index 000000000..7c730a5c7 --- /dev/null +++ b/db/migrate/20140325120619_create_spam_addresses.rb @@ -0,0 +1,9 @@ +class CreateSpamAddresses < ActiveRecord::Migration +  def change +    create_table :spam_addresses do |t| +      t.string :email, :null => false + +      t.timestamps +    end +  end +end diff --git a/spec/controllers/admin_spam_addresses_controller_spec.rb b/spec/controllers/admin_spam_addresses_controller_spec.rb new file mode 100644 index 000000000..da1e9bb5a --- /dev/null +++ b/spec/controllers/admin_spam_addresses_controller_spec.rb @@ -0,0 +1,91 @@ +require 'spec_helper' + +describe AdminSpamAddressesController do +    render_views +    before { basic_auth_login @request } + +    describe :index do + +        it 'lists the spam addresses' do +            3.times { FactoryGirl.create(:spam_address) } +            get :index +            assigns(:spam_addresses).should == SpamAddress.all +        end + +        it 'creates a new spam address for the form' do +            get :index +            expect(assigns(:spam_address)).to be_a_new(SpamAddress) +        end + +        it 'renders the index template' do +            get :index +            expect(response).to render_template('index') +        end + +    end + +    describe :create do + +        let(:spam_params) { FactoryGirl.attributes_for(:spam_address) } + +        it 'creates a new spam address with the given parameters' do +            post :create, :spam_address => spam_params +            assigns(:spam_address).email.should == spam_params[:email] +            assigns(:spam_address).should be_persisted +        end + +        it 'redirects to the index action if successful' do +            SpamAddress.any_instance.stub(:save).and_return(true) +            post :create, :spam_address => spam_params +            expect(response).to redirect_to(spam_addresses_path) +        end + +        it 'notifies the admin the spam address has been created' do +            SpamAddress.any_instance.stub(:save).and_return(true) +            post :create, :spam_address => spam_params +            msg = "#{ spam_params[:email] } has been added to the spam addresses list" +            flash[:notice].should == msg +        end + +        it 'renders the index action if the address could not be saved' do +            SpamAddress.any_instance.stub(:save).and_return(false) +            post :create, :spam_address => spam_params +            expect(response).to render_template('index') +        end + +        it 'collects the spam addresses if the address could not be saved' do +            3.times { FactoryGirl.create(:spam_address) } +            SpamAddress.any_instance.stub(:save).and_return(false) +            post :create, :spam_address => spam_params +            assigns(:spam_addresses).should == SpamAddress.all +        end + +    end + +    describe :delete do + +        before(:each) do +            @spam = FactoryGirl.create(:spam_address) +            delete :destroy, :id => @spam.id +        end + +        it 'finds the spam address to delete' do +            assigns(:spam_address).should == @spam +        end + +        it 'destroys the spam address' do +            assigns(:spam_address).should be_destroyed +        end + +        it 'tells the admin the spam address has been deleted' do +            msg = "#{ @spam.email } has been removed from the spam addresses list" +            flash[:notice].should == msg +        end + +        it 'redirects to the index action' do +            expect(response).to redirect_to(spam_addresses_path) +        end + +    end + +end diff --git a/spec/controllers/track_controller_spec.rb b/spec/controllers/track_controller_spec.rb index 40865d2b9..d2b45b6bf 100644 --- a/spec/controllers/track_controller_spec.rb +++ b/spec/controllers/track_controller_spec.rb @@ -5,7 +5,7 @@ describe TrackController, "when making a new track on a request" do          @ir = mock_model(InfoRequest, :url_title => 'myrequest',                                        :title => 'My request')          @track_thing = mock_model(TrackThing, :save! => true, -                                              :params => {:list_description => 'list description'}, +                                              :params => {},                                                :track_medium= => nil,                                                :tracking_user_id= => nil)          TrackThing.stub!(:create_track_for_request).and_return(@track_thing) @@ -58,7 +58,7 @@ end  describe TrackController, "when unsubscribing from a track" do      before do -        @track_thing = FactoryGirl.create(:track_thing) +        @track_thing = FactoryGirl.create(:search_track)      end      it 'should destroy the track thing' do @@ -78,7 +78,7 @@ describe TrackController, "when unsubscribing from a track" do      end      it 'should not redirect to a url on another site' do -        track_thing = FactoryGirl.create(:track_thing) +        track_thing = FactoryGirl.create(:search_track)          get :update, {:track_id => @track_thing.id,                        :track_medium => 'delete',                        :r => 'http://example.com/'}, diff --git a/spec/factories.rb b/spec/factories.rb deleted file mode 100644 index 7dec41aaf..000000000 --- a/spec/factories.rb +++ /dev/null @@ -1,6 +0,0 @@ -# Factories are defined in spec/factories/*.rb -# -# You can use this file to define shared sequences -FactoryGirl.define do - -end diff --git a/spec/factories/spam_addresses.rb b/spec/factories/spam_addresses.rb new file mode 100644 index 000000000..bafb7cd50 --- /dev/null +++ b/spec/factories/spam_addresses.rb @@ -0,0 +1,5 @@ +FactoryGirl.define do +    factory :spam_address do +        sequence(:email) { |n| "spam-#{ n }@example.org" } +    end +end diff --git a/spec/factories/track_things.rb b/spec/factories/track_things.rb index d1a937c02..cf76b00b3 100644 --- a/spec/factories/track_things.rb +++ b/spec/factories/track_things.rb @@ -2,9 +2,29 @@ FactoryGirl.define do      factory :track_thing do          association :tracking_user, :factory => :user -        track_medium 'email_daily' -        track_type 'search_query' -        track_query 'Example Query' +        factory :search_track do +            track_medium 'email_daily' +            track_type 'search_query' +            track_query 'Example Query' +        end +        factory :user_track do +            association :tracked_user, :factory => :user +            track_type 'user_updates' +        end +        factory :public_body_track do +            association :public_body, :factory => :public_body +            track_type 'public_body_updates' +        end +        factory :request_update_track do +            association :info_request, :factory => :info_request +            track_type 'request_updates' +        end +        factory :successful_request_track do +            track_type 'all_successful_requests' +        end +        factory :new_request_track do +            track_type 'all_new_requests' +        end      end  end diff --git a/spec/helpers/track_helper_spec.rb b/spec/helpers/track_helper_spec.rb new file mode 100644 index 000000000..80857067b --- /dev/null +++ b/spec/helpers/track_helper_spec.rb @@ -0,0 +1,204 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe TrackHelper do + +    include TrackHelper +    include LinkToHelper + +    describe 'when displaying notices for a search track' do + +        before do +            @track_thing = FactoryGirl.build(:search_track) +        end + +        it 'should create an already subscribed_notice' do +            expected = %Q(You are already subscribed to <a href="/search/Example%20Query/newest/advanced">this search</a>) +            already_subscribed_notice(@track_thing).should == expected +        end + +        it 'should create an email subscription notice' do +            expected = %Q(You will now be emailed updates about <a href="/search/Example%20Query/newest/advanced">this search</a>) +            subscribe_email_notice(@track_thing).should == expected +        end + +        it 'should create a following subscription notice' do +            expected = %Q(You are now <a href="#{show_user_wall_path(:url_name => @track_thing.tracking_user.url_name)}">following</a> updates about <a href="/search/Example%20Query/newest/advanced">this search</a>) +            subscribe_follow_notice(@track_thing).should == expected +        end + +        it 'should create an unsubscribe notice' do +            expected = %Q(You are no longer following <a href="/search/Example%20Query/newest/advanced">this search</a>) +            unsubscribe_notice(@track_thing).should == expected +        end + +        it 'should create a description of the track' do +            expected = %Q(<a href="/search/Example%20Query/newest/advanced">anything matching text 'Example Query'</a>) +            track_description(@track_thing).should == expected +        end + +    end + +    describe 'when displaying notices for a user track' do + +        before do +            @track_thing = FactoryGirl.build(:user_track) +        end + +        it 'should create an already subscribed_notice' do +            expected = %Q(You are already subscribed to '#{user_link(@track_thing.tracked_user)}', a person) +            already_subscribed_notice(@track_thing).should == expected +        end + +        it 'should create an email subscription notice' do +            expected = %Q(You will now be emailed updates about '#{user_link(@track_thing.tracked_user)}', a person) +            subscribe_email_notice(@track_thing).should == expected +        end + +        it 'should create a following subscription notice' do +            expected = %Q(You are now <a href="#{show_user_wall_path(:url_name => @track_thing.tracking_user.url_name)}">following</a> updates about '#{user_link(@track_thing.tracked_user)}', a person) +            subscribe_follow_notice(@track_thing).should == expected +        end + +        it 'should create an unsubscribe notice' do +            expected = %Q(You are no longer following '#{user_link(@track_thing.tracked_user)}', a person) +            unsubscribe_notice(@track_thing).should == expected +        end + +        it 'should create a description of the track' do +            expected = %Q('#{user_link(@track_thing.tracked_user)}', a person) +            track_description(@track_thing).should == expected +        end + +    end + +    describe 'when displaying notices for a public body track' do + +        before do +            @track_thing = FactoryGirl.build(:public_body_track) +        end + +        it 'should create an already subscribed_notice' do +            expected = %Q(You are already subscribed to '#{public_body_link(@track_thing.public_body)}', a public authority) +            already_subscribed_notice(@track_thing).should == expected +        end + +        it 'should create an email subscription notice' do +            expected = %Q(You will now be emailed updates about '#{public_body_link(@track_thing.public_body)}', a public authority) +            subscribe_email_notice(@track_thing).should == expected +        end + +        it 'should create a following subscription notice' do +            expected = %Q(You are now <a href="#{show_user_wall_path(:url_name => @track_thing.tracking_user.url_name)}">following</a> updates about '#{public_body_link(@track_thing.public_body)}', a public authority) +            subscribe_follow_notice(@track_thing).should == expected +        end + +        it 'should create an unsubscribe notice' do +            expected = %Q(You are no longer following '#{public_body_link(@track_thing.public_body)}', a public authority) +            unsubscribe_notice(@track_thing).should == expected +        end + +        it 'should create a description of the track' do +            expected = %Q('#{public_body_link(@track_thing.public_body)}', a public authority) +            track_description(@track_thing).should == expected +        end +    end + +    describe 'when displaying notices for a successful request track' do + +        before do +            @track_thing = FactoryGirl.build(:successful_request_track) +        end + +        it 'should create an already subscribed_notice' do +            expected = %Q(You are already subscribed to any <a href="/list/successful">successful requests</a>) +            already_subscribed_notice(@track_thing).should == expected +        end + +        it 'should create an email subscription notice' do +            expected = %Q(You will now be emailed updates about <a href="/list/successful">successful requests</a>) +            subscribe_email_notice(@track_thing).should == expected +        end + +        it 'should create a following subscription notice' do +            expected = %Q(You are now <a href="#{show_user_wall_path(:url_name => @track_thing.tracking_user.url_name)}">following</a> updates about <a href="/list/successful">successful requests</a>) +            subscribe_follow_notice(@track_thing).should == expected +        end + +        it 'should create an unsubscribe notice' do +            expected = %Q(You are no longer following <a href="/list/successful">successful requests</a>) +            unsubscribe_notice(@track_thing).should == expected +        end + +        it 'should create a description of the track' do +            expected = %Q(<a href="/list/successful">successful requests</a>) +            track_description(@track_thing).should == expected +        end +    end + +    describe 'when displaying notices for a new request track' do + +        before do +            @track_thing = FactoryGirl.build(:new_request_track) +        end + +        it 'should create an already subscribed_notice' do +            expected = %Q(You are already subscribed to any <a href="/list">new requests</a>) +            already_subscribed_notice(@track_thing).should == expected +        end + +        it 'should create an email subscription notice' do +            expected = %Q(You will now be emailed updates about any <a href="/list">new requests</a>) +            subscribe_email_notice(@track_thing).should == expected +        end + +        it 'should create a following subscription notice' do +            expected = %Q(You are now <a href="#{show_user_wall_path(:url_name => @track_thing.tracking_user.url_name)}">following</a> updates about <a href="/list">new requests</a>) +            subscribe_follow_notice(@track_thing).should == expected +        end + +        it 'should create an unsubscribe notice' do +            expected = %Q(You are no longer following <a href="/list">new requests</a>) +            unsubscribe_notice(@track_thing).should == expected +        end + +        it 'should create a description of the track' do +            expected = %Q(<a href="/list">new requests</a>) +            track_description(@track_thing).should == expected +        end + +    end + +    describe 'when displaying notices for a request update track' do + +        before do +            @track_thing = FactoryGirl.build(:request_update_track) +        end + +        it 'should create an already subscribed_notice' do +            expected = %Q(You are already subscribed to '#{request_link(@track_thing.info_request)}', a request) +            already_subscribed_notice(@track_thing).should == expected +        end + +        it 'should create an email subscription notice' do +            expected = %Q(You will now be emailed updates about '#{request_link(@track_thing.info_request)}', a request) +            subscribe_email_notice(@track_thing).should == expected +        end + +        it 'should create a following subscription notice' do +            expected = %Q(You are now <a href="#{show_user_wall_path(:url_name => @track_thing.tracking_user.url_name)}">following</a> updates about '#{request_link(@track_thing.info_request)}', a request) +            subscribe_follow_notice(@track_thing).should == expected +        end + +        it 'should create an unsubscribe notice' do +            expected = %Q(You are no longer following '#{request_link(@track_thing.info_request)}', a request) +            unsubscribe_notice(@track_thing).should == expected +        end + +        it 'should create a description of the track' do +            expected = %Q('#{request_link(@track_thing.info_request)}', a request) +            track_description(@track_thing).should == expected +        end + +    end + +end diff --git a/spec/mailers/request_mailer_spec.rb b/spec/mailers/request_mailer_spec.rb index 516d13127..2c5d6e6a9 100644 --- a/spec/mailers/request_mailer_spec.rb +++ b/spec/mailers/request_mailer_spec.rb @@ -78,6 +78,16 @@ describe RequestMailer, " when receiving incoming mail" do          deliveries.clear      end +    it "should ignore mail sent to known spam addresses" do +        @spam_address = FactoryGirl.create(:spam_address) + +        receive_incoming_mail('incoming-request-plain.email', @spam_address.email) + +        deliveries = ActionMailer::Base.deliveries +        deliveries.size.should == 0 +        deliveries.clear +    end +      it "should return incoming mail to sender when a request is stopped fully for spam" do          # mark request as anti-spam          ir = info_requests(:fancy_dog_request) diff --git a/spec/models/spam_address_spec.rb b/spec/models/spam_address_spec.rb new file mode 100644 index 000000000..79a1afd11 --- /dev/null +++ b/spec/models/spam_address_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe SpamAddress do + +    describe :new do + +        it 'requres an email address' do +            SpamAddress.new().should_not be_valid +            SpamAddress.new(:email => 'spam@example.org').should be_valid +        end + +        it 'must have a unique email address' do +            existing = FactoryGirl.create(:spam_address) +            SpamAddress.new(:email => existing.email).should_not be_valid +        end + +    end + +    describe '.spam?' do + +        before(:each) do +            @spam_address = FactoryGirl.create(:spam_address) +        end + +        it 'is a spam address if the address is stored' do +           SpamAddress.spam?(@spam_address.email).should be_true +        end + +        it 'is not a spam address if the adress is not stored' do +            SpamAddress.spam?('genuine-email@example.com').should be_false +        end + +        describe 'when accepting an array of emails' do + +            it 'is spam if any of the emails are stored' do +                emails = ['genuine-email@example.com', @spam_address.email] +                SpamAddress.spam?(emails).should be_true +            end +  +            it 'is not spam if none of the emails are stored' do +                emails = ['genuine-email@example.com', 'genuine-email@example.org'] +                SpamAddress.spam?(emails).should be_false +            end +  +        end + +    end + +end diff --git a/spec/models/track_thing_spec.rb b/spec/models/track_thing_spec.rb index 1c582564b..3edf2d1ad 100644 --- a/spec/models/track_thing_spec.rb +++ b/spec/models/track_thing_spec.rb @@ -51,10 +51,11 @@ describe TrackThing, "when tracking changes" do      end      it "will make some sane descriptions of search-based tracks" do -        tests = { 'bob variety:user' => "users matching text 'bob'", -                  'bob (variety:sent OR variety:followup_sent OR variety:response OR variety:comment) (latest_status:successful OR latest_status:partially_successful OR latest_status:rejected OR latest_status:not_held)' => "comments or requests which are successful or unsuccessful matching text 'bob'", -                  '(latest_status:waiting_response OR latest_status:waiting_clarification OR waiting_classification:true)' => 'requests which are awaiting a response', -                  ' (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)' => 'all requests or comments' } +        tests = { ' (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)' => 'all requests or comments', +                  'bob (variety:sent OR variety:followup_sent OR variety:response OR variety:comment)' => "all requests or comments matching text 'bob'", +                  'bob (latest_status:successful OR latest_status:partially_successful)' => "requests which are successful matching text 'bob'", +                  '(latest_status:successful OR latest_status:partially_successful)' => 'requests which are successful', +                  'bob' => "anything matching text 'bob'" }          tests.each do |query, description|              track_thing = TrackThing.create_track_for_search_query(query)              track_thing.track_query_description.should == description | 
