mourningdove/htdocs/tools/memadd.bml
2026-05-24 01:03:05 +00:00

417 lines
15 KiB
Text

<?_c
# This code was forked from the LiveJournal project owned and operated
# by Live Journal, Inc. The code has been modified and expanded by
# Dreamwidth Studios, LLC. These files were originally licensed under
# the terms of the license supplied by Live Journal, Inc, which can
# currently be found at:
#
# http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt
#
# In accordance with the original license, this code and all its
# modifications are provided under the GNU General Public License.
# A copy of that license can be found in the LICENSE file included as
# part of this distribution.
_c?>
<?_code
{
use strict;
use vars qw(%GET %POST $title $body);
BML::decl_params(_default => qr/./);
my $dbr = LJ::get_db_reader();
$title = $ML{'.title'};
$body = "";
my $err = sub {
$title = "Error";
$body = LJ::bad_input(@_);
return;
};
$POST{'oldkeywords'} = [ split('\0', $POST{'oldkeywords'}) ];
unless (LJ::text_in(\%POST)) {
return $err->("Invalid UTF-8 Input");
}
my $remote = LJ::get_remote();
unless ($remote) {
$body = "<?needlogin?>";
return;
}
my $authas = $GET{'authas'} || $remote->{'user'};
my $memoryu = LJ::get_authas_user($authas);
return $err->($ML{'error.invalidauth'})
unless $memoryu;
my $authextra = $authas ne $remote->{'user'} ? "?authas=$authas" : '';
my %secopts = ( 'public' => $ML{'label.security.public'},
'friends' => $ML{'label.security.accesslist'},
'private' => $ML{'label.security.private'}, );
if ( $memoryu->is_community ) {
$secopts{'private'} = $ML{'label.security.maintainers'};
$secopts{'friends'} = $ML{'label.security.members'};
}
my $sth;
my $journal = $GET{'journal'} || $POST{'journal'};
my $ditemid = $GET{'itemid'}+0 || $POST{'itemid'}+0;
# OK. the memories schema is weird and stores *display* itemids in the database.
# additionally, we distinguish precluster itemids because they're stored without a userid.
# it's too late to fix it in the db, so we just work around it--
# all new memories still get userid+ditemid because we can't change the ditemid/itemid problem,
# but old-style itemids get fixed up to userid+ditemid.
# *however*, when editing old itemids we need to keep around
# the old-style ditemid so we can still edit it.
# to keep this all sorted out, we fixup variables like this:
# - itemid -- real, new-style itemid
# - ditemid -- display itemid (with anum)
# - dbitemid -- itemid that is in the database;
# usually same as ditemid, but different for old-style itemids.
my $dbitemid = $ditemid;
my $itemid;
my $oldstyle = 0;
my $ju;
my $jid;
my $anum;
if ($journal) {
$ju = LJ::load_user($journal);
$jid = $ju->{'userid'};
$anum = $ditemid % 256;
$itemid = int($ditemid / 256);
}
unless ($ju && $itemid) {
$title = $ML{'Error'};
$body = $ML{'error.nojournal'};
return;
}
# check to see if it already is memorable (thus we're editing, not adding);
my $memory = LJ::Memories::get_by_ditemid($memoryu, $oldstyle ? 0 : $jid, $ditemid);
# Always allow for a user to delete their memories, regardless of other permissions.
if ($POST{'mode'} eq "save")
{
unless ($POST{'des'}) {
# we're deleting.
unless (LJ::check_form_auth()) {
$body = "<?h1 $ML{'Error'} h1?><?p $ML{'error.invalidform'} p?>";
return;
}
if (defined $memory) {
LJ::Memories::delete_by_id($memoryu, $memory->{memid});
LJ::Memories::updated_keywords($memoryu);
$title = $ML{'.title.deleted'};
$body = "<?h1 $ML{'.error.deleted.title'} h1?><?p " .
BML::ml(".error.deleted.body2", { 'desc' => $memory->{'des'} }) .
" p?>";
$body .= "<ul><li><a href='$LJ::SITEROOT/tools/memories?user=" . $memoryu->user .
"'>" . "$ML{'.error.deleted.next'}</a></li></ul>";
return;
} else {
$title = $ML{'Error'};
$body = "<?h1 $ML{'.error.nodescription.title'} h1?><?p ";
$body .= BML::ml('.error.nodescription.body2');
$body .= " p?>";
return;
}
}
}
# do access check to see if they can see this entry
my $log = LJ::get_log2_row($ju, $itemid);
if ( $log ) {
my $entry = LJ::Entry->new_from_row( %$log );
if ( $entry && ! $entry->visible_to( $remote ) ) {
$title = $ML{'Error'};
$body = "You are not authorized to view this entry.<br/>";
if ($memoryu->{user} eq $authas && defined $memory) {
$body .= "<br /><form action='memadd$authextra' method='POST'>";
$body .= LJ::form_auth();
$body .= LJ::html_hidden(journal => $GET{journal}) if $GET{journal};
$body .= LJ::html_hidden(itemid => $GET{itemid});
$body .= LJ::html_hidden(des => "");
$body .= LJ::html_hidden('mode' => 'save');
$body .= LJ::html_submit('delete', 'Delete this memory') . "\n";
$body .= "</form>\n";
}
return;
}
}
# do check to see if entry is deleted
unless ( $log || $POST{'mode'}) {
$title = $ML{'Error'};
$body = "The entry that this memory references has been deleted.<br/>";
if ($memoryu->{user} eq $authas && defined $memory) {
$body .= "<br /><form action='memadd$authextra' method='POST'>";
$body .= LJ::form_auth();
$body .= LJ::html_hidden(journal => $GET{journal}) if $GET{journal};
$body .= LJ::html_hidden(itemid => $GET{itemid});
$body .= LJ::html_hidden('mode' => 'save');
$body .= LJ::html_submit('delete', 'Delete this memory') . "\n";
$body .= "</form>\n";
}
return;
}
my $subject = LJ::get_logtext2($ju, $itemid)->{$log->{jitemid}}[0];
my $dbcr = LJ::get_cluster_reader($ju);
# if the entry is pre-UTF-8 conversion, the
# subject may need conversion into UTF-8
{
my %props = ();
LJ::load_log_props2($dbcr, $log->{'journalid'}, [ $itemid ], \%props);
if ($props{$itemid}->{'unknown8bit'}) {
my $u = LJ::load_userid($log->{'journalid'});
my ($error, $subj);
$subj = LJ::text_convert($subject, $u, \$error);
$subject = $subj unless $error;
}
LJ::text_out(\$subject);
}
if ($oldstyle) {
# ditemid was an old-style itemid, so we update it to the new style.
$anum = $log->{anum};
$ditemid = $itemid<<8 + $anum;
}
# get keywords user has used
my $exist_kw = LJ::Memories::get_keywords($memoryu);
unless ($exist_kw) {
$title = $ML{'Error'};
$body = "Error fetching existing keywords.";
return;
}
if ($POST{'mode'} eq "")
{
my ($des, $keywords);
my @all_keywords;
my %selected_keyword;
@all_keywords = sort values %$exist_kw;
if (defined $memory) {
$title = $ML{'.title.edit_memory'};
$des = $memory->{'des'};
my $kwids = LJ::Memories::get_keywordids($memoryu, $memory->{memid}) || [];
foreach my $kwid (@$kwids) {
my $kw = $exist_kw->{$kwid};
next if ($kw eq "*");
if ($keywords) { $keywords .= ", "; }
$keywords .= $kw;
$selected_keyword{$kw} = 1;
}
if (!$log || ($jid && $log->{'anum'} != $anum))
{
LJ::Memories::delete_by_id($memoryu, $memory->{memid});
LJ::Memories::updated_keywords($memoryu);
$title = $ML{'Error'};
$body = $ML{'.error.entry_deleted2'};
return;
}
}
elsif (!$log || ($jid && $log->{'anum'} != $anum))
{
$title = $ML{'Error'};
$body = $ML{'error.noentry'};
return;
}
else
{
$title = $ML{'.title.add_memory'};
# this is a new memory.
my $user = LJ::get_username($log->{'journalid'});
my $dt = substr($log->{'eventtime'}, 0, 10);
$des = "$dt: $user: $subject";
}
# it'd be nice to only show the authas form when adding an entry and not
# when editing one, but if user u is logged in and has post p as a memory
# already then wants to add it to community c, when u clicks the "add memory"
# link on p, u gets the "edit entry" page and they need to be able to switch
# to c.
$body .= "<form method='get' action='memadd'>\n";
$body .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
$body .= LJ::html_hidden(journal => $GET{journal}) if $GET{journal};
$body .= LJ::html_hidden(itemid => $GET{itemid});
$body .= "</form>\n\n";
LJ::text_out(\$des);
LJ::text_out(\$keywords);
if (defined $memory) {
$body .= $ML{'.edit_previous'};
} else {
$body .= $ML{'.add_previous2'};
}
my $getextra = "?itemid=$dbitemid";
$getextra .= "&amp;authas=$authas" if $authas ne $remote->{'user'};
# we still need to pass the dbitemid and not the itemid to ourself.
$getextra .= "&amp;journal=$journal" unless $oldstyle;
$body .= "<form method='post' action='memadd$getextra'>";
$body .= LJ::form_auth();
$body .= LJ::html_hidden(mode => "save");
$body .= "<table cellpadding='4'>";
$body .= "<tr><th align='right' valign='top'>$ML{'.description'}</th><td>";
$body .= LJ::html_text({name => 'des', value => $des, maxlength => LJ::CMAX_MEMORY, size => 40});
$body .= "<br /><small>$ML{'.description.text2'}</small></td></tr>";
$body .= "<tr><th align='right' valign='top'>$ML{'.keywords'}</th><td>";
$body .= LJ::html_text({name => 'keywords', size => 40, value => $keywords});
$body .= "<br /><small>$ML{'.keywords.text'}</small><br />";
if (@all_keywords) {
my $size = scalar(@all_keywords);
$size = 15 if $size > 15;
$body .= "<small>$ML{'.keywords.select'}</small><div style='margin-left: 30px;'>";
$body .= LJ::html_select( { name => 'oldkeywords', size => $size, multiple => 1,
selected => [ keys %selected_keyword ], noescape => 1 },
map { (LJ::ehtml($_), LJ::ehtml($_)) } @all_keywords);
$body .= "</div><small>$ML{'.multiple_selections'}</small>";
} else {
$body .= "<small>$ML{'.keywords.example'}</small>";
}
$body .= "</td></tr>\n";
$body .= "<tr><th align='right' valign='top'>$ML{'.security'}</th><td>";
$body .= LJ::html_select({name => 'security', selected => defined $memory ? $memory->{'security'} : undef},
map { ($_, $secopts{$_}) } qw(public friends private));
if ( $memoryu->is_community ) {
$body .= "<br /><small>$ML{'.whocansee.comm'}</small></td></tr><tr><th></th><td>\n";
} else {
$body .= "<br /><small>$ML{'.whocansee'}</small></td></tr><tr><th></th><td>\n";
}
$body .= LJ::html_submit(undef, $ML{'.form.submit'});
$body .= LJ::html_submit(undef, $ML{'.form.reset'}, {type => 'reset'}) if defined $memory;
$body .= "</td></tr></table></form>";
return;
}
if ($POST{'mode'} eq "save")
{
return "<?h1 $ML{'Error'} h1?> $ML{'error.invalidform'}" unless LJ::check_form_auth();
my $dbh = LJ::get_db_writer();
#### we're inserting/replacing now into memories
my @keywords;
{
my %kws;
foreach (split(/\s*,\s*/, $POST{'keywords'})) { $kws{$_} = 1; }
# oldkeywords were split at the beginning
foreach (@{$POST{'oldkeywords'}}) { $kws{$_} = 1; }
@keywords = keys %kws;
}
if (scalar(@keywords) > 5) {
$title = $ML{'Error'};
$body = "<?h1 $ML{'Error'} h1?><?p $ML{'.error.fivekeywords'} p?>";
return;
}
@keywords = grep { $_ } map { s/\s\s+/ /g; LJ::trim($_); } @keywords;
push @keywords, "*" unless (@keywords);
my @kwid;
my $needflush = 0;
foreach my $kw (@keywords) {
if (length($kw) > 40) {
$title = $ML{'Error'};
$body = "<?h1 $ML{'Error'} h1?><?p " .
BML::ml(".error.maxsize", { 'keyword' => LJ::ehtml($kw) }) . " p?>";
return;
}
my $kwid = $memoryu->get_keyword_id( $kw );
$needflush = 1 unless defined $exist_kw->{$kwid};
push @kwid, $kwid;
}
unless (exists $secopts{$POST{'security'}}) {
$title = $ML{'Error'};
$body = $ML{'.error.invalid_security'};
return;
}
my $des = LJ::text_trim($POST{'des'}, LJ::BMAX_MEMORY, LJ::CMAX_MEMORY);
my $sec = $POST{'security'};
# handle edits by deleting the old memory and recreating
LJ::Memories::delete_by_id($memoryu, $memory->{memid})
if defined $memory;
LJ::Memories::create($memoryu, {
journalid => $jid,
ditemid => $ditemid,
des => $des,
security => $sec,
}, \@kwid);
LJ::Memories::updated_keywords($memoryu) if $needflush;
$exist_kw = LJ::Memories::get_keywords($memoryu) if $needflush;
$title = $ML{'.title.added'};
$body .= "<?h1 $ML{'.body.added.header'} h1?>";
$body .= "<?p $ML{'.body.added.text'} p?>";
my $entry = LJ::Entry->new($ju, jitemid => $itemid);
$body .= "<ul>";
$body .= "<li><a href='" . $entry->url . "'>$ML{'.body.added.next.entry'}</a></li>";
$body .= "<li><a href='$LJ::SITEROOT/tools/memories?user=" . $memoryu->user . "'>"
. "$ML{'.body.added.next.view'}</a></li>";
foreach my $kwid ( @kwid ) {
my $kw = $exist_kw->{$kwid};
my $ue_kw = LJ::eurl( $kw );
LJ::text_out( \$kw );
if ($kw eq "*") {
$kw = $ML{'.uncategorized'};
} else {
$kw = LJ::ehtml( $kw );
}
$body .= "<li><a href=\"/tools/memories?user=" . $memoryu->user .
"&amp;keyword=$ue_kw&amp;filter=all\">" .
BML::ml( ".body.added.next.keywords", { 'keyword' => $kw } ) . "</a></li>";
}
$body .= "<li><a href='" . $remote->journal_base . "/read'>$ML{'.body.added.next.friends'}</a></li>";
$body .= "<li>" . BML::ml(".body.added.next.journal", { 'user' => $ju->ljuser_display }) . "</li>";
$body .= "</ul>";
return;
}
$title = $ML{'Error'};
$body = $ML{'error.unknownmode'};
return;
}
_code?>
<?page
title=><?_code return $title; _code?>
body=> <?_code return $body; _code?>
page?>