aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Arter <davea@mysociety.org>2018-03-29 10:14:50 +0100
committerDave Arter <davea@mysociety.org>2018-04-03 16:31:12 +0100
commit8e8e3e1370b8b7744f9491ff78563f40c475e872 (patch)
tree5cf9c7ff5bbb79eacb2d57933187359baf6f886d
parent246a419d5026f9ff067b2a34c375d34044225042 (diff)
User import admin page
This is intended to be an internal tool for quickly creating staff users in bulk. As such, it's hidden at /admin/user_import and is only available to superusers.
-rw-r--r--CHANGELOG.md1
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm46
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm1
-rw-r--r--templates/web/base/admin/user_import.html76
4 files changed, 124 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16c91b885..e1ccaf4ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,6 +37,7 @@
- Users with 'user_edit' permission can search for users/reports. #2027
- Don't send sent-report emails to as-body/as-anonymous reports.
- Show Open311 service code as tooltip on admin category checkboxes. #2049
+ - Bulk user import admin page. #2057
- Development improvements:
- Add HTML email previewer.
- Add CORS header to Open311 output. #2022
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 96fe086c3..1256ae3b7 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -12,6 +12,7 @@ use DateTime::Format::Strptime;
use List::Util 'first';
use List::MoreUtils 'uniq';
use mySociety::ArrayUtils;
+use Text::CSV;
use FixMyStreet::SendReport;
use FixMyStreet::SMS;
@@ -1636,6 +1637,51 @@ sub user_edit : Path('user_edit') : Args(1) {
return 1;
}
+sub user_import : Path('user_import') {
+ my ( $self, $c, $id ) = @_;
+
+ $c->forward('/auth/get_csrf_token');
+ return unless $c->user_exists && $c->user->is_superuser;
+
+ if ($c->req->method eq 'POST') {
+ $c->forward('/auth/check_csrf_token');
+ $c->stash->{new_users} = [];
+ $c->stash->{existing_users} = [];
+
+ my @all_permissions = map { keys %$_ } values %{ $c->cobrand->available_permissions };
+ my %available_permissions = map { $_ => 1 } @all_permissions;
+
+ my $csv = Text::CSV->new({ binary => 1});
+ my $fh = $c->req->upload('csvfile')->fh;
+ $csv->getline($fh); # discard the header
+ while (my $row = $csv->getline($fh)) {
+ my ($name, $email, $from_body, $permissions) = @$row;
+ my @permissions = split(/:/, $permissions);
+
+ my $user = FixMyStreet::DB->resultset("User")->find_or_new({ email => $email, email_verified => 1 });
+ if ($user->in_storage) {
+ push @{$c->stash->{existing_users}}, $user;
+ next;
+ }
+
+ $user->name($name);
+ $user->from_body($from_body || undef);
+ $user->update_or_insert;
+
+ my @user_permissions = grep { $available_permissions{$_} } @permissions;
+ foreach my $permission_type (@user_permissions) {
+ $user->user_body_permissions->find_or_create({
+ body_id => $user->from_body->id,
+ permission_type => $permission_type,
+ });
+ }
+
+ push @{$c->stash->{new_users}}, $user;
+ }
+
+ }
+}
+
sub contact_cobrand_extra_fields : Private {
my ( $self, $c, $contact ) = @_;
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 8c4d8be53..99b247412 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -645,6 +645,7 @@ sub admin_pages {
$pages->{flagged} = [ _('Flagged'), 7 ];
$pages->{states} = [ _('States'), 8 ];
$pages->{config} = [ _('Configuration'), 9];
+ $pages->{user_import} = [ undef, undef ];
};
# And some that need special permissions
if ( $user->has_body_permission_to('category_edit') ) {
diff --git a/templates/web/base/admin/user_import.html b/templates/web/base/admin/user_import.html
new file mode 100644
index 000000000..f866ed955
--- /dev/null
+++ b/templates/web/base/admin/user_import.html
@@ -0,0 +1,76 @@
+[% INCLUDE 'admin/header.html' title=loc("User Import") -%]
+[% PROCESS 'admin/report_blocks.html' %]
+
+[% status_message %]
+
+<form method="post" id="user_edit" action="[% c.uri_for( 'user_import' ) %]" enctype="multipart/form-data" accept-charset="utf-8">
+ <input type="hidden" name="token" value="[% csrf_token %]" >
+ <input type="hidden" name="submit" value="1" >
+
+ <p>
+ <label>
+ [% loc('CSV File') %]
+ <input type="file" name="csvfile" id="form_csvfile" />
+ </label>
+ <input type="submit" class="btn" name="Import users" value="[% loc('Import users') %]" />
+ </p>
+</form>
+
+[% IF new_users %]
+ <h2>[% tprintf(loc('Created %d new users'), new_users.size ) %]</h2>
+ <table>
+ <tr>
+ <th>[% loc('Name') %]</th>
+ <th>[% loc('Email') %]</th>
+ <th>[% loc('Body') %]</th>
+ </tr>
+ [% FOREACH user IN new_users %]
+ <tr>
+ <td>
+ <a href="[% c.uri_for_action( 'admin/user_edit', user.id ) %]">
+ [% user.name %]
+ </a>
+ </td>
+ <td>[% user.email %]</td>
+ <td>[% user.from_body.name %]</td>
+ </tr>
+ [% END %]
+ </table>
+[% END %]
+
+[% IF existing_users %]
+ <h2>[% tprintf(loc("%d users already existed"), existing_users.size) %]</h2>
+ <p>[% loc("These users weren't updated.") %]</p>
+ <table>
+ <tr>
+ <th>[% loc('Name') %]</th>
+ <th>[% loc('Email') %]</th>
+ <th>[% loc('Body') %]</th>
+ </tr>
+ [% FOREACH user IN existing_users %]
+ <tr>
+ <td>
+ <a href="[% c.uri_for_action( 'admin/user_edit', user.id ) %]">
+ [% user.name %]
+ </a>
+ </td>
+ <td>[% user.email %]</td>
+ <td>[% user.from_body.name %]</td>
+ </tr>
+ [% END %]
+ </table>
+[% END %]
+
+<h2>[% loc('Usage notes') %]</h2>
+<p>[% loc('This page is a quick way to create many new staff users in one go.') %]</p>
+<p>[% loc("Existing users won't be modified.") %]</p>
+<p>
+ [% loc("The uploaded CSV file must contain a header row, and records must have the following fields (in this order):") %]
+ <pre>name,email,from_body,permissions</pre>
+ <ul>
+ <li><code>from_body</code>: [% loc("the database id of the body to associate that user with, e.g. <code>2217</code> for Buckinghamshire.") %]</li>
+ <li><code>permissions</code>: [% loc("a colon-separated list of permissions to grant that user, e.g. <code>contribute_as_body:moderate:user_edit</code>.") %]</li>
+ </ul>
+</p>
+
+[% INCLUDE 'admin/footer.html' %]