From 002781ecead2bc43c7bc3b465b4a3f312149f5b0 Mon Sep 17 00:00:00 2001 From: OliverKrueger Date: Sun, 16 Aug 2009 22:44:49 +0000 Subject: [PATCH] Item1918: adding rename and merge git-svn-id: http://svn.foswiki.org/trunk/TagsPlugin@4673 0b4bb1d4-4e5a-0410-9cc4-b2b747904278 --- lib/Foswiki/Plugins/TagsPlugin.pm | 16 +- lib/Foswiki/Plugins/TagsPlugin/Config.spec | 2 +- lib/Foswiki/Plugins/TagsPlugin/Merge.pm | 192 +++++++++++++++++++++ lib/Foswiki/Plugins/TagsPlugin/Rename.pm | 145 ++++++++++++++++ 4 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 lib/Foswiki/Plugins/TagsPlugin/Merge.pm create mode 100644 lib/Foswiki/Plugins/TagsPlugin/Rename.pm diff --git a/lib/Foswiki/Plugins/TagsPlugin.pm b/lib/Foswiki/Plugins/TagsPlugin.pm index c8e0c41..ca5a8e9 100644 --- a/lib/Foswiki/Plugins/TagsPlugin.pm +++ b/lib/Foswiki/Plugins/TagsPlugin.pm @@ -54,9 +54,11 @@ sub initPlugin { Foswiki::Func::registerRESTHandler( 'tag', \&tagCall ); Foswiki::Func::registerRESTHandler( 'untag', \&untagCall ); - Foswiki::Func::registerRESTHandler( 'delete', \&deleteCall ); - # Foswiki::Func::registerRESTHandler('updateGeoTags', \&updateGeoTags); + Foswiki::Func::registerRESTHandler( 'delete', \&deleteCall ); + Foswiki::Func::registerRESTHandler( 'rename', \&renameCall ); + Foswiki::Func::registerRESTHandler( 'merge', \&mergeCall ); Foswiki::Func::registerRESTHandler( 'initialiseDatabase', \&initialiseDatabase ); + # Foswiki::Func::registerRESTHandler('updateGeoTags', \&updateGeoTags); #TODO: augment the IfParser and the QuerySearch Parsers to add Tags? @@ -325,6 +327,16 @@ sub deleteCall { return Foswiki::Plugins::TagsPlugin::Delete::rest( @_ ); } +sub renameCall { + use Foswiki::Plugins::TagsPlugin::Rename; + return Foswiki::Plugins::TagsPlugin::Rename::rest( @_ ); +} + +sub mergeCall { + use Foswiki::Plugins::TagsPlugin::Merge; + return Foswiki::Plugins::TagsPlugin::Merge::rest( @_ ); +} + sub getUserId { my $session = shift; diff --git a/lib/Foswiki/Plugins/TagsPlugin/Config.spec b/lib/Foswiki/Plugins/TagsPlugin/Config.spec index fcf0188..c3ef34e 100644 --- a/lib/Foswiki/Plugins/TagsPlugin/Config.spec +++ b/lib/Foswiki/Plugins/TagsPlugin/Config.spec @@ -13,5 +13,5 @@ $Foswiki::cfg{TagsPlugin}{EnableCategories} = 1; $Foswiki::cfg{TagsPlugin}{EnableDataForms} = 1; # **STRING** -# Name of the TagAdminGroup (which is allowed to delete and merge tags) +# Name of the TagAdminGroup (which is allowed to delete, rename and merge tags) $Foswiki::cfg{TagsPlugin}{TagAdminGroup} = "AdminGroup"; \ No newline at end of file diff --git a/lib/Foswiki/Plugins/TagsPlugin/Merge.pm b/lib/Foswiki/Plugins/TagsPlugin/Merge.pm new file mode 100644 index 0000000..0db329b --- /dev/null +++ b/lib/Foswiki/Plugins/TagsPlugin/Merge.pm @@ -0,0 +1,192 @@ +# This script Copyright (c) 2009 Oliver Krueger, (wiki-one.net) +# and distributed under the GPL (see below) +# +# This program 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. +# +# This program 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, published at +# http://www.gnu.org/copyleft/gpl.html +# +# Author(s): Oliver Krueger + +package Foswiki::Plugins::TagsPlugin::Merge; + +use strict; +use warnings; +use Error qw(:try); + +=begin TML + +---++ rest( $session ) +This is the REST wrapper for merge. + +Takes the following url parameters: + tag1 : name of the tag to be renamed + tag2 : new name for the old tag + +It checks the prerequisites and sets the following status codes: + 200 : Ok + 400 : url parameter(s) are missing + 403 : the user is not allowed to rename + +Return: +In case of an error (!=200) just the status code incl. short description is returned. +Otherwise a 200 and the number of affected tags (usually 0 or 1) is returned. + +TODO: + force http POST method +=cut + +sub rest { + my $session = shift; + my $query = Foswiki::Func::getCgiQuery(); + + my $tag1 = $query->param('tag1') || ''; + my $tag2 = $query->param('tag2') || ''; + + $tag1 = Foswiki::Sandbox::untaintUnchecked($tag1); + $tag2 = Foswiki::Sandbox::untaintUnchecked($tag2); + + # + # checking prerequisites + # + + # first check the existence of all necessary url parameters + # + if ( !$tag1 ) { + $session->{response}->status(400); + return "

