1459 lines
45 KiB
Perl
1459 lines
45 KiB
Perl
|
use strict;
|
||
|
|
||
|
package LJR::Distributed;
|
||
|
|
||
|
my $warn = sub {
|
||
|
print join ("\n", @_);
|
||
|
print "\n";
|
||
|
};
|
||
|
|
||
|
my $err = sub {
|
||
|
if (ref($_[0])) {
|
||
|
my $dbh = shift;
|
||
|
$dbh->rollback;
|
||
|
}
|
||
|
my %res = ();
|
||
|
|
||
|
my $cstack = "\ncallstack:";
|
||
|
my $i = 0;
|
||
|
while ( 1 ) {
|
||
|
my $tfunc = (caller($i))[3];
|
||
|
if ($tfunc && $tfunc ne "") {
|
||
|
if ($tfunc !~ /\_\_ANON\_\_/) {
|
||
|
$cstack .= " " . $tfunc;
|
||
|
}
|
||
|
$i = $i + 1;
|
||
|
}
|
||
|
else {
|
||
|
last;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$res{"err"} = 1;
|
||
|
$res{"errtext"} = join ("\n", @_);
|
||
|
$res{"errtext"} .= $cstack;
|
||
|
return \%res;
|
||
|
};
|
||
|
|
||
|
#
|
||
|
# created from LJ::Talk::Post::enter_comment
|
||
|
#
|
||
|
sub create_imported_comment {
|
||
|
my ($journalu, $parent, $item, $comment) = @_;
|
||
|
|
||
|
return $err->("Invalid user object passed.") unless LJ::isu($journalu);
|
||
|
|
||
|
my $partid = $parent->{talkid};
|
||
|
my $itemid = $item->{jitemid};
|
||
|
my $posterid = $comment->{u} ? $comment->{u}{userid} : 0;
|
||
|
|
||
|
# TODO: change this to be remote server specific
|
||
|
my $time_float = "-3";
|
||
|
my $comment_time;
|
||
|
if ($comment->{datetime}) {
|
||
|
$comment_time = "'" . $comment->{datetime} . "' + INTERVAL " . $time_float . " HOUR";
|
||
|
}
|
||
|
else {
|
||
|
# deleted comments
|
||
|
$comment_time = "'1970-01-01T00:00:00Z'";
|
||
|
}
|
||
|
|
||
|
my $jtalkid = LJ::alloc_user_counter($journalu, "T");
|
||
|
return $err->("Could not generate a talkid necessary to import comment.") unless $jtalkid;
|
||
|
|
||
|
my $errstr;
|
||
|
$journalu->talk2_do(
|
||
|
"L", $itemid, \$errstr,
|
||
|
"INSERT INTO talk2 ".
|
||
|
"(journalid, jtalkid, nodetype, nodeid, parenttalkid, posterid, datepost, state) ".
|
||
|
"VALUES (?,?,'L',?,?,?," . $comment_time . ",?)",
|
||
|
$journalu->{userid}, $jtalkid, $itemid, $partid, $posterid, $comment->{state}
|
||
|
);
|
||
|
return $err->("error creating imported comment: " . $errstr) if ($errstr);
|
||
|
|
||
|
$comment->{talkid} = $jtalkid;
|
||
|
|
||
|
# add to poster's talkleft table, or the xfer place
|
||
|
if ($posterid) {
|
||
|
my $table;
|
||
|
my $db = LJ::get_cluster_master($comment->{u});
|
||
|
|
||
|
if ($db) {
|
||
|
# remote's cluster is writable
|
||
|
$table = "talkleft";
|
||
|
} else {
|
||
|
# log to global cluster, another job will move it later.
|
||
|
$db = LJ::get_db_writer();
|
||
|
$table = "talkleft_xfp";
|
||
|
}
|
||
|
my $pub = $item->{'security'} eq "public" ? 1 : 0;
|
||
|
if ($db) {
|
||
|
$db->do(
|
||
|
"INSERT INTO $table (userid, posttime, journalid, nodetype, ".
|
||
|
"nodeid, jtalkid, publicitem) VALUES (?, UNIX_TIMESTAMP(" . $comment_time . "), " .
|
||
|
"?, 'L', ?, ?, ?)",
|
||
|
undef, $posterid, $journalu->{userid}, $itemid, $jtalkid, $pub);
|
||
|
return $err->($db->errstr) if $db->err;
|
||
|
} else {
|
||
|
# both primary and backup talkleft hosts down. can't do much now.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$journalu->do(
|
||
|
"INSERT INTO talktext2 (journalid, jtalkid, subject, body) ".
|
||
|
"VALUES (?, ?, ?, ?)", undef,
|
||
|
$journalu->{userid}, $jtalkid, $comment->{subject},
|
||
|
LJ::text_compress($comment->{body})
|
||
|
);
|
||
|
return $err->($journalu->errstr) if $journalu->err;
|
||
|
|
||
|
my %talkprop = %{$comment->{props}}; # propname -> value
|
||
|
|
||
|
if (%talkprop) {
|
||
|
my $values;
|
||
|
my $hash = {};
|
||
|
foreach (keys %talkprop) {
|
||
|
my $p = LJ::get_prop("talk", $_);
|
||
|
next unless $p;
|
||
|
$hash->{$_} = $talkprop{$_};
|
||
|
my $tpropid = $p->{'tpropid'};
|
||
|
my $qv = $journalu->quote($talkprop{$_});
|
||
|
$values .= "($journalu->{'userid'}, $jtalkid, $tpropid, $qv),";
|
||
|
}
|
||
|
|
||
|
if ($values) {
|
||
|
chop $values;
|
||
|
$journalu->do("INSERT INTO talkprop2 (journalid, jtalkid, tpropid, value) VALUES $values");
|
||
|
return $err->($journalu->errstr) if $journalu->err;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# update the "replycount" summary field of the log table
|
||
|
if ($comment->{state} eq 'A' || $comment->{state} eq 'F') {
|
||
|
LJ::replycount_do($journalu, $itemid, "incr");
|
||
|
}
|
||
|
|
||
|
# update the "hasscreened" property of the log item if needed
|
||
|
if ($comment->{state} eq 'S') {
|
||
|
LJ::Talk::screenedcount_do($journalu, $itemid, "incr");
|
||
|
}
|
||
|
|
||
|
return $comment;
|
||
|
}
|
||
|
|
||
|
sub create_imported_comments {
|
||
|
my ($ru, $local_user, $throttle_num, $throttle_sec) = @_;
|
||
|
|
||
|
if (!$throttle_num) {
|
||
|
$throttle_num = 1000;
|
||
|
}
|
||
|
if (!$throttle_sec) {
|
||
|
$throttle_sec = 20;
|
||
|
}
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
# local journal where comment is to be created
|
||
|
my $journalu = LJ::load_user($local_user, 1);
|
||
|
|
||
|
$ru = LJR::Distributed::get_cu_field($ru, "cached_comments_maxid");
|
||
|
$ru->{cached_comments_maxid} = 0 if not defined $ru->{cached_comments_maxid};
|
||
|
|
||
|
$ru = LJR::Distributed::remote_local_assoc($ru, $journalu);
|
||
|
return $err->("error while getting remote-local association: " . $ru->{errtext})
|
||
|
if $ru->{err};
|
||
|
|
||
|
# check if someone deleted imported comments,
|
||
|
# delete inconsistent ljr_remote_comments entries and
|
||
|
# update corresponding ljr_remote_users.created_comments_maxid
|
||
|
my $sth_cc = $dbr->prepare("SELECT count(*) from ljr_remote_comments l
|
||
|
LEFT JOIN talk2 t on l.local_journalid = t.journalid and l.local_jtalkid = t.jtalkid
|
||
|
WHERE l.local_journalid = ? and t.journalid is NULL;");
|
||
|
$sth_cc->execute($journalu->{"userid"});
|
||
|
|
||
|
my $deleted_num;
|
||
|
if (($deleted_num = $sth_cc->fetchrow_array) && $deleted_num && $deleted_num gt 0) {
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"DELETE ljr_remote_comments FROM
|
||
|
ljr_remote_comments LEFT JOIN talk2 ON
|
||
|
ljr_remote_comments.local_journalid = talk2.journalid AND
|
||
|
ljr_remote_comments.local_jtalkid = talk2.jtalkid
|
||
|
WHERE
|
||
|
ljr_remote_comments.local_journalid = ? and
|
||
|
talk2.journalid is NULL;",
|
||
|
undef, $journalu->{"userid"});
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$dbh->do ("UPDATE ljr_remote_users
|
||
|
SET created_comments_maxid = created_comments_maxid - ?
|
||
|
WHERE ru_id=? and local_journalid=?",
|
||
|
undef, $deleted_num, $ru->{"ru_id"}, $journalu->{"userid"}
|
||
|
);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{"created_comments_maxid"} = $ru->{"created_comments_maxid"} - $deleted_num;
|
||
|
}
|
||
|
$sth_cc->finish;
|
||
|
|
||
|
# if we haven't posted all the cached comments, do it now
|
||
|
if ($ru->{"created_comments_maxid"} < $ru->{"cached_comments_maxid"}) {
|
||
|
LJ::load_props("talk");
|
||
|
return $err->("Can't load talkprops.") unless $LJ::CACHE_PROP{talk};
|
||
|
|
||
|
my $sth = $dbr->prepare("
|
||
|
SELECT ljr_cached_comments.* FROM ljr_cached_comments LEFT JOIN ljr_remote_comments
|
||
|
ON ljr_cached_comments.cc_id = ljr_remote_comments.cc_id and
|
||
|
ljr_remote_comments.local_journalid = ?
|
||
|
WHERE ljr_cached_comments.ru_id = ? and ljr_remote_comments.cc_id is NULL
|
||
|
");
|
||
|
$sth->execute($journalu->{"userid"}, $ru->{"ru_id"});
|
||
|
|
||
|
my $up; # local user which owns imported comment
|
||
|
my $item; # local journal entry where the comment is to be imported
|
||
|
my $parent; # parent comment (0 for comments to the entry)
|
||
|
my $comment; # comment being created
|
||
|
my $i = 0; # counter
|
||
|
|
||
|
while (my $r = $sth->fetchrow_hashref) {
|
||
|
if ($r->{posterid}) {
|
||
|
$up = LJR::Distributed::get_cached_user({ru_id => $r->{ru_id}});
|
||
|
|
||
|
$up->{ru_id} = 0;
|
||
|
$up->{userid} = $r->{posterid};
|
||
|
$up->{username} = "";
|
||
|
$up = LJR::Distributed::get_cached_user($up);
|
||
|
|
||
|
$up = LJR::Distributed::get_cu_field($up, "local_commenterid");
|
||
|
$up = LJ::load_userid ($up->{local_commenterid});
|
||
|
}
|
||
|
else {
|
||
|
$up = undef;
|
||
|
}
|
||
|
|
||
|
$item = LJR::Distributed::get_local_itemid ($journalu, $r->{ru_id}, $r->{jitemid});
|
||
|
|
||
|
if (!$item->{itemid}) {
|
||
|
$warn->("Can't find corresponding local entry while importing " .
|
||
|
$journalu->{name} .
|
||
|
" (remote entry " . $r->{ru_id} . ":" . $r->{jitemid} . ").");
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
$item = $item->{item};
|
||
|
|
||
|
if ($r->{"parentid"}) {
|
||
|
$parent = LJR::Distributed::get_local_commentid(
|
||
|
$journalu->{"userid"}, $r->{"ru_id"}, $r->{"parentid"});
|
||
|
|
||
|
if (!$parent->{"talkid"}) {
|
||
|
$warn->(
|
||
|
"Can't find corresponding parent comment while importing " .
|
||
|
$journalu->{"name"} .
|
||
|
" (remote parent id: " . $r->{"parentid"} . "), " .
|
||
|
"attaching to the local entry (" . $item->{"jitemid"} . ")"
|
||
|
);
|
||
|
$parent->{"talkid"} = 0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$parent->{"talkid"} = 0;
|
||
|
}
|
||
|
|
||
|
my $sth1 = $dbr->prepare("SELECT tpropid, value FROM ljr_cached_comprops WHERE cc_id=?");
|
||
|
$sth1->execute($r->{cc_id});
|
||
|
|
||
|
my %props = ();
|
||
|
while (my $p = $sth1->fetchrow_hashref) {
|
||
|
$props{$LJ::CACHE_PROPID{talk}->{$p->{tpropid}}->{name}} = $p->{value};
|
||
|
}
|
||
|
|
||
|
$sth1->finish();
|
||
|
|
||
|
$comment = {
|
||
|
u => $up,
|
||
|
subject => $r->{subject},
|
||
|
body => $r->{body},
|
||
|
state => $r->{state},
|
||
|
datetime => $r->{date},
|
||
|
props => \%props,
|
||
|
};
|
||
|
|
||
|
$comment = LJR::Distributed::create_imported_comment($journalu, $parent, $item, $comment);
|
||
|
return $err->("error while creating imported comment: " . $comment->{errtext})
|
||
|
if $comment->{err};
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_remote_comments VALUES (?,?,?)",
|
||
|
undef, $r->{cc_id}, $journalu->{userid}, $comment->{talkid});
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$dbh->do("UPDATE ljr_remote_users
|
||
|
SET created_comments_maxid = ?
|
||
|
WHERE ru_id=? and local_journalid=?",
|
||
|
undef, $r->{commentid}, $ru->{ru_id}, $journalu->{userid}
|
||
|
);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$i = $i + 1;
|
||
|
if ($i % $throttle_num == 0) {
|
||
|
sleep $throttle_sec;
|
||
|
}
|
||
|
}
|
||
|
$sth->finish();
|
||
|
}
|
||
|
|
||
|
return $ru;
|
||
|
}
|
||
|
|
||
|
sub cache_comment {
|
||
|
my ($c) = @_;
|
||
|
|
||
|
if ($c->{id}) {
|
||
|
$c->{commentid} = $c->{id};
|
||
|
}
|
||
|
if (!$c->{state}) {
|
||
|
$c->{state} = "A";
|
||
|
}
|
||
|
|
||
|
return $err->("cache_comment: no ru_id specified.") unless $c->{ru_id};
|
||
|
return $err->("cache_comment: no comment id specified.") unless $c->{commentid};
|
||
|
return $err->("cache_comment: no jitemid specified.") unless $c->{jitemid};
|
||
|
|
||
|
if ($c->{state} ne "D") {
|
||
|
return $err->("cache_comment: no body specified.") unless $c->{body};
|
||
|
return $err->("cache_comment: no date specified.") unless $c->{date};
|
||
|
}
|
||
|
else {
|
||
|
$c->{body} = "" unless $c->{body};
|
||
|
$c->{date} = "" unless $c->{date};
|
||
|
}
|
||
|
|
||
|
if (!$c->{posterid}) {
|
||
|
$c->{posterid} = 0;
|
||
|
}
|
||
|
if (!$c->{parentid}) {
|
||
|
$c->{parentid} = 0;
|
||
|
}
|
||
|
if (!$c->{subject}) {
|
||
|
$c->{subject} = "";
|
||
|
}
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
my $cc_id1 = $dbr->selectrow_array(
|
||
|
"SELECT cc_id FROM ljr_cached_comments " .
|
||
|
"WHERE ru_id=? and commentid=?",
|
||
|
undef, $c->{ru_id}, $c->{commentid});
|
||
|
|
||
|
if ($cc_id1) {
|
||
|
my $existing_comment = $dbr->selectrow_hashref(
|
||
|
"SELECT * FROM ljr_cached_comments " .
|
||
|
"WHERE ru_id=? and commentid=?",
|
||
|
undef, $c->{ru_id}, $c->{commentid});
|
||
|
|
||
|
# it just works (somehow clears some UTF8 flag)
|
||
|
$c->{body} = pack('C*', unpack('C*', $c->{body}))
|
||
|
if $c->{body};
|
||
|
$c->{subject} = pack('C*', unpack('C*', $c->{subject}))
|
||
|
if $c->{subject};
|
||
|
|
||
|
if (
|
||
|
$c->{jitemid} != $existing_comment->{jitemid} ||
|
||
|
$c->{parentid} != $existing_comment->{parentid} ||
|
||
|
$c->{subject} ne $existing_comment->{subject} ||
|
||
|
$c->{body} ne $existing_comment->{body} ||
|
||
|
$c->{date} ne $existing_comment->{date} ||
|
||
|
($c->{posterid} != 0 && $c->{posterid} != $existing_comment->{posterid})
|
||
|
) {
|
||
|
|
||
|
my $ru = LJR::Distributed::get_cached_user({ru_id => $c->{ru_id}});
|
||
|
return $err->("There already exists different comment id=$c->{commentid} for user $ru->{username} (ru_id = $ru->{ru_id}).!") ;
|
||
|
}
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_cached_comments " .
|
||
|
"SET posterid=?, state=? " .
|
||
|
"WHERE ru_id=? and commentid=?",
|
||
|
undef, $c->{posterid}, $c->{state}, $c->{ru_id}, $c->{commentid});
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
else {
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
# start transaction
|
||
|
$dbh->begin_work;
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_cached_comments " .
|
||
|
"(ru_id, commentid, posterid, state, jitemid, parentid, " .
|
||
|
"subject, body, date) VALUES " .
|
||
|
"(?,?,?,?,?,?,?,?,?)",
|
||
|
undef, $c->{ru_id}, $c->{commentid}, $c->{posterid}, $c->{state},
|
||
|
$c->{jitemid}, $c->{parentid}, $c->{subject}, $c->{body}, $c->{date});
|
||
|
return $err->($dbh, $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
# get newly cached comment id
|
||
|
$c->{cc_id} = $dbh->{mysql_insertid};
|
||
|
|
||
|
# save props
|
||
|
LJ::load_props("talk");
|
||
|
return $err->($dbh, "Can't load talkprops.") unless $LJ::CACHE_PROP{talk};
|
||
|
|
||
|
if ($c->{props}) {
|
||
|
foreach my $k (keys %{$c->{props}}) {
|
||
|
if (${$LJ::CACHE_PROP{talk}}{$k}->{tpropid}) {
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_cached_comprops VALUES (?, ?, ?) ",
|
||
|
undef,
|
||
|
$c->{cc_id},
|
||
|
${$LJ::CACHE_PROP{talk}}{$k}->{tpropid},
|
||
|
$c->{props}->{$k}
|
||
|
);
|
||
|
return $err->($dbh,
|
||
|
"Error caching property \"" . $k . "\": " . $dbh->errstr)
|
||
|
if $dbh->err;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$dbh->commit;
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
|
||
|
return $c;
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# copied from LJ::alloc_global_counter
|
||
|
#
|
||
|
sub alloc_global_counter {
|
||
|
my ($dom, $recurse) = @_;
|
||
|
|
||
|
return $err->("alloc_global_counter: invalid domain!") unless $dom =~ /^[I]$/;
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
my $newmax;
|
||
|
my $uid = 0; # userid is not needed, we just use '0'
|
||
|
|
||
|
my $rs = $dbh->do(
|
||
|
"UPDATE ljr_counter
|
||
|
SET max=LAST_INSERT_ID(max+1) WHERE journalid=? AND area=?",
|
||
|
undef, $uid, $dom);
|
||
|
|
||
|
if ($rs > 0) {
|
||
|
$newmax = $dbh->selectrow_array("SELECT LAST_INSERT_ID()");
|
||
|
return $newmax;
|
||
|
}
|
||
|
|
||
|
return undef if $recurse;
|
||
|
|
||
|
# no prior counter rows - initialize one.
|
||
|
if ($dom eq "I") {
|
||
|
$newmax = 0;
|
||
|
}
|
||
|
$newmax += 0;
|
||
|
|
||
|
$dbh->do("INSERT IGNORE INTO ljr_counter (journalid, area, max) VALUES (?,?,?)",
|
||
|
undef, $uid, $dom, $newmax) or return undef;
|
||
|
return LJR::Distributed::alloc_global_counter($dom, 1);
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# copied from LJ::User::load_identity_user
|
||
|
#
|
||
|
sub get_imported_user {
|
||
|
my ($ru) = @_;
|
||
|
|
||
|
return $err->("remote_serverid is not specified.")
|
||
|
unless $ru->{serverid};
|
||
|
return $err->("remote_username is not specified.")
|
||
|
unless $ru->{username};
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
$ru = LJR::Distributed::get_remote_server_byid($ru);
|
||
|
return $err->("Server " . $ru->{serverid} . "doesn't exist!") unless $ru->{"servername"};
|
||
|
|
||
|
my $serverurl = $ru->{servername};
|
||
|
my $identity = $serverurl . "/users/" . $ru->{username};
|
||
|
|
||
|
my $uid = $dbr->selectrow_array(
|
||
|
"SELECT userid FROM identitymap WHERE idtype=? AND identity=?",
|
||
|
undef, "G", $identity);
|
||
|
|
||
|
if (!$uid) {
|
||
|
my $impuser = 'imp_' . LJR::Distributed::alloc_global_counter('I');
|
||
|
|
||
|
$uid = LJ::create_account({
|
||
|
caps => undef,
|
||
|
user => $impuser,
|
||
|
name => $impuser,
|
||
|
journaltype => 'I',
|
||
|
imported => 1,
|
||
|
});
|
||
|
return $err->("can't create account!") unless $uid;
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT INTO identitymap (idtype, identity, userid) VALUES (?,?,?)",
|
||
|
undef, "G", $identity, $uid);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$uid = $dbr->selectrow_array(
|
||
|
"SELECT userid FROM identitymap WHERE idtype=? AND identity=?",
|
||
|
undef, "G", $identity);
|
||
|
return $err->("can't get identity userid for " . $identity) unless $uid;
|
||
|
}
|
||
|
|
||
|
$ru->{commenterid} = $uid;
|
||
|
return $ru;
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# gets ljr_cached_users field (identified with ru_id)
|
||
|
#
|
||
|
sub get_cu_field {
|
||
|
my ($ru, $field) = @_;
|
||
|
|
||
|
my $truid;
|
||
|
if (ref($ru)) {
|
||
|
$truid = $ru->{ru_id}
|
||
|
}
|
||
|
else {
|
||
|
$truid = $ru;
|
||
|
}
|
||
|
|
||
|
return $err->("get_cu_field: ru_id is not specified.")
|
||
|
unless $truid;
|
||
|
return $err->("get_cu_field: field is not specified.")
|
||
|
unless $field;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
my $tvalue = $dbr->selectrow_array(
|
||
|
"SELECT $field FROM ljr_cached_users " .
|
||
|
"WHERE ru_id=?", undef, $truid);
|
||
|
|
||
|
if (ref($ru)) {
|
||
|
$ru->{$field} = $tvalue;
|
||
|
return $ru;
|
||
|
}
|
||
|
else {
|
||
|
return $tvalue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# currently overwrites everything. maybe it shouldn't.
|
||
|
#
|
||
|
sub set_cu_field {
|
||
|
my ($ru, $field, $value) = @_;
|
||
|
|
||
|
return $err->("set_cu_field: no ru_id in ru hashref.")
|
||
|
unless $ru->{ru_id};
|
||
|
return $err->("set_cu_field: field is not specified (ru_id = $ru->{ru_id}).")
|
||
|
unless $field;
|
||
|
return $err->("set_cu_field: field value is not specified (field = $field).")
|
||
|
unless defined($value);
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
my $existing_field_value = $dbr->selectrow_array(
|
||
|
"SELECT $field FROM ljr_cached_users WHERE ru_id = ?", undef, $ru->{ru_id});
|
||
|
|
||
|
if (
|
||
|
defined($existing_field_value) && defined($value) && $existing_field_value != $value ||
|
||
|
$existing_field_value && !defined($value) ||
|
||
|
!defined($existing_field_value) && $value
|
||
|
) {
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
if ($existing_field_value) {
|
||
|
$warn->(
|
||
|
"ljr_cached_users: overwriting " . $field . " [" . $existing_field_value . "] " .
|
||
|
"with [ " . $value . " ] " .
|
||
|
"for ru_id = " . $ru->{ru_id});
|
||
|
}
|
||
|
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_cached_users SET $field = ? WHERE ru_id = ?",
|
||
|
undef, $value, $ru->{ru_id});
|
||
|
return $err->("error updating ljr_cached_users.${field}: " . $dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
|
||
|
$ru->{$field} = $value;
|
||
|
return $ru;
|
||
|
}
|
||
|
|
||
|
sub match_remote_server {
|
||
|
my ($remote_server) = @_;
|
||
|
my %res = ();
|
||
|
|
||
|
return $err->("no server name specified!") unless $remote_server;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
if ($remote_server =~ /.*\.(\w+\.\w+)\/?/) {
|
||
|
$remote_server = $1;
|
||
|
}
|
||
|
|
||
|
my ($serverid, $servername, $servertype) = $dbr->selectrow_array(
|
||
|
"SELECT remote_serverid, canonical_url, blog_type FROM ljr_remote_servers " .
|
||
|
"WHERE canonical_url like '%" . $remote_server . "'");
|
||
|
|
||
|
$res{"serverid"} = $serverid;
|
||
|
$res{"servertype"} = $servertype;
|
||
|
$res{"servername"} = $servername;
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
# <LJFUNC>
|
||
|
# name: LJR::Distributed::get_remote_server
|
||
|
# des: get remote server identification at the local site
|
||
|
# returns: $hashref->{serverid} or $hashref->{err} and $hashref->{errtext}
|
||
|
# args: remote_server
|
||
|
# des-remote_server: canonical name of the remote server
|
||
|
# </LJFUNC>
|
||
|
sub get_remote_server {
|
||
|
my ($remote_server) = @_;
|
||
|
my %res = ();
|
||
|
|
||
|
return $err->("no server name specified!") unless $remote_server;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
# TODO: maybe we'll have to change this to support https or smth else?
|
||
|
# TODO: note that we'll have to change LJ::Simple also, which currently
|
||
|
# TODO: work only with http://
|
||
|
if ($remote_server !~ /^http\:\/\//) {
|
||
|
$remote_server = "http://" . $remote_server;
|
||
|
}
|
||
|
|
||
|
my ($serverid, $servertype) = $dbr->selectrow_array(
|
||
|
"SELECT remote_serverid, blog_type FROM ljr_remote_servers " .
|
||
|
"WHERE canonical_url=?", undef, $remote_server);
|
||
|
|
||
|
if (!$serverid) {
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_remote_servers (canonical_url) VALUES (?)",
|
||
|
undef, $remote_server);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$serverid = $dbh->{mysql_insertid};
|
||
|
return $err->("Can't get serverid!") unless $serverid;
|
||
|
}
|
||
|
|
||
|
$res{"serverid"} = $serverid;
|
||
|
$res{"servertype"} = $servertype;
|
||
|
$res{"servername"} = $remote_server;
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
sub get_remote_server_byid {
|
||
|
my ($ru) = @_;
|
||
|
|
||
|
if ($ru->{"serverid"}) {
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("No database reader available!") unless $dbr;
|
||
|
|
||
|
($ru->{"servername"}, $ru->{"servertype"}) =
|
||
|
$dbr->selectrow_array(
|
||
|
"SELECT canonical_url, blog_type " .
|
||
|
"FROM ljr_remote_servers WHERE remote_serverid=?",
|
||
|
undef, $ru->{serverid});
|
||
|
}
|
||
|
return $ru;
|
||
|
}
|
||
|
|
||
|
sub remote_local_assoc {
|
||
|
my ($ru, $u) = @_;
|
||
|
|
||
|
return $err->("remote_local_assoc: no ru_id in ru hashref.")
|
||
|
unless $ru->{ru_id};
|
||
|
return $err->("remote_local_assoc: no userid in user hashref.")
|
||
|
unless $u->{userid};
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("No database reader available!") unless $dbr;
|
||
|
|
||
|
my ($r) = $dbr->selectrow_array(
|
||
|
"SELECT count(*) FROM ljr_remote_users " .
|
||
|
"WHERE ru_id=? and local_journalid=?",
|
||
|
undef, $ru->{ru_id}, $u->{userid});
|
||
|
if ($r) {
|
||
|
$ru->{created_comments_maxid} = $dbr->selectrow_array(
|
||
|
"SELECT created_comments_maxid FROM ljr_remote_users " .
|
||
|
"WHERE ru_id=? and local_journalid=?",
|
||
|
undef, $ru->{ru_id}, $u->{userid});
|
||
|
|
||
|
$ru->{assoc_existed} = 1;
|
||
|
}
|
||
|
else {
|
||
|
$ru->{assoc_existed} = 0;
|
||
|
$ru->{created_comments_maxid} = 0;
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT ljr_remote_users SET ru_id = ?, local_journalid = ?",
|
||
|
undef, $ru->{ru_id}, $u->{userid},
|
||
|
);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
|
||
|
return $ru;
|
||
|
}
|
||
|
|
||
|
sub change_identity {
|
||
|
my ($dbh, $remote_serverid, $old_username, $new_username) = @_;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("No database reader available!") unless $dbr;
|
||
|
|
||
|
my ($serverurl, $servertype) = $dbr->selectrow_array(
|
||
|
"SELECT canonical_url, blog_type FROM ljr_remote_servers " .
|
||
|
"WHERE remote_serverid=?", undef, $remote_serverid);
|
||
|
return $err->("Server " . $remote_serverid . "doesn't exist!") unless $serverurl;
|
||
|
|
||
|
my $old_identity = $serverurl . "/users/" . $old_username;
|
||
|
my $new_identity = $serverurl . "/users/" . $new_username;
|
||
|
|
||
|
my $uid = $dbr->selectrow_array(
|
||
|
"SELECT userid FROM identitymap WHERE idtype=? AND identity=?",
|
||
|
undef, "G", $old_identity);
|
||
|
return $err->("can't get identity userid for " . $old_identity) unless ($uid);
|
||
|
|
||
|
$dbh->do(
|
||
|
"UPDATE identitymap SET identity = ? WHERE userid = ?",
|
||
|
undef, $new_identity, $uid);
|
||
|
return $err->("Error changing identity: " . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
return {'err' => 0};
|
||
|
}
|
||
|
|
||
|
# <LJFUNC>
|
||
|
# name: LJR::Distributed::get_cached_user
|
||
|
# des: get cached user hashref
|
||
|
# des: $ru->{ru_id}
|
||
|
# des: $ru->{serverid}
|
||
|
# des: $ru->{userid}
|
||
|
# des: $ru->{username}
|
||
|
# des: $ru->{type}
|
||
|
# returns: $ru or $ru->{err} and $ru->{errtext}
|
||
|
# args: $ru->{serverid} && ($ru->{userid} and/or $ru->{username})
|
||
|
# </LJFUNC>
|
||
|
sub get_cached_user {
|
||
|
my ($ru) = @_;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("No database reader available!") unless $dbr;
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
if ($ru->{'ru_id'}) {
|
||
|
($ru->{'serverid'}, $ru->{'userid'}, $ru->{'username'}) =
|
||
|
$dbr->selectrow_array(
|
||
|
"SELECT remote_serverid, remote_userid, remote_username " .
|
||
|
"FROM ljr_cached_users WHERE ru_id=?",
|
||
|
undef, $ru->{'ru_id'});
|
||
|
}
|
||
|
else {
|
||
|
return $err->("remote_serverid is not specified.") unless $ru->{'serverid'};
|
||
|
|
||
|
my $remote_type;
|
||
|
if ($ru->{'type'}) {
|
||
|
$remote_type = $ru->{'type'}
|
||
|
}
|
||
|
else {
|
||
|
$remote_type = "P";
|
||
|
}
|
||
|
|
||
|
if ($ru->{'username'} && $ru->{'userid'}) {
|
||
|
my $update_ljr_cached_users = sub {
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_cached_users
|
||
|
SET remote_userid = ?, remote_username = ?
|
||
|
WHERE ljr_cached_users.ru_id = ?",
|
||
|
undef, $ru->{'userid'}, $ru->{'username'}, $ru->{'ru_id'});
|
||
|
return $err->($dbh, $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{'type'} = $dbr->selectrow_array(
|
||
|
"SELECT remote_type FROM ljr_cached_users WHERE ru_id = ?",
|
||
|
undef, $ru->{'ru_id'});
|
||
|
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
my $rename_remote_user = sub {
|
||
|
my ($ru_id, $old_username, $new_username) = @_;
|
||
|
|
||
|
my $rename_seq = $dbr->selectrow_array(
|
||
|
"SELECT max(rename_seq) FROM ljr_remote_renamed WHERE ru_id=?",
|
||
|
undef, $ru_id);
|
||
|
|
||
|
$rename_seq++;
|
||
|
|
||
|
# save old username
|
||
|
$dbh->do(
|
||
|
"INSERT ljr_remote_renamed (ru_id, rename_seq, old_username, new_username)
|
||
|
VALUES (?, ?, ?, ?)",
|
||
|
undef, $ru_id, $rename_seq, $old_username, $new_username);
|
||
|
return $err->($dbh, $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
# update identitymap
|
||
|
my $r = change_identity($dbh, $ru->{'serverid'}, $old_username, $new_username);
|
||
|
return $err->($dbh, $r->{"errtext"}) if $r->{"err"};
|
||
|
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
my $reid_remote_user = sub {
|
||
|
my ($remote_username, $old_ru_id, $new_ru_id) = @_;
|
||
|
|
||
|
my $reid_seq = $dbr->selectrow_array(
|
||
|
"SELECT max(reid_seq) FROM ljr_remote_reided " .
|
||
|
"WHERE remote_serverid=? and remote_username=?",
|
||
|
undef, $ru->{'serverid'}, $remote_username);
|
||
|
|
||
|
$reid_seq++;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_remote_reided (remote_serverid, remote_username,
|
||
|
reid_seq, old_ru_id, new_ru_id) VALUES (?, ?, ?, ?, ?)",
|
||
|
undef, $ru->{'serverid'}, $remote_username, $reid_seq, $old_ru_id, $new_ru_id);
|
||
|
return $err->($dbh, $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
my ($username_ru_id, $username_userid, $username_local_commenterid) = $dbr->selectrow_array(
|
||
|
"SELECT ru_id, remote_userid, local_commenterid FROM ljr_cached_users " .
|
||
|
"WHERE remote_serverid=? and remote_username=?",
|
||
|
undef, $ru->{'serverid'}, $ru->{'username'});
|
||
|
|
||
|
my ($userid_ru_id, $userid_username, $userid_local_commenterid) = $dbr->selectrow_array(
|
||
|
"SELECT ru_id, remote_username, local_commenterid FROM ljr_cached_users " .
|
||
|
"WHERE remote_serverid=? and remote_userid=?",
|
||
|
undef, $ru->{'serverid'}, $ru->{'userid'});
|
||
|
|
||
|
my $r;
|
||
|
|
||
|
if ($username_ru_id && $userid_ru_id) {
|
||
|
if ($username_userid && $userid_username) {
|
||
|
if ($username_ru_id ne $userid_ru_id) {
|
||
|
|
||
|
$warn->("get_cached_user: " .
|
||
|
$ru->{'username'} . " points to ${username_userid}, " .
|
||
|
$ru->{'userid'} . " points to ${userid_username}; " .
|
||
|
"trying to solve.");
|
||
|
|
||
|
$dbh->begin_work;
|
||
|
|
||
|
$r = $reid_remote_user->($ru->{'username'}, $username_ru_id, $userid_ru_id);
|
||
|
return $err->("gcu1.1: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
my $has_ex = 1;
|
||
|
my $ex_suff;
|
||
|
my $ex_name;
|
||
|
|
||
|
while ($has_ex) {
|
||
|
$ex_name = "ex_" . $ru->{'username'} . ($ex_suff ? ("_" . $ex_suff) : "");
|
||
|
|
||
|
$has_ex = $dbh->selectrow_array(
|
||
|
"SELECT count(remote_username) FROM ljr_cached_users
|
||
|
WHERE remote_serverid=? and remote_username=?",
|
||
|
undef, $ru->{'serverid'}, $ex_name);
|
||
|
|
||
|
$ex_suff = $ex_suff + 1;
|
||
|
}
|
||
|
|
||
|
$r = $rename_remote_user->($username_ru_id, $ru->{'username'}, $ex_name);
|
||
|
return $err->("gcu1.2: " . $ru->{'username'} . ": " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_cached_users SET remote_username = ?
|
||
|
WHERE ljr_cached_users.ru_id = ?",
|
||
|
undef, $ex_name, $username_ru_id);
|
||
|
return $err->($dbh, "gcu1.3: ${ex_name}:" . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$r = $rename_remote_user->($userid_ru_id, $userid_username, $ru->{'username'});
|
||
|
return $err->("gcu1.4: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_cached_users SET remote_username = ?
|
||
|
WHERE ljr_cached_users.ru_id = ?",
|
||
|
undef, $ru->{'username'}, $userid_ru_id);
|
||
|
return $err->($dbh, "gcu1.5: " . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{'ru_id'} = $userid_ru_id;
|
||
|
|
||
|
$r = $update_ljr_cached_users->();
|
||
|
return $err->("gcu1.6: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->commit;
|
||
|
}
|
||
|
else {
|
||
|
$ru->{'ru_id'} = $username_ru_id;
|
||
|
$r = $update_ljr_cached_users->();
|
||
|
return $err->("gcu1.7: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
}
|
||
|
}
|
||
|
elsif (! $username_userid && ! $username_local_commenterid && $userid_username) {
|
||
|
$dbh->begin_work;
|
||
|
$ru->{'ru_id'} = $userid_ru_id;
|
||
|
|
||
|
# ljr_cached_users for $ru->{'username'} doesn't have remote_userid
|
||
|
# it's bogus. deleting it.
|
||
|
$dbh->do ("DELETE FROM ljr_cached_users WHERE ru_id=?", undef, $username_ru_id);
|
||
|
return $err->($dbh, "gcu1.2: " . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
if ($userid_username ne $ru->{'username'}) {
|
||
|
$r = $rename_remote_user->($ru->{'ru_id'}, $userid_username, $ru->{'username'});
|
||
|
return $err->("gcu1.2: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
}
|
||
|
|
||
|
$r = $update_ljr_cached_users->();
|
||
|
return $err->("gcu1.2: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->commit;
|
||
|
}
|
||
|
else {
|
||
|
return $err->("ljr_cached_users inconsistency type 1 for $ru->{username} and $ru->{userid}.")
|
||
|
}
|
||
|
}
|
||
|
elsif ($username_ru_id) {
|
||
|
$dbh->begin_work;
|
||
|
|
||
|
if ($username_userid && $username_userid ne $ru->{'userid'}) {
|
||
|
my $has_ex = 1;
|
||
|
my $ex_suff;
|
||
|
my $ex_name;
|
||
|
|
||
|
while ($has_ex) {
|
||
|
$ex_name = "ex_" . $ru->{'username'} . ($ex_suff ? ("_" . $ex_suff) : "");
|
||
|
|
||
|
$has_ex = $dbr->selectrow_array(
|
||
|
"SELECT count(remote_username) FROM ljr_cached_users
|
||
|
WHERE remote_serverid=? and remote_username=?",
|
||
|
undef, $ru->{'serverid'}, $ex_name);
|
||
|
|
||
|
$ex_suff = $ex_suff + 1;
|
||
|
}
|
||
|
|
||
|
$r = $rename_remote_user->($username_ru_id, $ru->{'username'}, $ex_name);
|
||
|
return $err->("gcu2.1: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_cached_users SET remote_username = ?
|
||
|
WHERE ljr_cached_users.ru_id = ?",
|
||
|
undef, $ex_name, $username_ru_id);
|
||
|
return $err->($dbh, "gcu2.2: " . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_cached_users
|
||
|
(remote_serverid, remote_username, remote_userid, remote_type)
|
||
|
VALUES (?, ?, ?, ?)",
|
||
|
undef, $ru->{'serverid'}, $ru->{'username'}, $ru->{'userid'}, $remote_type);
|
||
|
return $err->($dbh, "gcu2.3: " . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{'ru_id'} = $dbh->{mysql_insertid};
|
||
|
|
||
|
$r = $reid_remote_user->($ru->{'username'}, $username_ru_id, $ru->{'ru_id'});
|
||
|
return $err->("gcu2.4: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
}
|
||
|
else {
|
||
|
$ru->{'ru_id'} = $username_ru_id;
|
||
|
}
|
||
|
|
||
|
$r = $update_ljr_cached_users->();
|
||
|
return $err->("gcu2.5: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->commit;
|
||
|
}
|
||
|
elsif ($userid_ru_id) {
|
||
|
$dbh->begin_work;
|
||
|
$ru->{'ru_id'} = $userid_ru_id;
|
||
|
|
||
|
if ($userid_username && $userid_username ne $ru->{'username'}) {
|
||
|
$r = $rename_remote_user->($ru->{'ru_id'}, $userid_username, $ru->{'username'});
|
||
|
return $err->("gcu3: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
}
|
||
|
|
||
|
$r = $update_ljr_cached_users->();
|
||
|
return $err->("gcu3: " . $r->{'errtext'}) if $r->{'err'};
|
||
|
|
||
|
$dbh->commit;
|
||
|
}
|
||
|
else {
|
||
|
$dbh->do(
|
||
|
"INSERT ljr_cached_users
|
||
|
(remote_serverid, remote_userid, remote_username, remote_type)
|
||
|
VALUES (?, ?, ?, ?)",
|
||
|
undef, $ru->{'serverid'}, $ru->{'userid'}, $ru->{'username'}, $remote_type);
|
||
|
return $err->("gcu4: " . $dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{'ru_id'} = $dbh->{mysql_insertid};
|
||
|
$ru->{'type'} = $remote_type;
|
||
|
}
|
||
|
}
|
||
|
elsif ($ru->{'username'} && !$ru->{'userid'}) {
|
||
|
my ($ru_id_1, $ljr_userid, $ljr_type);
|
||
|
|
||
|
($ru_id_1, $ljr_userid, $ljr_type) = $dbr->selectrow_array(
|
||
|
"SELECT ru_id, remote_userid, remote_type FROM ljr_cached_users " .
|
||
|
"WHERE remote_serverid=? and remote_username=?",
|
||
|
undef, $ru->{'serverid'}, $ru->{'username'});
|
||
|
|
||
|
# maybe the user was renamed at the remote site
|
||
|
if (!$ru_id_1) {
|
||
|
($ru_id_1, $ljr_userid, $ljr_type) = $dbr->selectrow_array(
|
||
|
"SELECT ljr_remote_renamed.ru_id, ljr_cached_users.remote_userid, ljr_cached_users.remote_type " .
|
||
|
"FROM ljr_remote_renamed, ljr_cached_users " .
|
||
|
"WHERE ljr_remote_renamed.old_username = ? and ljr_cached_users.remote_serverid = ? " .
|
||
|
"and ljr_remote_renamed.ru_id = ljr_cached_users.ru_id",
|
||
|
undef, $ru->{'username'}, $ru->{'serverid'});
|
||
|
}
|
||
|
|
||
|
if ($ru_id_1) {
|
||
|
$ru->{'ru_id'} = $ru_id_1;
|
||
|
$ru->{'userid'} = $ljr_userid;
|
||
|
$ru->{'type'} = $ljr_type;
|
||
|
}
|
||
|
else {
|
||
|
# TODO: try to get userid from userinfo.bml
|
||
|
# and maybe from lj_gate
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_cached_users
|
||
|
(remote_serverid, remote_username, remote_type)
|
||
|
VALUES (?, ?, ?)",
|
||
|
undef, $ru->{'serverid'}, $ru->{'username'}, $remote_type);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{'ru_id'} = $dbh->{mysql_insertid};
|
||
|
$ru->{'type'} = $remote_type;
|
||
|
}
|
||
|
}
|
||
|
elsif ($ru->{'userid'} && !$ru->{'username'}) {
|
||
|
my ($ru_id_2, $ljr_username, $ljr_type) = $dbr->selectrow_array(
|
||
|
"SELECT ru_id, remote_username, remote_type FROM ljr_cached_users " .
|
||
|
"WHERE remote_serverid=? and remote_userid=?",
|
||
|
undef, $ru->{'serverid'}, $ru->{'userid'});
|
||
|
if ($ru_id_2) {
|
||
|
$ru->{'ru_id'} = $ru_id_2;
|
||
|
$ru->{'username'} = $ljr_username;
|
||
|
$ru->{'type'} = $ljr_type;
|
||
|
}
|
||
|
else {
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_cached_users
|
||
|
(remote_serverid, remote_userid, remote_type)
|
||
|
VALUES (?, ?, ?)",
|
||
|
undef, $ru->{'serverid'}, $ru->{'userid'}, $remote_type);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
$ru->{'ru_id'} = $dbh->{mysql_insertid};
|
||
|
$ru->{'type'} = $remote_type;
|
||
|
}
|
||
|
}
|
||
|
elsif (!$ru->{'userid'} && !$ru->{'username'}) {
|
||
|
return $err->("no userid and username supplied.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $ru;
|
||
|
}
|
||
|
|
||
|
sub get_local_commentid {
|
||
|
my ($local_userid, $ru_id, $remote_talkid) = @_;
|
||
|
my %res = ();
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("No database reader available!") unless $dbr;
|
||
|
|
||
|
my $jtalkid;
|
||
|
my $local_user;
|
||
|
|
||
|
if ($local_userid) {
|
||
|
$jtalkid = $dbr->selectrow_array(
|
||
|
"SELECT local_jtalkid FROM ljr_cached_comments, ljr_remote_comments " .
|
||
|
"WHERE ru_id = ? and commentid = ? and ljr_cached_comments.cc_id = ljr_remote_comments.cc_id " .
|
||
|
"and local_journalid = ?",
|
||
|
undef, $ru_id, $remote_talkid, $local_userid);
|
||
|
return $err->("Can't find remote comment (" . $ru_id . ":" . $remote_talkid .
|
||
|
") for local user $local_userid.") unless $jtalkid;
|
||
|
}
|
||
|
else {
|
||
|
($local_userid, $jtalkid) = $dbr->selectrow_array(
|
||
|
"SELECT local_journalid, local_jtalkid FROM ljr_cached_comments, ljr_remote_comments " .
|
||
|
"WHERE ru_id = ? and commentid = ? and ljr_cached_comments.cc_id = ljr_remote_comments.cc_id " .
|
||
|
"limit 1",
|
||
|
undef, $ru_id, $remote_talkid);
|
||
|
return $err->("Can't find remote comment (" . $ru_id . ":" . $remote_talkid . ")")
|
||
|
unless $local_userid && $jtalkid;
|
||
|
|
||
|
$local_user = LJ::load_userid ($local_userid);
|
||
|
}
|
||
|
|
||
|
$res{"journalid"} = $local_user->{"userid"};
|
||
|
$res{"journalname"} = $local_user->{"user"};
|
||
|
$res{"talkid"} = $jtalkid;
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
# <LJFUNC>
|
||
|
# name: LJR::Distributed::get_local_itemid
|
||
|
# des: returns local itemid corresponding to remote entry
|
||
|
# returns: $hashref->{itemid} or $hashref->{err} and $hashref->{errtext}
|
||
|
# args: local_user, remote_server, remote_journal, remote_itemid
|
||
|
# des-local_user: user object of journal into which we're importing
|
||
|
# des-remote_server: remote serverid
|
||
|
# des-remote_journal: remote journalid
|
||
|
# des-remote_itemid: remote jitemid
|
||
|
# </LJFUNC>
|
||
|
sub get_local_itemid {
|
||
|
my ($local_user, $ru_id, $remote_itemid, $type) = @_;
|
||
|
my %res = ();
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("No database reader available!") unless $dbr;
|
||
|
|
||
|
$type = "I" unless $type;
|
||
|
|
||
|
my $jitemid;
|
||
|
my $item;
|
||
|
|
||
|
if ($local_user) {
|
||
|
# find first jitemid
|
||
|
$jitemid = $dbr->selectrow_array(
|
||
|
"SELECT local_jitemid FROM ljr_remote_entries " .
|
||
|
"WHERE local_journalid=? and sync_type=? and ru_id=? and remote_jitemid=?",
|
||
|
undef, $local_user->{"userid"}, $type, $ru_id, $remote_itemid);
|
||
|
}
|
||
|
else {
|
||
|
my $tid;
|
||
|
($tid, $jitemid) = $dbr->selectrow_array(
|
||
|
"SELECT local_journalid, local_jitemid FROM ljr_remote_entries " .
|
||
|
"WHERE ru_id=? and sync_type=? and remote_jitemid=? limit 1",
|
||
|
undef, $ru_id, $type, $remote_itemid);
|
||
|
$local_user = LJ::load_userid ($tid);
|
||
|
|
||
|
return $err->("Error loading user $tid") unless $local_user;
|
||
|
}
|
||
|
|
||
|
# check that local entry is still there
|
||
|
if ($jitemid) {
|
||
|
$item = LJ::get_log2_row($local_user, $jitemid);
|
||
|
|
||
|
# if it's not there then break association
|
||
|
if (!$item) {
|
||
|
$jitemid = 0;
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do(
|
||
|
"DELETE FROM ljr_remote_entries WHERE
|
||
|
local_journalid=? and sync_type=? and
|
||
|
ru_id=? and remote_jitemid=?",
|
||
|
undef, $local_user->{"userid"}, $type, $ru_id, $remote_itemid);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
$jitemid = 0;
|
||
|
}
|
||
|
|
||
|
$res{"journalid"} = $local_user->{"userid"};
|
||
|
$res{"journalname"} = $local_user->{"user"};
|
||
|
$res{"itemid"} = $jitemid;
|
||
|
$res{"item"} = $item;
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
|
||
|
# <LJFUNC>
|
||
|
# name: LJR::Distributed::store_remote_itemid
|
||
|
# des: associates remote entry with local entry
|
||
|
# returns: 1 or $hashref->{err} and $hashref->{errtext}
|
||
|
# args: local_user, remote_server, remote_journal, remote_itemid
|
||
|
# des-local_user: user object of journal into which we're importing
|
||
|
# des-local_jitemd: local journal entry id
|
||
|
# des-remote_server: remote serverid
|
||
|
# des-remote_journal: remote journalid
|
||
|
# des-remote_itemid: remote jitemid
|
||
|
# </LJFUNC>
|
||
|
sub store_remote_itemid {
|
||
|
my ($local_user, $local_jitemid, $ru_id, $remote_itemid, $remote_htmlid, $type) = @_;
|
||
|
my %res = ();
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$type = "I" unless $type;
|
||
|
|
||
|
$dbh->do("INSERT INTO ljr_remote_entries VALUES (?,?,?,?,?,?)",
|
||
|
undef, $local_user->{"userid"}, $local_jitemid, $ru_id, $remote_itemid, $remote_htmlid, $type);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
sub remove_remote_itemid {
|
||
|
my ($local_user, $local_jitemid, $ru_id, $remote_itemid, $type) = @_;
|
||
|
my %res = ();
|
||
|
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
$dbh->do("delete from ljr_remote_entries where local_journalid=? and local_jitemid=?
|
||
|
and ru_id=? and remote_jitemid=? and sync_type=?",
|
||
|
undef, $local_user->{"userid"}, $local_jitemid, $ru_id, $remote_itemid, $type);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
|
||
|
return \%res;
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# get remote item id
|
||
|
# type: I for imported items, E for exported (gated) items
|
||
|
#
|
||
|
sub get_remote_itemid {
|
||
|
my ($local_journalid, $local_jitemid, $type) = @_;
|
||
|
my $res = {};
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
$type = "I" unless $type;
|
||
|
|
||
|
my ($ru_id, $ritemid, $rhtmlid) = $dbr->selectrow_array(
|
||
|
"select ru_id, remote_jitemid, remote_htmlid from ljr_remote_entries " .
|
||
|
"WHERE local_journalid=? and local_jitemid=? and sync_type=?",
|
||
|
undef, $local_journalid, $local_jitemid, $type);
|
||
|
|
||
|
if ($ru_id) {
|
||
|
$res->{"ru_id"} = $ru_id;
|
||
|
$res->{"ritemid"} = $ritemid;
|
||
|
$res->{"rhtmlid"} = $rhtmlid;
|
||
|
|
||
|
$res = LJR::Distributed::get_cached_user($res);
|
||
|
return undef unless $res->{"username"};
|
||
|
|
||
|
$res = LJR::Distributed::get_remote_server_byid($res);
|
||
|
return undef unless $res->{"servername"};
|
||
|
|
||
|
$res->{"original_entry"} =
|
||
|
$res->{"servername"} . "/users/" .
|
||
|
$res->{"username"} . "/" .
|
||
|
$res->{"rhtmlid"} . ".html";
|
||
|
|
||
|
return $res;
|
||
|
}
|
||
|
else {
|
||
|
return undef;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub sign_imported_entry {
|
||
|
my ($journalid, $entryid, $event) = @_;
|
||
|
|
||
|
my $ru = LJR::Distributed::get_remote_itemid ($journalid, $entryid);
|
||
|
|
||
|
if ($ru && $ru->{"original_entry"}) {
|
||
|
$$event .=
|
||
|
"\n\n<tt><font size=0>" .
|
||
|
"<a href=/import-faq.bml>Imported event</a> " .
|
||
|
"<a href=" . $ru->{"original_entry"} . ">Original</a>" .
|
||
|
"</font></tt>";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub sign_exported_rss_entry {
|
||
|
my ($u, $jitemid, $anum, $event) = @_;
|
||
|
my $item_url = LJ::item_link($u, $jitemid, $anum);
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
my ($font, $color, $ljr_es_lastmod) = $dbr->selectrow_array(
|
||
|
"SELECT font_name, font_color FROM ljr_export_settings WHERE user=?",
|
||
|
undef, $u->{'user'});
|
||
|
|
||
|
$font = "gdLargeFont" unless $font;
|
||
|
$color = "blue" unless $color;
|
||
|
|
||
|
my $img = LJR::GD::generate_number(0, $font, $color, " ");
|
||
|
my $padded_width = $img->width;
|
||
|
my $padded_height = $img->height;
|
||
|
#my $replycounturl = $LJ::SITEROOT . "/comments/" . $jitemid . "/" . $u->{'userid'} ;
|
||
|
my $ditemid = $jitemid * 256 + $anum;
|
||
|
my $replycounturl = $LJ::SITEROOT . "/numreplies/" . $u->{'user'} . "/" . $ditemid ;
|
||
|
|
||
|
my $talklink =
|
||
|
"<br /><br /><div style=\"text-align:left\">" .
|
||
|
"<font size=\"-2\"><a href=\"" . $item_url . "\">" .
|
||
|
"<img src=\"" . $replycounturl . "\"" .
|
||
|
" border=0 width=$padded_width height=$padded_height " .
|
||
|
" alt=\"number of comments\" style=\"border:0px;\" />" .
|
||
|
" <strong>Comments</strong></a>" .
|
||
|
"</div>";
|
||
|
$$event .= $talklink;
|
||
|
}
|
||
|
|
||
|
sub sign_exported_gate_entry {
|
||
|
my ($u, $jitemid, $anum, $event) = @_;
|
||
|
my $item_url = LJ::item_link($u, $jitemid, $anum);
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
my ($font, $color, $ljr_es_lastmod) = $dbr->selectrow_array(
|
||
|
"SELECT font_name, font_color FROM ljr_export_settings WHERE user=?",
|
||
|
undef, $u->{'user'});
|
||
|
|
||
|
$font = "gdLargeFont" unless $font;
|
||
|
$color = "blue" unless $color;
|
||
|
|
||
|
my $img = LJR::GD::generate_number(0, $font, $color, " ");
|
||
|
my $padded_width = $img->width;
|
||
|
my $padded_height = $img->height;
|
||
|
#my $replycounturl = $LJ::SITEROOT . "/comments/" . $jitemid . "/" . $u->{'userid'} ;
|
||
|
my $ditemid = $jitemid * 256 + $anum;
|
||
|
my $replycounturl = $LJ::SITEROOT . "/numreplies/" . $u->{'user'} . "/" . $ditemid ;
|
||
|
|
||
|
my $talklink =
|
||
|
"<div style=\"text-align:right\">" .
|
||
|
"<font size=\"-2\">(<a href=\"" . $item_url . "\">" .
|
||
|
"<img src=\"" . $replycounturl . "\"" .
|
||
|
" border=0 width=$padded_width height=$padded_height " .
|
||
|
" alt=\"number of comments\" style=\"border:0px;\" />" .
|
||
|
" <strong>Comments</strong></a> |<a href=\"" .
|
||
|
$item_url .
|
||
|
"?mode=reply\">Comment on this</a>)</div>";
|
||
|
$$event .= $talklink;
|
||
|
}
|
||
|
|
||
|
sub update_export_status {
|
||
|
my ($local_user, $mode, $status_text) = @_;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
my $u = LJ::load_user($local_user, 1);
|
||
|
return $err->("Invalid local user: " . $local_user) unless $u;
|
||
|
|
||
|
my ($record_exists) = $dbr->selectrow_array(
|
||
|
"select count(*) from ljr_export_settings where user=? ",
|
||
|
undef, $local_user);
|
||
|
|
||
|
return err->("Export is not configured for $local_user") unless $record_exists;
|
||
|
|
||
|
if ($mode) {
|
||
|
$mode = 1;
|
||
|
}
|
||
|
else {
|
||
|
$mode = 0;
|
||
|
}
|
||
|
|
||
|
$dbh->do (
|
||
|
"UPDATE ljr_export_settings set enabled=?, update_time=NOW(), last_status=? WHERE user=?",
|
||
|
undef, $mode, $status_text, $local_user
|
||
|
);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
|
||
|
sub update_export_settings {
|
||
|
my ($local_user, $ru_id, $remote_password) = @_;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
my $dbh = LJ::get_db_writer();
|
||
|
return $err->("Can't get database writer!") unless $dbh;
|
||
|
|
||
|
my $u = LJ::load_user($local_user, 1);
|
||
|
return $err->("Invalid local user: " . $local_user) unless $u;
|
||
|
|
||
|
return $err->("ru_id or remote_password not specified") unless $ru_id && $remote_password;
|
||
|
|
||
|
my ($record_exists) = $dbr->selectrow_array(
|
||
|
"select count(*) from ljr_export_settings where user=? ",
|
||
|
undef, $local_user);
|
||
|
|
||
|
if ($record_exists) {
|
||
|
$dbh->do(
|
||
|
"UPDATE ljr_export_settings SET ru_id=?, remote_password=?, update_time=NOW() WHERE user=?",
|
||
|
undef, $ru_id, $remote_password, $local_user
|
||
|
);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
else {
|
||
|
$dbh->do(
|
||
|
"INSERT INTO ljr_export_settings " .
|
||
|
"(user, ru_id, remote_password, update_time) " .
|
||
|
"VALUES (?,?,?,NOW())",
|
||
|
undef, $local_user, $ru_id, $remote_password
|
||
|
);
|
||
|
return $err->($dbh->errstr) if $dbh->err;
|
||
|
}
|
||
|
return LJR::Distributed::update_export_status($local_user, 1, "OK: Updated settings.");
|
||
|
}
|
||
|
|
||
|
sub is_gated_local {
|
||
|
my ($username) = @_;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
my ($exported) = $dbr->selectrow_array(
|
||
|
"select enabled from ljr_export_settings where user=?",
|
||
|
undef, $username);
|
||
|
|
||
|
return $exported;
|
||
|
}
|
||
|
|
||
|
sub is_gated_remote {
|
||
|
my ($server, $username) = @_;
|
||
|
|
||
|
return $err->("Server and username must be specified.") unless $server && $username;
|
||
|
|
||
|
my $dbr = LJ::get_db_reader();
|
||
|
return $err->("Can't get database reader!") unless $dbr;
|
||
|
|
||
|
my $ru = LJR::Distributed::get_remote_server($server);
|
||
|
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||
|
|
||
|
$ru->{'username'} = $username;
|
||
|
$ru = LJR::Distributed::get_cached_user($ru);
|
||
|
return $err->($ru->{"errtext"}) if $ru->{"err"};
|
||
|
|
||
|
my ($exported) = $dbr->selectrow_array(
|
||
|
"select count(*) from ljr_export_settings where ru_id=?",
|
||
|
undef, $ru->{'ru_id'});
|
||
|
|
||
|
return $exported;
|
||
|
}
|