Bug 8130 - attach PDF files to a patron record
authorKyle M Hall <kyle@bywatersolutions.com>
Mon, 21 May 2012 20:42:53 +0000 (16:42 -0400)
committerPaul Poulain <paul.poulain@biblibre.com>
Thu, 28 Jun 2012 08:55:51 +0000 (10:55 +0200)
Adds the ability to attach unlimited arbitrary files to
a borrower record.

Test Plan:
1) Enable system preference EnableBorrowerFiles
2) Look up borrower record, click 'Files' tab on left
3) Upload a file, download the file, delete the file.

Signed-off-by: Liz Rea <wizzyrea@gmail.com>
rebased for current master.

Signed-off-by: Ian Walls <koha.sekjal@gmail.com>
rebased again; some indentation issues in include menus.

C4/Auth.pm
Koha/Borrower/Files.pm [new file with mode: 0644]
installer/data/mysql/sysprefs.sql
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/includes/circ-menu.inc
koha-tmpl/intranet-tmpl/prog/en/includes/members-menu.inc
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/patrons.pref
koha-tmpl/intranet-tmpl/prog/en/modules/members/files.tt [new file with mode: 0644]
members/files.pl [new file with mode: 0755]

index 143fe3f..f796d11 100644 (file)
@@ -365,6 +365,7 @@ sub get_template_and_user {
             LocalCoverImages            => C4::Context->preference('LocalCoverImages'),
             OPACLocalCoverImages        => C4::Context->preference('OPACLocalCoverImages'),
             AllowMultipleCovers         => C4::Context->preference('AllowMultipleCovers'),
+            EnableBorrowerFiles         => C4::Context->preference('EnableBorrowerFiles'),
         );
     }
     else {
diff --git a/Koha/Borrower/Files.pm b/Koha/Borrower/Files.pm
new file mode 100644 (file)
index 0000000..91a5463
--- /dev/null
@@ -0,0 +1,155 @@
+package Koha::Borrower::Files;
+
+# Copyright 2012 Kyle M Hall
+#
+# This file is part of Koha.
+#
+# Koha 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.
+#
+# Koha 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 Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use Modern::Perl;
+
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
+
+use C4::Context;
+use C4::Output;
+use C4::Dates;
+use C4::Debug;
+
+BEGIN {
+
+    # set the version for version checking
+    $VERSION = 0.01;
+    require Exporter;
+    @ISA    = qw(Exporter);
+    @EXPORT = qw(
+
+    );
+
+    my $debug = C4::Context->preference("DebugLevel");
+}
+
+=head1 NAME
+
+Koha::Borrower::Files - Module for managing borrower files
+
+=cut
+
+sub new {
+    my ( $class, %args ) = @_;
+    my $self = bless( {}, $class );
+
+    $self->{'borrowernumber'} = $args{'borrowernumber'};
+
+    return $self;
+}
+
+=item GetFilesInfo()
+
+    my $bf = Koha::Borrower::Files->new( borrowernumber => $borrowernumber );
+    my $files_hashref = $bf->GetFilesInfo
+
+=cut
+
+sub GetFilesInfo {
+    my $self = shift;
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        SELECT
+            file_id,
+            file_name,
+            file_type,
+            file_description,
+            date_uploaded
+        FROM borrower_files
+        WHERE borrowernumber = ?
+        ORDER BY file_name, date_uploaded
+    ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute( $self->{'borrowernumber'} );
+    return $sth->fetchall_arrayref( {} );
+}
+
+=item AddFile()
+    my $bf = Koha::Borrower::Files->new( borrowernumber => $borrowernumber );
+    $bh->AddFile( name => $filename, type => $mimetype, description => $description, content => $content );
+=cut
+
+sub AddFile {
+    my ( $self, %args ) = @_;
+
+    my $name        = $args{'name'};
+    my $type        = $args{'type'};
+    my $description = $args{'description'};
+    my $content     = $args{'content'};
+
+    return unless ( $name && $content );
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        INSERT INTO borrower_files ( borrowernumber, file_name, file_type, file_description, file_content )
+        VALUES ( ?,?,?,?,? )
+    ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute( $self->{'borrowernumber'},
+        $name, $type, $description, $content );
+}
+
+=item GetFile()
+    my $bf = Koha::Borrower::Files->new( borrowernumber => $borrowernumber );
+    my $file = $bh->GetFile( file_id => $file_id );
+=cut
+
+sub GetFile {
+    my ( $self, %args ) = @_;
+
+    my $file_id = $args{'id'};
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        SELECT * FROM borrower_files WHERE file_id = ? AND borrowernumber = ?
+    ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute( $file_id, $self->{'borrowernumber'} );
+    return $sth->fetchrow_hashref();
+}
+
+=item DelFile()
+    my $bf = Koha::Borrower::Files->new( borrowernumber => $borrowernumber );
+    $bh->DelFile( file_id => $file_id );
+=cut
+
+sub DelFile {
+    my ( $self, %args ) = @_;
+
+    my $file_id = $args{'id'};
+
+    my $dbh   = C4::Context->dbh;
+    my $query = "
+        DELETE FROM borrower_files WHERE file_id = ? AND borrowernumber = ?
+    ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute( $file_id, $self->{'borrowernumber'} );
+}
+
+1;
+__END__
+
+=back
+
+=head1 AUTHOR
+
+Kyle M Hall <kyle.m.hall@gmail.com>
+
+=cut
index 8e3066d..9474336 100644 (file)
@@ -372,3 +372,4 @@ INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('
 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('DefaultLanguageField008','','Fill in the default language for field 008 Range 35-37 (e.g. eng, nor, ger, see <a href="http://www.loc.gov/marc/languages/language_code.html">MARC Code List for Languages</a>)','','Free');
 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OPACShowBarcode','0','Show items barcode in holding tab','','YesNo');
 INSERT INTO systempreferences (variable,value,options,explanation,type) VALUES ('OPACShowUnusedAuthorities','1','','Show authorities that are not being used in the OPAC.','YesNo');
+INSERT INTO systempreferences (variable,value,explanation,type) VALUES('EnableBorrowerFiles','0','If enabled, allows librarians to upload and attach arbitrary files to a borrower record.','YesNo');
index 4d1f37b..f3acaad 100755 (executable)
@@ -5423,6 +5423,28 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
     SetVersion ($DBversion);
 }
 
+$DBversion = "3.09.00.020";
+if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
+    $dbh->do("INSERT INTO systempreferences (variable,value,explanation,type) VALUES('EnableBorrowerFiles','0','If enabled, allows librarians to upload and attach arbitrary files to a borrower record.','YesNo')");
+    $dbh->do("
+CREATE TABLE IF NOT EXISTS borrower_files (
+  file_id int(11) NOT NULL AUTO_INCREMENT,
+  borrowernumber int(11) NOT NULL,
+  file_name varchar(255) NOT NULL,
+  file_type varchar(255) NOT NULL,
+  file_description varchar(255) DEFAULT NULL,
+  file_content longblob NOT NULL,
+  date_uploaded timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY (file_id),
+  KEY borrowernumber (borrowernumber)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
+    ");
+    $dbh->do("ALTER TABLE borrower_files ADD CONSTRAINT borrower_files_ibfk_1 FOREIGN KEY (borrowernumber) REFERENCES borrowers (borrowernumber) ON DELETE CASCADE ON UPDATE CASCADE");
+
+    print "Upgrade to $DBversion done (Added borrow_files table, EnableBorrowerFiles syspref)\n";
+    SetVersion($DBversion);
+}
+
 =head1 FUNCTIONS
 
 =head2 TableExists($table)
index 7014c39..3c8c1bf 100644 (file)
 <div id="menu">
 <ul>
     [% IF ( circview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% borrowernumber %]">Check out</a></li>
-       [% IF ( CAN_user_borrowers ) %]
-       [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">Details</a></li>
-       [% END %]
-        [% IF ( CAN_user_updatecharges ) %]
-       [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Fines</a></li>
-       [% END %]
-    [% IF ( intranetreadinghistory ) %][% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrowernumber %]">Circulation history</a></li>[% END %]
-    [% IF ( CAN_user_parameters ) %][% IF ( logview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/tools/viewlog.pl?do_it=1&amp;modules=MEMBERS&amp;modules=circulation&amp;object=[% borrowernumber %]&amp;src=circ">Modification log</a></li>[% END %]
+    [% IF ( CAN_user_borrowers ) %]
+        [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">Details</a></li>
+    [% END %]
+    [% IF ( CAN_user_updatecharges ) %]
+        [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Fines</a></li>
+    [% END %]
+    [% IF ( intranetreadinghistory ) %]
+        [% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrowernumber %]">Circulation history</a></li>
+    [% END %]
+    [% IF ( CAN_user_parameters ) %]
+        [% IF ( logview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/tools/viewlog.pl?do_it=1&amp;modules=MEMBERS&amp;modules=circulation&amp;object=[% borrowernumber %]&amp;src=circ">Modification log</a></li>
+    [% END %]
     [% IF ( EnhancedMessagingPreferences ) %]
-    [% END %]  
        [% IF ( sentnotices ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/notices.pl?borrowernumber=[% borrowernumber %]">Notices</a></li>
+    [% END %]
     [% IF (  statisticsview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/statistics.pl?borrowernumber=[% borrowernumber %]">Statistics</a></li>
+    [% IF ( sentnotices ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/notices.pl?borrowernumber=[% borrowernumber %]">Notices</a></li>
+    [% IF EnableBorrowerFiles %]
+        [% IF ( borrower_files ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/files.pl?borrowernumber=[% borrowernumber %]">Files</a></li>
+    [% END %]
 </ul></div>
 [% END %]
 
index 4b771d8..9bd5285 100644 (file)
@@ -1,15 +1,24 @@
 [% IF ( borrowernumber ) %]
 <div id="menu">
-<ul>   [% IF ( circview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% borrowernumber %]">Check out</a></li>
-       [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">Details</a></li>
-       [% IF ( CAN_user_updatecharges ) %]
-       [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Fines</a></li>
-       [% END %]
-    [% IF ( intranetreadinghistory ) %][% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrowernumber %]">Circulation history</a></li>[% END %]
-    [% IF ( CAN_user_parameters ) %][% IF ( logview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/tools/viewlog.pl?do_it=1&amp;modules=MEMBERS&amp;action=MODIFY&amp;object=[% borrowernumber %]">Modification log</a></li>[% END %]
-    [% IF ( EnhancedMessagingPreferences ) %]
+  <ul>
+    [% IF ( circview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/circ/circulation.pl?borrowernumber=[% borrowernumber %]">Check out</a></li>
+    [% IF ( detailview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">Details</a></li>
+    [% IF ( CAN_user_updatecharges ) %]
+        [% IF ( finesview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/boraccount.pl?borrowernumber=[% borrowernumber %]">Fines</a></li>
+    [% END %]
+    [% IF ( intranetreadinghistory ) %]
+        [% IF ( readingrecordview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/readingrec.pl?borrowernumber=[% borrowernumber %]">Circulation history</a></li>
+    [% END %]
+    [% IF ( CAN_user_parameters ) %]
+        [% IF ( logview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/tools/viewlog.pl?do_it=1&amp;modules=MEMBERS&amp;action=MODIFY&amp;object=[% borrowernumber %]">Modification log</a></li>
     [% END %]
+    [% IF ( EnhancedMessagingPreferences ) %]
        [% IF ( sentnotices ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/notices.pl?borrowernumber=[% borrowernumber %]">Notices</a></li>
+    [% END %]
     [% IF (  statisticsview ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/statistics.pl?borrowernumber=[% borrowernumber %]">Statistics</a></li>
-</ul></div>
+    [% IF EnableBorrowerFiles %]
+        [% IF ( borrower_files ) %]<li class="active">[% ELSE %]<li>[% END %]<a href="/cgi-bin/koha/members/files.pl?borrowernumber=[% borrowernumber %]">Files</a></li>
+    [% END %]
+  </ul>
+</div>
 [% END %]
index 030f376..70af762 100644 (file)
@@ -131,3 +131,9 @@ Patrons:
          - pref: StatisticsFields
            class: multi
          - Define Fields (from the items table) used for statistics members (separate fields with |, for example:"location|itype|ccode").
+     -
+         - pref: EnableBorrowerFiles
+           choices:
+               yes: Do
+               no: "Don't"
+         - enable the ability to upload and attach arbitrary files to a borrower record.
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/files.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/files.tt
new file mode 100644 (file)
index 0000000..1655823
--- /dev/null
@@ -0,0 +1,74 @@
+[% USE KohaDates %]
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Files for [% INCLUDE 'patron-title.inc' %]</title>
+[% INCLUDE 'doc-head-close.inc' %]
+</head>
+<body>
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'patron-search.inc' %]
+
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/members/members-home.pl">Patrons</a>  &rsaquo; Files for [% INCLUDE 'patron-title.inc' %]</div>
+
+<div id="doc3" class="yui-t2">
+    <div id="bd">
+        <div id="yui-main">
+            <div class="yui-b">
+                [% INCLUDE 'circ-toolbar.inc' %]
+
+                <h1>Files</h1>
+
+                <table>
+                    <thead>
+                        <th>Name</th>
+                        <th>Type</th>
+                        <th>Description</th>
+                        <th>Uploaded</th>
+                        [% IF CAN_user_borrowers %]<th>&nbsp;</th>[% END %]
+                    </thead>
+
+                    <tbody>
+                        [% IF errors %]
+                            <div class="error warn">
+                                [% IF errors.empty_upload %]The file you are attempting to upload has no contents.[% END %]
+                                [% IF errors.no_file %]You did not select a file to upload.[% END %]
+                            </div>
+                        [% END %]
+
+                        [% FOREACH f IN files %]
+                            <tr>
+                                 <td><a href="?borrowernumber=[% borrowernumber %]&op=download&file_id=[% f.file_id %]">[% f.file_name %]</a></td>
+                                 <td>[% f.file_type %]</td>
+                                 <td>[% f.file_description %]</td>
+                                 <td>[% f.date_uploaded | $KohaDates %]</td>
+                                 [% IF CAN_user_borrowers %]<td><a href="?borrowernumber=[% borrowernumber %]&op=delete&file_id=[% f.file_id %]">Delete</a></td>[% END %]
+                            </tr>
+                        [% END %]
+                    </tbody>
+                </table>
+
+                <form method="post" enctype="multipart/form-data">
+                    <fieldset>
+                        <legend>Upload New File</legend>
+
+                        <input type="hidden" name="op" value="upload" />
+                        <input type="hidden" name="borrowernumber" value="[% borrowernumber %]" />
+                        <input type="hidden" name="MAX_FILE_SIZE" value="2000000" />
+
+                        <label for="description">Description:</label>
+                        <input name="description" type="text" />
+
+                        <input name="uploadfile" type="file" id="uploadfile" />
+
+                        <input name="upload" type="submit" id="upload" value="Upload File" />
+                    </fieldset>
+                </form>
+
+            </div>
+        </div>
+
+        <div class="yui-b">
+            [% INCLUDE 'circ-menu.inc' %]
+        </div>
+    </div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/members/files.pl b/members/files.pl
new file mode 100755 (executable)
index 0000000..ccd11bc
--- /dev/null
@@ -0,0 +1,115 @@
+#!/usr/bin/perl
+
+# Copyright 2012 ByWater Solutions
+#
+# This file is part of Koha.
+#
+# Koha 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.
+#
+# Koha 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 Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use CGI;
+
+use C4::Auth;
+use C4::Output;
+use C4::Members;
+use C4::Debug;
+
+use Koha::DateUtils;
+use Koha::Borrower::Files;
+
+my $cgi = CGI->new;
+
+my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+    {
+        template_name   => "members/files.tmpl",
+        query           => $cgi,
+        type            => "intranet",
+        authnotrequired => 0,
+        flagsrequired   => { borrowers => 1 },
+        debug           => 1,
+    }
+);
+$template->param( 'borrower_files' => 1 );
+
+my $borrowernumber = $cgi->param('borrowernumber');
+my $bf = Koha::Borrower::Files->new( borrowernumber => $borrowernumber );
+
+my $op = $cgi->param('op') || '';
+
+if ( $op eq 'download' ) {
+    my $file_id = $cgi->param('file_id');
+    my $file = $bf->GetFile( id => $file_id );
+
+    print $cgi->header(
+        -type       => $file->{'file_type'},
+        -charset    => 'utf-8',
+        -attachment => $file->{'file_name'}
+    );
+    print $file->{'file_content'};
+}
+else {
+    my $data = GetMember( borrowernumber => $borrowernumber );
+    $template->param(%$data);
+
+    my %errors;
+
+    if ( $op eq 'upload' ) {
+        my $uploaded_file = $cgi->upload('uploadfile');
+
+        if ($uploaded_file) {
+            my $filename = $cgi->param('uploadfile');
+            my $mimetype = $cgi->uploadInfo($filename)->{'Content-Type'};
+
+            $errors{'empty_upload'} = 1 unless ( length($uploaded_file) > 0 );
+
+            if (%errors) {
+                $template->param( errors => %errors );
+            }
+            else {
+                my $file_content;
+                while (<$uploaded_file>) {
+                    $file_content .= $_;
+                }
+
+                $bf->AddFile(
+                    name    => $filename,
+                    type    => $mimetype,
+                    content => $file_content,
+                    description => $cgi->param('description'),
+                );
+            }
+        }
+        else {
+            $errors{'no_file'} = 1;
+        }
+    } elsif ( $op eq 'delete' ) {
+        $bf->DelFile( id => $cgi->param('file_id') );
+    }
+
+    $template->param(
+        files => Koha::Borrower::Files->new( borrowernumber => $borrowernumber )
+          ->GetFilesInfo(),
+
+        errors => %errors
+    );
+    output_html_with_http_headers $cgi, $cookie, $template->output;
+}
+
+=head1 AUTHOR
+
+Kyle M Hall <kyle@bywatersolutions.com>
+
+=cut