[Koha-patches] [PATCH] Initial commit for Tags back-end moderation. Requires AJAX functions from Output.

Joe Atzberger joe.atzberger at liblime.com
Mon May 19 23:23:37 CEST 2008


---
 C4/Tags.pm                                         |   52 ++--
 .../intranet-tmpl/prog/en/modules/tags/review.tmpl |  361 ++++++++++++++++++++
 tags/review.pl                                     |  238 +++++++++++++
 3 files changed, 629 insertions(+), 22 deletions(-)
 create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tags/review.tmpl
 create mode 100755 tags/review.pl

diff --git a/C4/Tags.pm b/C4/Tags.pm
index 4d3c1c1..68591b4 100644
--- a/C4/Tags.pm
+++ b/C4/Tags.pm
@@ -60,10 +60,14 @@ INIT {
 	$select_all = "SELECT " . join(',', at fields) . "\n FROM   tags_all\n";
 }
 
-sub remove_tag ($) {
-	my $tag_id = shift;
-	my $rows = get_tag_rows({tag_id=>$tag_id}) or return 0;
-	(scalar(@$rows) == 1) or return undef;
+sub remove_tag ($;$) {
+	my $tag_id  = shift or return undef;
+	my $user_id = (@_) ? shift : undef;
+	my $rows = (defined $user_id) ?
+			get_tag_rows({tag_id=>$tag_id, borrowernumber=>$user_id}) :
+			get_tag_rows({tag_id=>$tag_id}) ;
+	$rows or return 0;
+	(scalar(@$rows) == 1) or return undef;	# should never happen (duplicate ids)
 	my $row = shift(@$rows);
 	($tag_id == $row->{tag_id}) or return 0;
 	my $tags = get_tags({term=>$row->{term}, biblionumber=>$row->{biblionumber}});
@@ -126,11 +130,11 @@ sub get_tag_rows ($) {
 			carp "Empty argument key to get_tag_rows: ignoring!";
 			next;
 		}
-		unless (1 == scalar grep {/^ $key $/xi} @ok_fields) {
+		unless (1 == scalar grep {/^ $key $/x} @ok_fields) {
 			carp "get_tag_rows received unreconized argument key '$key'.";
 			next;
 		}
-		if ($key =~ /^limit$/i) {
+		if ($key eq 'limit') {
 			my $val = $hash->{$key};
 			unless ($val =~ /^(\d+,)?\d+$/) {
 				carp "Non-nuerical limit value '$val' ignored!";
@@ -167,18 +171,18 @@ sub get_tags (;$) {		# i.e., from tags_index
 			carp "Empty argument key to get_tags: ignoring!";
 			next;
 		}
-		unless (1 == scalar grep {/^ $key $/xi} @ok_fields) {
+		unless (1 == scalar grep {/^ $key $/x} @ok_fields) {
 			carp "get_tags received unreconized argument key '$key'.";
 			next;
 		}
-		if ($key =~ /^limit$/i) {
+		if ($key eq 'limit') {
 			my $val = $hash->{$key};
 			unless ($val =~ /^(\d+,)?\d+$/) {
 				carp "Non-nuerical limit value '$val' ignored!";
 				next;
 			}
 			$limit = " LIMIT $val\n";
-		} elsif ($key =~ /^sort$/i) {
+		} elsif ($key eq 'sort') {
 			foreach my $by (split /\,/, $hash->{$key}) {
 				unless (
 					$by =~ /^([-+])?(term)/ or
@@ -197,10 +201,12 @@ sub get_tags (;$) {		# i.e., from tags_index
 			}
 			
 		} else {
-			my $whereval = $key;
-			($key =~ /^term$/i) and $whereval = 'tags_index.term';
-			$wheres .= ($wheres) ? " AND    $whereval = ?\n" : " WHERE  $whereval = ?\n";
-			push @exe_args, $hash->{$key};
+			my $whereval = $hash->{$key};
+			my $longkey = ($key eq 'term') ? 'tags_index.term' : $key;
+			my $op = ($whereval =~ s/^(>=|<=)// or
+					  $whereval =~ s/^(>|=|<)//   ) ? $1 : '=';
+			$wheres .= ($wheres) ? " AND    $longkey $op ?\n" : " WHERE  $longkey $op ?\n";
+			push @exe_args, $whereval;
 		}
 	}
 	my $query = "
@@ -233,18 +239,18 @@ sub get_approval_rows (;$) {		# i.e., from tags_approval
 			carp "Empty argument key to get_approval_rows: ignoring!";
 			next;
 		}
-		unless (1 == scalar grep {/^ $key $/xi} @ok_fields) {
+		unless (1 == scalar grep {/^ $key $/x} @ok_fields) {
 			carp "get_approval_rows received unreconized argument key '$key'.";
 			next;
 		}
-		if ($key =~ /^limit$/i) {
+		if ($key eq 'limit') {
 			my $val = $hash->{$key};
 			unless ($val =~ /^(\d+,)?\d+$/) {
 				carp "Non-nuerical limit value '$val' ignored!";
 				next;
 			}
 			$limit = " LIMIT $val\n";
-		} elsif ($key =~ /^sort$/i) {
+		} elsif ($key eq 'sort') {
 			foreach my $by (split /\,/, $hash->{$key}) {
 				unless (
 					$by =~ /^([-+])?(term)/            or
@@ -265,10 +271,11 @@ sub get_approval_rows (;$) {		# i.e., from tags_approval
 			}
 			
 		} else {
-			my $whereval = $key;
-			# ($key =~ /^term$/i) and $whereval = 'tags_index.term';
-			$wheres .= ($wheres) ? " AND    $whereval = ?\n" : " WHERE  $whereval = ?\n";
-			push @exe_args, $hash->{$key};
+			my $whereval = $hash->{$key};
+			my $op = ($whereval =~ s/^(>=|<=)// or
+					  $whereval =~ s/^(>|=|<)//   ) ? $1 : '=';
+			$wheres .= ($wheres) ? " AND    $key $op ?\n" : " WHERE  $key $op ?\n";
+			push @exe_args, $whereval;
 		}
 	}
 	my $query = "
@@ -298,7 +305,7 @@ sub is_approved ($) {
 	my $sth = C4::Context->dbh->prepare("SELECT approved FROM tags_approval WHERE term = ?");
 	$sth->execute($term);
 	unless ($sth->rows) {
-		$ext_dict and return (spellcheck($term) ? 0 : 1);
+		$ext_dict and return (spellcheck($term) ? 0 : 1);	# spellcheck returns empty on OK word
 		return undef;
 	}
 	return $sth->fetch;
@@ -391,7 +398,8 @@ sub add_tag_approval ($;$$) {	# or disapproval
 }
 
 sub mod_tag_approval ($$$) {
-	my $operator = shift or return undef;
+	my $operator = shift;
+	defined $operator or return undef; # have to test defined to allow =0 (kohaadmin)
 	my $term     = shift or return undef;
 	my $approval = (@_ ? shift : 1);	# default is to approve
 	my $query = "UPDATE tags_approval SET approved_by=?, approved=?, date_approved=NOW() WHERE term = ?";
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tags/review.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/tags/review.tmpl
new file mode 100644
index 0000000..402451e
--- /dev/null
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tags/review.tmpl
@@ -0,0 +1,361 @@
+<!-- TMPL_INCLUDE NAME="doc-head-open.inc" -->
+<title>Koha &rsaquo; Tags &rsaquo; <!-- TMPL_IF NAME="do_it" -->Review &rsaquo; <!-- TMPL_ELSE -->Review Tags<!-- /TMPL_IF --></title>
+<!-- TMPL_INCLUDE NAME="doc-head-close.inc" -->
+<!-- TMPL_INCLUDE NAME="calendar.inc" -->
+<style type="text/css">
+.setlabel {width: 6em; font-family: courier; background-color:#E8E8E8;}
+.red      {color:darkred;   background-color: pink;}
+.green    {color:darkgreen; background-color: #D1EFD5; text-align: center;}
+.pending  {background-color: lightyellow;}
+</style>
+<script type="text/javascript">
+//<![CDATA[
+	// <!-- TMPL_VAR NAME="script_name" -->
+	$.ajaxSetup({
+	  url: "/cgi-bin/koha/tags/review.pl",
+	  type: "POST",
+	  dataType: "script"
+	});
+	var ok_count  = 0;
+	var nok_count = 0;
+	var rej_count = 0;
+	var alerted = 0;
+	function pull_counts () {
+		ok_count  = parseInt(document.getElementById("terms_summary_approved_count"  ).innerHTML);
+		nok_count = parseInt(document.getElementById("terms_summary_unapproved_count").innerHTML);
+		rej_count = parseInt(document.getElementById("terms_summary_rejected_count"  ).innerHTML);
+	}
+	function count_approve () {
+		pull_counts();
+		if (nok_count > 0) {
+			$("#terms_summary_unapproved_count").html(nok_count -1);
+			$("#terms_summary_approved_count"  ).html( ok_count +1);
+		}
+	}
+	function count_reject () {
+		pull_counts();
+		if (nok_count > 0) {
+			$("#terms_summary_unapproved_count").html(nok_count -1);
+			$("#terms_summary_rejected_count"  ).html(rej_count +1);
+		}
+	}
+	function warn_once (evt) {
+		if (alerted <= 1 && ($(evt.target).is('.ok') || $(evt.target).is('.rej'))) {
+			alerted += 1;
+			window.alert("this is: " + this + "is '.ok': " + $(evt.target).is('.ok') + "  is '.rej': " + $(evt.target).is('.rej'));
+		}
+	}
+	var success_approve = function(tag){
+		window.alert('AJAX approved tag: ' + tag);
+	};
+	var failure_approve = function(tag){
+		window.alert('AJAX failed to approve tag: ' + tag);
+	};
+	var success_reject  = function(tag){
+		window.alert('AJAX rejected tag: ' + tag);
+	};
+	var failure_reject  = function(tag){
+		window.alert('AJAX failed to reject tag: ' + tag);
+	};
+	var success_test    = function(tag){
+		$('#verdict').html(tag + ' is permitted!');
+	};
+	var failure_test    = function(tag){
+		$('#verdict').html(tag + ' is prohibited!');
+	};
+
+	var success_test_call = function() {
+		$('#test_button').removeAttr("disabled");
+		$('#test_button').attr("value","test");
+	};
+	function readCookie(name) { // from http://www.quirksmode.org/js/cookies.html
+		var nameEQ = name + "=";
+		var ca = document.cookie.split(';');
+			for(var i=0;i < ca.length;i++) {
+				var c = ca[i];
+				while (c.charAt(0)==' '){ c = c.substring(1,c.length); }
+				if (c.indexOf(nameEQ) == 0){ return c.substring(nameEQ.length,c.length); }
+			}
+		return null;
+	}
+	function check_all() {
+		$(':checkbox').each(function(){this.checked="checked"});
+	}
+	function uncheck_all() {
+		$(':checkbox').each(function(){this.checked=""});
+	}
+	$(document).ready(function() {
+		$('.ajax_buttons' ).css({visibility:"visible"});
+		$('body').click(function(event) {
+			pull_counts();
+			// window.alert("Click detected on " + event.target + ": " + $(event.target).html);
+			if ($(event.target).is('.ok')) {
+				$.ajax({
+					"data": {ok: $(event.target).attr("title"), CGISESSID: readCookie('CGISESSID')},
+					"success": count_approve // success_approve
+				});
+				$(event.target).next(".rej").removeAttr("disabled");
+				$(event.target).attr(   "value","approved");
+				$(event.target).attr("disabled","disabled");
+				return false;	// cancel submit
+			}
+			if ($(event.target).is('.rej')) {
+				$.ajax({
+					"data": {rej: $(event.target).attr("title"), CGISESSID: readCookie('CGISESSID')},
+					"success": count_reject // success_reject
+				});
+				$(event.target).prev(".ok").removeAttr("disabled");
+				$(event.target).attr(   "value","rejected");
+				$(event.target).attr("disabled","disabled");
+				return false;	// cancel submit
+			}
+			if ($(event.target).is('#test_button')) {
+				$(event.target).attr(   "value","testing...");
+				$(event.target).attr("disabled","disabled");
+				$.ajax({
+					"data": {test: $('#test').attr("value")},
+					"success": success_test_call // success_reject
+				});
+				return false;	// cancel submit
+			}
+		});
+		$("*").ajaxError(function(evt, request, settings){
+			if ((alerted +=1) <= 1){ window.alert("AJAX error (" + alerted + " alert)"); }
+		});
+	});
+//]]>
+</script>
+</head>
+<body>
+<!-- TMPL_INCLUDE NAME="header.inc" -->
+<!-- TMPL_INCLUDE NAME="cat-search.inc" -->
+
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/tags/review.pl">Tags</a> &rsaquo; Review Tags</div>
+
+<div id="doc3" class="yui-t2">
+ <div id="bd">
+  <div id="yui-main">
+   <div class="yui-b">
+
+<form method="post" action="/cgi-bin/koha/tags/review.pl">
+<fieldset>
+  <legend>Filters</legend>
+	<input type="submit" value="Apply Filter(s)" />
+  <br />
+  <br />
+  <table>
+    <tr>
+		<th>Term</th>
+		<th>Status</th>
+		<th>Reviewer</th>
+		<th>Date</th>
+	</tr>
+	<tr>
+	    <td><input type="text" name="tag" value="<!-- TMPL_VAR NAME="filter_tag" -->" />
+	    </td>
+	    <td><select name="approved">
+			<option <!-- TMPL_IF NAME="filter_approved_all"     -->selected="selected" <!-- /TMPL_IF -->value="all">all</option>
+			<option <!-- TMPL_IF NAME="filter_approved_ok"      -->selected="selected" <!-- /TMPL_IF -->value="1">approved</option>
+			<option <!-- TMPL_IF NAME="filter_approved_pending" -->selected="selected" <!-- /TMPL_IF -->value="0">pending</option>
+			<option <!-- TMPL_IF NAME="filter_approved_rej"     -->selected="selected" <!-- /TMPL_IF -->value="-1">rejected</option>
+			</select>
+	    </td>
+	    <td><input type="text" name="approver" value="<!-- TMPL_VAR NAME="filter_approver" -->" />
+	    </td>
+	    <td>
+			<label for="from" class="setlabel">from </label>
+			<input type="text" size="10" id="from" name="from" value="<!-- TMPL_VAR NAME="filter_date_approved_from" -->" />
+			<img src="<!-- TMPL_VAR Name="themelang" -->/lib/calendar/cal.gif" border="0" alt="Show Calendar" style="cursor: pointer;" id="openCalendarFrom" />
+			<br />
+			<label for="to" class="setlabel">&nbsp;&nbsp;to </label>
+			<input type="text" size="10" id="to"   name="to"   value="<!-- TMPL_VAR NAME="filter_date_approved_to" -->" />
+			<img src="<!-- TMPL_VAR Name="themelang" -->/lib/calendar/cal.gif" border="0" alt="Show Calendar" style="cursor: pointer;" id="openCalendarTo" />
+	    </td>
+	</tr>
+  </table>
+</fieldset>
+</form>
+<script type="text/javascript">
+//<![CDATA[
+// function submit_check (from_id,to_id) {
+//	var dateFrom = Date_from_syspref(document.getElementById(from_id).value);
+//	var dateTo   = Date_from_syspref(document.getElementById(  to_id).value);
+//	var today = new Date();
+// 	if (dateFrom < dateTo) { 
+//		alert("The starting date cannot be after the ending date.");
+//		document.getElementById(to_id).select();
+//		return false;
+//	}
+// 	if (dateFrom > today) { 
+//		alert("The starting date cannot be in the future.");
+//		document.getElementById(from_id).select();
+//		return false;
+//	}
+// }
+
+// return true if the date is blocked.
+function disable_from(date) {var limit = get_Calendar_limit(date,'to'  ); return (limit && limit < date);}
+function disable_to  (date) {var limit = get_Calendar_limit(date,'from'); return (limit && limit > date);}
+
+Calendar.setup({
+	inputField : "from",
+	  ifFormat : "<!-- TMPL_VAR NAME="DHTMLcalendar_dateformat" -->",
+		button : "openCalendarFrom",
+	   disableFunc : disable_from,
+	dateStatusFunc : disable_from
+});
+Calendar.setup({
+	inputField : "to",
+	  ifFormat : "<!-- TMPL_VAR NAME="DHTMLcalendar_dateformat" -->",
+		button : "openCalendarTo",
+	   disableFunc : disable_to,
+	dateStatusFunc : disable_to
+});
+//]]>
+</script>
+<form method="post" action="/cgi-bin/koha/tags/review.pl">
+  <h4>Displaying 
+	<!-- TMPL_IF NAME="filter_approved_all"     -->ALL<!-- /TMPL_IF -->
+	<!-- TMPL_IF NAME="filter_approved_ok"      -->Approved<!-- /TMPL_IF -->
+	<!-- TMPL_IF NAME="filter_approved_pending" -->Pending<!-- /TMPL_IF -->
+	<!-- TMPL_IF NAME="filter_approved_rej"     -->Rejected<!-- /TMPL_IF -->
+	Terms
+  </h4>
+  <p>
+   <input type="submit" value="approve" id="approve_button" name="op" />
+   <input type="submit" value="reject"  id="reject_button"  name="op" />
+   <input type="button" value="check all" class="ajax_buttons" onclick="check_all()" />
+   <input type="button" value="uncheck all" class="ajax_buttons" onclick="uncheck_all()" />
+  </p>
+  <!-- TMPL_IF NAME="op_count" -->
+  <div class="message" id="main_status">
+  		<!-- TMPL_IF EXPR="op eq 'approve'" -->		Approved
+  		<!-- TMPL_ELSIF EXPR="op eq 'reject'" -->	Rejected
+  		<!-- TMPL_ELSIF EXPR="op eq 'test'" -->		Tested
+  		<!-- TMPL_ELSE -->							Unkown Operation (<!-- TMPL_VAR NAME="op" -->) on
+  		<!-- /TMPL_IF -->
+	<!-- TMPL_VAR NAME="op_count" --> Term(s).
+  </div>
+  <!-- /TMPL_IF -->
+  <!-- TMPL_IF NAME="message_loop" -->
+  <div class="error" id="main_error">
+	<!-- TMPL_LOOP NAME="message_loop" -->
+		<!-- TMPL_IF    NAME="date_from"  -->ERROR: Date from is not a legal value (<!-- TMPL_VAR NAME="date_from" -->).
+		<!-- TMPL_ELSIF NAME="date_to"    -->ERROR: Date to is not a legal value (<!-- TMPL_VAR NAME="date_to" -->).
+		<!-- TMPL_ELSIF NAME="failed_ok"  -->ERROR: Failed to approve term (<!-- TMPL_VAR NAME="failed_ok" -->).
+		<!-- TMPL_ELSIF NAME="failed_rej" -->ERROR: Failed to reject term (<!-- TMPL_VAR NAME="failed_rej" -->).
+		<!-- TMPL_ELSIF NAME="approver"   -->ERROR: No match for user (<!-- TMPL_VAR NAME="approver" -->). FILTER REQUIRES BORROWERNUMBER (not name).
+		<!-- TMPL_ELSIF NAME="approved_by"-->ERROR: No match for borrowernumber (<!-- TMPL_VAR NAME="approved_by" -->).
+		<!-- TMPL_ELSIF NAME="op_zero"    -->ERROR: The root koha user in your KOHA_CONF file
+				(default: kohaadmin) is not a valid tag moderator.  These actions are logged 
+				by borrowernumber, so the moderator must exist in your borrowers table.
+				Please login as a different authorized staff user to moderate tags.  
+		<!-- TMPL_ELSE -->					Unrecognized error! 
+		<!-- /TMPL_IF -->
+		<br />
+	<!-- /TMPL_LOOP -->
+  </div>
+  <!-- /TMPL_IF -->
+  <!-- TMPL_IF NAME="pagination_bar" -->
+  <div class="pagination" id="pagination_top">
+  	<!-- TMPL_VAR NAME="pagination_bar" -->
+  </div>
+  <!-- /TMPL_IF -->
+  <!-- TMPL_IF NAME="tagloop" -->
+  <table>
+    <tr>
+    	<th>&nbsp;</th>
+    	<th>&nbsp;</th>
+		<th>Status</th>
+		<th>Term</th>
+		<th>Weight</th>
+		<th>Actions</th>
+		<th>Reviewer</th>
+		<th>Date</th>
+	</tr>
+	<!-- TMPL_LOOP NAME="tagloop" -->
+	<tr>
+	    <td class="count"><!-- TMPL_VAR EXPR="offset + __counter__" -->
+	    </td>
+	    <td><span><input type="checkbox" value="<!-- TMPL_VAR NAME="term"-->" name="tags" /></span>
+	    </td>
+	    <!-- TMPL_IF EXPR="approved == -1" --><td class="red">rejected
+		<!-- TMPL_ELSIF EXPR="approved == 1" --><td class="green"><img alt="OK" src="/intranet-tmpl/prog/img/approve.gif" />
+		<!-- TMPL_ELSE --><td class="pending">
+		<!-- /TMPL_IF -->
+	    </td>
+	    <td><!-- TMPL_VAR NAME="term" -->
+	    </td>
+		<td><!-- TMPL_VAR NAME="weight_total" -->
+	    </td>
+		<!-- TMPL_IF NAME="approved" -->
+	    <td><span class="ajax_buttons" style="visibility:hidden">
+			<!-- TMPL_IF EXPR="approved == -1" -->
+			<input class="ok"  type="submit" title="<!-- TMPL_VAR NAME="term"-->" value="approve" name="approve" />
+			<input class="rej" disabled="disabled" type="submit" title="<!-- TMPL_VAR NAME="term"-->" value="reject" name="reject" />
+			<!-- TMPL_ELSE -->
+			<input class="ok"  disabled="disabled" type="submit" title="<!-- TMPL_VAR NAME="term"-->" value="approve" name="approve" />
+			<input class="rej" type="submit" title="<!-- TMPL_VAR NAME="term"-->" value="reject" name="reject" />
+			<!-- /TMPL_IF -->
+			</span>
+	    </td>
+	    <td><a href="?approved_by=<!-- TMPL_VAR NAME="approved_by" -->&amp;approved=all"><!-- TMPL_VAR NAME="approved_by_name" --></a>
+	    </td>
+		<!-- TMPL_ELSE -->
+		<td colspan="2"><span class="ajax_buttons" style="visibility:hidden">
+	    	<input class="ok"  type="submit" title="<!-- TMPL_VAR NAME="term"-->" value="approve" name="approve" />
+			<input class="rej" type="submit" title="<!-- TMPL_VAR NAME="term"-->" value="reject" name="reject" />
+			</span>
+	    </td>
+		<!-- /TMPL_IF -->
+	    <td><!-- TMPL_VAR NAME="date_approved"-->
+	    </td>
+	</tr>
+	<!-- /TMPL_LOOP -->
+  </table>
+  <!-- /TMPL_IF -->
+  </form>
+  </div>
+ </div>
+ <div class="yui-b noprint">
+<h1>Tags</h1>
+
+  <fieldset>
+  <legend>Terms Summary</legend>
+  <table class="summary">
+  	<tr><td><a href="review.pl?approved=1">Approved</a>:</td>
+		<td><span id="terms_summary_approved_count"><!-- TMPL_VAR NAME="approved_count" --></span></td>
+  	</tr>
+  	<tr><td><a href="review.pl?approved=-1">Rejected</a>:</td>
+		<td><span id="terms_summary_rejected_count"><!-- TMPL_VAR NAME="rejected_count" --></span></td>
+  	</tr>
+	<tr><td><a href="review.pl?approved=0">Pending</a>:</td>
+		<td><span id="terms_summary_unapproved_count"><!-- TMPL_VAR NAME="unapproved_count" --></span></td>
+  	</tr>
+	<tr><td><a href="review.pl?approved=all">Total</a>:</td>
+		<td><span id="terms_summary_approved_total"><!-- TMPL_VAR NAME="approved_total" --></span></td>
+  	</tr>
+  </table>
+  <span id="terms_summary_status">&nbsp;</span>
+  </fieldset>
+  <fieldset>
+   <legend>Test Blacklist</legend>
+   <div class="description">Enter a word or phrase here to test against your whitelist/blacklist.</div>
+   <form method="post" action="/cgi-bin/koha/tags/review.pl">
+   <input type="text" size="14" name="test" id="test" />
+   <input type="submit" value="test" id="test_button" name="op" />
+   <div id="verdict">
+	<!-- TMPL_IF NAME="test_term" -->
+	<!-- TMPL_IF NAME="verdict_ok" -->
+		&quot;<!-- TMPL_VAR NAME="test_term" -->&quot; is permitted.
+	<!-- TMPL_ELSIF NAME="verdict_rej" -->
+		&quot;<!-- TMPL_VAR NAME="test_term" -->&quot; is prohibited.
+	<!-- /TMPL_IF -->
+	<!-- /TMPL_IF -->
+   </div>
+   </form>
+  </fieldset>
+ </div>
+</div>
+<!-- TMPL_INCLUDE NAME="intranet-bottom.inc" -->
+
diff --git a/tags/review.pl b/tags/review.pl
new file mode 100755
index 0000000..291e84a
--- /dev/null
+++ b/tags/review.pl
@@ -0,0 +1,238 @@
+#!/usr/bin/perl
+
+# This software is placed under the gnu General Public License, v2 (http://www.gnu.org/licenses/gpl.html)
+
+# Copyright 2008 LibLime
+#
+# 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., 59 Temple Place,
+# Suite 330, Boston, MA  02111-1307 USA
+
+use warnings;
+use strict;
+use Data::Dumper;
+use POSIX;
+use CGI;
+use CGI::Cookie; # need to check cookies before having CGI parse the POST request
+
+use C4::Auth qw(:DEFAULT check_cookie_auth);;
+use C4::Context;
+use C4::Dates qw(format_date format_date_in_iso);
+# use C4::Koha;
+use C4::Output 3.02 qw(:html :ajax pagination_bar);
+use C4::Debug;
+use C4::Tags 0.02 qw(get_tags get_approval_rows whitelist blacklist is_approved);
+
+sub counts () { 
+	my $query = "SELECT " .
+	# 		(SELECT count(*) FROM tags_all     ) as tags_all,
+	# 		(SELECT count(*) FROM tags_index   ) as tags_index,
+	"		(SELECT count(*) FROM tags_approval WHERE approved= 1) as approved_count,
+			(SELECT count(*) FROM tags_approval WHERE approved=-1) as rejected_count,
+			(SELECT count(*) FROM tags_approval WHERE approved= 0) as unapproved_count
+	";
+	my $sth = C4::Context->dbh->prepare($query);
+	$sth->execute;
+	my $result = $sth->fetchrow_hashref();
+	$result->{approved_total} = $result->{approved_count} + $result->{rejected_count} + $result->{unapproved_count};
+	$debug and warn "counts returned: " . Dumper $result;
+	return $result;
+}
+
+my $script_name = "/cgi-bin/koha/tags/review.pl";
+my $needed_flags = { tools => 'moderate_comments' };	# FIXME: replace when more specific permission is created.
+
+sub ajax_auth_cgi ($) {		# returns CGI object
+	my $needed_flags = shift;
+	my %cookies = fetch CGI::Cookie;
+	my $input = CGI->new;
+	my $sessid = $cookies{'CGISESSID'}->value || $input->param('CGISESSID');
+	my ($auth_status, $auth_sessid) = check_cookie_auth($sessid, $needed_flags);
+	$debug and
+	print STDERR "($auth_status, $auth_sessid) = check_cookie_auth($sessid," . Dumper($needed_flags) . ")\n";
+	if ($auth_status ne "ok") {
+		output_ajax_with_http_headers $input,
+			"window.alert('Your CGI session cookie ($sessid) is not current.  " . 
+			"Please refresh the page and try again.');\n";
+		exit 0;
+	}
+	$debug and print STDERR "AJAX request: " . Dumper($input),
+		"\n(\$auth_status,\$auth_sessid) = ($auth_status,$auth_sessid)\n";
+	return $input;
+}
+
+if (is_ajax()) {
+	my $input = &ajax_auth_cgi($needed_flags);
+	my $operator = C4::Context->userenv->{'number'};  # must occur AFTER auth
+	$debug and print STDERR "op: " . Dumper($operator) . "\n";
+	my ($tag, $js_reply);
+	if ($tag = $input->param('test')) {
+		$js_reply = ( is_approved(          $tag) ? 'success' : 'failure') . "_test('$tag');\n";
+	}
+	if ($tag = $input->param('ok')) {
+		$js_reply = (   whitelist($operator,$tag) ? 'success' : 'failure') . "_approve('$tag');\n";
+	} 
+	if ($tag = $input->param('rej')) {
+		$js_reply = (   blacklist($operator,$tag) ? 'success' : 'failure')  . "_reject('$tag');\n";
+	}
+	output_ajax_with_http_headers $input, $js_reply;
+	exit;
+}
+
+### Below is the sad, boring, necessary non-AJAX HTML code.
+
+my $input = CGI->new;
+my ($template, $borrowernumber, $cookie) = get_template_and_user({
+		template_name => "tags/review.tmpl",
+		query => $input,
+		 type => "intranet",
+		debug => 1,
+		authnotrequired => 0,
+	 	  flagsrequired => $needed_flags,
+});
+
+my ($op, @errors, @tags);
+$op   = $input->param('op') || 'none';
+ at tags = $input->param('tags');
+
+$borrowernumber == 0 and push @errors, {op_zero=>1};
+     if ($op eq 'approve') {
+	foreach (@tags) {
+	 	whitelist($borrowernumber,$_) or push @errors, {failed_ok=>$_};
+	}
+} elsif ($op eq 'reject' ) {
+	foreach (@tags) {
+	 	blacklist($borrowernumber,$_) or push @errors, {failed_rej=>$_};
+	}
+} elsif ($op eq 'test'   ) {
+	my $tag = $input->param('test');
+	push @tags, $tag;
+	$template->param(
+		test_term => $tag,
+		(is_approved($tag) ? 'verdict_ok' : 'verdict_rej') => 1,
+	);
+}
+
+my $counts = &counts;
+foreach (keys %$counts) {
+	$template->param($_ => $counts->{$_});
+}
+
+sub pagination_calc ($;$) {
+	my $query = shift or return undef;	
+	my $hardlimit = (@_) ? shift : 100;	# hardcoded, could be another syspref
+	my $pagesize = $query->param('limit' ) || $hardlimit;
+	my $page     = $query->param('page'  ) || 1;
+	my $offset   = $query->param('offset') || 0;
+	($pagesize <= $hardlimit) or $pagesize = $hardlimit;
+	if ($page > 1) {
+		$offset = ($page-1)*$pagesize;
+	} else {
+		$page = 1;
+	}
+	return ($pagesize,$page,$offset);
+}
+
+my ($pagesize,$page,$offset) = pagination_calc($input,100);
+
+my %filters = (
+	limit => $offset ? "$offset,$pagesize" : $pagesize,
+	 sort => 'approved,-weight_total,+term',
+);
+my ($filter,$date_from,$date_to);
+if (defined $input->param('approved')) { # 0 is valid value, must check defined
+	$filter = $input->param('approved');
+} else {
+	$filter = 0;
+}
+if ($filter eq 'all') {
+	$template->param(filter_approved_all => 1);
+} elsif ($filter =~ /-?[01]/) {
+	$filters{approved} = $filter;
+	$template->param(
+		($filter == 1  ? 'filter_approved_ok'      : 
+		 $filter == 0  ? 'filter_approved_pending' :
+		 $filter == -1 ? 'filter_approved_rej'     :
+		'filter_approved') => 1
+	);
+}
+
+# my $q_count = get_approval_rows({limit=>$pagesize, sort=>'approved,-weight_total,+term', count=>1});
+if ($filter = $input->param('tag')) {
+	$template->param(filter_tag=>$filter);
+	$filters{term} = $filter;
+}
+if ($filter = $input->param('from')) {
+	if ($date_from = format_date_in_iso($filter)) {
+		$template->param(filter_date_approved_from=>$filter);
+		$filters{date_approved} = ">=$date_from";
+	} else {
+		push @errors, {date_from=>$filter};
+	}
+}
+if ($filter = $input->param('to')) {
+	if ($date_to = format_date_in_iso($filter)) {
+		$template->param(filter_date_approved_to=>$filter);
+		$filters{date_approved} = "<=$date_to";
+	} else {
+		push @errors, {date_to=>$filter};
+	}
+}
+if ($filter = $input->param('approver')) {		# name (or borrowernumber) from input box
+	if (($filter =~ /^\d+$/ and $filter > 0) or
+		(1) ){	# $filter=get borrowernumber from name
+		$template->param(filter_approver=>$filter);
+		$filters{approved_by} = $filter;
+	# } else {
+		push @errors, {approver=>$filter};
+	}
+}
+if ($filter = $input->param('approved_by')) {	# borrowernumber from link
+	if ($filter =~ /^\d+$/ and $filter > 0) {
+		$template->param(filter_approver=>$filter);
+		$filters{approved_by} = $filter;
+	} else {
+		push @errors, {approved_by=>$filter};
+	}
+}
+$debug and print STDERR "filters: " . Dumper(\%filters);
+my $tagloop = get_approval_rows(\%filters);
+my $qstring = $input->query_string;
+$qstring =~ s/([&;])*\blimit=\d+//;		# remove pagination vars
+# $qstring =~ s/([&;])*\bpage=\d+//;		# remove pagination vars
+# $qstring =~ s/\&[\&]+/&/g;		# compress duplicates
+# $qstring =~ s/;;+/;/g;		# compress duplicates
+# $qstring =~ s/\&;//g;		# remove empties
+# $qstring =~ s/;+$//;		# remove trailing delim
+$qstring =~ s/^;+//;		# remove leading delim
+$qstring = "limit=$pagesize" . ($qstring ? '&amp;' . $qstring : '');
+$debug and print STDERR "number of approval_rows: " . scalar(@$tagloop) . "rows\n";
+(scalar @errors) and $template->param(message_loop=>\@errors);
+$template->param(
+	DHTMLcalendar_dateformat => C4::Dates->DHTMLcalendar(),
+	offset => $offset,	# req'd for EXPR
+	op => $op,
+	op_count => scalar(@tags),
+	script_name => $script_name,
+	approved => 0,		# dummy value (also EXPR)
+	tagloop => $tagloop,
+	pagination_bar => pagination_bar(
+		"$script_name?$qstring\&amp;",
+		ceil($counts->{approved_total}/$pagesize),	# $page, 'page'
+	)
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
+__END__
+
-- 
1.5.5.GIT




More information about the Koha-patches mailing list