219 lines
6.5 KiB
Perl
219 lines
6.5 KiB
Perl
|
#!/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> </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> </td></tr>";
|
||
|
|
||
|
$ret .= "<tr><td> </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> ";
|
||
|
if ($ct >= $showlinks && $caplinks > $LINK_MIN) {
|
||
|
$ret .= LJ::html_submit('action:morelinks', "More →",
|
||
|
{ 'disabled' => $ct >= $caplinks,
|
||
|
'noescape' => 1 });
|
||
|
}
|
||
|
$ret .= "</td></tr>";
|
||
|
|
||
|
# blank line unless this is the last line
|
||
|
$ret .= "<tr><td colspan='3'> </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> </td></tr>";
|
||
|
|
||
|
$ret .= "</table>";
|
||
|
|
||
|
return $ret;
|
||
|
}
|
||
|
|
||
|
1;
|