400 'tag1' parameter missing

"; + } + if ( !$tag2 ) { + $session->{response}->status(400); + return "

400 'tag2' parameter missing

"; + } + + # check if current user is allowed to do so + # + my $tagAdminGroup = $Foswiki::cfg{TagsPlugin}{TagAdminGroup} || "AdminGroup"; + if ( !Foswiki::Func::isGroupMember( $tagAdminGroup, Foswiki::Func::getWikiName()) ) { + $session->{response}->status(403); + return "

403 Forbidden

"; + } + + # + # actioning + # + $session->{response}->status(200); + + # returning 0 on failure and some other positive number on success + return Foswiki::Plugins::TagsPlugin::Merge::do( $tag1, $tag2 ); + +} + +=begin TML + +---++ do( $tag1, $tag2 ) +This does the merging. Updates both Stat tables and deletes unused entries for obsolete tag2. + +Takes the following parameters: + tag1 : name of the tag which remains + tag2 : name of the tag which will be merged into tag1 + +This routine does not check any prerequisites and/or priviledges. It returns 0, if +tag1 or tag2 was not found. + +Return: + 0 on failure, any other positive number on success. +=cut + +sub do { + my ( $tag1, $tag2 ) = @_; + my $db = new Foswiki::Contrib::DbiContrib; + + # determine tag_id for given tag1 and exit if its not there + # + my $tag_id1; + my $statement = sprintf( 'SELECT %s from %s WHERE %s = ? AND %s = ?', + qw( item_id Items item_name item_type) ); + my $arrayRef = $db->dbSelect( $statement, $tag1, 'tag' ); + if ( defined( $arrayRef->[0][0] ) ) { + $tag_id1 = $arrayRef->[0][0]; + } + else { return " 0"; } + + # determine tag_id for given tag2 and exit if its not there + # + my $tag_id2; + $statement = sprintf( 'SELECT %s from %s WHERE %s = ? AND %s = ?', + qw( item_id Items item_name item_type) ); + my $arrayRef = $db->dbSelect( $statement, $tag2, 'tag' ); + if ( defined( $arrayRef->[0][0] ) ) { + $tag_id2 = $arrayRef->[0][0]; + } + else { return " 0"; } + + # now we are ready to actually merge + # + + # merge the usage of the tags (in UserItemTag) + # IGNOREing duplicate entries, which usually occur (may leave some garbage behind) + $statement = + sprintf( 'UPDATE IGNORE %s SET %s = ? WHERE %s = ?', + qw( UserItemTag tag_id tag_id ) ); + my $affected_rows = $db->dbInsert( $statement, $tag_id1, $tag_id2 ); + Foswiki::Func::writeDebug("Merge: $statement; ($tag_id1, $tag_id2) -> $affected_rows"); + if ( $affected_rows eq "0E0" ) { $affected_rows=0; }; + # DELETEing the garbage (usually tags on topics, which were tagged with tag1 and tag2) + $statement = + sprintf( 'DELETE from %s WHERE %s = ?', + qw( UserItemTag tag_id) ); + my $modified = $db->dbDelete( $statement, $tag_id2 ); + Foswiki::Func::writeDebug("Merge: $statement; ($tag_id2) -> $modified"); + + # update stats in TagStat (rebuild it actually) + my $tagstat = 0; + $statement = sprintf( 'SELECT count(*) as count from %s WHERE %s = ?', + qw( UserItemTag tag_id ) ); + $arrayRef = $db->dbSelect( $statement, $tag_id1 ); + if ( defined( $arrayRef->[0][0] ) ) { + $tagstat = $arrayRef->[0][0]; + } + $statement = + sprintf( 'UPDATE %s SET %s=? WHERE %s = ?', + qw( TagStat num_items tag_id) ); + $modified = $db->dbInsert( $statement, $tagstat, $tag_id1 ); + Foswiki::Func::writeDebug("Merge: $statement; ($tagstat, $tag_id1) -> $modified"); + unless ( $modified ) { + $statement = + sprintf( 'INSERT INTO %s (%s, %s) VALUES (?, ?)', + qw( TagStat tag_id num_items ) ); + $modified = $db->dbInsert( $statement, $tag_id1, $tagstat ); + Foswiki::Func::writeDebug("Merge: $statement; ($tag_id1, $tagstat) -> $modified"); + } + $statement = + sprintf( 'DELETE from %s WHERE %s = ?', + qw( TagStat tag_id) ); + $modified = $db->dbDelete( $statement, $tag_id2 ); + Foswiki::Func::writeDebug("Merge: $statement; ($tag_id2) -> $modified"); + + # update stats in UserTagStat + ### TODO: implement rebuilding UserTagStat rebuild + + # delete (empty) tag2 + $statement = + sprintf( 'DELETE from %s WHERE %s = ?', + qw( Items item_id) ); + $modified = $db->dbDelete( $statement, $tag_id2 ); + Foswiki::Func::writeDebug("Merge: $statement; ($tag_id2) -> $modified"); + + # flushing data to dbms + # + $db->commit(); + + # add extra space, so that zero affected rows does not clash with returning "0" from rest invocation + return " $affected_rows"; +} + +1; \ No newline at end of file diff --git a/lib/Foswiki/Plugins/TagsPlugin/Rename.pm b/lib/Foswiki/Plugins/TagsPlugin/Rename.pm new file mode 100644 index 0000000..535e6e5 --- /dev/null +++ b/lib/Foswiki/Plugins/TagsPlugin/Rename.pm @@ -0,0 +1,145 @@ +# This script Copyright (c) 2009 Oliver Krueger, (wiki-one.net) +# and distributed under the GPL (see below) +# +# This program 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. +# +# This program 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, published at +# http://www.gnu.org/copyleft/gpl.html +# +# Author(s): Oliver Krueger + +package Foswiki::Plugins::TagsPlugin::Rename; + +use strict; +use warnings; +use Error qw(:try); + +=begin TML + +---++ rest( $session ) +This is the REST wrapper for rename. + +Takes the following url parameters: + oldtag : name of the tag to be renamed + newtag : new name for the old tag + +It checks the prerequisites and sets the following status codes: + 200 : Ok + 400 : url parameter(s) are missing + 403 : the user is not allowed to rename + +Return: +In case of an error (!=200) just the status code incl. short description is returned. +Otherwise a 200 and the number of affected tags (usually 0 or 1) is returned. + +TODO: + force http POST method +=cut + +sub rest { + my $session = shift; + my $query = Foswiki::Func::getCgiQuery(); + + my $tag_old = $query->param('oldtag') || ''; + my $tag_new = $query->param('newtag') || ''; + + $tag_old = Foswiki::Sandbox::untaintUnchecked($tag_old); + $tag_new = Foswiki::Sandbox::untaintUnchecked($tag_new); + + # + # checking prerequisites + # + + # first check the existence of all necessary url parameters + # + if ( !$tag_old ) { + $session->{response}->status(400); + return "

