1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include <check.h>
#include <string.h>
#include "irc.h"
#include "set.h"
#include "util.h"
START_TEST(test_strip_linefeed)
{
int i;
const char *get[] = { "Test", "Test\r", "Test\rX\r", NULL };
const char *expected[] = { "Test", "Test", "TestX", NULL };
for (i = 0; get[i]; i++) {
char copy[20];
strcpy(copy, get[i]);
strip_linefeed(copy);
fail_unless (strcmp(copy, expected[i]) == 0,
"(%d) strip_linefeed broken: %s -> %s (expected: %s)",
i, get[i], copy, expected[i]);
}
}
END_TEST
START_TEST(test_strip_newlines)
{
int i;
const char *get[] = { "Test", "Test\r\n", "Test\nX\n", NULL };
const char *expected[] = { "Test", "Test ", "Test X ", NULL };
for (i = 0; get[i]; i++) {
char copy[20], *ret;
strcpy(copy, get[i]);
ret = strip_newlines(copy);
fail_unless (strcmp(copy, expected[i]) == 0,
"(%d) strip_newlines broken: %s -> %s (expected: %s)",
i, get[i], copy, expected[i]);
fail_unless (copy == ret, "Original string not returned");
}
}
END_TEST
Suite *util_suite (void)
{
Suite *s = suite_create("Util");
TCase *tc_core<package FixMyStreet::Cobrand::Buckinghamshire;
use parent 'FixMyStreet::Cobrand::Whitelabel';
use strict;
use warnings;
use Moo;
with 'FixMyStreet::Roles::ConfirmValidation';
sub council_area_id { return 2217; }
sub council_area { return 'Buckinghamshire'; }
sub council_name { return 'Buckinghamshire County Council'; }
sub council_url { return 'buckinghamshire'; }
sub disambiguate_location {
my $self = shift;
my $string = shift;
my $town = 'Buckinghamshire';
return {
%{ $self->SUPER::disambiguate_location() },
town => $town,
centre => '51.7852948471218,-0.812140044990842',
span => '0.596065946222112,0.664092167105497',
bounds => [ 51.4854160129405, -1.1406945585036, 52.0814819591626, -0.476602391398098 ],
};
}
sub on_map_default_status { 'open' }
sub pin_colour {
my ( $self, $p, $context ) = @_;
return 'grey' if $p->state eq 'not responsible' || !$self->owns_problem( $p );
return 'green' if $p->is_fixed || $p->is_closed;
return 'red' if $p->state eq 'confirmed';
return 'yellow';
}
sub admin_user_domain { 'buckscc.gov.uk' }
sub send_questionnaires {
return 0;
}
sub open311_config {
my ($self, $row, $h, $params) = @_;
my $extra = $row->get_extra_fields;
push @$extra,
{ name => 'report_url',
value => $h->{url} },
{ name => 'title',
value => $row->title },
{ name => 'description',
value => $row->detail };
# Reports made via FMS.com or the app probably won't have a site code
# value because we don't display the adopted highways layer on those
# frontends. Instead we'll look up the closest asset from the WFS
# service at the point we're sending the report over Open311.
if (!$row->get_extra_field_value('site_code')) {
if (my $site_code = $self->lookup_site_code($row)) {
push @$extra,
{ name => 'site_code',
value => $site_code };
}
}
$row->set_extra_fields(@$extra);
}
sub open311_pre_send {
my ($self, $row, $open311) = @_;
return unless $row->extra;
my $extra = $row->get_extra_fields;
if (@$extra) {
@$extra = grep { $_->{name} ne 'road-placement' } @$extra;
$row->set_extra_fields(@$extra);
}
}
sub open311_post_send {
my ($self, $row, $h) = @_;
# Check Open311 was successful
return unless $row->external_id;
# For certain categories, send an email also
my $emails = $self->feature('open311_email');
my $addresses = {
'Flytipping' => [ $emails->{flytipping}, "TfB" ],
'Blocked drain' => [ $emails->{flood}, "Flood Management" ],
'Ditch issue' => [ $emails->{flood}, "Flood Management" ],
'Flooded subway' => [ $emails->{flood}, "Flood Management" ],
};
my $dest = $addresses->{$row->category};
return unless $dest;
my $sender = FixMyStreet::SendReport::Email->new( to => [ $dest ] );
$sender->send($row, $h);
}
sub open311_config_updates {
my ($self, $params) = @_;
$params->{mark_reopen} = 1;
}
sub open311_contact_meta_override {
my ($self, $service, $contact, $meta) = @_;
push @$meta, {
code => 'road-placement',
datatype => 'singlevaluelist',
description => 'Is the fly-tip located on',
order => 100,
required => 'true',
variable => 'true',
values => [
{ key => 'road', name => 'The road' },
{ key => 'off-road', name => 'Off the road/on a verge' },
],
} if $service->{service_name} eq 'Flytipping';
}
sub process_open311_extras {
my ($self, $c, $body, $extra) = @_;
return unless $c->stash->{report}; # Don't care about updates
$self->flytipping_body_fix(
$c->stash->{report},
$c->get_param('road-placement'),
$c->stash->{field_errors},
);
}
sub flytipping_body_fix {
my ($self, $report, $road_placement, $errors) = @_;
return unless $report->category eq 'Flytipping';
if ($report->bodies_str =~ /,/) {
# Sent to both councils in the area
my @bodies = values %{$report->bodies};
my $county = (grep { $_->name =~ /^Buckinghamshire/ } @bodies)[0];
my $district = (grep { $_->name !~ /^Buckinghamshire/ } @bodies)[0];
# Decide which to send to based upon the answer to the extra question:
if ($road_placement eq 'road') {
$report->bodies_str($county->id);
} elsif ($road_placement eq 'off-road') {
$report->bodies_str($district->id);
}
} else {
# If the report is only being sent to the district, we do
# not care about the road question, if it is missing
if (!$report->to_body_named('Buckinghamshire')) {
delete $errors->{'road-placement'};
}
}
}
sub filter_report_description {
my ($self, $description) = @_;
# this allows _ in the domain name but I figure it's unlikely to
# generate false positives so lets go with that for the same of
# a simpler regex
$description =~ s/\b[\w.!#$%&'*+\-\/=?^_{|}~]+\@[\w\-]+\.[^ ]+\b//g;
$description =~ s/ (?: \+ \d{2} \s? | \b 0 ) (?:
\d{2} \s? \d{4} \s? \d{4} # 0xx( )xxxx( )xxxx
| \d{3} \s \d{3} \s? \d{4} # 0xxx xxx( )xxxx
| \d{3} \s? \d{2} \s \d{4,5} # 0xxx( )xx xxxx(x)
| \d{4} \s \d{5,6} # 0xxxx xxxxx(x)
) \b //gx;
return $description;
}
sub map_type { 'Buckinghamshire' }
sub default_map_zoom { 3 }
sub _dashboard_export_add_columns {
my $self = shift;
my $c = $self->{c};
push @{$c->stash->{csv}->{headers}}, "Staff User";
push @{$c->stash->{csv}->{columns}}, "staff_user";
# All staff users, for contributed_by lookup
my @user_ids = $c->model('DB::User')->search(
{ from_body => $self->body->id },
{ columns => [ 'id', 'email', ] })->all;
my %user_lookup = map { $_->id => $_->email } @user_ids;
$c->stash->{csv}->{extra_data} = sub {
my $report = shift;
my $staff_user = '';
if (my $contributed_by = $report->get_extra_metadata('contributed_by')) {
$staff_user = $user_lookup{$contributed_by};
}
return {
staff_user => $staff_user,
};
};
}
sub dashboard_export_updates_add_columns {
shift->_dashboard_export_add_columns;
}
sub dashboard_export_problems_add_columns {
shift->_dashboard_export_add_columns;
}
# Enable adding/editing of parish councils in the admin
sub add_extra_areas {
my ($self, $areas) = @_;
# This is a list of all Parish Councils within Buckinghamshire,
# taken from https://mapit.mysociety.org/area/2217/covers.json?type=CPC
my $parish_ids = [
"135493",
"135494",
"148713",
"148714",
"53319",
"53360",
"53390",
"53404",
"53453",
"53486",
"53515",
"53542",
"53612",
"53822",
"53874",
"53887",
"53942",
"53991",
"54003",
"54014",
"54158",
"54174",
"54178",
"54207",
"54289",
"54305",
"54342",
"54355",
"54402",
"54465",
"54479",
"54493",
"54590",
"54615",
"54672",
"54691",
"54721",
"54731",
"54787",
"54846",
"54879",
"54971",
"55290",
"55326",
"55534",
"55638",
"55724",
"55775",
"55896",
"55900",
"55915",
"55945",
"55973",
"56007",
"56091",
"56154",
"56268",
"56350",
"56379",
"56418",
"56432",
"56498",
"56524",
"56592",
"56609",
"56641",
"56659",
"56664",
"56709",
"56758",
"56781",
"57099",
"57138",
"57330",
"57332",
"57366",
"57367",
"57507",
"57529",
"57582",
"57585",
"57666",
"57701",
"58166",
"58208",
"58229",
"58279",
"58312",
"58333",
"58405",
"58523",
"58659",
"58815",
"58844",
"58891",
"58965",
"58980",
"59003",
"59007",
"59012",
"59067",
"59144",
"59152",
"59179",
"59211",
"59235",
"59288",
"59353",
"59491",
"59518",
"59727",
"59763",
"59971",
"60027",
"60137",
"60321",
"60322",
"60438",
"60456",
"60462",
"60532",
"60549",
"60598",
"60622",
"60640",
"60731",
"60777",
"60806",
"60860",
"60954",
"61100",
"61102",
"61107",
"61142",
"61144",
"61167",
"61172",
"61249",
"61268",
"61269",
"61405",
"61445",
"61471",
"61479",
"61898",
"61902",
"61920",
"61964",
"62226",
"62267",
"62296",
"62311",
"62321",
"62431",
"62454",
"62640",
"62657",
"62938",
"63040",
"63053",
"63068",
"63470",
"63476",
"63501",
"63507",
"63517",
"63554",
"63715",
"63723"
];
my $ids_string = join ",", @{ $parish_ids };
my $extra_areas = mySociety::MaPit::call('areas', [ $ids_string ]);
my %all_areas = (
%$areas,
%$extra_areas
);
return \%all_areas;
}
# Make sure CPC areas are included in point lookups for new reports
sub add_extra_area_types {
my ($self, $types) = @_;
my @types = (
@$types,
'CPC',
);
return \@types;
}
sub is_two_tier { 1 }
sub should_skip_sending_update {
my ($self, $update ) = @_;
# Bucks don't want to receive updates into Confirm that were made by anyone
# except the original problem reporter.
return $update->user_id != $update->problem->user_id;
}
sub disable_phone_number_entry { 1 }
sub report_sent_confirmation_email { 'external_id' }
sub is_council_with_case_management { 1 }
# Try OSM for Bucks as it provides better disamiguation descriptions.
sub get_geocoder { 'OSM' }
sub categories_restriction {
my ($self, $rs) = @_;
# Buckinghamshire is a two-tier council, but mostly want to display
# county-level categories on their cobrand.
return $rs->search(
[
{ 'body_areas.area_id' => 2217 },
{ category => [ 'Flytipping', 'Car Parks' ] },
],
{ join => { body => 'body_areas' } }
);
}
sub lookup_site_code_config { {
buffer => 200, # metres
url => "https://tilma.mysociety.org/mapserver/bucks",
srsname => "urn:ogc:def:crs:EPSG::27700",
typename => "Whole_Street",
property => "site_code",
accept_feature => sub {
my $feature = shift;
# There are only certain features we care about, the rest can be ignored.
my @valid_types = ( "2", "3A", "3B", "4A", "4B", "HE", "HWOA", "HWSA", "P" );
my %valid_types = map { $_ => 1 } @valid_types;
my $type = $feature->{properties}->{feature_ty};
return $valid_types{$type};
}
} }
1;
|