Add ability to actually rename icon keywords. When you edit the
keywords on an icon, you can click a box to do a rename on those keywords, and
comments and posts you've made with the old keywords will be updated to use the
new ones.
Patch by allen.
diffs (441 lines):
diff -r e36a761d81b3 -r be246bd19221 bin/worker/userpic-rename
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/worker/userpic-rename Tue Nov 24 20:12:09 2009 +0000
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+#
+# bin/worker/userpic-rename
+#
+# TheSchwartz worker for renaming userpics
+#
+# Authors:
+# Allen Petersen <[email protected]>
+#
+# Copyright (c) 2009 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+
+use strict;
+use warnings;
+
+use lib "$ENV{LJHOME}/cgi-bin";
+use LJ::Worker::TheSchwartz;
+use DW::Worker::UserpicRenameWorker;
+
+foreach my $capability
(DW::Worker::UserpicRenameWorker->schwartz_capabilities) {
+ schwartz_decl( $capability );
+}
+
+schwartz_work(); # Never returns.
diff -r e36a761d81b3 -r be246bd19221 cgi-bin/DW/Worker/UserpicRenameWorker.pm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cgi-bin/DW/Worker/UserpicRenameWorker.pm Tue Nov 24 20:12:09 2009 +0000
@@ -0,0 +1,144 @@
+#!/usr/bin/perl
+#
+# DW::Worker::UserpicRenameWorker
+#
+# TheSchwartz worker module for renaming userpics. Called with
+# LJ::theschwartz()->insert('DW::Worker::UserpicRenameWorker', {
+# 'uid' => $u->userid, 'keywordmap' => Storable::nfreeze(\%keywordmap);
+#
+# Authors:
+# Allen Petersen <[email protected]>
+#
+# Copyright (c) 2009 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+
+use strict;
+use warnings;
+use lib "$LJ::HOME/cgi-bin";
+
+package DW::Worker::UserpicRenameWorker;
+use base 'TheSchwartz::Worker';
+
+sub schwartz_capabilities { return ('DW::Worker::UserpicRenameWorker'); }
+
+sub keep_exit_status_for { 86400 } # 24 hours
+
+my $logpropid;
+my $talkpropid;
+
+sub work {
+ my ($class, $job) = @_;
+
+ my $arg = $job->arg;
+
+ my ($uid, $keywordmapstring) = map { delete $arg->{$_} } qw( uid
keywordmap );
+
+ return $job->permanent_failure("Unknown keys: " . join(", ", keys %$arg))
+ if keys %$arg;
+ return $job->permanent_failure("Missing argument")
+ unless defined $uid && defined $keywordmapstring;
+
+ my $keywordmap = eval { Storable::thaw($keywordmapstring) } or return
$job->failed("Failed to load keywordmap from arg '$keywordmapstring': " . $@);
+
+ # get the user from the uid
+ my $u = LJ::want_user($uid) or return $job->failed("Unable to load user
with uid $uid");
+
+ # only get the propids once; they're not going to change
+ unless ($logpropid && $talkpropid) {
+ $logpropid = LJ::get_prop( log => 'picture_keyword' )->{id};
+ $talkpropid = LJ::get_prop( talk => 'picture_keyword' )->{id};
+ }
+
+ # only update 1000 rows at a time.
+ my $LIMIT = 1000;
+
+ # now we go through each cluster and update the logprop2 and talkprop2
+ # tables with the new values.
+ foreach my $cluster_id (@LJ::CLUSTERS) {
+ my $dbcm = LJ::get_cluster_master($cluster_id);
+
+ foreach my $kw (keys %$keywordmap) {
+ # find entries for clearing cache
+ my $matches = $dbcm->selectall_arrayref(q{
+ SELECT log2.journalid AS journalid,
+ log2.jitemid AS jitemid
+ FROM logprop2
+ INNER JOIN log2
+ ON ( logprop2.journalid = log2.journalid
+ AND logprop2.jitemid = log2.jitemid )
+ WHERE posterid = ?
+ AND propid=?
+ AND value = ?
+ }, undef, $u->id, $logpropid, $kw);
+
+ # update entries
+ my $updateresults = $LIMIT;
+ while ($updateresults == $LIMIT) {
+ $updateresults = $dbcm->do( q{
+ UPDATE logprop2
+ SET value = ?
+ WHERE propid=?
+ AND value = ?
+ AND EXISTS (
+ SELECT posterid
+ FROM log2
+ WHERE log2.journalid = logprop2.journalid
+ AND log2.jitemid = logprop2.jitemid
+ AND log2.posterid = ? )
+ LIMIT ?
+ }, undef, $keywordmap->{$kw}, $logpropid, $kw, $u->id,
$LIMIT);
+ return $job->permanent_failure($dbcm->errstr) if $dbcm->err;
+ }
+
+ # clear cache
+ foreach my $match (@$matches) {
+ LJ::MemCache::delete([ $match->[0], "logprop:" . $match->[0].
":" . $match->[1] ]);
+ }
+
+ # update comments
+ # find comments for clearing cache
+ $matches = $dbcm->selectall_arrayref( q{
+ SELECT talkprop2.journalid AS journalid,
+ talkprop2.jtalkid AS jtalkid
+ FROM talkprop2
+ INNER JOIN talk2
+ ON ( talkprop2.journalid = talk2.journalid
+ AND talkprop2.jtalkid = talk2.jtalkid )
+ WHERE posterid = ?
+ AND tpropid=?
+ AND value = ?
+ }, undef, $u->id, $talkpropid, $kw);
+
+ # update coments
+ $updateresults = $LIMIT;
+ while ($updateresults == $LIMIT) {
+ $updateresults = $dbcm->do( q{
+ UPDATE talkprop2
+ SET value = ?
+ WHERE tpropid=?
+ AND value = ?
+ AND EXISTS (
+ SELECT posterid
+ FROM talk2
+ WHERE talk2.journalid = talkprop2.journalid
+ AND talk2.jtalkid = talkprop2.jtalkid
+ AND talk2.posterid = ? )
+ LIMIT ?
+ }, undef, $keywordmap->{$kw}, $talkpropid, $kw, $u->id,
$LIMIT);
+ return $job->permanent_failure($dbcm->errstr) if $dbcm->err;
+ }
+
+ # clear cache
+ foreach my $match (@$matches) {
+ LJ::MemCache::delete([ $match->[0], "talkprop:" . $match->[0].
":" . $match->[1] ]);
+ }
+ }
+ }
+
+ $job->completed;
+}
+
+1;
diff -r e36a761d81b3 -r be246bd19221 cgi-bin/LJ/Userpic.pm
--- a/cgi-bin/LJ/Userpic.pm Tue Nov 24 20:03:33 2009 +0000
+++ b/cgi-bin/LJ/Userpic.pm Tue Nov 24 20:12:09 2009 +0000
@@ -4,6 +4,7 @@ use Digest::MD5;
use Digest::MD5;
use LJ::Event::NewUserpic;
use LJ::Constants;
+use Storable;
##
## Potential properties of an LJ::Userpic object
@@ -919,6 +920,97 @@ sub set_keywords {
return 1;
}
+
+# instance method: takes two strings of comma-separated keywords, the first
+# being the new set of keywords, the second being the old set of keywords.
+#
+# the new keywords must be the same number as the old keywords; that is,
+# if the userpic has three keywords and you want to rename them, you must
+# rename them to three keywords (some can match). otherwise there would be
+# some ambiguity about which old keywords should match up with the new
+# keywords. if the number of keywords don't match, then an error is thrown
+# and no changes are made to the keywords for this userpic.
+#
+# all new keywords must not currently be in use; you can't rename a keyword
+# to a keyword currently mapped to another (or the same) userpic. this will
+# result in an error and no changes made to these keywords.
+#
+# the setting of new keywords is done by Userpic->set_keywords; the remapping
+# of existing pics is done asynchonously via TheSchwartz using the
+# DW::Worker::UserpicRenameWorker.
+sub set_and_rename_keywords {
+ my $self = shift;
+ my $new_keyword_string = $_[0];
+ my $orig_keyword_string = $_[1];
+
+ my $sclient = LJ::theschwartz();
+
+ # error out if TheSchwartz isn't available.
+ LJ::errobj("Userpic::RenameKeywords",
+ origkw => $orig_keyword_string,
+ newkw => $new_keyword_string)->throw unless $sclient;
+
+ my @keywords = split(',', $new_keyword_string);
+ my @orig_keywords = split(',', $orig_keyword_string);
+
+ # don't allow renames involving no-keyword (pic#0001) values
+ if ( grep ( /^\s*pic\#\d+\s*$/, @orig_keywords ) || grep (
/^\s*pic\#\d+\s*$/, @keywords )) {
+ LJ::errobj("Userpic::RenameBlankKeywords",
+ origkw => $orig_keyword_string,
+ newkw => $new_keyword_string)->throw;
+ }
+
+ # compare sizes
+ if (scalar @keywords ne scalar @orig_keywords) {
+ LJ::errobj("Userpic::MismatchRenameKeywords",
+ origkw => $orig_keyword_string,
+ newkw => $new_keyword_string)->throw;
+ }
+
+ #interleave these into a map, excluding duplicates
+ my %keywordmap;
+ foreach my $newkw (@keywords) {
+ my $origkw = shift(@orig_keywords);
+ # clear whitespace
+ $newkw =~ s/^\s+//;
+ $newkw =~ s/\s+$//;
+ $origkw =~ s/^\s+//;
+ $origkw =~ s/\s+$//;
+
+ $keywordmap{$origkw} = $newkw if $origkw ne $newkw;
+ }
+
+ # make sure there is at least one change.
+ if (keys(%keywordmap)) {
+
+ #make sure that none of the target keywords already exist.
+ my $u = $self->owner;
+ foreach my $kw (keys %keywordmap) {
+ if (LJ::get_picid_from_keyword($u, $keywordmap{$kw}, -1) != -1) {
+ LJ::errobj("Userpic::RenameKeywordExisting",
+ keyword => $keywordmap{$kw})->throw;
+ }
+ }
+
+ # set the keywords for this userpic to the new set of keywords
+ $self->set_keywords(@keywords);
+
+ # send to TheSchwartz to do the actual renaming
+ my $job = TheSchwartz::Job->new_from_array(
+ 'DW::Worker::UserpicRenameWorker', {
+ 'uid' => $u->userid,
+ 'keywordmap' => Storable::nfreeze(\%keywordmap) } );
+
+ unless ($job && $sclient->insert($job)) {
+ LJ::errobj("Userpic::RenameKeywords",
+ origkw => $orig_keyword_string,
+ newkw => $new_keyword_string)->throw;
+ }
+ }
+
+ return 1;
+}
+
sub set_fullurl {
my ($self, $url) = @_;
my $u = $self->owner;
@@ -988,6 +1080,45 @@ sub as_html {
{ 'filetype' => $self->{'type'} });
}
+package LJ::Error::Userpic::MismatchRenameKeywords;
+sub user_caused { 1 }
+sub fields { qw(origkw newkw); }
+sub as_html {
+ my $self = shift;
+ return BML::ml("/editpics.bml.error.rename.mismatchedlength",
+ { 'origkw' => $self->{'origkw'},
+ 'newkw' => $self->{'newkw'} });
+}
+
+package LJ::Error::Userpic::RenameBlankKeywords;
+sub user_caused { 1 }
+sub fields { qw(origkw newkw); }
+sub as_html {
+ my $self = shift;
+ return BML::ml("/editpics.bml.error.rename.blankkw",
+ { 'origkw' => $self->{'origkw'},
+ 'newkw' => $self->{'newkw'} });
+}
+
+package LJ::Error::Userpic::RenameKeywordExisting;
+sub user_caused { 1 }
+sub fields { qw(keyword); }
+sub as_html {
+ my $self = shift;
+ return BML::ml("/editpics.bml.error.rename.keywordexists",
+ { 'keyword' => $self->{'keyword'} });
+}
+
+package LJ::Error::Userpic::RenameKeywords;
+sub user_caused { 0 }
+sub fields { qw(origkw newkw); }
+sub as_html {
+ my $self = shift;
+ return BML::ml("/editpics.bml.error.rename.keywords",
+ { 'origkw' => $self->{'origkw'},
+ 'newkw' => $self->{'newkw'} });
+}
+
package LJ::Error::Userpic::DeleteFailed;
sub user_caused { 0 }
diff -r e36a761d81b3 -r be246bd19221 htdocs/editpics.bml
--- a/htdocs/editpics.bml Tue Nov 24 20:03:33 2009 +0000
+++ b/htdocs/editpics.bml Tue Nov 24 20:12:09 2009 +0000
@@ -78,6 +78,9 @@ use strict;
### save changes to existing pics
if ($POST{'action:save'}) {
my $refresh = update_userpics(\...@userpics, $u, $err);
+
+ # push all the errors to info
+ push(@info, @errors);
# reload the pictures to account for deleted
@userpics = LJ::Userpic->load_user_userpics($u) if $refresh;
@@ -474,6 +477,8 @@ use strict;
$body .= "</div>";
$body .= "<div id='list_userpics' style='width: 98%; float: left;'>";
+ my $display_rename = LJ::theschwartz() ? 1 : 0;
+
foreach my $pic (@userpics) {
my $pid = $pic->id;
@@ -489,9 +494,20 @@ use strict;
$body .= "<label class='left'
for='kw_$pid'>$ML{'.label.keywords'}</label>\n ";
$body .= LJ::html_text({'name' => "kw_$pid", 'class' => "text",
'id' => "kw_$pid",
'value' => $keywords,
- 'disabled' => $pic->inactive }) . "\n";
+ 'disabled' => $pic->inactive,
+ 'onfocus' => $display_rename ?
"\$(\'rename_div_$pid\').style.display = \'block\';" : ""
+ }) . "\n";
$body .= LJ::html_hidden({ 'name' => "kw_orig_$pid",
'value' => $keywords }) . "\n";
+ if ($display_rename) {
+ $body .= "<div id='rename_div_$pid' class='userpic_rename
pkg'>\n";
+ $body .= "<script
type='text/javascript'>document.getElementById('rename_div_$pid').style.display
= 'none';</script>\n";
+ $body .= LJ::html_check({ 'type' => 'checkbox', 'name' =>
"rename_keyword_$pid", 'class' => "checkbox",
+ 'id' => "rename_keyword_$pid",
'value' => 1,
+ 'disabled' =>
$LJ::DISABLE_MEDIA_UPLOADS });
+ $body .= "<label
for='rename_keyword_$pid'>$ML{'.label.rename'}</label>";
+ $body .= "</div>\n";
+ }
$body .= "</div>\n";
$body .= "<div class='userpic_comments pkg'>\n";
@@ -612,10 +628,15 @@ sub update_userpics
if ($POST{"kw_$picid"} ne $POST{"kw_orig_$picid"}) {
my $kws = $POST{"kw_$picid"};
- eval {
- $up->set_keywords($kws);
- } or push @errors, $@;
-
+ if ($POST{"rename_keyword_$picid"}) {
+ eval {
+ $up->set_and_rename_keywords($kws,
$POST{"kw_orig_$picid"});
+ } or push @errors, $...@->as_html;
+ } else {
+ eval {
+ $up->set_keywords($kws);
+ } or push @errors, $@;
+ }
}
eval {
diff -r e36a761d81b3 -r be246bd19221 htdocs/editpics.bml.text
--- a/htdocs/editpics.bml.text Tue Nov 24 20:03:33 2009 +0000
+++ b/htdocs/editpics.bml.text Tue Nov 24 20:12:09 2009 +0000
@@ -39,6 +39,14 @@
.error.nourl=You must enter the URL of an image
.error.nomediauploads.delete=Unable to delete userpics at this time. Media
modification is currently disabled for the site.
+
+.error.rename.blankkw=Error renaming '[[origkw]]' to '[[newkw]]': renaming of
blank (pic#) keywords not allowed.
+
+.error.rename.keywordexists=Cannot rename to '[[keyword]]': keyword already
exists.
+
+.error.rename.keywords=An error occurred trying to rename '[[origkw]]' to
'[[newkw]]'; entries and comments with the old keywords may not have changed to
use the new keywords.
+
+.error.rename.mismatchedlength=Error renaming '[[origkw]]' to '[[newkw]]':
must rename to the same number of keywords.
.error.toolarge.separately=Image is too large; please submit it separately to
resize.
@@ -89,6 +97,8 @@
.label.keywords.desc=Comma-separated list of terms you'll use to select this
picture.
+.label.rename=Rename Keywords
+
.makedefault=Make this your <u>d</u>efault picture
.makedefault.key|notes=Enter here a <b>lower-case</b> version of the letter
you underlined in ".makedefault". This is the shortcut key for the makedefault
option.
diff -r e36a761d81b3 -r be246bd19221 htdocs/stc/editpics.css
--- a/htdocs/stc/editpics.css Tue Nov 24 20:03:33 2009 +0000
+++ b/htdocs/stc/editpics.css Tue Nov 24 20:12:09 2009 +0000
@@ -88,6 +88,12 @@ hr {
.userpic_defaultdelete {
width: 200px;
}
+.userpic_rename {
+ width: 200px;
+ margin-left: 6.5em;
+ margin-bottom: 4px;
+ margin-top: 4px;
+}
* html .userpic_keywords,
* html .userpic_comments,
* html .userpic_descriptions {
_______________________________________________
dw-changelog mailing list
[email protected]
http://lists.dwscoalition.org/mailman/listinfo/dw-changelog