400 'oldtag' parameter missing

"; + } + if ( !$tag_new ) { + $session->{response}->status(400); + return "

400 'newtag' parameter missing

"; + } + + # check if current user is allowed to do so + # + my $tagAdminGroup = $Foswiki::cfg{TagsPlugin}{TagAdminGroup} || "AdminGroup"; + if ( !Foswiki::Func::isGroupMember( $tagAdminGroup, Foswiki::Func::getWikiName()) ) { + $session->{response}->status(403); + return "

403 Forbidden

"; + } + + # + # actioning + # + $session->{response}->status(200); + + # returning the number of affected tags + return Foswiki::Plugins::TagsPlugin::Rename::do( $tag_old, $tag_new ); + +} + +=begin TML + +---++ do( $tag_old, $tag_new ) +This does untagging. + +Takes the following parameters: + tag_old : name of tag to be renamed + tag_new : new name for the old tag + +This routine does not check any prerequisites and/or priviledges. It returns 0, if +the old tagname was not found or the new tagname already exists. + +Return: + number of affected tags. +=cut + +sub do { + my ( $tag_old, $tag_new ) = @_; + my $db = new Foswiki::Contrib::DbiContrib; + + # determine tag_id for given tag_old and exit if its not there + # + my $tag_id; + my $statement = sprintf( 'SELECT %s from %s WHERE %s = ? AND %s = ?', + qw( item_id Items item_name item_type) ); + my $arrayRef = $db->dbSelect( $statement, $tag_old, 'tag' ); + if ( defined( $arrayRef->[0][0] ) ) { + $tag_id = $arrayRef->[0][0]; + } + else { return " 0"; } + + # check if new tagname already exists by probing for an tag_id + # + $statement = sprintf( 'SELECT %s from %s WHERE %s = ? AND %s = ?', + qw( item_id Items item_name item_type) ); + $arrayRef = $db->dbSelect( $statement, $tag_new, 'tag' ); + if ( defined( $arrayRef->[0][0] ) ) { + return " 0"; + } + + # now we are ready to actually rename + # + $statement = + sprintf( 'UPDATE %s SET %s = ? WHERE %s = ?', + qw( Items item_name item_id ) ); + Foswiki::Func::writeDebug("Rename: $statement; ($tag_new, $tag_id)"); + my $affected_rows = $db->dbInsert( $statement, $tag_new, $tag_id ); + if ( $affected_rows eq "0E0" ) { $affected_rows=0; }; + + # flushing data to dbms + # + $db->commit(); + + # add extra space, so that zero affected rows does not clash with returning "0" from rest invocation + return " $affected_rows"; +} + +1; \ No newline at end of file