Skip to content

Commit

Permalink
[Northumberland] Being able to filter on only one category in multipl…
Browse files Browse the repository at this point in the history
…e parent categories

Set up categories in index to include name of their group.

Use this group name to check if a report is in the
selected category (through extra->group).

If there are reports that don't identify as being in that category, then
still use a 'Multiple' category.

mysociety/societyworks#4039
  • Loading branch information
MorayMySoc committed Apr 3, 2024
1 parent 016d81d commit f9cb3dc
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 38 deletions.
91 changes: 67 additions & 24 deletions perllib/FixMyStreet/App/Controller/Dashboard.pm
Original file line number Diff line number Diff line change
Expand Up @@ -136,24 +136,42 @@ sub index : Path : Args(0) {
}

my %group_names = map { $_->{name} => $_->{categories} } @{$c->stash->{category_groups}};
# See if we've had anything from the body dropdowns
$c->stash->{category} = [ $c->get_param_list('category') ];
my @remove_from_display;

foreach (@{$c->stash->{category}}) {
next unless /^group-(.*)/;
for my $contact (@{$group_names{$1}}) {
push @{ $c->stash->{category} }, $contact->category;
push @remove_from_display, $contact->category;

# Categories being received are expected to carry group information
# from the interface. A category can be:
# 'group-Roads' -> A master category 'Roads' which will contain subcategories
# 'Potholes-group-Roads' -> A 'Potholes' category under roads
# 'Potholes-group-' -> A 'Potholes' category not under any other category
# We need to reformat any categories that may be manually put into the url
# which may be bookmarks from before grouping was added

my %display_categories;
foreach my $display ($c->get_param_list('category')) {

Check warning on line 149 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L148-L149

Added lines #L148 - L149 were not covered by tests
if ($display !~ /group-/) {
$display = $display . '-group-';

Check warning on line 151 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L151

Added line #L151 was not covered by tests
}
$display_categories{$display} = 1;

Check warning on line 153 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L153

Added line #L153 was not covered by tests
}

my %display_categories = map { $_ => 1 } @{$c->stash->{category}};
delete $display_categories{$_} for (@remove_from_display);
$c->stash->{display_categories} = \%display_categories;

@{$c->stash->{category}} = grep { $_ !~ /^group-/} @{$c->stash->{category}};
my (@categories, @groups_selected_from);
for my $param (keys %display_categories) {

Check warning on line 157 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L156-L157

Added lines #L156 - L157 were not covered by tests
if ($param =~ /\-group\-/) {
my ($category, $group) = split(/\-group\-/, $param);
push @categories, $category;

Check warning on line 160 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L159-L160

Added lines #L159 - L160 were not covered by tests
push @groups_selected_from, $group if $group;
$display_categories{$param} = $category;

Check warning on line 162 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L162

Added line #L162 was not covered by tests
} elsif ($param =~ /^group-(.*)/) {
push @groups_selected_from, $1;
$display_categories{$param} = 'group-' . $1;
for my $contact (@{$group_names{$1}}) {
push @categories, $contact->category;

Check warning on line 167 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L164-L167

Added lines #L164 - L167 were not covered by tests
}
}
};

$c->stash->{category} = \@categories;
$c->stash->{groups_selected_from} = \@groups_selected_from;
$c->stash->{display_categories} = { reverse %display_categories };

Check warning on line 174 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L172-L174

Added lines #L172 - L174 were not covered by tests
$c->stash->{ward} = [ $c->get_param_list('ward') ];

if ($c->user_exists) {
Expand Down Expand Up @@ -256,18 +274,28 @@ sub generate_grouped_data : Private {
%grouped = map { $_->category => {} } @{$c->stash->{contacts}};
}
my $problems = $c->stash->{objects_rs}->search(undef, {
group_by => [ map { ref $_ ? $_->{-as} : $_ } @groups ],
select => [ @groups, { count => 'me.id' } ],
as => [ @groups == 2 ? qw/key1 key2 count/ : qw/key1 count/ ],
group_by => [ map { ref $_ ? $_->{-as} : $_ } (@groups, 'me.extra') ],
select => [ @groups, { count => 'me.id' }, 'me.extra' ],
as => [ @groups == 2 ? qw/key1 key2 count extra/ : qw/key1 count extra/ ],
} );
$c->stash->{group_by} = $group_by;

my %columns;
while (my $p = $problems->next) {
my %cols = $p->get_columns;
my ($col1, $col2) = ($cols{key1}, $cols{key2});
my ($col1, $col2, $col3) = ($cols{key1}, $cols{key2}, $cols{extra});

Check warning on line 286 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L286

Added line #L286 was not covered by tests
if ($group_by eq 'category+state') {
$col2 = $state_map->{$cols{key2}};
}
if ($group_by eq 'category+state' || $group_by eq 'category') {
if ($col3 && decode_json($col3)->{group}) {
my $group = decode_json($col3)->{group};

Check warning on line 292 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L292

Added line #L292 was not covered by tests
if (grep { /$group/ } @{$c->stash->{groups_selected_from}} ) {
$col1 = decode_json($col3)->{group} . "::" . $col1;

Check warning on line 294 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L294

Added line #L294 was not covered by tests
} else {
next;

Check warning on line 296 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L296

Added line #L296 was not covered by tests
}
}
} elsif ($group_by eq 'month') {
$col1 = Time::Piece->strptime("2017-$cols{key1}-01", '%Y-%m-%d')->fullmonth;
}
Expand Down Expand Up @@ -295,23 +323,38 @@ sub generate_grouped_data : Private {
$am <=> $bm;
} @rows;
} elsif ($group_by eq 'category+state' || $group_by eq 'category') {
my @subcategory_specific = grep { $_ =~ /::/ } @rows;

Check warning on line 326 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L326

Added line #L326 was not covered by tests
@rows = ();
my @sorting_categories;
my %category_to_group;
for my $group (@{$c->stash->{category_groups}}) {
for my $category (@{$group->{categories}}) {
push @sorting_categories, $category->category;
if (!$category_to_group{$category->category}) {
$category_to_group{$category->category} = $group->{name};
$category_to_group{$category->category}{group} = $group->{name} || '';
$category_to_group{$category->category}{display_name} = $category->category;

Check warning on line 335 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L334-L335

Added lines #L334 - L335 were not covered by tests
} else {
$category_to_group{$category->category} = 'Multiple';
$category_to_group{$category->category}{group} = 'Multiple';
$category_to_group{$category->category}{display_name} = $category->category;

Check warning on line 338 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L337-L338

Added lines #L337 - L338 were not covered by tests
}
}
};
my ($single_group, $multiple_groups) = part { $category_to_group{$_} eq 'Multiple'} @sorting_categories;
my @multiple = sort (uniq(@$multiple_groups));

push @rows, @$single_group if $single_group;
for (@subcategory_specific) {
my ($group, $display_name) = split(/::/, $_);
push @sorting_categories, $_;
$category_to_group{$_}{group} = $group;
$category_to_group{$_}{display_name} = $display_name;

Check warning on line 346 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L342-L346

Added lines #L342 - L346 were not covered by tests
}
my ($single_group, $multiple_groups) = part { $category_to_group{$_}{group} eq 'Multiple'} @sorting_categories;

Check warning on line 348 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L348

Added line #L348 was not covered by tests
my @single_group = sort {
$category_to_group{$a}{group} cmp $category_to_group{$b}{group}

Check warning on line 350 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L350

Added line #L350 was not covered by tests
|| $category_to_group{$a}{display_name} cmp $category_to_group{$b}{display_name}
} (@$single_group);
my @multiple = sort {
$category_to_group{$a}{group} cmp $category_to_group{$b}{group}

Check warning on line 354 in perllib/FixMyStreet/App/Controller/Dashboard.pm

View check run for this annotation

Codecov / codecov/patch

perllib/FixMyStreet/App/Controller/Dashboard.pm#L354

Added line #L354 was not covered by tests
|| $category_to_group{$a}{display_name} cmp $category_to_group{$b}{display_name}
} (uniq(@$multiple_groups));
push @rows, @single_group if scalar @single_group;
push @rows, @multiple if scalar @multiple;
$c->stash->{category_to_group} = \%category_to_group;
} else {
Expand Down
2 changes: 1 addition & 1 deletion perllib/FixMyStreet/Reporting.pm
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ has filename => ( is => 'rw', isa => Str, lazy => 1, default => sub {
start_date => $self->start_date,
end_date => $self->end_date,
);
$where{category} = @{$self->category} < 3 ? join(',', @{$self->category}) : 'multiple-categories';
$where{category} = @{$self->category} < 3 ? join(',', sort @{$self->category}) : 'multiple-categories';
$where{body} = $self->body->id if $self->body;
$where{role} = $self->role_id if $self->role_id;
my $host = URI->new($self->cobrand->base_url)->host;
Expand Down
35 changes: 28 additions & 7 deletions t/app/controller/dashboard.t
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ my @cats = ('Litter', 'Other', 'Potholes', 'Traffic lights & bells', 'White line
for my $contact ( @cats ) {
my $c = $mech->create_contact_ok(body_id => $body->id, category => $contact, email => "$contact\@example.org");
if ($contact eq 'Potholes' || $contact eq 'White lines') {
$c->set_extra_metadata(group => ['Road & more']);
$c->set_extra_metadata(group => ['Road & more', 'Pavements']);
$c->update;
}
}
Expand Down Expand Up @@ -161,7 +161,7 @@ FixMyStreet::override_config {

subtest 'The correct categories and totals shown by default' => sub {
$mech->get_ok("/dashboard");
my $expected_cats = [ 'Litter', 'Other', 'Traffic lights & bells', 'All Road & more', 'Potholes', 'White lines' ];
my $expected_cats = [ 'Litter', 'Other', 'Traffic lights & bells', 'All Pavements', 'Potholes', 'White lines', 'All Road & more', 'Potholes', 'White lines' ];
my $res = $categories->scrape( $mech->content );
$mech->content_contains('<optgroup label="Road &amp; more">');
$mech->content_contains('<option value="group-Road &amp; more"');
Expand All @@ -182,21 +182,42 @@ FixMyStreet::override_config {
my $end = DateTime->now->subtract(months => 1)->strftime('%Y-%m-%d');
$mech->submit_form_ok({ with_fields => { state => '', start_date => $start, end_date => $end } });
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3);
$mech->get_ok("/dashboard?category=Litter&category=Potholes");
$mech->get_ok("/dashboard?category=Litter-group-&category=Potholes-group-");
test_table($mech->content, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 6, 0, 0, 0, 0, 3, 0, 4, 7);
$mech->get_ok("/dashboard?category=Traffic+lights+%26+bells");
$mech->content_contains("<option value='Traffic lights &amp; bells' selected>");
$mech->get_ok("/dashboard?category=Traffic+lights+%26+bells-group-");
$mech->content_contains("<option value='Traffic lights &amp; bells-group-' selected>");
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 0, 10);
$mech->get_ok("/dashboard?category=group-Road+%26+more");
$mech->content_contains('<option value="group-Road &amp; more" selected>');
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 6, 1, 0, 0, 1, 3, 0, 4, 7);
$mech->get_ok("/dashboard?category=group-Road+%26+more&category=Potholes");
$mech->get_ok("/dashboard?category=group-Road+%26+more&category=Potholes-group-");
test_table($mech->content, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 6, 1, 0, 0, 1, 3, 0, 4, 7);
$mech->get_ok("/dashboard?category=group-Road+%26+more&category=Litter");
$mech->get_ok("/dashboard?category=group-Road+%26+more&category=Litter-group-");
test_table($mech->content, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 6, 1, 0, 0, 1, 4, 0, 4, 8);

my ($sub_pothole_pavement) = $mech->create_problems_for_body(1, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Potholes', cobrand => 'no2fat' });
$sub_pothole_pavement->set_extra_metadata( group => 'Pavements');
$sub_pothole_pavement->update;
$mech->get_ok("/dashboard?category=group-Road+%26+more&category=Litter-group-");
test_table($mech->content, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 6, 1, 0, 0, 1, 4, 0, 4, 8);
my ($sub_pothole_road) = $mech->create_problems_for_body(1, $body->id, 'Title', { areas => ",$area_id,2651,", category => 'Potholes', cobrand => 'no2fat' });
$sub_pothole_road->set_extra_metadata( group => 'Road & more');
$sub_pothole_road->state('closed');
$sub_pothole_road->update;
$mech->get_ok("/dashboard?category=group-Road+%26+more&category=Litter-group-");
test_table($mech->content, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 0, 4, 6, 1, 0, 0, 1, 4, 1, 4, 9);
$sub_pothole_pavement->delete; $sub_pothole_pavement->update;
$sub_pothole_road->delete; $sub_pothole_road->update;
};

subtest 'test grouping' => sub {
my $contacts = FixMyStreet::DB->resultset('Contact')->search( { body_id => $body->id } );
while (my $contact = $contacts->next) {
if ($contact->category eq 'Potholes' || $contact->category eq 'White lines') {
$contact->set_extra_metadata(group => ['Road & more']);
$contact->update;
}
}
$mech->get_ok("/dashboard?group_by=category");
my $top_level = test_table($mech->content, 1, 0, 10, 6, 1, 18);
is_deeply $top_level, ['Road & more'], 'Road group created';
Expand Down
14 changes: 8 additions & 6 deletions templates/web/base/dashboard/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ <h1>[% loc('Summary statistics') %]</h1>
<select class="form-control js-multiple" multiple name="category" id="category">
[% BLOCK category_option %]
[% SET category_safe = mark_safe(cat.category) %]
<option value='[% cat.category | html %]'[% ' selected' IF display_categories.$category_safe %]>[% cat.category_display | html %]</option>
<option value='[% cat.category | html %]-[% group.group_id | html %]'[% ' selected' IF display_categories.$category_safe %]>[% cat.category_display | html %]</option>
[% END %]
[%~ INCLUDE 'report/new/_category_select.html' include_group_option=1 ~%]
</select>
Expand Down Expand Up @@ -156,19 +156,21 @@ <h1>[% loc('Summary statistics') %]</h1>
</tr>
[% SET current_category = '' %]
[% FOR k IN rows %][% k_safe = mark_safe(k) %]
[% IF category_to_group.$k_safe AND category_to_group.$k_safe != current_category %]
[% SET current_category = category_to_group.$k_safe %]
[% IF category_to_group.$k_safe.group AND category_to_group.$k_safe.group != current_category %]
[% SET current_category = category_to_group.$k_safe.group %]
<tr>
[% IF group_by == 'category+state' %]
<th colspan="5" scope="colgroup">[% category_to_group.$k_safe %]</th>
[% IF group_by == 'category+state' OR group_by == 'category' %]
<th colspan="5" scope="colgroup">[% category_to_group.$k_safe.group %]</th>
[% ELSE %]
<th colspan="2" scope="colgroup">[% category_to_group.$k_safe %]</th>
<th colspan="2" scope="colgroup">[% $k_safe %]</th>
[% END %]
</tr>
[% END %]
<tr>
[% IF group_by == 'state' %]
<th scope="row">[% prettify_state(k) %]</th>
[% ELSIF group_by == 'category' OR group_by == 'category+state' %]
<th scope="row">[% category_to_group.$k_safe.display_name %]</th>
[% ELSE %]
<th scope="row">[% k %]</th>
[% END %]
Expand Down

0 comments on commit f9cb3dc

Please sign in to comment.