aboutsummaryrefslogtreecommitdiffstats
path: root/perllib
diff options
context:
space:
mode:
Diffstat (limited to 'perllib')
-rw-r--r--perllib/FixMyStreet/App.pm2
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin/States.pm102
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm20
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Reports.pm7
-rw-r--r--perllib/FixMyStreet/App/Controller/Root.pm33
-rw-r--r--perllib/FixMyStreet/App/Model/DB.pm1
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm8
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm29
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm13
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm68
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm64
-rw-r--r--perllib/FixMyStreet/DB/Result/State.pm48
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm10
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/State.pm78
-rw-r--r--perllib/FixMyStreet/DB/Schema.pm2
-rw-r--r--perllib/FixMyStreet/Roles/Extra.pm16
-rw-r--r--perllib/FixMyStreet/Script/Questionnaires.pm3
-rw-r--r--perllib/FixMyStreet/TestAppProve.pm2
19 files changed, 402 insertions, 111 deletions
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index 25d3d744e..a0477ca40 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -173,6 +173,7 @@ sub setup_request {
$c->setup_dev_overrides();
my $cobrand = $c->cobrand;
+ FixMyStreet::DB->schema->cobrand($cobrand);
$cobrand->call_hook('add_response_headers');
@@ -218,6 +219,7 @@ sub setup_request {
mySociety::MaPit::configure( "http://$host/fakemapit/" );
}
+ $c->stash->{has_fixed_state} = FixMyStreet::DB::Result::Problem::fixed_states->{fixed};
$c->cobrand->call_hook('setup_states');
if (FixMyStreet->test_mode) {
diff --git a/perllib/FixMyStreet/App/Controller/Admin/States.pm b/perllib/FixMyStreet/App/Controller/Admin/States.pm
new file mode 100644
index 000000000..e4c07c9ca
--- /dev/null
+++ b/perllib/FixMyStreet/App/Controller/Admin/States.pm
@@ -0,0 +1,102 @@
+package FixMyStreet::App::Controller::Admin::States;
+use Moose;
+use namespace::autoclean;
+
+BEGIN { extends 'Catalyst::Controller'; }
+
+sub begin : Private {
+ my ( $self, $c ) = @_;
+
+ $c->forward('/admin/begin');
+}
+
+sub index : Path : Args(0) {
+ my ( $self, $c ) = @_;
+
+ $c->forward('/auth/get_csrf_token');
+ $c->forward('/admin/fetch_languages');
+ my $rs = $c->model('DB::State');
+
+ if ($c->req->method eq 'POST') {
+ $c->forward('/auth/check_csrf_token');
+
+ $c->forward('process_new')
+ && $c->forward('delete')
+ && $c->forward('update');
+
+ $rs->clear;
+ }
+
+ $c->stash->{open_states} = $rs->open;
+ $c->stash->{closed_states} = $rs->closed;
+ $c->stash->{fixed_states} = $rs->fixed;
+}
+
+sub process_new : Private {
+ my ($self, $c) = @_;
+ if ($c->get_param('new_fixed')) {
+ $c->model('DB::State')->create({
+ label => 'fixed',
+ type => 'fixed',
+ name => _('Fixed'),
+ });
+ return 0;
+ }
+ return 1 unless $c->get_param('new');
+ my %params = map { $_ => $c->get_param($_) } qw/label type name/;
+ $c->model('DB::State')->create(\%params);
+ return 0;
+}
+
+sub delete : Private {
+ my ($self, $c) = @_;
+
+ my @params = keys %{ $c->req->params };
+ my ($to_delete) = map { /^delete:(.*)/ } grep { /^delete:/ } @params;
+ if ($to_delete) {
+ $c->model('DB::State')->search({ label => $to_delete })->delete;
+ return 0;
+ }
+ return 1;
+}
+
+sub update : Private {
+ my ($self, $c) = @_;
+
+ my $rs = $c->model('DB::State');
+ my %db_states = map { $_->label => $_ } @{$rs->states};
+ my @params = keys %{ $c->req->params };
+ my @states = map { /^type:(.*)/ } grep { /^type:/ } @params;
+
+ foreach my $state (@states) {
+ # If there is only one language, we still store confirmed/closed
+ # as translations, as that seems a sensible place to store them.
+ if ($state eq 'confirmed' or $state eq 'closed') {
+ if (my $name = $c->get_param("name:$state")) {
+ my ($lang) = keys %{$c->stash->{languages}};
+ $db_states{$state}->add_translation_for('name', $lang, $name);
+ }
+ } else {
+ $db_states{$state}->update({
+ type => $c->get_param("type:$state"),
+ name => $c->get_param("name:$state"),
+ });
+ }
+
+ foreach my $lang (keys(%{$c->stash->{languages}})) {
+ my $id = $c->get_param("translation_id:$state:$lang");
+ my $text = $c->get_param("translation:$state:$lang");
+ if ($text) {
+ $db_states{$state}->add_translation_for('name', $lang, $text);
+ } elsif ($id) {
+ $c->model('DB::Translation')->find({ id => $id })->delete;
+ }
+ }
+ }
+
+ return 1;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index 83fb0554c..825066026 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -128,6 +128,18 @@ sub email_sign_in : Private {
return;
}
+ # If user registration is disabled then bail out at this point
+ # if there's not already a user with this email address.
+ # NB this uses the same template as a successful sign in to stop
+ # enumeration of valid email addresses.
+ if ( FixMyStreet->config('SIGNUPS_DISABLED')
+ && !$c->model('DB::User')->search({ email => $good_email })->count
+ && !$c->stash->{current_user} # don't break the change email flow
+ ) {
+ $c->stash->{template} = 'auth/token.html';
+ return;
+ }
+
my $user_params = {};
$user_params->{password} = $c->get_param('password_register')
if $c->get_param('password_register');
@@ -199,6 +211,10 @@ sub token : Path('/M') : Args(1) {
my $user = $c->model('DB::User')->find_or_new({ email => $data->{email} });
+ # Bail out if this is a new user and SIGNUPS_DISABLED is set
+ $c->detach( '/page_error_403_access_denied', [] )
+ if FixMyStreet->config('SIGNUPS_DISABLED') && !$user->in_storage && !$data->{old_email};
+
if ($data->{old_email}) {
# Were logged in as old_email, want to switch to email ($user)
if ($user->in_storage) {
@@ -244,6 +260,8 @@ sub fb : Private {
sub facebook_sign_in : Private {
my ( $self, $c ) = @_;
+ $c->detach( '/page_error_403_access_denied', [] ) if FixMyStreet->config('SIGNUPS_DISABLED');
+
my $fb = $c->forward('/auth/fb');
my $url = $fb->get_authorization_url(scope => ['email']);
@@ -302,6 +320,8 @@ sub tw : Private {
sub twitter_sign_in : Private {
my ( $self, $c ) = @_;
+ $c->detach( '/page_error_403_access_denied', [] ) if FixMyStreet->config('SIGNUPS_DISABLED');
+
my $twitter = $c->forward('/auth/tw');
my $url = $twitter->get_authentication_url(callback => $c->uri_for('/auth/Twitter'));
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
index fbe5a2dc9..f3989e760 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -24,6 +24,8 @@ sub example : Local : Args(0) {
my ( $self, $c ) = @_;
$c->stash->{template} = 'dashboard/index.html';
+ $c->stash->{filter_states} = $c->cobrand->state_groups_inspect;
+
$c->stash->{children} = {};
for my $i (1..3) {
$c->stash->{children}{$i} = { id => $i, name => "Ward $i" };
@@ -93,6 +95,7 @@ sub index : Path : Args(0) {
$c->stash->{body} = $body;
# Set up the data for the dropdowns
+ $c->stash->{filter_states} = $c->cobrand->state_groups_inspect;
# Just take the first area ID we find
my $area_id = $body->body_areas->first->area_id;
@@ -145,12 +148,10 @@ sub index : Path : Args(0) {
# List of reports underneath summary table
$c->stash->{q_state} = $c->get_param('state') || '';
- if ( $c->stash->{q_state} eq 'fixed' ) {
+ if ( $c->stash->{q_state} eq 'fixed - council' ) {
$prob_where->{'me.state'} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
} elsif ( $c->stash->{q_state} ) {
$prob_where->{'me.state'} = $c->stash->{q_state};
- $prob_where->{'me.state'} = { IN => [ 'planned', 'action scheduled' ] }
- if $prob_where->{'me.state'} eq 'action scheduled';
}
my $params = {
%$prob_where,
diff --git a/perllib/FixMyStreet/App/Controller/Reports.pm b/perllib/FixMyStreet/App/Controller/Reports.pm
index b597cb7a8..8f8205719 100644
--- a/perllib/FixMyStreet/App/Controller/Reports.pm
+++ b/perllib/FixMyStreet/App/Controller/Reports.pm
@@ -558,12 +558,11 @@ sub stash_report_filter_status : Private {
if ($c->user and ($c->user->is_superuser or (
$c->stash->{body} and $c->user->belongs_to_body($c->stash->{body}->id)
))) {
+ $c->stash->{filter_states} = $c->cobrand->state_groups_inspect;
foreach my $state (FixMyStreet::DB::Result::Problem->visible_states()) {
if ($status{$state}) {
- %filter_problem_states = (%filter_problem_states, ($state => 1));
- my $pretty_state = $state;
- $pretty_state =~ tr/ /_/;
- $filter_status{$pretty_state} = 1;
+ $filter_problem_states{$state} = 1;
+ $filter_status{$state} = 1;
}
}
}
diff --git a/perllib/FixMyStreet/App/Controller/Root.pm b/perllib/FixMyStreet/App/Controller/Root.pm
index 64d7fa6ae..7f70623ae 100644
--- a/perllib/FixMyStreet/App/Controller/Root.pm
+++ b/perllib/FixMyStreet/App/Controller/Root.pm
@@ -16,6 +16,18 @@ FixMyStreet::App::Controller::Root - Root Controller for FixMyStreet::App
=head1 METHODS
+=head2 begin
+
+Any pre-flight checking for all requests
+
+=cut
+sub begin : Private {
+ my ( $self, $c ) = @_;
+
+ $c->forward( 'check_login_required' );
+}
+
+
=head2 auto
Set up general things for this instance
@@ -130,6 +142,27 @@ sub page_error : Private {
$c->response->status($code);
}
+sub check_login_required : Private {
+ my ($self, $c) = @_;
+
+ return if $c->user_exists || !FixMyStreet->config('LOGIN_REQUIRED');
+
+ # Whitelisted URL patterns are allowed without login
+ my $whitelist = qr{
+ ^auth(/|$)
+ | ^js/translation_strings\.(.*?)\.js
+ | ^[PACQM]/ # various tokens that log the user in
+ }x;
+ return if $c->request->path =~ $whitelist;
+
+ # Blacklisted URLs immediately 404
+ # This is primarily to work around a Safari bug where the appcache
+ # URL is requested in an infinite loop if it returns a 302 redirect.
+ $c->detach('/page_error_404_not_found', []) if $c->request->path =~ /^offline/;
+
+ $c->detach( '/auth/redirect' );
+}
+
=head2 end
Attempt to render a view, if needed.
diff --git a/perllib/FixMyStreet/App/Model/DB.pm b/perllib/FixMyStreet/App/Model/DB.pm
index db8e72c27..c116abffc 100644
--- a/perllib/FixMyStreet/App/Model/DB.pm
+++ b/perllib/FixMyStreet/App/Model/DB.pm
@@ -21,6 +21,7 @@ __PACKAGE__->config(
sub build_per_context_instance {
my ( $self, $c ) = @_;
+ # $self->schema->cobrand($c->cobrand);
$self->schema->cache({});
return $self;
}
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index 93c459e26..93aa0e2fb 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -170,12 +170,8 @@ sub decode {
sub prettify_state {
my ($self, $c, $text, $single_fixed) = @_;
- # New template to prevent interaction with current one
- my $tt = FixMyStreet::Template->new({ INCLUDE_PATH => $self->{include_path} });
- my $var;
- $tt->process('report/state-list.html', { state => $text }, \$var);
- $var =~ s/ - .*// if $single_fixed;
- return $var;
+
+ return FixMyStreet::DB->resultset("State")->display($text, $single_fixed);
}
1;
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 5dcdc9a4b..250919d09 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -179,7 +179,7 @@ sub restriction {
return $self->moniker ? { cobrand => $self->moniker } : {};
}
-=head2 base_url_with_lang
+=head2 base_url_with_lang
=cut
@@ -358,7 +358,7 @@ sub front_stats_data {
Returns any disambiguating information available. Defaults to none.
-=cut
+=cut
sub disambiguate_location { FixMyStreet->config('GEOCODING_DISAMBIGUATION') or {}; }
@@ -642,6 +642,7 @@ sub admin_pages {
# There are some pages that only super users can see
if ( $user->is_superuser ) {
$pages->{flagged} = [ _('Flagged'), 7 ];
+ $pages->{states} = [ _('States'), 8 ];
$pages->{config} = [ _('Configuration'), 9];
};
# And some that need special permissions
@@ -820,7 +821,7 @@ sub is_two_tier { 0; }
=item council_rss_alert_options
-Generate a set of options for council rss alerts.
+Generate a set of options for council rss alerts.
=cut
@@ -1066,6 +1067,28 @@ sub show_unconfirmed_reports {
0;
}
+sub state_groups_admin {
+ my $rs = FixMyStreet::DB->resultset("State");
+ my @fixed = FixMyStreet::DB::Result::Problem->fixed_states;
+ [
+ [ $rs->display('confirmed'), [ FixMyStreet::DB::Result::Problem->open_states ] ],
+ @fixed ? [ $rs->display('fixed'), [ FixMyStreet::DB::Result::Problem->fixed_states ] ] : (),
+ [ $rs->display('closed'), [ FixMyStreet::DB::Result::Problem->closed_states ] ],
+ [ $rs->display('hidden'), [ FixMyStreet::DB::Result::Problem->hidden_states ] ]
+ ]
+}
+
+sub state_groups_inspect {
+ my $rs = FixMyStreet::DB->resultset("State");
+ my @fixed = FixMyStreet::DB::Result::Problem->fixed_states;
+ [
+ [ $rs->display('confirmed'), [ grep { $_ ne 'planned' } FixMyStreet::DB::Result::Problem->open_states ] ],
+ @fixed ? [ $rs->display('fixed'), [ 'fixed - council' ] ] : (),
+ [ $rs->display('closed'), [ grep { $_ ne 'closed' } FixMyStreet::DB::Result::Problem->closed_states ] ],
+ [ $rs->display('hidden'), [ 'hidden' ] ]
+ ]
+}
+
=head2 never_confirm_updates
If true then we never send an email to confirm an update
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
index a061ff46c..b3d6b28c3 100644
--- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -122,12 +122,19 @@ sub path_to_pin_icons {
sub pin_hover_title {
my ($self, $problem, $title) = @_;
- my $state = $self->{c}->render_fragment(
- 'report/state-list.html',
- { state => $problem->state });
+ my $state = FixMyStreet::DB->resultset("State")->display($problem->state, 1);
return "$state: $title";
}
+sub state_groups_inspect {
+ [
+ [ _('New'), [ 'confirmed', 'investigating' ] ],
+ [ _('Scheduled'), [ 'action scheduled' ] ],
+ [ _('Fixed'), [ 'fixed - council' ] ],
+ [ _('Closed'), [ 'not responsible', 'duplicate', 'unable to fix' ] ],
+ ]
+}
+
sub open311_config {
my ($self, $row, $h, $params) = @_;
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index d688eb8b9..562f29693 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -227,8 +227,6 @@ sub meta_line {
my $meta = '';
- $c->stash->{last_state} ||= '';
-
if ($self->anonymous or !$self->name) {
$meta = sprintf( _( 'Posted anonymously at %s' ), Utils::prettify_dt( $self->confirmed ) )
} elsif ($self->user->from_body) {
@@ -257,60 +255,36 @@ sub meta_line {
$meta = sprintf( _( 'Posted by %s at %s' ), FixMyStreet::Template::html_filter($self->name), Utils::prettify_dt( $self->confirmed ) )
}
+ if ($self->get_extra_metadata('defect_raised')) {
+ $meta .= ', ' . _( 'and a defect raised' );
+ }
+
+ return $meta;
+};
+
+sub problem_state_display {
+ my ( $self, $c ) = @_;
+
my $update_state = '';
+ my $cobrand = $c->cobrand->moniker;
if ($self->mark_fixed) {
- $update_state = _( 'marked as fixed' );
+ return FixMyStreet::DB->resultset("State")->display('fixed', 1);
} elsif ($self->mark_open) {
- $update_state = _( 'reopened' );
+ return FixMyStreet::DB->resultset("State")->display('confirmed', 1);
} elsif ($self->problem_state) {
my $state = $self->problem_state;
-
- if ($state eq 'confirmed') {
- if ($c->stash->{last_state}) {
- $update_state = _( 'reopened' )
- }
- } elsif ($state eq 'investigating') {
- $update_state = _( 'marked as investigating' )
- } elsif ($state eq 'planned') {
- $update_state = _( 'marked as planned' )
- } elsif ($state eq 'in progress') {
- $update_state = _( 'marked as in progress' )
- } elsif ($state eq 'action scheduled') {
- $update_state = _( 'marked as action scheduled' )
- } elsif ($state eq 'closed') {
- $update_state = _( 'marked as closed' )
- } elsif ($state =~ /^fixed/) {
- $update_state = _( 'marked as fixed' )
- } elsif ($state eq 'unable to fix') {
- $update_state = _( 'marked as no further action' )
- } elsif ($state eq 'not responsible') {
- $update_state = _( "marked as not the council's responsibility" )
- } elsif ($state eq 'duplicate') {
- $update_state = _( 'closed as a duplicate report' )
- } elsif ($state eq 'internal referral') {
- $update_state = _( 'marked as an internal referral' )
- }
-
- if ($c->cobrand->moniker eq 'bromley' || $self->problem->to_body_named('Bromley')) {
- if ($state eq 'not responsible') {
- $update_state = 'marked as third party responsibility'
+ if ($state eq 'not responsible') {
+ $update_state = _( "not the council's responsibility" );
+ if ($cobrand eq 'bromley' || $self->problem->to_body_named('Bromley')) {
+ $update_state = 'third party responsibility';
}
+ } else {
+ $update_state = FixMyStreet::DB->resultset("State")->display($state, 1);
}
-
}
- if ($update_state ne $c->stash->{last_state} and $update_state) {
- $meta .= ", $update_state";
- }
-
- if ($self->get_extra_metadata('defect_raised')) {
- $meta .= ', ' . _( 'and a defect raised' );
- }
-
- $c->stash->{last_state} = $update_state;
-
- return $meta;
-};
+ return $update_state;
+}
1;
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index a74a04828..77190679b 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -220,15 +220,8 @@ HASHREF.
=cut
sub open_states {
- my $states = {
- 'confirmed' => 1,
- 'investigating' => 1,
- 'in progress' => 1,
- 'planned' => 1,
- 'action scheduled' => 1,
- };
-
- return wantarray ? keys %{$states} : $states;
+ my @states = map { $_->label } @{FixMyStreet::DB->resultset("State")->open};
+ return wantarray ? @states : { map { $_ => 1 } @states };
}
=head2
@@ -242,13 +235,9 @@ HASHREF.
=cut
sub fixed_states {
- my $states = {
- 'fixed' => 1,
- 'fixed - user' => 1,
- 'fixed - council' => 1,
- };
-
- return wantarray ? keys %{ $states } : $states;
+ my @states = map { $_->label } @{FixMyStreet::DB->resultset("State")->fixed};
+ push @states, 'fixed - user', 'fixed - council' if @states;
+ return wantarray ? @states : { map { $_ => 1 } @states };
}
=head2
@@ -262,18 +251,10 @@ HASHREF.
=cut
sub closed_states {
- my $states = {
- 'closed' => 1,
- 'unable to fix' => 1,
- 'not responsible' => 1,
- 'duplicate' => 1,
- 'internal referral' => 1,
- };
-
- return wantarray ? keys %{$states} : $states;
+ my @states = map { $_->label } @{FixMyStreet::DB->resultset("State")->closed};
+ return wantarray ? @states : { map { $_ => 1 } @states };
}
-
=head2
@states = FixMyStreet::DB::Problem::all_states();
@@ -289,21 +270,10 @@ sub all_states {
'hidden' => 1,
'partial' => 1,
'unconfirmed' => 1,
- 'confirmed' => 1,
- 'investigating' => 1,
- 'in progress' => 1,
- 'planned' => 1,
- 'action scheduled' => 1,
- 'fixed' => 1,
'fixed - council' => 1,
'fixed - user' => 1,
- 'unable to fix' => 1,
- 'not responsible' => 1,
- 'duplicate' => 1,
- 'closed' => 1,
- 'internal referral' => 1,
};
-
+ map { $states->{$_->label} = 1 } @{FixMyStreet::DB->resultset("State")->states};
return wantarray ? keys %{$states} : $states;
}
@@ -920,15 +890,21 @@ sub photos {
my $id = $self->id;
my @photos = map {
my $cachebust = substr($_, 0, 8);
+ # Some Varnish configurations (e.g. on mySociety infra) strip cookies from
+ # images, which means image requests will be redirected to the login page
+ # if LOGIN_REQUIRED is set. To stop this happening, Varnish should be
+ # configured to not strip cookies if the cookie_passthrough param is
+ # present, which this line ensures will be if LOGIN_REQUIRED is set.
+ my $extra = (FixMyStreet->config('LOGIN_REQUIRED')) ? "&cookie_passthrough=1" : "";
my ($hash, $format) = split /\./, $_;
{
id => $hash,
- url_temp => "/photo/temp.$hash.$format",
- url_temp_full => "/photo/fulltemp.$hash.$format",
- url => "/photo/$id.$i.$format?$cachebust",
- url_full => "/photo/$id.$i.full.$format?$cachebust",
- url_tn => "/photo/$id.$i.tn.$format?$cachebust",
- url_fp => "/photo/$id.$i.fp.$format?$cachebust",
+ url_temp => "/photo/temp.$hash.$format$extra",
+ url_temp_full => "/photo/fulltemp.$hash.$format$extra",
+ url => "/photo/$id.$i.$format?$cachebust$extra",
+ url_full => "/photo/$id.$i.full.$format?$cachebust$extra",
+ url_tn => "/photo/$id.$i.tn.$format?$cachebust$extra",
+ url_fp => "/photo/$id.$i.fp.$format?$cachebust$extra",
idx => $i++,
}
} $photoset->all_ids;
diff --git a/perllib/FixMyStreet/DB/Result/State.pm b/perllib/FixMyStreet/DB/Result/State.pm
new file mode 100644
index 000000000..b8a35d42b
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/State.pm
@@ -0,0 +1,48 @@
+use utf8;
+package FixMyStreet::DB::Result::State;
+
+# 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", "EncodedColumn");
+__PACKAGE__->table("state");
+__PACKAGE__->add_columns(
+ "id",
+ {
+ data_type => "integer",
+ is_auto_increment => 1,
+ is_nullable => 0,
+ sequence => "state_id_seq",
+ },
+ "label",
+ { data_type => "text", is_nullable => 0 },
+ "type",
+ { data_type => "text", is_nullable => 0 },
+ "name",
+ { data_type => "text", is_nullable => 0 },
+);
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->add_unique_constraint("state_label_key", ["label"]);
+__PACKAGE__->add_unique_constraint("state_name_key", ["name"]);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2017-08-22 15:17:43
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dvtAOpeYqEF9T3otHHgLqw
+
+use Moo;
+use namespace::clean;
+
+with 'FixMyStreet::Roles::Translatable';
+
+sub msgstr {
+ my $self = shift;
+ my $lang = $self->result_source->schema->lang;
+ return $self->name unless $lang && $self->translated->{name}{$lang};
+ return $self->translated->{name}{$lang}{msgstr};
+}
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index e44b2530f..19adf5d49 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -295,6 +295,16 @@ sub permissions {
sub has_permission_to {
my ($self, $permission_type, $body_ids) = @_;
+ # Nobody, including superusers, can have a permission which isn't available
+ # in the current cobrand.
+ my $cobrand = $self->result_source->schema->cobrand;
+ my $cobrand_perms = $cobrand->available_permissions;
+ my %available = map { %$_ } values %$cobrand_perms;
+ # The 'trusted' permission is never set in the cobrand's
+ # available_permissions (see note there in Default.pm) so include it here.
+ $available{trusted} = 1;
+ return 0 unless $available{$permission_type};
+
return 1 if $self->is_superuser;
return 0 if !$body_ids || (ref $body_ids && !@$body_ids);
$body_ids = [ $body_ids ] unless ref $body_ids;
diff --git a/perllib/FixMyStreet/DB/ResultSet/State.pm b/perllib/FixMyStreet/DB/ResultSet/State.pm
new file mode 100644
index 000000000..8b6a8963e
--- /dev/null
+++ b/perllib/FixMyStreet/DB/ResultSet/State.pm
@@ -0,0 +1,78 @@
+package FixMyStreet::DB::ResultSet::State;
+use base 'DBIx::Class::ResultSet';
+
+use strict;
+use warnings;
+use Memcached;
+
+sub _hardcoded_states {
+ my $rs = shift;
+ my $open = $rs->new({ id => -1, label => 'confirmed', type => 'open', name => _("Open") });
+ my $closed = $rs->new({ id => -2, label => 'closed', type => 'closed', name => _("Closed") });
+ return ($open, $closed);
+}
+
+# As states will change rarely, and then only through the admin,
+# we cache these in the package on first use, and clear on update.
+
+sub clear {
+ Memcached::set('states', '');
+}
+
+sub states {
+ my $rs = shift;
+
+ my $states = Memcached::get('states');
+ if ($states && !FixMyStreet->test_mode) {
+ # Need to reattach schema
+ $states->[0]->result_source->schema( $rs->result_source->schema ) if $states->[0];
+ return $states;
+ }
+
+ # Pick up and cache any translations
+ my $q = $rs->result_source->schema->resultset("Translation")->search({
+ tbl => 'state',
+ col => 'name',
+ });
+ my %trans;
+ $trans{$_->object_id}{$_->lang} = { id => $_->id, msgstr => $_->msgstr } foreach $q->all;
+
+ my @states = ($rs->_hardcoded_states, $rs->search(undef, { order_by => 'label' })->all);
+ $_->translated->{name} = $trans{$_->id} || {} foreach @states;
+ $states = \@states;
+ Memcached::set('states', $states);
+ return $states;
+}
+
+# Some functions to provide filters on the above data
+
+sub open { [ $_[0]->_filter(sub { $_->type eq 'open' }) ] }
+sub closed { [ $_[0]->_filter(sub { $_->type eq 'closed' }) ] }
+sub fixed { [ $_[0]->_filter(sub { $_->type eq 'fixed' }) ] }
+
+# We sometimes have only a state label to display, no associated object.
+# This function can be used to return that label's display name.
+
+sub display {
+ my ($rs, $label, $single_fixed) = @_;
+ my $unchanging = {
+ unconfirmed => _("Unconfirmed"),
+ hidden => _("Hidden"),
+ partial => _("Partial"),
+ 'fixed - council' => _("Fixed - Council"),
+ 'fixed - user' => _("Fixed - User"),
+ };
+ $label = 'fixed' if $single_fixed && $label =~ /^fixed - (council|user)$/;
+ return $unchanging->{$label} if $unchanging->{$label};
+ my ($state) = $rs->_filter(sub { $_->label eq $label });
+ return $label unless $state;
+ return $state->msgstr;
+}
+
+sub _filter {
+ my ($rs, $fn) = @_;
+ my $states = $rs->states;
+ grep &$fn, @$states;
+}
+
+1;
diff --git a/perllib/FixMyStreet/DB/Schema.pm b/perllib/FixMyStreet/DB/Schema.pm
index 10bbd434f..be39069d8 100644
--- a/perllib/FixMyStreet/DB/Schema.pm
+++ b/perllib/FixMyStreet/DB/Schema.pm
@@ -25,6 +25,8 @@ __PACKAGE__->connection(FixMyStreet->dbic_connect_info);
has lang => ( is => 'rw' );
+has cobrand => ( is => 'rw' );
+
has cache => ( is => 'rw', lazy => 1, default => sub { {} } );
1;
diff --git a/perllib/FixMyStreet/Roles/Extra.pm b/perllib/FixMyStreet/Roles/Extra.pm
index dc2e5c241..445f6d91c 100644
--- a/perllib/FixMyStreet/Roles/Extra.pm
+++ b/perllib/FixMyStreet/Roles/Extra.pm
@@ -175,4 +175,20 @@ sub get_extra {
return $extra;
}
+=head2 get_extra_field_value
+
+Return the value of a field stored in `_fields` in extra, or undefined if
+it's not present.
+
+=cut
+
+sub get_extra_field_value {
+ my ($self, $name) = @_;
+
+ my @fields = @{ $self->get_extra_fields() };
+
+ my ($field) = grep { $_->{name} eq $name } @fields;
+ return $field->{value};
+}
+
1;
diff --git a/perllib/FixMyStreet/Script/Questionnaires.pm b/perllib/FixMyStreet/Script/Questionnaires.pm
index 3f22eb150..ec6139d2d 100644
--- a/perllib/FixMyStreet/Script/Questionnaires.pm
+++ b/perllib/FixMyStreet/Script/Questionnaires.pm
@@ -16,6 +16,9 @@ sub send {
sub send_questionnaires_period {
my ( $period, $params ) = @_;
+ # Don't send if we don't have a fixed state
+ return unless FixMyStreet::DB::Result::Problem::fixed_states->{fixed};
+
my $rs = FixMyStreet::DB->resultset('Questionnaire');
# Select all problems that need a questionnaire email sending
diff --git a/perllib/FixMyStreet/TestAppProve.pm b/perllib/FixMyStreet/TestAppProve.pm
index f6e09fbe9..7a387547d 100644
--- a/perllib/FixMyStreet/TestAppProve.pm
+++ b/perllib/FixMyStreet/TestAppProve.pm
@@ -75,7 +75,7 @@ sub run {
$SIG{__WARN__} =
sub { print STDERR @_ if $_[0] !~ m/NOTICE: CREATE TABLE/; };
$dbh->do( path('db/schema.sql')->slurp ) or die $!;
- $dbh->do( path('db/alert_types.sql')->slurp ) or die $!;
+ $dbh->do( path('db/fixture.sql')->slurp ) or die $!;
$dbh->do( path('db/generate_secret.sql')->slurp ) or die $!;
$SIG{__WARN__} = $tmpwarn;