[MKDoc-commit] CSV patch from Sam

chris at mkdoc.demon.co.uk chris at mkdoc.demon.co.uk
Mon May 9 10:12:52 BST 2005


Log Message:
-----------
CSV patch from Sam

Tags:
----
mkdoc-1-6

Modified Files:
--------------
    mkd/templates/admin/user_list:
        en.html

Added Files:
-----------
    mkd/flo/plugin/Admin:
        UserCSV.pm

-------------- next part --------------
--- /dev/null
+++ flo/plugin/Admin/UserCSV.pm
@@ -0,0 +1,278 @@
+package flo::plugin::Admin::UserCSV;
+use strict;
+use warnings;
+
+=head1 NAME
+
+flo::plugin::Admin::UserCSV - CSV download for user data
+
+=head1 SYNOPSIS
+
+Link to this plugin like so:
+
+  <a href=".admin.usercsv">Download the user CSV!</a>
+
+When clicked the client's browser will download a file called
+mkdoc_users.csv containing all user data.
+
+=head1 DESCRIPTION
+
+This plugin provides a CSV download of all user data.
+
+=head1 SUBCLASSING
+
+Two methods are provided to aid in subclassing this plugin:
+
+=head2 add_headers
+
+  @new_headers = $self->add_headers(@headers);
+
+This callback passes in the default list of headers.  The return value
+is used as the new header list.
+
+=head2 add_data
+
+  @new_data = $self->add_data($user, @data);
+
+This callback passes in the row data for a single user.  The return
+value is as the new data list.  Obviously the order must match
+whatever changes are made in add_headers().
+
+=head1 AUTHOR
+
+Sam Tregar <sam at tregar.com>
+
+=head1 COPYRIGHT
+
+Copyright MKDoc Holdings Ltd, 2005
+
+=head1 LICENSE
+
+MKDoc is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+MKDoc is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with MKDoc; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+=cut
+
+use flo::Standard;
+use base qw /flo::Plugin/;
+use Text::CSV_XS;
+use flo::Record::Preference::Audience qw(LIKE DONT_MIND HATE);
+
+# only admin can access this plugin
+sub activate {
+    my $self = shift;
+    $self->SUPER::activate(@_) || return;
+    $self->user()->id() == 1   || return;
+    return 1;
+}
+
+sub template_path { 'admin/unused' }
+
+# hooks for sub-classes
+sub add_headers {@_[1..$#_]}
+sub add_data    {@_[1..$#_]}
+
+# return the CSV to the user
+sub http_get {
+    my $self = shift;
+
+    # setup header to get the browser to download as mkdoc_users.csv
+    my $header = new flo::HTTP::Header;
+    $header->set("Content-Type: application/x-download");
+    $header->set("Content-Disposition: attachment; filename=mkdoc_users.csv");
+    print $header->header;
+
+    # all done for head requests
+    return 'TERMINATE'
+      if $ENV{REQUEST_METHOD} and $ENV{REQUEST_METHOD} =~ /^HEAD$/i;
+
+    # build CSV output
+    $self->build_csv();
+    
+    return 'TERMINATE';
+}
+
+# build the CSV using Text::CSV_XS
+sub build_csv {
+    my $self = shift;
+    my $csv  = Text::CSV_XS->new({always_quote => 1, 
+                                  binary       => 1, 
+                                  eol          => "\n"});
+    my ($group_ids, $audience_ids, $language_ids) = $self->print_header($csv);
+
+    foreach my $user ($self->users()) {
+        my @data = $self->data_fields($user, $group_ids, 
+                                      $audience_ids, $language_ids);
+        $self->print_row($csv, @data);
+    }
+}
+
+# prints out the header and returns IDs needed for row generation
+sub print_header {
+    my ($self, $csv) = @_;
+    my $dbh = lib::sql::DBH->get();    
+
+    # get info for variable columns
+    my $results = $dbh->selectall_arrayref('SELECT ID, Name FROM Grp 
+                                            ORDER BY Name');
+    my @group_names = map { $_->[1] } @$results;
+    my @group_ids   = map { $_->[0] } @$results;
+
+    $results = $dbh->selectall_arrayref('SELECT ID, Label FROM Audience
+                                         ORDER BY Label');
+    my @audience_names = map { $_->[1] } @$results;
+    my @audience_ids   = map { $_->[0] } @$results;
+
+    $results = $dbh->selectall_arrayref('SELECT DISTINCT(Language_ID)
+                                         FROM Preference_Language
+                                         ORDER BY Language_ID');
+    my @language_names = map { $_->[0] } @$results;
+    my @language_ids   = @language_names;
+
+    my @headers = ( "Login",
+                    "Email",
+                    "First Name",
+                    "Family Name",
+                    "Disabled Status",
+                    "Daily Newsletter",
+                    "Weekly Newsletter",
+                    "Monthly Newsletter",
+                    "Editor Status",
+                    "Documents Created",
+                    (map { "$_ (Group)" }    @group_names),
+                    (map { "$_ (Audience)" } @audience_names),
+                    (map { "$_ (Language)" } @language_names) );
+    @headers = $self->add_headers(@headers);
+    
+    # print out CSV header
+    $self->print_row($csv, @headers);
+
+    return (\@group_ids, \@audience_ids, \@language_ids);
+}
+
+# encode booleans as "" for false or "0E0" and "TRUE" for all else
+sub _bool ($) {
+    my $val = shift;
+    $val ? ($val eq '0E0' ? "" : "TRUE") : "";
+}
+
+# output a single row of data
+sub data_fields {
+    my ($self, $user, $group_ids, $audience_ids, $language_ids) = @_;
+    my $pref = $user->preferences;
+
+    # login, email, first name, family name
+    my @data = map { $user->$_ } qw(login email first_name family_name);
+
+    # disabled status
+    push @data, _bool not $user->enabled;
+
+    # daily newsletter, weekly newsletter, monthly newsletter
+    push @data,
+      _bool $pref->general_preference('newsletter-daily'),
+      _bool $pref->general_preference('newsletter-weekly'),
+      _bool $pref->general_preference('newsletter-monthly');
+
+    # editor status
+    push @data, _bool($user->group eq 'editor');
+
+    # documents created
+    push @data, $self->documents_created($user);
+
+    # group membership
+    push @data, map { _bool($self->group_member($user, $_)) } @$group_ids;
+
+    # audicence membership
+    push @data, map { $self->audience_setting($user, $_) } @$audience_ids;
+
+    # language membership
+    push @data, map { $self->language_setting($user, $_) } @$language_ids;
+
+    return $self->add_data($user, @data);
+}
+
+# print a CSV row with error checking
+sub print_row {
+    my ($self, $csv, @data) = @_;
+    if ($csv->combine(@data)) {
+        print $csv->string;
+    } else {
+        my $err = $csv->error_input;
+        die "Text::CSV_XS::combine() failed on (" . 
+          join(', ', map { defined($_) ? qq{'$_'} : "undef" } @data) . "): " .
+            $err;
+    }
+}
+
+# returns all uses as flo::Record::Editor objects (this could use an
+# iterator if there are too many users to load all at once)
+sub users {
+    my $self = shift;
+    my $editor_t = flo::Standard::table ('Editor');
+    my @res = $editor_t->select (
+	cols => '*',
+	sort => [ 'First_Name', 'Family_Name' ],
+	desc => 0,
+       )->fetch_all();
+
+    return wantarray ? @res : \@res;
+}
+
+sub documents_created {
+    my ($self, $user) = @_;
+    my $dbh = lib::sql::DBH->get();
+    my ($count) = $dbh->selectrow_array('SELECT COUNT(*) FROM Document
+                                         WHERE Editor_Created_ID = ?', 
+                                        undef, $user->id);
+    return $count || 0;
+}
+
+sub group_member {
+    my ($self, $user, $grp_id) = @_;
+    my $dbh = lib::sql::DBH->get();
+    
+    my ($exists) = 
+      $dbh->selectrow_array('SELECT 1 FROM Editor_Grp
+                             WHERE Grp_ID = ? AND Editor_ID = ?', 
+                            undef, $grp_id, $user->id);
+
+    return $exists;
+}
+
+
+sub audience_setting {
+    my ($self, $user, $aud_id) = @_;
+    my $dbh = lib::sql::DBH->get();
+    
+    my ($value) = 
+      $dbh->selectrow_array('SELECT Value FROM Preference_Audience
+                             WHERE Audience_ID = ? AND Editor_ID = ?', 
+                            undef, $aud_id, $user->id);
+    $value ||= DONT_MIND;
+    return $value == LIKE ? "TRUE" : "";
+}
+
+sub language_setting {
+    my ($self, $user, $lang_id) = @_;
+    my $dbh = lib::sql::DBH->get();
+    
+    my ($value) = 
+      $dbh->selectrow_array('SELECT Value FROM Preference_Language
+                             WHERE Language_ID = ? AND Editor_ID = ?', 
+                            undef, $lang_id, $user->id);
+    $value ||= DONT_MIND;
+    return $value == LIKE ? "TRUE" : "";
+}
+
+1;
Index: en.html
===================================================================
RCS file: /var/spool/cvs/mkd/templates/admin/user_list/Attic/en.html,v
retrieving revision 1.1.2.10
retrieving revision 1.1.2.11
diff -Ltemplates/admin/user_list/en.html -Ltemplates/admin/user_list/en.html -u -r1.1.2.10 -r1.1.2.11
--- templates/admin/user_list/en.html
+++ templates/admin/user_list/en.html
@@ -76,6 +76,16 @@
         or edit or delete the existing users using the links in the following table.
       </p>
 
+      <p
+        lang="en"
+        xml:lang="en"
+        dir="ltr"
+      >
+        <a
+          href=".admin.usercsv"
+        >Download user data CSV</a> for offline analysis.
+      </p>
+
       <table
         cellpadding="4"
         cellspacing="0"


More information about the MKDoc-commit mailing list