Bugzilla – Attachment 19379 Details for
Bug 9032
Share a list
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
[SIGNED-OFF] Bug 9032: Share a list (part 1: send the invitation)
SIGNED-OFF-Bug-9032-Share-a-list-part-1-send-the-i.patch (text/plain), 15.89 KB, created by
Owen Leonard
on 2013-07-03 16:02:23 UTC
(
hide
)
Description:
[SIGNED-OFF] Bug 9032: Share a list (part 1: send the invitation)
Filename:
MIME Type:
Creator:
Owen Leonard
Created:
2013-07-03 16:02:23 UTC
Size:
15.89 KB
patch
obsolete
>From 6fe9b3593064a87cc171f06459d72ec5523f8ac2 Mon Sep 17 00:00:00 2001 >From: Marcel de Rooy <m.de.rooy@rijksmuseum.nl> >Date: Mon, 20 May 2013 17:57:39 +0200 >Subject: [PATCH] [SIGNED-OFF] Bug 9032: Share a list (part 1: send the > invitation) >Content-Type: text/plain; charset="utf-8" > >Adds a Share button for OPAC private lists. >Allows you to send an invitation to share a list. >Checks on validity of email addresses (with Email::Valid). > >NOTE: This patch adds a routine to VirtualShelves.pm but does not add a test >in VirtualShelves.t. This is intentional: I will still add a test, but saw >report 10290 and came across a few other problems in this unit test. Will >add a patch under report 10386. > >Test plan: > >1) Sharing depends on syspref and login. >Toggle the pref OpacAllowSharingPrivateList. >If enabled, you should see the Share button in OPAC/Private lists. >Click on the Share button. You should get Share a list. >Logout and try to go back to opac/opac-shareshelf.pl >It should now present you the login form. > >2) Try to share a public list or a list you do not own. >Find a security hole in the interface. Or hack the shareshelf URL and replace >the shelfnumber with a public list number. > >3) Enter no email address or invalid ones (no domain, forbidden chars). >If you enter no address, submit should not work. >If you enter only wrong addresses (separated by: ,:; ), you get a message. > >4) Test if sending the invitation works. >Share one of your private lists. Enter your own email address. >After your proc_message_queue cronjob ran, you should have an email. >Check also if you see a new record in the virtualshelfshares table. >Note that the followup patch handles the second part of accepting this share. > >Signed-off-by: Owen Leonard <oleonard@myacpl.org> >--- > C4/VirtualShelves.pm | 29 ++- > .../opac-tmpl/prog/en/modules/opac-shareshelf.tt | 69 ++++++ > .../opac-tmpl/prog/en/modules/opac-shelves.tt | 18 +- > opac/opac-shareshelf.pl | 226 ++++++++++++++++++++ > 4 files changed, 340 insertions(+), 2 deletions(-) > create mode 100644 koha-tmpl/opac-tmpl/prog/en/modules/opac-shareshelf.tt > create mode 100755 opac/opac-shareshelf.pl > >diff --git a/C4/VirtualShelves.pm b/C4/VirtualShelves.pm >index 38fa0e8..f464199 100644 >--- a/C4/VirtualShelves.pm >+++ b/C4/VirtualShelves.pm >@@ -29,6 +29,8 @@ use constant SHELVES_COMBO_MAX => 10; #add to combo in search > use constant SHELVES_MGRPAGE_MAX => 20; #managing page > use constant SHELVES_POPUP_MAX => 40; #addbybiblio popup > >+use constant SHARE_INVITATION_EXPIRY_DAYS => 14; #two weeks to accept >+ > use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); > > BEGIN { >@@ -42,7 +44,7 @@ BEGIN { > &ModShelf > &ShelfPossibleAction > &DelFromShelf &DelShelf >- &GetBibliosShelves >+ &GetBibliosShelves &AddShare > ); > @EXPORT_OK = qw( > &GetAllShelves &ShelvesMax >@@ -640,6 +642,31 @@ sub HandleDelBorrower { > $dbh->do($query,undef,($borrower)); > } > >+=head2 AddShare >+ >+ AddShare($shelfnumber, $key); >+ >+Adds a share request to the virtualshelves table. >+Authorization must have been checked, and a key must be supplied. See script >+opac-shareshelf.pl for an example. >+This request is not yet confirmed. So it has no borrowernumber, it does have an >+expiry date. >+ >+=cut >+ >+sub AddShare { >+ my ($shelfnumber, $key)= @_; >+ return if !$shelfnumber || !$key; >+ >+ my $sql; >+ my $dbh = C4::Context->dbh; >+ $sql="DELETE FROM virtualshelfshares WHERE sharedate<NOW() LIMIT 10"; >+ #housekeeping: add one, remove max 10 expired ones >+ $dbh->do($sql); >+ $sql="INSERT INTO virtualshelfshares (shelfnumber, invitekey, sharedate) VALUES (?, ?, ADDDATE(NOW(),?))"; >+ $dbh->do($sql, undef, ($shelfnumber, $key, SHARE_INVITATION_EXPIRY_DAYS)); >+} >+ > # internal subs > > sub _shelf_count { >diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-shareshelf.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-shareshelf.tt >new file mode 100644 >index 0000000..63c17bc >--- /dev/null >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-shareshelf.tt >@@ -0,0 +1,69 @@ >+[% INCLUDE 'doc-head-open.inc' %][% IF ( LibraryNameTitle ) %][% LibraryNameTitle %][% ELSE %]Koha online[% END %] catalog › Share a list >+[% INCLUDE 'doc-head-close.inc' %] >+</head> >+<body id="opac-shareshelf"> >+<div id="doc3" class="yui-t1"> >+<div id="bd"> >+[% INCLUDE 'masthead.inc' %] >+ >+<div id="yui-main"> >+ <div class="yui-b"><div class="yui-g"> >+ >+[%# This section contains the essential code for error messages and three operations: invite, confirm_invite and accept. %] >+ <h1>Share a list with another patron</h1> >+ [% IF errcode %] >+ [% IF errcode==1 && op %]<div class="dialog alert">The operation [% op %] is not supported.</div>[% END %] >+ [% IF errcode==1 && !op %]<div class="dialog alert">No operation parameter has been passed.</div>[% END %] >+ [% IF errcode==2 %]<div class="dialog alert">Invalid shelf number.</div>[% END %] >+ [% IF errcode==3 %]<div class="dialog alert">The feature of sharing lists is not in use in this library.</div>[% END %] >+ [% IF errcode==4 %]<div class="dialog alert">You can only share a list if you are the owner.</div>[% END %] >+ [% IF errcode==5 %]<div class="dialog alert">You cannot share a public list.</div>[% END %] >+ [% IF errcode==6 %]<div class="dialog alert">Sorry, but you did not enter any valid email address.</div>[% END %] >+ >+ [% ELSIF op=='invite' %] >+ <form method="post" onsubmit="return $('#invite_address').val().trim()!='';"> >+ <input type="hidden" name="op" value="conf_invite"/> >+ <input type="hidden" name="shelfnumber" value="[% shelfnumber %]"/> >+ <table> >+ <tr> >+ <td><label for="list_name">List name</label></td> >+ <td>[% shelfname %]</td> >+ </tr> >+ <tr> >+ <td><label for="invite_address">Email address</label></td> >+ <td><input id="invite_address" name="invite_address"/></td> >+ </tr> >+ </table> >+ <input type="submit" value="Send"/> >+ </form> >+ >+ [% ELSIF op=='conf_invite' %] >+ <p>We have sent invitation emails to share list [% shelfname %] to the mail queue for [% approvedaddress %].</p> >+ [% IF failaddress %] >+ <p>The following addresses appear to be invalid. Please correct them and try again. These are: [% failaddress %]</p> >+ [% END %] >+ <p>You will be notified if someone accepts your share within two weeks.</p> >+ >+ [% ELSIF op=='accept' %] >+ [%# TODO: Replace the following two lines %] >+ <p>Thank you for testing this feature.</p> >+ <p>Your signoff will certainly help in finishing the remaining part!</p> >+ >+ [% END %] >+[%# End of essential part %] >+ >+</div> >+</div> >+</div> >+ >+[% IF ( OpacNav ) %] >+ <div class="yui-b"> >+ <div id="opacnav" class="container"> >+ [% INCLUDE 'navigation.inc' %] >+ </div> >+ </div> >+[% END %] >+ >+</div> >+</div> >+[% INCLUDE 'opac-bottom.inc' %] >diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-shelves.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-shelves.tt >index 66ff9bc..a6c0507 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-shelves.tt >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-shelves.tt >@@ -1,3 +1,4 @@ >+[% USE Koha %] > [% SET TagsShowEnabled = ( TagsEnabled && TagsShowOnList ) %] > [% SET TagsInputEnabled = ( opacuserlogin && TagsEnabled && TagsInputOnList ) %] > >@@ -349,7 +350,15 @@ $(document).ready(function() { > <input type="hidden" value="1" name="shelves"/> > <input type="hidden" value="1" name="DEL-[% shelfnumber %]"/> > [% IF ( showprivateshelves ) %]<input type="hidden" name="display" value="privateshelves"/>[% END %]<input type="submit" class="deleteshelf" value="Delete list" onclick="return confirmDelete(MSG_CONFIRM_DELETE_LIST);"/> >- </form> [% END %] >+ </form> >+ [% IF showprivateshelves && Koha.Preference('OpacAllowSharingPrivateLists') %] >+ <form action="opac-shareshelf.pl" method="post"> >+ <input type="hidden" name="shelfnumber" value="[% shelfnumber %]" /> >+ <input type="hidden" name="op" value="invite" /> >+ <input type="submit" class="Share" value="Share" /> >+ </form> >+ [% END %] >+ [% END %] > > > </div> >@@ -629,7 +638,14 @@ $(document).ready(function() { > [% ELSE %] > <input type="submit" class="deleteshelf" onclick="return confirmDelete(MSG_CONFIRM_DELETE_LIST);" value="Delete" /> > [% END %] >+ </form> >+ [% IF Koha.Preference('OpacAllowSharingPrivateLists') %] >+ <form action="opac-shareshelf.pl" method="post"> >+ <input type="hidden" name="shelfnumber" value="[% shelveslooppri.shelf %]" /> >+ <input type="hidden" name="op" value="invite" /> >+ <input type="submit" class="Share" value="Share" /> > </form> >+ [% END %] > [% END %] > </td> > </tr> >diff --git a/opac/opac-shareshelf.pl b/opac/opac-shareshelf.pl >new file mode 100755 >index 0000000..6c95f0d >--- /dev/null >+++ b/opac/opac-shareshelf.pl >@@ -0,0 +1,226 @@ >+#!/usr/bin/perl >+ >+# Copyright 2013 Rijksmuseum >+# >+# 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 constant KEYLENGTH => 10; >+ >+use CGI; >+use Email::Valid; >+ >+use C4::Auth; >+use C4::Context; >+use C4::Letters; >+use C4::Output; >+use C4::VirtualShelves; >+ >+#------------------------------------------------------------------------------- >+ >+my $query= new CGI; >+my ($shelfname, $owner); >+my ($template, $loggedinuser, $cookie); >+my $errcode=0; >+my (@addr, $fail_addr, @newkey); >+my @base64alphabet= ('A'..'Z', 'a'..'z', 0..9, '+', '/'); >+ >+my $shelfnumber= $query->param('shelfnumber')||0; >+my $op= $query->param('op')||''; >+my $addrlist= $query->param('invite_address')||''; >+my $key= $query->param('key')||''; >+ >+#------------------------------------------------------------------------------- >+ >+check_common_errors(); >+load_template("opac-shareshelf.tmpl"); >+if($errcode) { >+ #nothing to do >+} >+elsif($op eq 'invite') { >+ show_invite(); >+} >+elsif($op eq 'conf_invite') { >+ confirm_invite(); >+} >+elsif($op eq 'accept') { >+ show_accept(); >+} >+load_template_vars(); >+output_html_with_http_headers $query, $cookie, $template->output; >+ >+#------------------------------------------------------------------------------- >+ >+sub check_common_errors { >+ if($op!~/^(invite|conf_invite|accept)$/) { >+ $errcode=1; #no operation specified >+ return; >+ } >+ if($shelfnumber!~/^\d+$/) { >+ $errcode=2; #invalid shelf number >+ return; >+ } >+ if(!C4::Context->preference('OpacAllowSharingPrivateLists')) { >+ $errcode=3; #not or no longer allowed? >+ return; >+ } >+} >+ >+sub show_invite { >+ return unless check_owner_category(); >+} >+ >+sub confirm_invite { >+ return unless check_owner_category(); >+ process_addrlist(); >+ if(@addr) { >+ send_invitekey(); >+ } >+ else { >+ $errcode=6; #not one valid address >+ } >+} >+ >+sub show_accept { >+ #TODO Add some code here to accept an invitation (followup report) >+} >+ >+sub process_addrlist { >+ my @temp= split /[,:;]/, $addrlist; >+ $fail_addr=''; >+ foreach my $a (@temp) { >+ $a=~s/^\s+//; >+ $a=~s/\s+$//; >+ if(IsEmailAddress($a)) { >+ push @addr, $a; >+ } >+ else { >+ $fail_addr.= ($fail_addr? '; ': '').$a; >+ } >+ } >+} >+ >+sub send_invitekey { >+ my $fromaddr= C4::Context->preference('KohaAdminEmailAddress'); >+ my $url= 'http://'.C4::Context->preference('OPACBaseURL'); >+ $url.= "/cgi-bin/koha/opac-shareshelf.pl?shelfnumber=$shelfnumber"; >+ $url.= "&op=accept&key="; >+ #FIXME Waiting for the right http or https solution (BZ 8952 a.o.) >+ >+ foreach my $a (@addr) { >+ @newkey=randomlist(KEYLENGTH, 64); #generate a new key >+ >+ #prepare letter >+ my $letter= C4::Letters::GetPreparedLetter( >+ module => 'members', >+ letter_code => 'SHARE_INVITE', >+ branchcode => C4::Context->userenv->{"branch"}, >+ tables => { borrowers => $loggedinuser, }, >+ substitute => { >+ listname => $shelfname, >+ shareurl => $url.keytostring(\@newkey,0), >+ }, >+ ); >+ >+ #send letter to queue >+ C4::Letters::EnqueueLetter( { >+ letter => $letter, >+ message_transport_type => 'email', >+ from_address => $fromaddr, >+ to_address => $a, >+ }); >+ #add a preliminary share record >+ AddShare($shelfnumber,keytostring(\@newkey,1)); >+ } >+} >+ >+sub check_owner_category { >+ #FIXME candidate for a module? what held me back is: getting back the two different error codes and the shelfname >+ (undef,$shelfname,$owner,my $category)= GetShelf($shelfnumber); >+ $errcode=4 if $owner!= $loggedinuser; #should be owner >+ $errcode=5 if !$errcode && $category!=1; #should be private >+ return $errcode==0; >+} >+ >+sub load_template { >+ my ($file)= @_; >+ ($template, $loggedinuser, $cookie)= get_template_and_user({ >+ template_name => $file, >+ query => $query, >+ type => "opac", >+ authnotrequired => 0, #should be a user >+ }); >+} >+ >+sub load_template_vars { >+ $template->param( >+ errcode => $errcode, >+ op => $op, >+ shelfnumber => $shelfnumber, >+ shelfname => $shelfname, >+ approvedaddress => (join '; ', @addr), >+ failaddress => $fail_addr, >+ ); >+} >+ >+sub IsEmailAddress { >+ #FIXME candidate for a module? >+ return Email::Valid->address($_[0])? 1: 0; >+} >+ >+sub randomlist { >+#uses rand, safe enough for this application but not for more sensitive data >+ my ($length, $base)= @_; >+ return map { int(rand($base)); } 1..$length; >+} >+ >+sub keytostring { >+ my ($keyref, $flgBase64)= @_; >+ if($flgBase64) { >+ return join '', map { base64chr($_); } @$keyref; >+ } >+ return join '', map { sprintf("%02d",$_); } @$keyref; >+} >+ >+sub stringtokey { >+ my ($str, $flgBase64)= @_; >+ my @temp=split '', $str||''; >+ if($flgBase64) { >+ return map { base64ord($_); } @temp; >+ } >+ return () if $str!~/^\d+$/; >+ my @retval; >+ for(my $i=0; $i<@temp-1; $i+=2) { >+ push @retval, $temp[$i]*10+$temp[$i+1]; >+ } >+ return @retval; >+} >+ >+sub base64ord { #base64 ordinal >+ my ($char)=@_; >+ return 0 -ord('A')+ord($char) if $char=~/[A-Z]/; >+ return 26-ord('a')+ord($char) if $char=~/[a-z]/; >+ return 52-ord('0')+ord($char) if $char=~/[0-9]/; >+ return 62 if $char eq '+'; >+ return 63 if $char eq '/'; >+ return; >+} >+ >+sub base64chr { #reverse operation for ord >+ return $_[0]=~/^\d+$/ && $_[0]<64? $base64alphabet[$_[0]]: undef; >+} >-- >1.7.9.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 9032
:
18260
|
18542
|
18543
|
18546
|
18547
|
18587
|
18619
|
18682
|
18692
|
19377
|
19378
|
19379
|
19394
|
19934
|
19935
|
25847
|
25848
|
25849
|
25850
|
25851
|
25852
|
25853
|
25862
|
25886
|
25893
|
26253
|
26291
|
26292
|
26293
|
26294
|
26295
|
26296
|
26297
|
26298
|
26299
|
26300
|
26302
|
26303
|
26351
|
26458
|
26509
|
26513
|
26577
|
26578
|
26579
|
26580
|
26581
|
26582
|
26583
|
26584
|
26585
|
26586
|
26587
|
26588