aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/DB/Result
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/DB/Result')
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm88
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm31
-rw-r--r--perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm24
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm180
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm7
5 files changed, 182 insertions, 148 deletions
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index b217bf96c..82476ba10 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -110,6 +110,61 @@ with 'FixMyStreet::Roles::Abuser',
'FixMyStreet::Roles::Moderation',
'FixMyStreet::Roles::PhotoSet';
+=head2 FOREIGNBUILDARGS
+
+Make sure that when creating a new Comment object, certain
+other fields are set based upon the supplied data.
+
+=cut
+
+sub FOREIGNBUILDARGS {
+ my ($class, $opts) = @_;
+
+ if (my $user = $opts->{user}) {
+ my $name;
+ if ($user->is_superuser) {
+ $opts->{extra}->{is_superuser} = 1;
+ $name = _('an administrator');
+ } elsif (my $body = $user->from_body) {
+ $opts->{extra}->{is_body_user} = $body->id;
+ $name = $body->name;
+ $name = 'Island Roads' if $name eq 'Isle of Wight Council';
+ } else {
+ $name = $user->name;
+ }
+ $opts->{name} //= $name;
+ }
+
+ $opts->{anonymous} //= 0;
+ $opts->{mark_fixed} //= 0;
+ $opts->{state} //= 'confirmed'; # it's only public updates that need to be unconfirmed
+ if ($opts->{state} eq 'confirmed') {
+ $opts->{confirmed} //= \'current_timestamp';
+ }
+
+ return $opts;
+};
+
+=head2 around user
+
+Also make sure we catch the setting of a user on an object at a time other than
+object creation, to set the extra field needed.
+
+=cut
+
+around user => sub {
+ my ( $orig, $self ) = ( shift, shift );
+ my $res = $self->$orig(@_);
+ if (@_) {
+ if ($_[0]->is_superuser) {
+ $self->set_extra_metadata( is_superuser => 1 );
+ } elsif (my $body = $_[0]->from_body) {
+ $self->set_extra_metadata( is_body_user => $body->id );
+ }
+ }
+ return $res;
+};
+
=head2 get_cobrand_logged
Get a cobrand object for the cobrand the update was made on.
@@ -207,13 +262,19 @@ about an update. Can include HTML.
=cut
sub meta_line {
- my ( $self, $c ) = @_;
+ my ( $self, $user ) = @_;
+ my $cobrand = $self->result_source->schema->cobrand;
my $meta = '';
- if ($self->anonymous or !$self->name) {
- $meta = sprintf( _( 'Posted anonymously at %s' ), Utils::prettify_dt( $self->confirmed ) )
- } elsif ($self->user->from_body || $self->get_extra_metadata('is_body_user') || $self->get_extra_metadata('is_superuser') ) {
+ my $contributed_as = $self->get_extra_metadata('contributed_as') || '';
+ my $staff = $self->user->from_body || $self->get_extra_metadata('is_body_user') || $self->get_extra_metadata('is_superuser');
+ my $anon = $self->anonymous || !$self->name;
+
+ if ($anon && (!$staff || $contributed_as eq 'anonymous_user' || $contributed_as eq 'another_user')) {
+ $meta = $cobrand->call_hook(update_anonymous_message => $self);
+ $meta ||= sprintf( _( 'Posted anonymously at %s' ), Utils::prettify_dt( $self->confirmed ) )
+ } elsif ($staff) {
my $user_name = FixMyStreet::Template::html_filter($self->user->name);
my $body;
if ($self->get_extra_metadata('is_superuser')) {
@@ -237,9 +298,9 @@ sub meta_line {
$body = 'Island Roads';
}
}
- my $cobrand_always_view_body_user = $c->cobrand->call_hook("always_view_body_contribute_details");
+ my $cobrand_always_view_body_user = $cobrand->call_hook("always_view_body_contribute_details");
my $can_view_contribute = $cobrand_always_view_body_user ||
- ($c->user_exists && $c->user->has_permission_to('view_body_contribute_details', $self->problem->bodies_str_ids));
+ ($user && $user->has_permission_to('view_body_contribute_details', $self->problem->bodies_str_ids));
if ($self->text) {
if ($can_view_contribute) {
$meta = sprintf( _( 'Posted by <strong>%s</strong> (%s) at %s' ), $body, $user_name, Utils::prettify_dt( $self->confirmed ) );
@@ -268,16 +329,20 @@ sub problem_state_processed {
my $self = shift;
return 'fixed - user' if $self->mark_fixed;
return 'confirmed' if $self->mark_open;
- return $self->problem_state;
+ my $cobrand = $self->result_source->schema->cobrand;
+ my $cobrand_state = $cobrand->call_hook(problem_state_processed => $self);
+
+ return $cobrand_state || $self->problem_state;
}
sub problem_state_display {
- my ( $self, $c ) = @_;
+ my $self = shift;
my $state = $self->problem_state_processed;
return '' unless $state;
- my $cobrand_name = $c->cobrand->moniker;
+ my $cobrand = $self->result_source->schema->cobrand;
+ my $cobrand_name = $cobrand->moniker;
my $names = join(',,', @{$self->problem->body_names});
if ($names =~ /(Bromley|Isle of Wight|TfL)/) {
($cobrand_name = lc $1) =~ s/ //g;
@@ -313,7 +378,8 @@ sub hide {
}
sub as_hashref {
- my ($self, $c, $cols) = @_;
+ my ($self, $cols) = @_;
+ my $cobrand = $self->result_source->schema->cobrand;
my $out = {
id => $self->id,
@@ -329,7 +395,7 @@ sub as_hashref {
if ($self->confirmed) {
$out->{confirmed} = $self->confirmed if !$cols || $cols->{confirmed};
- $out->{confirmed_pp} = $c->cobrand->prettify_dt( $self->confirmed ) if !$cols || $cols->{confirmed_pp};
+ $out->{confirmed_pp} = $cobrand->prettify_dt( $self->confirmed ) if !$cols || $cols->{confirmed_pp};
}
return $out;
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index affc6d480..69f8886eb 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -113,9 +113,11 @@ sub category_display {
$self->get_extra_metadata('display_name') || $self->translate_column('category');
}
+# Returns an arrayref of groups this Contact is in; if it is
+# not in any group, returns an arrayref of the empty string.
sub groups {
my $self = shift;
- my $groups = $self->get_extra_metadata('group') || [];
+ my $groups = $self->get_extra_metadata('group') || [''];
$groups = [ $groups ] unless ref $groups eq 'ARRAY';
return $groups;
}
@@ -175,4 +177,31 @@ sub disable_form_field {
return $field;
}
+sub sent_by_open311 {
+ my $self = shift;
+ my $body = $self->body;
+ my $method = $self->send_method || '';
+ my $body_method = $body->send_method || '';
+ return 1 if
+ (!$body->can_be_devolved && $body_method eq 'Open311')
+ || ($body->can_be_devolved && $body_method eq 'Open311' && !$method)
+ || ($body->can_be_devolved && $method eq 'Open311');
+ return 0;
+}
+
+# We do not want to allow editing of a category's name
+# if it's Open311, unless it's marked as protected
+# Also prevent editing of hardcoded categories
+sub category_uneditable {
+ my $self = shift;
+ return 1 if
+ $self->in_storage
+ && !$self->get_extra_metadata('open311_protect')
+ && $self->sent_by_open311;
+ return 1 if
+ $self->in_storage
+ && $self->get_extra_metadata('hardcoded');
+ return 0;
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm b/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm
index 1805e1fd2..dd76a52c0 100644
--- a/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm
+++ b/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm
@@ -156,6 +156,20 @@ sub compare_photo {
return FixMyStreet::Template::SafeString->new($s);
}
+# This is a list of extra keys that could be set on a report after a moderation
+# has occurred. This can confuse the display of the last moderation entry, as
+# the comparison with the problem's extra will be wrong.
+my @keys_to_ignore = (
+ 'sent_to', # SendReport::Email adds this arrayref when sent
+ 'closed_updates', # Marked to close a report to updates
+ 'closure_alert_sent_at', # Set by alert sending if update closes a report
+ # Can be set/changed by an Open311 update
+ 'external_status_code', 'customer_reference',
+ # Can be set by inspectors
+ 'traffic_information', 'detailed_information', 'duplicates', 'duplicate_of', 'order',
+);
+my %keys_to_ignore = map { $_ => 1 } @keys_to_ignore;
+
sub compare_extra {
my ($self, $other) = @_;
@@ -163,18 +177,20 @@ sub compare_extra {
my $new = $other->get_extra_metadata;
my $both = { %$old, %$new };
- my @all_keys = sort keys %$both;
+ my @all_keys = grep { !$keys_to_ignore{$_} } sort keys %$both;
my @s;
foreach (@all_keys) {
+ $old->{$_} = join(', ', @{$old->{$_}}) if ref $old->{$_} eq 'ARRAY';
+ $new->{$_} = join(', ', @{$new->{$_}}) if ref $new->{$_} eq 'ARRAY';
if ($old->{$_} && $new->{$_}) {
push @s, string_diff("$_ = $old->{$_}", "$_ = $new->{$_}");
} elsif ($new->{$_}) {
push @s, string_diff("", "$_ = $new->{$_}");
- } else {
+ } elsif ($old->{$_}) {
push @s, string_diff("$_ = $old->{$_}", "");
}
}
- return join ', ', grep { $_ } @s;
+ return join '; ', grep { $_ } @s;
}
sub extra_diff {
@@ -193,7 +209,7 @@ sub string_diff {
$new = FixMyStreet::Template::html_filter($new);
if ($options{single}) {
- return unless $old;
+ return '' unless $old;
$old = [ $old ];
$new = [ $new ];
}
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index 37563d327..ceb41b40f 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -193,6 +193,27 @@ __PACKAGE__->might_have(
cascade_copy => 0, cascade_delete => 1 },
);
+# Add a possible join for the Contact object associated with
+# this report (based on bodies_str and category). If the report
+# was sent to multiple bodies, only returns the first.
+__PACKAGE__->belongs_to(
+ contact => "FixMyStreet::DB::Result::Contact",
+ sub {
+ my $args = shift;
+ return {
+ "$args->{foreign_alias}.category" => { -ident => "$args->{self_alias}.category" },
+ -and => [
+ \[ "CAST($args->{foreign_alias}.body_id AS text) = (regexp_split_to_array($args->{self_alias}.bodies_str, ','))[1]" ],
+ ]
+ };
+ },
+ {
+ join_type => "LEFT",
+ on_delete => "NO ACTION",
+ on_update => "NO ACTION",
+ },
+);
+
__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
__PACKAGE__->rabx_column('extra');
__PACKAGE__->rabx_column('geocode');
@@ -407,30 +428,11 @@ sub confirm {
sub category_display {
my $self = shift;
- my $contact = $self->category_row;
+ my $contact = $self->contact;
return $self->category unless $contact; # Fallback; shouldn't happen, but some tests
return $contact->category_display;
}
-=head2 category_row
-
-Returns the corresponding Contact object for this problem's category and body.
-If the report was sent to multiple bodies, only returns the first.
-
-=cut
-
-sub category_row {
- my $self = shift;
- my $schema = $self->result_source->schema;
- my $body_id = $self->bodies_str_ids->[0];
- return unless $body_id && $body_id =~ /^[0-9]+$/;
- my $contact = $schema->resultset("Contact")->find({
- body_id => $body_id,
- category => $self->category,
- });
- return $contact;
-}
-
sub bodies_str_ids {
my $self = shift;
return [] unless $self->bodies_str;
@@ -629,13 +631,14 @@ meta data about the report.
=cut
sub meta_line {
- my ( $problem, $c ) = @_;
+ my ( $problem, $user ) = @_;
+ my $cobrand = $problem->result_source->schema->cobrand;
my $date_time = Utils::prettify_dt( $problem->confirmed );
my $meta = '';
my $category = $problem->category_display;
- $category = $c->cobrand->call_hook(change_category_text => $category) || $category;
+ $category = $cobrand->call_hook(change_category_text => $category) || $category;
if ( $problem->anonymous ) {
if ( $problem->service and $category && $category ne _('Other') ) {
@@ -654,8 +657,8 @@ sub meta_line {
} else {
my $problem_name = $problem->name;
- if ($c->user_exists and
- $c->user->has_permission_to('view_body_contribute_details', $problem->bodies_str_ids) and
+ if ($user and
+ $user->has_permission_to('view_body_contribute_details', $problem->bodies_str_ids) and
$problem->name ne $problem->user->name) {
$problem_name = sprintf('%s (%s)', $problem->name, $problem->user->name );
}
@@ -690,12 +693,12 @@ sub nearest_address {
}
sub body {
- my ( $problem, $c ) = @_;
+ my ( $problem, $link ) = @_;
my $body;
if ($problem->external_body) {
if ($problem->cobrand eq 'zurich') {
my $cache = $problem->result_source->schema->cache;
- return $cache->{bodies}{$problem->external_body} //= $c->model('DB::Body')->find({ id => $problem->external_body });
+ return $cache->{bodies}{$problem->external_body} //= FixMyStreet::DB->resultset('Body')->find({ id => $problem->external_body });
} else {
$body = FixMyStreet::Template::html_filter($problem->external_body);
}
@@ -703,7 +706,7 @@ sub body {
my $bodies = $problem->bodies;
my @body_names = sort map {
my $name = $_->name;
- if ($c and FixMyStreet->config('AREA_LINKS_FROM_PROBLEMS')) {
+ if ($link and FixMyStreet->config('AREA_LINKS_FROM_PROBLEMS')) {
'<a href="' . $_->url . '">' . FixMyStreet::Template::html_filter($name) . '</a>';
} else {
FixMyStreet::Template::html_filter($name);
@@ -777,7 +780,11 @@ alphabetical order of name.
sub response_priorities {
my $self = shift;
- return $self->result_source->schema->resultset('ResponsePriority')->for_bodies($self->bodies_str_ids, $self->category);
+ my $rs = $self->result_source->schema->resultset('ResponsePriority')->for_bodies($self->bodies_str_ids, $self->category);
+ $rs->search([
+ 'me.deleted' => 0,
+ 'me.id' => $self->response_priority_id,
+ ]);
}
=head2 defect_types
@@ -808,9 +815,10 @@ sub can_display_external_id {
# This can return HTML and is safe, so returns a FixMyStreet::Template::SafeString
sub duration_string {
- my ( $problem, $c ) = @_;
- my $body = $c->cobrand->call_hook(link_to_council_cobrand => $problem) || $problem->body($c);
- my $handler = $c->cobrand->call_hook(get_body_handler_for_problem => $problem);
+ my $problem = shift;
+ my $cobrand = $problem->result_source->schema->cobrand;
+ my $body = $cobrand->call_hook(link_to_council_cobrand => $problem) || $problem->body(1);
+ my $handler = $cobrand->call_hook(get_body_handler_for_problem => $problem);
if ( $handler && $handler->call_hook('is_council_with_case_management') ) {
my $s = sprintf(_('Received by %s moments later'), $body);
return FixMyStreet::Template::SafeString->new($s);
@@ -836,87 +844,6 @@ sub local_coords {
}
}
-=head2 update_from_open311_service_request
-
- $p->update_from_open311_service_request( $request, $body, $system_user );
-
-Updates the problem based on information in the passed in open311 request
-(standard, not the extension that uses GetServiceRequestUpdates) . If the
-request has an older update time than the problem's lastupdate time then
-nothing happens.
-
-Otherwise a comment will be created if there is status update text in the
-open311 request. If the open311 request has a state of closed then the problem
-will be marked as fixed.
-
-NB: a comment will always be created if the problem is being marked as fixed.
-
-Fixed problems will not be re-opened by this method.
-
-=cut
-
-sub update_from_open311_service_request {
- my ( $self, $request, $body, $system_user ) = @_;
-
- my ( $updated, $status_notes );
-
- if ( ! ref $request->{updated_datetime} ) {
- $updated = $request->{updated_datetime};
- }
-
- if ( ! ref $request->{status_notes} ) {
- $status_notes = $request->{status_notes};
- }
-
- my $update = $self->new_related(comments => {
- state => 'confirmed',
- created => $updated || \'current_timestamp',
- confirmed => \'current_timestamp',
- text => $status_notes,
- mark_open => 0,
- mark_fixed => 0,
- user => $system_user,
- anonymous => 0,
- name => $body->name,
- });
-
- my $w3c = DateTime::Format::W3CDTF->new;
- my $req_time = $w3c->parse_datetime( $request->{updated_datetime} );
-
- # set a timezone here as the $req_time will have one and if we don't
- # use a timezone then the date comparisons are invalid.
- # of course if local timezone is not the one that went into the data
- # base then we're also in trouble
- my $lastupdate = $self->lastupdate;
- $lastupdate->set_time_zone( FixMyStreet->local_time_zone );
-
- # update from open311 is older so skip
- if ( $req_time < $lastupdate ) {
- return 0;
- }
-
- if ( $request->{status} eq 'closed' ) {
- if ( $self->state ne 'fixed' ) {
- $self->state('fixed');
- $update->mark_fixed(1);
-
- if ( !$status_notes ) {
- # FIXME - better text here
- $status_notes = _('Closed by council');
- }
- }
- }
-
- if ( $status_notes ) {
- $update->text( $status_notes );
- $self->lastupdate( $req_time );
- $self->update;
- $update->insert;
- }
-
- return 1;
-}
-
sub update_send_failed {
my $self = shift;
my $msg = shift;
@@ -975,7 +902,8 @@ sub resend {
}
sub as_hashref {
- my ($self, $c, $cols) = @_;
+ my ($self, $cols) = @_;
+ my $cobrand = $self->result_source->schema->cobrand;
my $state_t = FixMyStreet::DB->resultset("State")->display($self->state);
@@ -995,11 +923,11 @@ sub as_hashref {
};
$out->{is_fixed} = $self->fixed_states->{ $self->state } ? 1 : 0 if !$cols || $cols->{is_fixed};
$out->{photos} = [ map { $_->{url} } @{$self->photos} ] if !$cols || $cols->{photos};
- $out->{meta} = $self->confirmed ? $self->meta_line( $c ) : '' if !$cols || $cols->{meta};
- $out->{created_pp} = $c->cobrand->prettify_dt( $self->created ) if !$cols || $cols->{created_pp};
+ $out->{meta} = $self->confirmed ? $self->meta_line : '' if !$cols || $cols->{meta};
+ $out->{created_pp} = $cobrand->prettify_dt( $self->created ) if !$cols || $cols->{created_pp};
if ($self->confirmed) {
$out->{confirmed} = $self->confirmed if !$cols || $cols->{confirmed};
- $out->{confirmed_pp} = $c->cobrand->prettify_dt( $self->confirmed ) if !$cols || $cols->{confirmed_pp};
+ $out->{confirmed_pp} = $cobrand->prettify_dt( $self->confirmed ) if !$cols || $cols->{confirmed_pp};
}
return $out;
}
@@ -1052,10 +980,11 @@ has get_cobrand_logged => (
sub pin_data {
- my ($self, $c, $page, %opts) = @_;
- my $colour = $c->cobrand->pin_colour($self, $page);
+ my ($self, $page, %opts) = @_;
+ my $cobrand = $self->result_source->schema->cobrand;
+ my $colour = $cobrand->pin_colour($self, $page);
my $title = $opts{private} ? $self->title : $self->title_safe;
- $title = $c->cobrand->call_hook(pin_hover_title => $self, $title) || $title;
+ $title = $cobrand->call_hook(pin_hover_title => $self, $title) || $title;
{
latitude => $self->latitude,
longitude => $self->longitude,
@@ -1065,7 +994,7 @@ sub pin_data {
problem => $self,
draggable => $opts{draggable},
type => $opts{type},
- base_url => $c->cobrand->relative_url_for_report($self),
+ base_url => $cobrand->relative_url_for_report($self),
}
};
@@ -1196,17 +1125,6 @@ has duplicates => (
},
);
-has traffic_management_options => (
- is => 'ro',
- lazy => 1,
- default => sub {
- my $self = shift;
- my $cobrand = $self->get_cobrand_logged;
- $cobrand = $cobrand->call_hook(get_body_handler_for_problem => $self) || $cobrand;
- return $cobrand->traffic_management_options;
- },
-);
-
has inspection_log_entry => (
is => 'ro',
lazy => 1,
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index b0a05d0b7..e5be14abf 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -179,6 +179,11 @@ sub check_password {
}
}
+sub access_token {
+ my $self = shift;
+ return $self->get_extra_metadata('access_token');
+}
+
around password => sub {
my ($orig, $self) = (shift, shift);
if (@_) {
@@ -444,7 +449,7 @@ sub permissions {
my $body_id = $problem->bodies_str;
- return unless $self->belongs_to_body($body_id);
+ return {} unless $self->belongs_to_body($body_id);
my @permissions = grep { $_->{body_id} == $self->from_body->id } @{$self->body_permissions};
return { map { $_->{permission} => 1 } @permissions };