ljr/livejournal/cgi-bin/ljlinks.pl

219 lines
6.5 KiB
Perl
Raw Normal View History

2019-02-05 21:49:12 +00:00
#!/usr/bin/perl
#
# Functions for lists of links created by users for display in their journals
#
use strict;
package LJ::Links;
# linkobj structure:
#
# $linkobj = [
# { 'title' => 'link title',
# 'url' => 'http://www.somesite.com',
# 'children' => [ ... ],
# },
# { ... },
# { ... },
# ];
sub load_linkobj
{
my ($u, $use_master) = @_;
return unless LJ::isu($u);
# check memcache for linkobj
my $memkey = [$u->{'userid'}, "linkobj:$u->{'userid'}"];
my $linkobj = LJ::MemCache::get($memkey);
return $linkobj if defined $linkobj;
# didn't find anything in memcache
$linkobj = [];
{
# not in memcache, need to build one from db
my $db = $use_master ? LJ::get_cluster_def_reader($u) : LJ::get_cluster_reader($u);
local $" = ",";
my $sth = $db->prepare("SELECT ordernum, parentnum, title, url " .
"FROM links WHERE journalid=?");
$sth->execute($u->{'userid'});
push @$linkobj, $_ while $_ = $sth->fetchrow_hashref;
}
# sort in perl-space
@$linkobj = sort { $a->{'ordernum'} <=> $b->{'ordernum'} } @$linkobj;
# fix up the data structure
foreach (@$linkobj) {
# TODO: build child relationships
# and store in $_->{'children'}
# ordernum/parentnum are only exposed via the
# array structure, delete them here
delete $_->{'ordernum'};
delete $_->{'parentnum'};
}
# set linkobj in memcache
LJ::MemCache::set($memkey, $linkobj);
return $linkobj;
}
sub save_linkobj
{
my ($u, $linkobj) = @_;
return undef unless LJ::isu($u) && ref $linkobj eq 'ARRAY' && $u->writer;
# delete old links, we'll rebuild them shortly
$u->do("DELETE FROM links WHERE journalid=?", undef, $u->{'userid'});
# only save allowed number of links
my $numlinks = @$linkobj;
my $caplinks = LJ::get_cap($u, "userlinks");
$numlinks = $caplinks if $numlinks > $caplinks;
# build insert query
my (@bind, @vals);
foreach my $ct (1..$numlinks) {
my $it = $linkobj->[$ct-1];
# journalid, ordernum, parentnum, url, title
push @bind, "(?,?,?,?,?)";
push @vals, ($u->{'userid'}, $ct, 0, $it->{'url'}, $it->{'title'});
}
# invalidate memcache
my $memkey = [$u->{'userid'}, "linkobj:$u->{'userid'}"];
LJ::MemCache::delete($memkey);
# insert into database
{
local $" = ",";
return $u->do("INSERT INTO links (journalid, ordernum, parentnum, url, title) " .
"VALUES @bind", undef, @vals);
}
}
sub make_linkobj_from_form
{
my ($u, $post) = @_;
return unless LJ::isu($u) && ref $post eq 'HASH';
my $linkobj = [];
# remove leading and trailing spaces
my $stripspaces = sub {
my $str = shift;
$str =~ s/^\s*//;
$str =~ s/\s*$//;
return $str;
};
# find number of links allowed
my $numlinks = $post->{'numlinks'};
my $caplinks = LJ::get_cap($u, "userlinks");
$numlinks = $caplinks if $numlinks > $caplinks;
foreach my $num (sort { $post->{"link_${a}_ordernum"} <=>
$post->{"link_${b}_ordernum"} } (1..$numlinks)) {
# title is required
my $title = $post->{"link_${num}_title"};
$title = $stripspaces->($title);
next unless $title;
my $url = $post->{"link_${num}_url"};
$url = $stripspaces->($url);
# smartly add http:// to url unless they are just inserting a blank line
if ($url && $title ne '-') {
$url = LJ::CleanHTML::canonical_url($url);
}
# build link object element
$post->{"link_${num}_url"} = $url;
push @$linkobj, { 'title' => $title, 'url' => $url };
# TODO: build child relationships
# push @{$linkobj->[$parentnum-1]->{'children'}}, $myself
}
return $linkobj;
}
# this form is in the lib so we can put it in /customize/ directly later
sub make_modify_form
{
my ($u, $linkobj, $post) = @_;
return unless LJ::isu($u) && ref $linkobj eq 'ARRAY' && ref $post eq 'HASH';
# TODO: parentnum column is not implemented yet
# -- it should link to the ordernum of the parent link
# so we can support nesting/categories of links
my $LINK_MIN = 5; # how many do they start with ?
my $LINK_MORE = 5; # how many do they get when they click "more"
my $ORDER_STEP = 10; # step order numbers by
# how many link inputs to show?
my $showlinks = $post->{'numlinks'} || @$linkobj;
my $caplinks = LJ::get_cap($u, "userlinks");
$showlinks += $LINK_MORE if $post->{'action:morelinks'};
$showlinks = $LINK_MIN if $showlinks < $LINK_MIN;
$showlinks = $caplinks if $showlinks > $caplinks;
my $ret = "<table border='0' cellspacing='3' cellpadding='0'>";
$ret .= "<tr><th>Order</th><th>Title/URL</th><td>&nbsp;</td></tr>";
foreach my $ct (1..$showlinks) {
my $it = $linkobj->[$ct-1] || {};
$ret .= "<tr><td>";
$ret .= LJ::html_text({ 'name' => "link_${ct}_ordernum",
'size' => 2,
'value' => $ct * $ORDER_STEP });
$ret .= "</td><td>";
$ret .= LJ::html_text({ 'name' => "link_${ct}_title",
'size' => 50, 'maxlength' => 255,
'value' => $it->{'title'} });
$ret .= "</td><td>&nbsp;</td></tr>";
$ret .= "<tr><td>&nbsp;</td><td>";
$ret .= LJ::html_text({ 'name' => "link_${ct}_url",
'size' => 50, 'maxlength' => 255,
'value' => $it->{'url'} || "http://"});
# more button at the end of the last line, but only if
# they are allowed more than the minimum
$ret .= "<td>&nbsp;";
if ($ct >= $showlinks && $caplinks > $LINK_MIN) {
$ret .= LJ::html_submit('action:morelinks', "More &rarr;",
{ 'disabled' => $ct >= $caplinks,
'noescape' => 1 });
}
$ret .= "</td></tr>";
# blank line unless this is the last line
$ret .= "<tr><td colspan='3'>&nbsp;</td></tr>"
unless $ct >= $showlinks;
}
# submit button
$ret .= "<tr><td colspan='2' align='center'>";
$ret .= LJ::html_hidden('numlinks' => $showlinks);
$ret .= LJ::html_submit('action:savelinks', "Save Changes");
$ret .= "</td><td>&nbsp;</td></tr>";
$ret .= "</table>";
return $ret;
}
1;