diff options
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r-- | perllib/FixMyStreet/Alert.pm | 106 | ||||
-rwxr-xr-x | perllib/FixMyStreet/App/Controller/Rss.pm | 143 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Alert.pm | 16 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/AlertSent.pm | 38 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/AlertType.pm | 55 |
5 files changed, 248 insertions, 110 deletions
diff --git a/perllib/FixMyStreet/Alert.pm b/perllib/FixMyStreet/Alert.pm index 06873c228..1857abbba 100644 --- a/perllib/FixMyStreet/Alert.pm +++ b/perllib/FixMyStreet/Alert.pm @@ -21,11 +21,9 @@ use Error qw(:try); use File::Slurp; use FindBin; use POSIX qw(strftime); -use XML::RSS; use Cobrand; use mySociety::AuthToken; -use mySociety::Config; use mySociety::DBHandle qw(dbh); use mySociety::Email; use mySociety::EmailUtil; @@ -33,8 +31,6 @@ use mySociety::Gaze; use mySociety::Locale; use mySociety::MaPit; use mySociety::Random qw(random_bytes); -use mySociety::Sundries qw(ordinal); -use mySociety::Web qw(ent); # Add a new alert sub create ($$$$;@) { @@ -244,105 +240,3 @@ sub _send_aggregated_alert_email(%) { } } -sub generate_rss ($) { - my $c = shift; - my $type = $c->stash->{type}; - $c->stash->{qs} ||= ''; - $c->stash->{db_params} ||= []; - my $cobrand_data = $c->cobrand->extra_data; - my $q = dbh()->prepare('select * from alert_type where ref=?'); - $q->execute($type); - my $alert_type = $q->fetchrow_hashref; - my ($site_restriction, $site_id) = $c->cobrand->site_restriction($cobrand_data); - throw FixMyStreet::Alert::Error('Unknown alert type') unless $alert_type; - - # Do our own encoding - my $rss = new XML::RSS( version => '2.0', encoding => 'UTF-8', - stylesheet=> $c->cobrand->feed_xsl, encode_output => undef ); - $rss->add_module(prefix=>'georss', uri=>'http://www.georss.org/georss'); - - # Only apply a site restriction if the alert uses the problem table - $site_restriction = '' unless $alert_type->{item_table} eq 'problem'; - my $query = 'select * from ' . $alert_type->{item_table} . ' where ' - . ($alert_type->{head_table} ? $alert_type->{head_table}.'_id=? and ' : '') - . $alert_type->{item_where} . $site_restriction . ' order by ' - . $alert_type->{item_order}; - my $rss_limit = mySociety::Config::get('RSS_LIMIT'); - $query .= " limit $rss_limit" unless $type =~ /^all/; - $q = dbh()->prepare($query); - if ($query =~ /\?/) { - throw FixMyStreet::Alert::Error('Missing parameter') unless @{ $c->stash->{db_params} }; - $q->execute( @{ $c->stash->{db_params} } ); - } else { - $q->execute(); - } - - while (my $row = $q->fetchrow_hashref) { - - $row->{name} ||= 'anonymous'; - - my $pubDate; - if ($row->{confirmed}) { - $row->{confirmed} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/; - $pubDate = mySociety::Locale::in_gb_locale { - strftime("%a, %d %b %Y %H:%M:%S %z", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0) - }; - $row->{confirmed} = strftime("%e %B", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0); - $row->{confirmed} =~ s/^\s+//; - $row->{confirmed} =~ s/^(\d+)/ordinal($1)/e if $mySociety::Locale::lang eq 'en-gb'; - } - - (my $title = _($alert_type->{item_title})) =~ s/{{(.*?)}}/$row->{$1}/g; - (my $link = $alert_type->{item_link}) =~ s/{{(.*?)}}/$row->{$1}/g; - (my $desc = _($alert_type->{item_description})) =~ s/{{(.*?)}}/$row->{$1}/g; - my $url = $c->uri_for( $link ); - my %item = ( - title => ent($title), - link => $url, - guid => $url, - description => ent(ent($desc)) # Yes, double-encoded, really. - ); - $item{pubDate} = $pubDate if $pubDate; - $item{category} = $row->{category} if $row->{category}; - - my $display_photos = $c->cobrand->allow_photo_display; - if ($display_photos && $row->{photo}) { - $item{description} .= ent("\n<br><img src=\"". $c->uri_for( $c->cobrand->base_url ) . "/photo?id=$row->{id}\">"); - } - my $recipient_name = $c->cobrand->contact_name; - $item{description} .= ent("\n<br><a href='$url'>" . - sprintf(_("Report on %s"), $recipient_name) . "</a>"); - - if ($row->{latitude} || $row->{longitude}) { - $item{georss} = { point => "$row->{latitude} $row->{longitude}" }; - } - $rss->add_item( %item ); - } - - my $row = {}; - if ($alert_type->{head_sql_query}) { - $q = dbh()->prepare($alert_type->{head_sql_query}); - if ($alert_type->{head_sql_query} =~ /\?/) { - $q->execute(@{ $c->stash->{db_params} }); - } else { - $q->execute(); - } - $row = $q->fetchrow_hashref; - } - foreach ( keys %{ $c->stash->{title_params} } ) { - $row->{$_} = $c->stash->{title_params}->{$_}; - } - (my $title = _($alert_type->{head_title})) =~ s/{{(.*?)}}/$row->{$1}/g; - (my $link = $alert_type->{head_link}) =~ s/{{(.*?)}}/$row->{$1}/g; - (my $desc = _($alert_type->{head_description})) =~ s/{{(.*?)}}/$row->{$1}/g; - $rss->channel( - title => ent($title), link => $link . $c->stash->{qs}, description => ent($desc), - language => 'en-gb' - ); - - my $out = $rss->as_string; - my $uri = $c->uri_for( '/' . $c->req->path ); - $out =~ s{<link>(.*?)</link>}{"<link>" . $c->uri_for( $1 ) . "</link><uri>$uri</uri>"}e; - - return $out; -} diff --git a/perllib/FixMyStreet/App/Controller/Rss.pm b/perllib/FixMyStreet/App/Controller/Rss.pm index fa9e3a4de..f41ffe217 100755 --- a/perllib/FixMyStreet/App/Controller/Rss.pm +++ b/perllib/FixMyStreet/App/Controller/Rss.pm @@ -2,11 +2,15 @@ package FixMyStreet::App::Controller::Rss; use Moose; use namespace::autoclean; +use POSIX qw(strftime); use URI::Escape; -use FixMyStreet::Alert; +use XML::RSS; + use mySociety::Gaze; use mySociety::Locale; use mySociety::MaPit; +use mySociety::Sundries qw(ordinal); +use mySociety::Web qw(ent); BEGIN { extends 'Catalyst::Controller'; } @@ -157,8 +161,143 @@ sub local_problems_ll : Private { sub output : Private { my ( $self, $c ) = @_; + + $c->stash->{alert_type} = $c->model('DB::AlertType')->find( { ref => $c->stash->{type} } ); + $c->detach( '/page_error_404_not_found', [ _('Unknown alert type') ] ) + unless $c->stash->{alert_type}; + + $c->forward( 'query_main' ); + + # Do our own encoding + $c->stash->{rss} = new XML::RSS( + version => '2.0', + encoding => 'UTF-8', + stylesheet => $c->cobrand->feed_xsl, + encode_output => undef + ); + $c->stash->{rss}->add_module( + prefix => 'georss', + uri => 'http://www.georss.org/georss' + ); + + while (my $row = $c->stash->{query_main}->fetchrow_hashref) { + $c->forward( 'add_row', [ $row ] ); + } + + $c->forward( 'add_parameters' ); + + my $out = $c->stash->{rss}->as_string; + my $uri = $c->uri_for( '/' . $c->req->path ); + $out =~ s{<link>(.*?)</link>}{"<link>" . $c->uri_for( $1 ) . "</link><uri>$uri</uri>"}e; + $c->response->header('Content-Type' => 'application/xml; charset=utf-8'); - $c->response->body( FixMyStreet::Alert::generate_rss( $c ) ); + $c->response->body( $out ); +} + +sub query_main : Private { + my ( $self, $c ) = @_; + my $alert_type = $c->stash->{alert_type}; + + my ( $site_restriction, $site_id ) = $c->cobrand->site_restriction( $c->cobrand->extra_data ); + # Only apply a site restriction if the alert uses the problem table + $site_restriction = '' unless $alert_type->item_table eq 'problem'; + + # FIXME Do this in a nicer way at some point in the future... + my $query = 'select * from ' . $alert_type->item_table . ' where ' + . ($alert_type->head_table ? $alert_type->head_table . '_id=? and ' : '') + . $alert_type->item_where . $site_restriction . ' order by ' + . $alert_type->item_order; + my $rss_limit = mySociety::Config::get('RSS_LIMIT'); + $query .= " limit $rss_limit" unless $c->stash->{type} =~ /^all/; + + my $q = $c->model('DB::Alert')->result_source->storage->dbh->prepare($query); + + $c->stash->{db_params} ||= []; + if ($query =~ /\?/) { + $c->detach( '/page_error_404_not_found', [ 'Missing parameter' ] ) + unless @{ $c->stash->{db_params} }; + $q->execute( @{ $c->stash->{db_params} } ); + } else { + $q->execute(); + } + $c->stash->{query_main} = $q; +} + +sub add_row : Private { + my ( $self, $c, $row ) = @_; + my $alert_type = $c->stash->{alert_type}; + + $row->{name} ||= 'anonymous'; + + my $pubDate; + if ($row->{confirmed}) { + $row->{confirmed} =~ /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/; + $pubDate = mySociety::Locale::in_gb_locale { + strftime("%a, %d %b %Y %H:%M:%S %z", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0) + }; + $row->{confirmed} = strftime("%e %B", $6, $5, $4, $3, $2-1, $1-1900, -1, -1, 0); + $row->{confirmed} =~ s/^\s+//; + $row->{confirmed} =~ s/^(\d+)/ordinal($1)/e if $c->stash->{lang_code} eq 'en-gb'; + } + + (my $title = _($alert_type->item_title)) =~ s/{{(.*?)}}/$row->{$1}/g; + (my $link = $alert_type->item_link) =~ s/{{(.*?)}}/$row->{$1}/g; + (my $desc = _($alert_type->item_description)) =~ s/{{(.*?)}}/$row->{$1}/g; + my $url = $c->uri_for( $link ); + my %item = ( + title => ent($title), + link => $url, + guid => $url, + description => ent(ent($desc)) # Yes, double-encoded, really. + ); + $item{pubDate} = $pubDate if $pubDate; + $item{category} = $row->{category} if $row->{category}; + + if ($c->cobrand->allow_photo_display && $row->{photo}) { + my $key = $alert_type->item_table eq 'comment' ? 'c' : 'id'; + $item{description} .= ent("\n<br><img src=\"". $c->cobrand->base_url . "/photo?$key=$row->{id}\">"); + } + my $recipient_name = $c->cobrand->contact_name; + $item{description} .= ent("\n<br><a href='$url'>" . + sprintf(_("Report on %s"), $recipient_name) . "</a>"); + + if ($row->{latitude} || $row->{longitude}) { + $item{georss} = { point => "$row->{latitude} $row->{longitude}" }; + } + + $c->stash->{rss}->add_item( %item ); +} + +sub add_parameters : Private { + my ( $self, $c ) = @_; + my $alert_type = $c->stash->{alert_type}; + + my $row = {}; + if ($alert_type->head_sql_query) { + my $q = $c->model('DB::Alert')->result_source->storage->dbh->prepare( + $alert_type->head_sql_query + ); + if ($alert_type->head_sql_query =~ /\?/) { + $q->execute(@{ $c->stash->{db_params} }); + } else { + $q->execute(); + } + $row = $q->fetchrow_hashref; + } + foreach ( keys %{ $c->stash->{title_params} } ) { + $row->{$_} = $c->stash->{title_params}->{$_}; + } + + (my $title = _($alert_type->head_title)) =~ s/{{(.*?)}}/$row->{$1}/g; + (my $link = $alert_type->head_link) =~ s/{{(.*?)}}/$row->{$1}/g; + (my $desc = _($alert_type->head_description)) =~ s/{{(.*?)}}/$row->{$1}/g; + + $c->stash->{rss}->channel( + title => ent($title), + link => $link . ($c->stash->{qs} || ''), + description => ent($desc), + language => 'en-gb', + ); } sub local_problems_legacy : LocalRegex('^(\d+)[,/](\d+)(?:/(\d+))?$') { diff --git a/perllib/FixMyStreet/DB/Result/Alert.pm b/perllib/FixMyStreet/DB/Result/Alert.pm index e0017b94d..b99c83a45 100644 --- a/perllib/FixMyStreet/DB/Result/Alert.pm +++ b/perllib/FixMyStreet/DB/Result/Alert.pm @@ -45,15 +45,27 @@ __PACKAGE__->add_columns( ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->belongs_to( + "alert_type", + "FixMyStreet::DB::Result::AlertType", + { ref => "alert_type" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); +__PACKAGE__->belongs_to( "user", "FixMyStreet::DB::Result::User", { id => "user_id" }, { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, ); +__PACKAGE__->has_many( + "alert_sents", + "FixMyStreet::DB::Result::AlertSent", + { "foreign.alert_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); -# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-05-24 15:32:43 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:MV8kPZiQVJH7coYT4FmXLg +# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-06-03 16:48:36 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:NlyhWyg0NrH5/kZYYO36qg # You can replace this text with custom code or comments, and it will be preserved on regeneration diff --git a/perllib/FixMyStreet/DB/Result/AlertSent.pm b/perllib/FixMyStreet/DB/Result/AlertSent.pm new file mode 100644 index 000000000..85a9000d5 --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/AlertSent.pm @@ -0,0 +1,38 @@ +package FixMyStreet::DB::Result::AlertSent; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime"); +__PACKAGE__->table("alert_sent"); +__PACKAGE__->add_columns( + "alert_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "parameter", + { data_type => "text", is_nullable => 1 }, + "whenqueued", + { + data_type => "timestamp", + default_value => \"ms_current_timestamp()", + is_nullable => 0, + }, +); +__PACKAGE__->belongs_to( + "alert", + "FixMyStreet::DB::Result::Alert", + { id => "alert_id" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-06-03 16:48:36 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:x1nMIiNFSTKxdPxZmko18Q + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/perllib/FixMyStreet/DB/Result/AlertType.pm b/perllib/FixMyStreet/DB/Result/AlertType.pm new file mode 100644 index 000000000..7a3cd1e36 --- /dev/null +++ b/perllib/FixMyStreet/DB/Result/AlertType.pm @@ -0,0 +1,55 @@ +package FixMyStreet::DB::Result::AlertType; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components("FilterColumn", "InflateColumn::DateTime"); +__PACKAGE__->table("alert_type"); +__PACKAGE__->add_columns( + "ref", + { data_type => "text", is_nullable => 0 }, + "head_sql_query", + { data_type => "text", is_nullable => 0 }, + "head_table", + { data_type => "text", is_nullable => 0 }, + "head_title", + { data_type => "text", is_nullable => 0 }, + "head_link", + { data_type => "text", is_nullable => 0 }, + "head_description", + { data_type => "text", is_nullable => 0 }, + "item_table", + { data_type => "text", is_nullable => 0 }, + "item_where", + { data_type => "text", is_nullable => 0 }, + "item_order", + { data_type => "text", is_nullable => 0 }, + "item_title", + { data_type => "text", is_nullable => 0 }, + "item_link", + { data_type => "text", is_nullable => 0 }, + "item_description", + { data_type => "text", is_nullable => 0 }, + "template", + { data_type => "text", is_nullable => 0 }, +); +__PACKAGE__->set_primary_key("ref"); +__PACKAGE__->has_many( + "alerts", + "FixMyStreet::DB::Result::Alert", + { "foreign.alert_type" => "self.ref" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07010 @ 2011-06-03 16:48:36 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:KNZ7eWU/VgF8xzsjCHKVjw + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; |