aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Cobrand
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/Cobrand')
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm91
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm23
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyBarangay.pm8
-rw-r--r--perllib/FixMyStreet/Cobrand/LichfieldDC.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/SeeSomething.pm8
-rw-r--r--perllib/FixMyStreet/Cobrand/UK.pm88
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm14
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm444
9 files changed, 552 insertions, 128 deletions
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 11851c5a1..0c8d567c4 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -476,14 +476,14 @@ sub format_postcode {
return $postcode;
}
-=head2 council_check
+=head2 area_check
-Paramters are COUNCILS, QUERY, CONTEXT. Return a boolean indicating whether
-COUNCILS pass any extra checks. CONTEXT is where we are on the site.
+Paramters are AREAS, QUERY, CONTEXT. Return a boolean indicating whether
+AREAS pass any extra checks. CONTEXT is where we are on the site.
=cut
-sub council_check { return ( 1, '' ); }
+sub area_check { return ( 1, '' ); }
=head2 all_councils_report
@@ -526,7 +526,7 @@ Show the problem creation graph in the admin interface
sub admin_show_creation_graph { 1 }
-=head2 area_types, area_min_generation
+=head2 area_types
The MaPit types this site handles
@@ -534,7 +534,6 @@ The MaPit types this site handles
sub area_types { FixMyStreet->config('MAPIT_TYPES') || [ 'ZZZ' ] }
sub area_types_children { FixMyStreet->config('MAPIT_TYPES_CHILDREN') || [] }
-sub area_min_generation { '' }
=head2 contact_name, contact_email
@@ -556,39 +555,28 @@ sub email_host {
return 1;
}
-=item remove_redundant_councils
+=item remove_redundant_areas
-Remove councils whose reports go to another council
+Remove areas whose reports go to another area (XXX)
=cut
-sub remove_redundant_councils {
+sub remove_redundant_areas {
my $self = shift;
- my $all_councils = shift;
-}
-
-=item filter_all_council_ids_list
-
-Removes any council IDs that we don't need from an array and returns the
-filtered array
-
-=cut
-
-sub filter_all_council_ids_list {
- my $self = shift;
- return @_;
+ my $all_areas = shift;
}
=item short_name
-Remove extra information from council names for tidy URIs
+Remove extra information from body names for tidy URIs
=cut
sub short_name {
my $self = shift;
- my ($area, $info) = @_;
- my $name = $area->{name};
+ my ($area) = @_;
+
+ my $name = $area->{name} || $area->name;
$name = URI::Escape::uri_escape_utf8($name);
$name =~ s/%20/+/g;
return $name;
@@ -615,10 +603,10 @@ Generate a set of options for council rss alerts.
=cut
sub council_rss_alert_options {
- my ( $self, $all_councils, $c ) = @_;
+ my ( $self, $all_areas, $c ) = @_;
my ( @options, @reported_to_options );
- foreach (values %$all_councils) {
+ foreach (values %$all_areas) {
$_->{short_name} = $self->short_name( $_ );
( $_->{id_name} = $_->{short_name} ) =~ tr/+/_/;
push @options, {
@@ -662,31 +650,26 @@ Get stats to display on the council reports page
sub get_report_stats { return 0; }
-sub get_council_sender {
- my ( $self, $area_id, $area_info, $category ) = @_;
-
- my $send_method;
+sub get_body_sender {
+ my ( $self, $body, $category ) = @_;
- my $council_config = FixMyStreet::App->model("DB::Open311conf")->search( { area_id => $area_id } )->first;
- $send_method = $council_config->send_method if $council_config;
-
- if ( $council_config && $council_config->can_be_devolved ) {
+ if ( $body->can_be_devolved ) {
# look up via category
- my $config = FixMyStreet::App->model("DB::Contact")->search( { area_id => $area_id, category => $category } )->first;
+ my $config = FixMyStreet::App->model("DB::Contact")->search( { body_id => $body->id, category => $category } )->first;
if ( $config->send_method ) {
return { method => $config->send_method, config => $config };
} else {
- return { method => $send_method, config => $council_config };
+ return { method => $body->send_method, config => $body };
}
- } elsif ( $send_method ) {
- return { method => $send_method, config => $council_config };
+ } elsif ( $body->send_method ) {
+ return { method => $body->send_method, config => $body };
}
- return $self->_fallback_council_sender( $area_id, $area_info, $category );
+ return $self->_fallback_body_sender( $body, $category );
}
-sub _fallback_council_sender {
- my ( $self, $area_id, $area_info, $category ) = @_;
+sub _fallback_body_sender {
+ my ( $self, $body, $category ) = @_;
return { method => 'Email' };
};
@@ -699,7 +682,7 @@ sub example_places {
=head2 only_authed_can_create
-If true, only users with the from_council flag set are able to create reports.
+If true, only users with the from_body flag set are able to create reports.
=cut
@@ -726,7 +709,7 @@ Returns the colour of pin to be used for a particular report
sub pin_colour {
my ( $self, $p, $context ) = @_;
#return 'green' if time() - $p->confirmed_local->epoch < 7 * 24 * 60 * 60;
- return 'yellow' if $context eq 'around';
+ return 'yellow' if $context eq 'around' || $context eq 'reports';
return $p->is_fixed ? 'green' : 'red';
}
@@ -746,15 +729,6 @@ sub default_map_zoom { undef };
sub users_can_hide { return 0; }
-=head2 reports_by_body
-
-Can /reports show reports indexed by external_body? This is a temporary measure
-until the contacts/area/body handling is rewritten to be better.
-
-=cut
-
-sub reports_by_body { 0; }
-
=head2 default_show_name
Returns true if the show name checkbox should be ticked by default.
@@ -810,5 +784,16 @@ a name key
sub anonymous_account { undef; }
+=head2 show_unconfirmed_reports
+
+Whether reports in state 'unconfirmed' should still be shown on the public site.
+(They're always included in the admin interface.)
+
+=cut
+
+sub show_unconfirmed_reports {
+ 0;
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
index 6bec115dd..5e90db038 100644
--- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -100,33 +100,26 @@ sub guess_road_operator {
return '';
}
-sub remove_redundant_councils {
+sub remove_redundant_areas {
my $self = shift;
- my $all_councils = shift;
+ my $all_areas = shift;
# Oslo is both a kommune and a fylke, we only want to show it once
- delete $all_councils->{301} #
- if $all_councils->{3};
-}
-
-sub filter_all_council_ids_list {
- my $self = shift;
- my @all_councils_ids = @_;
-
- # as above we only want to show Oslo once
- return grep { $_ != 301 } @all_councils_ids;
+ delete $all_areas->{301}
+ if $all_areas->{3};
}
sub short_name {
my $self = shift;
my ($area, $info) = @_;
- if ($area->{name} =~ /^(Os|Nes|V\xe5ler|Sande|B\xf8|Her\xf8y)$/) {
+ my $name = $area->{name} || $area->name;
+
+ if ($name =~ /^(Os|Nes|V\xe5ler|Sande|B\xf8|Her\xf8y)$/) {
my $parent = $info->{$area->{parent_area}}->{name};
- return URI::Escape::uri_escape_utf8("$area->{name}, $parent");
+ return URI::Escape::uri_escape_utf8("$name, $parent");
}
- my $name = $area->{name};
$name =~ s/ & / and /;
$name = URI::Escape::uri_escape_utf8($name);
$name =~ s/%20/+/g;
diff --git a/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm b/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
index 53bf9f3b4..1eda6cf43 100644
--- a/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMyBarangay.pm
@@ -33,6 +33,9 @@ sub only_authed_can_create {
return 1;
}
+# effectively allows barangay staff to hide reports
+sub council_id { return [ 1, 2 ]; }
+
sub areas_on_around {
return [ 1, 2 ];
}
@@ -41,8 +44,6 @@ sub can_support_problems {
return 1;
}
-sub reports_by_body { 1 }
-
sub default_show_name {
my $self = shift;
@@ -55,5 +56,8 @@ sub send_questionnaires {
return 0;
}
+# let staff hide reports in their own barangay
+sub users_can_hide { 1 }
+
1;
diff --git a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
index 31d5bf987..6a534fc18 100644
--- a/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
+++ b/perllib/FixMyStreet/Cobrand/LichfieldDC.pm
@@ -13,7 +13,7 @@ sub is_two_tier { return 1; }
# Different to councils parent due to this being a two-tier council. If we get
# more, this can be genericised in the parent.
sub problems_clause {
- return { council => { like => '%2434%' } };
+ return { bodies_str => { like => '%2434%' } };
}
# FIXME - need to double check this is all correct
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
index 9aa054020..62550e626 100644
--- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -18,7 +18,7 @@ sub base_url {
# Different to councils parent due to this being a two-tier council. If we get
# more, this can be genericised in the parent.
sub problems_clause {
- return { council => { like => '%2237%' } };
+ return { bodies_str => { like => '%2237%' } };
}
sub path_to_web_templates {
diff --git a/perllib/FixMyStreet/Cobrand/SeeSomething.pm b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
index dc28156dc..88d5f6b78 100644
--- a/perllib/FixMyStreet/Cobrand/SeeSomething.pm
+++ b/perllib/FixMyStreet/Cobrand/SeeSomething.pm
@@ -14,12 +14,12 @@ sub site_title { return 'See Something, Say Something'; }
sub site_restriction {
my $self = shift;
- return { council => { IN => $self->council_id } };
+ return { bodies_str => { IN => $self->council_id } };
}
sub problems_clause {
my $self = shift;
- return { council => { IN => $self->council_id } };
+ return { bodies_str => { IN => $self->council_id } };
}
sub path_to_web_templates {
@@ -30,10 +30,10 @@ sub path_to_web_templates {
];
}
-sub council_check {
+sub area_check {
my ( $self, $params, $context ) = @_;
- my $councils = $params->{all_councils};
+ my $councils = $params->{all_areas};
my $council_match = grep { $councils->{$_} } @{ $self->council_id };
if ($council_match) {
diff --git a/perllib/FixMyStreet/Cobrand/UK.pm b/perllib/FixMyStreet/Cobrand/UK.pm
index 4eee1869e..ff613ffa8 100644
--- a/perllib/FixMyStreet/Cobrand/UK.pm
+++ b/perllib/FixMyStreet/Cobrand/UK.pm
@@ -1,6 +1,7 @@
package FixMyStreet::Cobrand::UK;
use base 'FixMyStreet::Cobrand::Default';
+use mySociety::MaPit;
use mySociety::VotingArea;
sub path_to_web_templates {
@@ -11,7 +12,6 @@ sub path_to_web_templates {
sub country { return 'GB'; }
sub area_types { [ 'DIS', 'LBO', 'MTD', 'UTA', 'CTY', 'COI', 'LGD' ] }
sub area_types_children { $mySociety::VotingArea::council_child_types }
-sub area_min_generation { 10 }
sub enter_postcode_text {
my ( $self ) = @_;
@@ -31,8 +31,11 @@ sub disambiguate_location {
};
}
-sub _fallback_council_sender {
- my ( $self, $area_id, $area_info, $category ) = @_;
+sub _fallback_body_sender {
+ my ( $self, $body, $category ) = @_;
+
+ my $first_area = $body->body_areas->first->area_id;
+ my $area_info = mySociety::MaPit::call('area', $first_area);
return { method => 'London' } if $area_info->{type} eq 'LBO';
return { method => 'NI' } if $area_info->{type} eq 'LGD';
return { method => 'Email' };
@@ -41,11 +44,12 @@ sub _fallback_council_sender {
sub process_extras {
my $self = shift;
my $ctx = shift;
- my $area_id = shift;
+ my $body_id = shift;
my $extra = shift;
my $fields = shift || [];
- if ( $area_id eq '2482' ) {
+ # XXX Hardcoded body ID matching mapit area ID
+ if ( $body_id eq '2482' ) {
my @fields = ( 'fms_extra_title', @$fields );
for my $field ( @fields ) {
my $value = $ctx->request->param( $field );
@@ -97,46 +101,38 @@ sub geocode_postcode {
return {};
}
-sub remove_redundant_councils {
+sub remove_redundant_areas {
my $self = shift;
- my $all_councils = shift;
+ my $all_areas = shift;
# Ipswich & St Edmundsbury are responsible for everything in their
# areas, not Suffolk
- delete $all_councils->{2241}
- if $all_councils->{2446} #
- || $all_councils->{2443};
+ delete $all_areas->{2241}
+ if $all_areas->{2446} #
+ || $all_areas->{2443};
# Norwich is responsible for everything in its areas, not Norfolk
- delete $all_councils->{2233} #
- if $all_councils->{2391};
+ delete $all_areas->{2233} #
+ if $all_areas->{2391};
}
-sub filter_all_council_ids_list {
+sub short_name {
my $self = shift;
- my @all_councils_ids = @_;
+ my ($area) = @_;
- # Ignore the four council areas introduced because of generation 15
- # (where we put the new boundaries under the old IDs)
- return grep { $_ < 141648 || $_ > 141651 } @all_councils_ids;
-}
+ my $name = $area->{name} || $area->name;
-sub short_name {
- my $self = shift;
- my ($area, $info) = @_;
- # Special case Durham as it's the only place with two councils of the same name
- return 'Durham+County' if $area->{name} eq 'Durham County Council';
- return 'Durham+City' if $area->{name} eq 'Durham City Council';
-
- my $name = $area->{name};
- $name =~ s/ (Borough|City|District|County) Council$//;
- $name =~ s/ Council$//;
- $name =~ s/ & / and /;
- $name =~ s{/}{_}g;
- $name = URI::Escape::uri_escape_utf8($name);
- $name =~ s/%20/+/g;
- return $name;
+ # Special case Durham as it's the only place with two councils of the same name
+ return 'Durham+County' if $name eq 'Durham County Council';
+ return 'Durham+City' if $name eq 'Durham City Council';
+ $name =~ s/ (Borough|City|District|County) Council$//;
+ $name =~ s/ Council$//;
+ $name =~ s/ & / and /;
+ $name =~ s{/}{_}g;
+ $name = URI::Escape::uri_escape_utf8($name);
+ $name =~ s/%20/+/g;
+ return $name;
}
sub find_closest {
@@ -174,11 +170,11 @@ sub reports_body_check {
if (length($code) == 6) {
my $council = mySociety::MaPit::call( 'area', $area->{parent_area} );
$c->stash->{ward} = $area;
- $c->stash->{council} = $council;
+ $c->stash->{body} = $council;
} else {
- $c->stash->{council} = $area;
+ $c->stash->{body} = $area;
}
- $c->detach( 'redirect_area' );
+ $c->detach( 'redirect_body' );
}
# New ONS codes
@@ -188,11 +184,11 @@ sub reports_body_check {
if ($code =~ /^(E05|W05|S13)/) {
my $council = mySociety::MaPit::call( 'area', $area->{parent_area} );
$c->stash->{ward} = $area;
- $c->stash->{council} = $council;
- $c->detach( 'redirect_area' );
+ $c->stash->{body} = $council;
+ $c->detach( 'redirect_body' );
} elsif ($code =~ /^(W06|S12|E0[6-9]|E10)/) {
- $c->stash->{council} = $area;
- $c->detach( 'redirect_area' );
+ $c->stash->{body} = $area;
+ $c->detach( 'redirect_body' );
}
}
@@ -200,17 +196,17 @@ sub reports_body_check {
sub council_rss_alert_options {
my $self = shift;
- my $all_councils = shift;
- my $c = shift;
+ my $all_areas = shift;
+ my $c = shift;
my %councils = map { $_ => 1 } @{$self->area_types};
- my $num_councils = scalar keys %$all_councils;
+ my $num_councils = scalar keys %$all_areas;
my ( @options, @reported_to_options );
if ( $num_councils == 1 or $num_councils == 2 ) {
my ($council, $ward);
- foreach (values %$all_councils) {
+ foreach (values %$all_areas) {
if ($councils{$_->{type}}) {
$council = $_;
$council->{short_name} = $self->short_name( $council );
@@ -249,7 +245,7 @@ sub council_rss_alert_options {
} elsif ( $num_councils == 4 ) {
# Two-tier council
my ($county, $district, $c_ward, $d_ward);
- foreach (values %$all_councils) {
+ foreach (values %$all_areas) {
$_->{short_name} = $self->short_name( $_ );
( $_->{id_name} = $_->{short_name} ) =~ tr/+/_/;
if ($_->{type} eq 'CTY') {
@@ -320,7 +316,7 @@ sub council_rss_alert_options {
};
} else {
- throw Error::Simple('An area with three tiers of council? Impossible! '. join('|',keys %$all_councils));
+ throw Error::Simple('An area with three tiers of council? Impossible! '. join('|',keys %$all_areas));
}
return ( \@options, @reported_to_options ? \@reported_to_options : undef );
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 4c80da4f3..354b1b72a 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -13,7 +13,7 @@ sub is_council {
sub site_restriction {
my $self = shift;
- return { council => sprintf('%d', $self->council_id) };
+ return { bodies_str => sprintf('%d', $self->council_id) };
}
sub site_key {
my $self = shift;
@@ -27,7 +27,7 @@ sub restriction {
# Different function to site_restriction due to two-tier use
sub problems_clause {
my $self = shift;
- return { council => sprintf('%d', $self->council_id) };
+ return { bodies_str => sprintf('%d', $self->council_id) };
}
sub problems {
@@ -51,10 +51,10 @@ sub enter_postcode_text {
return 'Enter a ' . $self->council_area . ' postcode, or street name and area';
}
-sub council_check {
+sub area_check {
my ( $self, $params, $context ) = @_;
- my $councils = $params->{all_councils};
+ my $councils = $params->{all_areas};
my $council_match = defined $councils->{$self->council_id};
if ($council_match) {
return 1;
@@ -86,11 +86,13 @@ sub recent_photos {
return $self->problems->recent_photos( $num, $lat, $lon, $dist );
}
+# If we ever link to a county problem report, needs to be to main FixMyStreet
sub base_url_for_report {
my ( $self, $report ) = @_;
if ( $self->is_two_tier ) {
- my %councils = map { $_ => 1 } @{$report->councils};
- if ( $councils{$self->council_id} ) {
+ my $bodies = $report->bodies;
+ my %areas = map { %{$_->areas} } values %$bodies;
+ if ( $areas{$self->council_id} ) {
return $self->base_url;
} else {
return FixMyStreet->config('BASE_URL');
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
index e5d646c8b..ec65ec8f0 100644
--- a/perllib/FixMyStreet/Cobrand/Zurich.pm
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -1,9 +1,29 @@
package FixMyStreet::Cobrand::Zurich;
use base 'FixMyStreet::Cobrand::Default';
+use DateTime;
+use POSIX qw(strcoll);
+
use strict;
use warnings;
+sub shorten_recency_if_new_greater_than_fixed {
+ return 0;
+}
+
+sub pin_colour {
+ my ( $self, $p, $context ) = @_;
+ return 'green' if $p->is_fixed || $p->is_closed;
+ return 'red' if $p->state eq 'unconfirmed' || $p->state eq 'confirmed';
+ return 'yellow';
+}
+
+# This isn't used
+sub find_closest {
+ my ( $self, $latitude, $longitude, $problem ) = @_;
+ return '';
+}
+
sub enter_postcode_text {
my ( $self ) = @_;
return _('Enter a Z&uuml;rich street name');
@@ -13,4 +33,428 @@ sub example_places {
return [ 'Langstrasse', 'Basteiplatz' ];
}
+sub languages { [ 'de-ch,Deutsch,de_CH', 'en-gb,English,en_GB' ] };
+
+# If lat/lon are in the URI, we must have zoom as well, otherwise OpenLayers defaults to 0.
+sub uri {
+ my ( $self, $uri ) = @_;
+
+ $uri->query_param( zoom => 7 )
+ if $uri->query_param('lat') && !$uri->query_param('zoom');
+ return $uri;
+}
+
+sub remove_redundant_areas {
+ my $self = shift;
+ my $all_areas = shift;
+
+ # Remove all except Zurich
+ foreach (keys %$all_areas) {
+ delete $all_areas->{$_} unless $_ eq 274456;
+ }
+}
+
+sub show_unconfirmed_reports {
+ 1;
+}
+
+sub get_body_sender {
+ my ( $self, $body, $category ) = @_;
+ return { method => 'Zurich' };
+}
+
+# Report overdue functions
+
+my %public_holidays = map { $_ => 1 } (
+ '2013-01-01', '2013-01-02', '2013-03-29', '2013-04-01',
+ '2013-04-15', '2013-05-01', '2013-05-09', '2013-05-20',
+ '2013-08-01', '2013-09-09', '2013-12-25', '2013-12-26',
+ '2014-01-01', '2014-01-02', '2014-04-18', '2014-04-21',
+ '2014-04-28', '2014-05-01', '2014-05-29', '2014-06-09',
+ '2014-08-01', '2014-09-15', '2014-12-25', '2014-12-26',
+);
+
+sub is_public_holiday {
+ my $dt = shift;
+ return $public_holidays{$dt->ymd};
+}
+
+sub is_weekend {
+ my $dt = shift;
+ return $dt->dow > 5;
+}
+
+sub add_days {
+ my ( $dt, $days ) = @_;
+ $dt = $dt->clone;
+ while ( $days > 0 ) {
+ $dt->add ( days => 1 );
+ next if is_public_holiday($dt) or is_weekend($dt);
+ $days--;
+ }
+ return $dt;
+}
+
+sub sub_days {
+ my ( $dt, $days ) = @_;
+ $dt = $dt->clone;
+ while ( $days > 0 ) {
+ $dt->subtract ( days => 1 );
+ next if is_public_holiday($dt) or is_weekend($dt);
+ $days--;
+ }
+ return $dt;
+}
+
+sub overdue {
+ my ( $self, $problem ) = @_;
+
+ my $w = $problem->whensent;
+ return 0 unless $w;
+
+ if ( $problem->state eq 'unconfirmed' || $problem->state eq 'confirmed' ) {
+ # One working day
+ $w = add_days( $w, 1 );
+ return $w < DateTime->now();
+ } elsif ( $problem->state eq 'in progress' ) {
+ # Five working days
+ $w = add_days( $w, 5 );
+ return $w < DateTime->now();
+ } else {
+ return 0;
+ }
+}
+
+# Specific administrative displays
+
+sub admin_pages {
+ my $self = shift;
+ my $c = $self->{c};
+
+ my $type = $c->stash->{admin_type};
+ my $pages = {
+ 'summary' => [_('Summary'), 0],
+ 'reports' => [_('Reports'), 2],
+ 'report_edit' => [undef, undef],
+ 'update_edit' => [undef, undef],
+ };
+ return $pages if $type eq 'sdm';
+
+ $pages = { %$pages,
+ 'bodies' => [_('Bodies'), 1],
+ 'body' => [undef, undef],
+ 'body_edit' => [undef, undef],
+ };
+ return $pages if $type eq 'dm';
+
+ $pages = { %$pages,
+ 'users' => [_('Users'), 3],
+ 'user_edit' => [undef, undef],
+ };
+ return $pages if $type eq 'super';
+}
+
+sub admin_type {
+ my $self = shift;
+ my $c = $self->{c};
+ my $body = $c->user->from_body;
+ $c->stash->{body} = $body;
+
+ my $parent = $body->parent;
+ my $children = $body->bodies->count;
+
+ my $type;
+ if (!$parent) {
+ $type = 'super';
+ } elsif ($parent && $children) {
+ $type = 'dm';
+ } elsif ($parent) {
+ $type = 'sdm';
+ }
+
+ $c->stash->{admin_type} = $type;
+ return $type;
+}
+
+sub admin {
+ my $self = shift;
+ my $c = $self->{c};
+ my $type = $c->stash->{admin_type};
+
+ if ($type eq 'dm') {
+ $c->stash->{template} = 'admin/index-dm.html';
+
+ my $body = $c->stash->{body};
+ my @children = map { $_->id } $body->bodies->all;
+ my @all = (@children, $body->id);
+
+ # XXX No multiples or missing bodies
+ $c->stash->{unconfirmed} = $c->cobrand->problems->search({
+ state => [ 'unconfirmed', 'confirmed' ],
+ bodies_str => $c->stash->{body}->id,
+ });
+ $c->stash->{approval} = $c->cobrand->problems->search({
+ state => 'planned',
+ bodies_str => $c->stash->{body}->id,
+ });
+ $c->stash->{other} = $c->cobrand->problems->search({
+ state => { -not_in => [ 'unconfirmed', 'confirmed', 'planned' ] },
+ bodies_str => \@all,
+ });
+ } elsif ($type eq 'sdm') {
+ $c->stash->{template} = 'admin/index-sdm.html';
+
+ my $body = $c->stash->{body};
+
+ # XXX No multiples or missing bodies
+ $c->stash->{reports_new} = $c->cobrand->problems->search( {
+ state => 'in progress',
+ bodies_str => $body->id,
+ } );
+ $c->stash->{reports_unpublished} = $c->cobrand->problems->search( {
+ state => 'planned',
+ bodies_str => $body->parent->id,
+ } );
+ $c->stash->{reports_published} = $c->cobrand->problems->search( {
+ state => 'fixed - council',
+ bodies_str => $body->parent->id,
+ } );
+ }
+}
+
+sub admin_report_edit {
+ my $self = shift;
+ my $c = $self->{c};
+ my $type = $c->stash->{admin_type};
+
+ my $problem = $c->stash->{problem};
+ my $body = $c->stash->{body};
+
+ if ($type ne 'super') {
+ my %allowed_bodies = map { $_->id => 1 } ( $body->bodies->all, $body );
+ $c->detach( '/page_error_404_not_found' )
+ unless $allowed_bodies{$problem->bodies_str};
+ }
+
+ if ($type eq 'super') {
+
+ my @bodies = $c->model('DB::Body')->all();
+ @bodies = sort { strcoll($a->name, $b->name) } @bodies;
+ $c->stash->{bodies} = \@bodies;
+
+ # Can change category to any other
+ my @categories = $c->model('DB::Contact')->not_deleted->all;
+ $c->stash->{categories} = [ map { $_->category } @categories ];
+
+ } elsif ($type eq 'dm') {
+
+ # Can assign to:
+ my @bodies = $c->model('DB::Body')->search( [
+ { 'me.parent' => $body->parent->id }, # Other DMs on the same level
+ { 'me.parent' => $body->id }, # Their subdivisions
+ { 'me.parent' => undef, 'bodies.id' => undef }, # External bodies
+ ], { join => 'bodies', distinct => 1 } );
+ @bodies = sort { strcoll($a->name, $b->name) } @bodies;
+ $c->stash->{bodies} = \@bodies;
+
+ # Can change category to any other
+ my @categories = $c->model('DB::Contact')->not_deleted->all;
+ $c->stash->{categories} = [ map { $_->category } @categories ];
+
+ }
+
+ # Problem updates upon submission
+ if ( ($type eq 'super' || $type eq 'dm') && $c->req->param('submit') ) {
+ $c->forward('check_token');
+
+ # Predefine the hash so it's there for lookups
+ # XXX Note you need to shallow copy each time you set it, due to a bug? in FilterColumn.
+ my $extra = $problem->extra || {};
+ $extra->{internal_notes} = $c->req->param('internal_notes');
+ $extra->{publish_photo} = $c->req->params->{publish_photo} || 0;
+ $extra->{third_personal} = $c->req->params->{third_personal} || 0;
+ # Make sure we have a copy of the original detail field
+ $extra->{original_detail} = $problem->detail unless $extra->{original_detail};
+ $problem->extra( { %$extra } );
+
+ # Workflow things
+ my $redirect = 0;
+ my $new_cat = $c->req->params->{category};
+ if ( $new_cat && $new_cat ne $problem->category ) {
+ my $cat = $c->model('DB::Contact')->search( { category => $c->req->params->{category} } )->first;
+ $problem->category( $new_cat );
+ $problem->external_body( undef );
+ $problem->bodies_str( $cat->body_id );
+ $problem->whensent( undef );
+ $redirect = 1 if $cat->body_id ne $body->id;
+ } elsif ( my $subdiv = $c->req->params->{body_subdivision} ) {
+ $problem->state( 'in progress' );
+ $problem->external_body( undef );
+ $problem->bodies_str( $subdiv );
+ $problem->whensent( undef );
+ $redirect = 1;
+ } elsif ( my $external = $c->req->params->{body_external} ) {
+ $problem->state( 'closed' );
+ $problem->external_body( $external );
+ $problem->whensent( undef );
+ _admin_send_email( $c, 'problem-external.txt', $problem );
+ $redirect = 1;
+ } else {
+ $problem->state( $c->req->params->{state} ) if $c->req->params->{state};
+ if ( $problem->state eq 'hidden' ) {
+ _admin_send_email( $c, 'problem-rejected.txt', $problem );
+ }
+ }
+
+ $problem->title( $c->req->param('title') );
+ $problem->detail( $c->req->param('detail') );
+
+ # Final, public, Update from DM
+ if (my $update = $c->req->param('status_update')) {
+ $extra->{public_response} = $update;
+ $problem->extra( { %$extra } );
+ if ($c->req->params->{publish_response}) {
+ $problem->state( 'fixed - council' );
+ _admin_send_email( $c, 'problem-closed.txt', $problem );
+ }
+ }
+
+ $problem->lastupdate( \'ms_current_timestamp()' );
+ $problem->update;
+
+ $c->stash->{status_message} =
+ '<p><em>' . _('Updated!') . '</em></p>';
+
+ # do this here otherwise lastupdate and confirmed times
+ # do not display correctly
+ $problem->discard_changes;
+
+ if ( $redirect ) {
+ $c->detach('index');
+ }
+
+ $c->stash->{updates} = [ $c->model('DB::Comment')
+ ->search( { problem_id => $problem->id }, { order_by => 'created' } )
+ ->all ];
+
+ return 1;
+ }
+
+ if ($type eq 'sdm') {
+
+ # Has cut-down edit template for adding update and sending back up only
+ $c->stash->{template} = 'admin/report_edit-sdm.html';
+
+ if ($c->req->param('send_back')) {
+ $c->forward('check_token');
+
+ $problem->bodies_str( $body->parent->id );
+ $problem->state( 'confirmed' );
+ $problem->update;
+ # log here
+ $c->res->redirect( '/admin/summary' );
+
+ } elsif ($c->req->param('submit')) {
+ $c->forward('check_token');
+
+ my $extra = $problem->extra || {};
+ $extra->{internal_notes} ||= '';
+ if ($c->req->param('internal_notes') && $c->req->param('internal_notes') ne $extra->{internal_notes}) {
+ $extra->{internal_notes} = $c->req->param('internal_notes');
+ $problem->extra( { %$extra } );
+ $problem->update;
+ }
+
+ # Add new update from status_update
+ if (my $update = $c->req->param('status_update')) {
+ FixMyStreet::App->model('DB::Comment')->create( {
+ text => $update,
+ user => $c->user->obj,
+ state => 'unconfirmed',
+ problem => $problem,
+ mark_fixed => 0,
+ problem_state => 'fixed - council',
+ anonymous => 1,
+ } );
+ }
+
+ $c->stash->{status_message} = '<p><em>' . _('Updated!') . '</em></p>';
+
+ # If they clicked the no more updates button, we're done.
+ if ($c->req->param('no_more_updates')) {
+ $problem->bodies_str( $body->parent->id );
+ $problem->whensent( undef );
+ $problem->state( 'planned' );
+ $problem->update;
+ # log here
+ $c->res->redirect( '/admin/summary' );
+ }
+ }
+
+ $c->stash->{updates} = [ $c->model('DB::Comment')
+ ->search( { problem_id => $problem->id }, { order_by => 'created' } )
+ ->all ];
+
+ return 1;
+
+ }
+
+ return 0;
+
+}
+
+sub _admin_send_email {
+ my ( $c, $template, $problem ) = @_;
+
+ return unless $problem->extra && $problem->extra->{email_confirmed};
+
+ my $to = $problem->name
+ ? [ $problem->user->email, $problem->name ]
+ : $problem->user->email;
+
+ $c->send_email( $template, {
+ to => [ $to ],
+ url => $c->uri_for_email( $problem->url ),
+ } );
+}
+
+sub admin_fetch_all_bodies {
+ my ( $self, @bodies ) = @_;
+
+ sub tree_sort {
+ my ( $level, $id, $sorted, $out ) = @_;
+
+ my @sorted;
+ my $array = $sorted->{$id};
+ if ( $level == 0 ) {
+ @sorted = sort {
+ # Want Zurich itself at the top.
+ return -1 if $sorted->{$a->id};
+ return 1 if $sorted->{$b->id};
+ # Otherwise, by name
+ strcoll($a->name, $b->name)
+ } @$array;
+ } else {
+ @sorted = sort { strcoll($a->name, $b->name) } @$array;
+ }
+ foreach ( @sorted ) {
+ $_->api_key( $level ); # Misuse
+ push @$out, $_;
+ if ($sorted->{$_->id}) {
+ tree_sort( $level+1, $_->id, $sorted, $out );
+ }
+ }
+ }
+
+ my %sorted;
+ foreach (@bodies) {
+ my $p = $_->parent ? $_->parent->id : 0;
+ push @{$sorted{$p}}, $_;
+ }
+
+ my @out;
+ tree_sort( 0, 0, \%sorted, \@out );
+ return @out;
+}
+
1;