874 lines
37 KiB
Plaintext
874 lines
37 KiB
Plaintext
|
<?_code
|
||
|
{
|
||
|
use strict;
|
||
|
use vars qw(%GET %POST $title $body @errors);
|
||
|
|
||
|
LJ::set_active_crumb('editpics');
|
||
|
|
||
|
$body = "";
|
||
|
@errors = ();
|
||
|
|
||
|
my $err = sub {
|
||
|
$title = "Error";
|
||
|
$body = LJ::bad_input(@_);
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
unless (LJ::text_in(\%POST)) {
|
||
|
return $err->("Invalid UTF-8 Input");
|
||
|
}
|
||
|
|
||
|
my $remote = LJ::get_remote();
|
||
|
return $err->($ML{'error.noremote'})
|
||
|
unless $remote;
|
||
|
|
||
|
if ($remote->underage) {
|
||
|
return BML::redirect("$LJ::SITEROOT/agecheck/?s=1");
|
||
|
}
|
||
|
|
||
|
my $authas = $GET{'authas'} || $remote->{'user'};
|
||
|
my $u = LJ::get_authas_user($authas);
|
||
|
return $err->($ML{'error.invalidauth'})
|
||
|
unless $u;
|
||
|
|
||
|
# extra arguments for get requests
|
||
|
my $getextra = $authas ne $remote->{'user'} ? "?authas=$authas" : '';
|
||
|
|
||
|
my $returl = LJ::CleanHTML::canonical_url($POST{'ret'});
|
||
|
my $picurl = LJ::CleanHTML::canonical_url($POST{'urlpic'});
|
||
|
my $fotobilder = index($returl, $LJ::FB_SITEROOT) == 0 &&
|
||
|
$picurl =~ m!^$LJ::FB_SITEROOT/~?$remote->{'user'}/pic/!;
|
||
|
|
||
|
if ($fotobilder &&
|
||
|
(LJ::check_referer($returl) || LJ::check_referer('/editpics.bml'))) {
|
||
|
|
||
|
return $err->('Invalid referring site or redirection not allowed')
|
||
|
unless $returl =~ /$LJ::FB_DOMAIN/ && LJ::get_cap($u, 'fb_account');
|
||
|
}
|
||
|
|
||
|
if (LJ::get_cap($u, "readonly")) {
|
||
|
$title = "Read-only mode";
|
||
|
$body = $LJ::MSG_READONLY_USER;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
# update this user's activated pics
|
||
|
LJ::activate_userpics($u);
|
||
|
|
||
|
my ($dbh, $dbcm, $dbcr, $sth);
|
||
|
|
||
|
# Put $count and $max in larger scope so they can be used in output
|
||
|
my $count;
|
||
|
$dbcm = LJ::get_cluster_master($u);
|
||
|
return $err->($ML{'error.nodb'}) unless $dbcm;
|
||
|
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$dbcr = LJ::get_cluster_def_reader($u);
|
||
|
return $err->($ML{'error.nodb'}) unless $dbcr;
|
||
|
$count = $dbcr->selectrow_array("SELECT COUNT(*) FROM userpic2 " .
|
||
|
"WHERE userid=? AND state <> 'X'", undef, $u->{'userid'});
|
||
|
} else {
|
||
|
$dbh = LJ::get_db_writer();
|
||
|
return $err->($ML{'error.nodb'}) unless $dbh;
|
||
|
$count = $dbh->selectrow_array("SELECT COUNT(*) FROM userpic " .
|
||
|
"WHERE userid=? AND state <> 'X'", undef, $u->{'userid'});
|
||
|
}
|
||
|
my $max = LJ::get_cap($u, "userpics");
|
||
|
|
||
|
### save mode
|
||
|
if (LJ::did_post()) {
|
||
|
|
||
|
### save changes to existing pics
|
||
|
if ($POST{'action:save'}) {
|
||
|
# form being posted isn't multipart, since we were able to read from %POST
|
||
|
|
||
|
my %exist_kwids;
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$sth = $dbcr->prepare("SELECT kwid, picid FROM userpicmap2 WHERE userid=?");
|
||
|
} else {
|
||
|
$sth = $dbh->prepare("SELECT kwid, picid FROM userpicmap WHERE userid=?");
|
||
|
}
|
||
|
$sth->execute($u->{'userid'});
|
||
|
while (my ($kwid, $picid) = $sth->fetchrow_array) {
|
||
|
push @{$exist_kwids{$picid}}, $kwid;
|
||
|
}
|
||
|
|
||
|
my @inactive_picids;
|
||
|
my @delete;
|
||
|
my %picid_of_kwid;
|
||
|
my %ctype; # picid -> contenttype, for delete mode
|
||
|
my %states; # picid -> state, for setting new default
|
||
|
my %locations; # picid -> location, for deleting
|
||
|
my @comments;
|
||
|
my %exist_comments;
|
||
|
|
||
|
# select all of their userpics and iterate through them
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$sth = $dbcr->prepare("SELECT picid, width, height, state, fmt, comment, location " .
|
||
|
"FROM userpic2 WHERE userid=?");
|
||
|
} else {
|
||
|
$sth = $dbh->prepare("SELECT picid, width, height, state, contenttype " .
|
||
|
"FROM userpic WHERE userid=?");
|
||
|
}
|
||
|
$sth->execute($u->{'userid'});
|
||
|
while (my $pic = $sth->fetchrow_hashref)
|
||
|
{
|
||
|
# ignore anything expunged
|
||
|
next if $pic->{state} eq 'X';
|
||
|
|
||
|
# store picture information
|
||
|
$states{$pic->{picid}} = $pic->{state};
|
||
|
$locations{$pic->{picid}} = $pic->{location}
|
||
|
if $u->{dversion} > 6;
|
||
|
$exist_comments{$pic->{picid}} = $pic->{comment};
|
||
|
|
||
|
# delete this pic
|
||
|
if ($POST{"delete_$pic->{'picid'}"}) {
|
||
|
push @delete, $pic->{'picid'};
|
||
|
$ctype{$pic->{picid}} = ($u->{'dversion'} > 6) ? $pic->{'fmt'} : $pic->{'contenttype'};
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
# make a list of inactive picids
|
||
|
if ($pic->{'state'} eq 'I') {
|
||
|
push @inactive_picids, $pic->{'picid'};
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
# we're going to modify keywords on active pictures
|
||
|
my $c = 1;
|
||
|
my @kw_errors;
|
||
|
|
||
|
my @keywords = split(/\s*,\s*/, $POST{"kw_$pic->{'picid'}"});
|
||
|
@keywords = grep { s/^\s+//; s/\s+$//; $_; } @keywords;
|
||
|
foreach my $kw (@keywords) {
|
||
|
my $kwid = ($u->{'dversion'} > 6) ? LJ::get_keyword_id($u, $kw) : LJ::get_keyword_id($kw);
|
||
|
next unless $kwid;
|
||
|
|
||
|
if ($c > $LJ::MAX_USERPIC_KEYWORDS) {
|
||
|
my $ekw = LJ::ehtml($kw);
|
||
|
push @kw_errors, $ekw;
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
if ($picid_of_kwid{$kwid}) {
|
||
|
my $ekw = LJ::ehtml($kw);
|
||
|
push @errors, BML::ml(".error.keywords", {'ekw' => $ekw});
|
||
|
}
|
||
|
$picid_of_kwid{$kwid} = $pic->{'picid'};
|
||
|
$c++;
|
||
|
}
|
||
|
|
||
|
# Let the user know about any we didn't save
|
||
|
if (@kw_errors) {
|
||
|
my $num_words = scalar(@kw_errors);
|
||
|
my $kws = join (", ", @kw_errors);
|
||
|
push @errors, BML::ml(".error.toomanykeywords", {'numwords' => $num_words, 'words' => $kws, 'max' => $LJ::MAX_USERPIC_KEYWORDS});
|
||
|
}
|
||
|
|
||
|
# Find if they changed the comment and then save the new one
|
||
|
if ($u->{'dversion'} > 6 && $POST{"com_$pic->{'picid'}"} ne $exist_comments{$pic->{'picid'}}) {
|
||
|
my $comment = LJ::text_trim($POST{"com_$pic->{'picid'}"}, LJ::BMAX_UPIC_COMMENT, LJ::CMAX_UPIC_COMMENT);
|
||
|
$u->do("UPDATE userpic2 SET comment=? WHERE userid=? AND picid=?",
|
||
|
undef, $comment, $u->{'userid'}, $pic->{'picid'});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# now, reapply the existing picids to the inactive pics, unless
|
||
|
# that picid has already been assigned to a new active one
|
||
|
foreach my $picid (@inactive_picids) {
|
||
|
next unless $exist_kwids{$picid};
|
||
|
|
||
|
foreach (@{$exist_kwids{$picid}}) {
|
||
|
$picid_of_kwid{$_} ||= $picid;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (@delete) {
|
||
|
my $id_in;
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$id_in = join(", ", map { $dbcm->quote($_) } @delete);
|
||
|
} else {
|
||
|
$id_in = join(", ", map { $dbh->quote($_) } @delete);
|
||
|
}
|
||
|
|
||
|
# delete data from user cluster
|
||
|
foreach my $picid (@delete) {
|
||
|
my $fmt;
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$fmt = {
|
||
|
'G' => 'gif',
|
||
|
'J' => 'jpg',
|
||
|
'P' => 'png',
|
||
|
}->{$ctype{$picid}};
|
||
|
} else {
|
||
|
$fmt = {
|
||
|
'image/gif' => 'gif',
|
||
|
'image/jpeg' => 'jpg',
|
||
|
'image/png' => 'png',
|
||
|
}->{$ctype{$picid}};
|
||
|
}
|
||
|
|
||
|
my $deleted = 0;
|
||
|
|
||
|
# try and delete from either the blob server or database,
|
||
|
# and only after deleting the image do we delete the metadata.
|
||
|
if ($locations{$picid} eq 'mogile') {
|
||
|
$deleted = 1
|
||
|
if LJ::mogclient()->delete($u->mogfs_userpic_key($picid));
|
||
|
} elsif ($LJ::USERPIC_BLOBSERVER &&
|
||
|
LJ::Blob::delete($u, "userpic", $fmt, $picid)) {
|
||
|
$deleted = 1;
|
||
|
} elsif ($u->do("DELETE FROM userpicblob2 WHERE ".
|
||
|
"userid=? AND picid=?", undef,
|
||
|
$u->{userid}, $picid) > 0) {
|
||
|
$deleted = 1;
|
||
|
}
|
||
|
|
||
|
# now delete the metadata if we got the real data
|
||
|
if ($deleted) {
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("DELETE FROM userpic2 WHERE picid=? AND userid=?",
|
||
|
undef, $picid, $u->{'userid'});
|
||
|
} else {
|
||
|
$dbh->do("DELETE FROM userpic WHERE picid=?", undef, $picid);
|
||
|
}
|
||
|
$u->do("DELETE FROM userblob WHERE journalid=? AND blobid=? " .
|
||
|
"AND domain=?", undef, $u->{'userid'}, $picid,
|
||
|
LJ::get_blob_domainid('userpic'));
|
||
|
|
||
|
# decrement $count to reflect deletion
|
||
|
$count--;
|
||
|
}
|
||
|
|
||
|
# if we didn't end up deleting, it's either because of
|
||
|
# some transient error, or maybe there was nothing to delete
|
||
|
# for some bizarre reason, in which case we should verify
|
||
|
# that and make sure they can delete their metadata
|
||
|
if (! $deleted) {
|
||
|
my $present;
|
||
|
if ($locations{$picid} eq 'mogile') {
|
||
|
my $blob = LJ::mogclient()->get_file_data($u->mogfs_userpic_key($picid));
|
||
|
$present = length($blob) ? 1 : 0;
|
||
|
} elsif ($LJ::USERPIC_BLOBSERVER) {
|
||
|
my $blob = LJ::Blob::get($u, "userpic", $fmt, $picid);
|
||
|
$present = length($blob) ? 1 : 0;
|
||
|
}
|
||
|
$present ||= $dbcm->selectrow_array("SELECT COUNT(*) FROM userpicblob2 WHERE ".
|
||
|
"userid=? AND picid=?", undef, $u->{'userid'},
|
||
|
$picid);
|
||
|
if (! int($present)) {
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("DELETE FROM userpic2 WHERE picid=? AND userid=?",
|
||
|
undef, $picid, $u->{'userid'});
|
||
|
} else {
|
||
|
$dbh->do("DELETE FROM userpic WHERE picid=?", undef, $picid);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# if any of the userpics they want to delete are active, then we want to
|
||
|
# re-run LJ::activate_userpics() - turns out it's faster to not check to
|
||
|
# see if we need to do this
|
||
|
LJ::activate_userpics($u);
|
||
|
}
|
||
|
|
||
|
if (%picid_of_kwid) {
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("REPLACE INTO userpicmap2 (userid, kwid, picid) VALUES " .
|
||
|
join(",", map { "(" .
|
||
|
join(",",
|
||
|
$dbcm->quote($u->{'userid'}),
|
||
|
$dbcm->quote($_),
|
||
|
$dbcm->quote($picid_of_kwid{$_})) .
|
||
|
")"
|
||
|
}
|
||
|
keys %picid_of_kwid)
|
||
|
);
|
||
|
} else {
|
||
|
$dbh->do("REPLACE INTO userpicmap (userid, kwid, picid) VALUES " .
|
||
|
join(",", map { "(" .
|
||
|
join(",",
|
||
|
$dbh->quote($u->{'userid'}),
|
||
|
$dbh->quote($_),
|
||
|
$dbh->quote($picid_of_kwid{$_})) .
|
||
|
")"
|
||
|
}
|
||
|
keys %picid_of_kwid)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Delete keywords that are no longer being used
|
||
|
my @kwid_del;
|
||
|
|
||
|
foreach my $kwids (values %exist_kwids) {
|
||
|
foreach my $kwid (@$kwids) {
|
||
|
if (! $picid_of_kwid{$kwid}) {
|
||
|
push @kwid_del, $kwid+0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (@kwid_del) {
|
||
|
my $kwid_del = join(",", @kwid_del);
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("DELETE FROM userpicmap2 WHERE userid=$u->{userid} " .
|
||
|
"AND kwid IN ($kwid_del)");
|
||
|
} else {
|
||
|
$dbh->do("DELETE FROM userpicmap WHERE userid=$u->{userid} " .
|
||
|
"AND kwid IN ($kwid_del)");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $new_default = $POST{'defaultpic'}+0;
|
||
|
if ($POST{"delete_$POST{'defaultpic'}"}) {
|
||
|
# deleting your default
|
||
|
$new_default = 0;
|
||
|
}
|
||
|
if ($new_default != $u->{'defaultpicid'}) {
|
||
|
|
||
|
# see if they are trying to make an inactive userpic their default
|
||
|
if ($states{$new_default} eq 'N' || !$new_default) {
|
||
|
LJ::update_user($u, { defaultpicid => $new_default });
|
||
|
$u->{'defaultpicid'} = $new_default;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $memkey = [$u->{'userid'},"upicinf:$u->{'userid'}"];
|
||
|
LJ::MemCache::delete($memkey);
|
||
|
$memkey = [$u->{'userid'},"upiccom:$u->{'userid'}"];
|
||
|
LJ::MemCache::delete($memkey);
|
||
|
$memkey = [$u->{'userid'},"upicurl:$u->{'userid'}"];
|
||
|
LJ::MemCache::delete($memkey);
|
||
|
}
|
||
|
|
||
|
### no post, so we'll parse the multipart data
|
||
|
unless (%POST) {
|
||
|
|
||
|
my $MAX_UPLOAD = 40960;
|
||
|
|
||
|
my $error;
|
||
|
# Add some slop to account for the size of the form headers etc.
|
||
|
BML::parse_multipart(\%POST, \$error, $MAX_UPLOAD + 2048);
|
||
|
|
||
|
# was there an error parsing the multipart form?
|
||
|
if ($error) {
|
||
|
if ($error =~ /^\[(\S+?)\]/) {
|
||
|
my $code = $1;
|
||
|
if ($code eq "toolarge") {
|
||
|
return $err->(BML::ml('.error.filetoolarge',
|
||
|
{ 'maxsize' => int($MAX_UPLOAD / 1024) .
|
||
|
$ML{'.kilobytes'} }));
|
||
|
}
|
||
|
$error = BML::ml("BML.parse_multipart.$code");
|
||
|
}
|
||
|
return $err->($error) if $error;
|
||
|
}
|
||
|
|
||
|
# error check input contents
|
||
|
if ($POST{'src'} eq "url" && $POST{'urlpic'} !~ /^http:\/\//) {
|
||
|
return $err->($ML{'.error.badurl'});
|
||
|
}
|
||
|
|
||
|
if ($POST{'src'} eq "file") {
|
||
|
|
||
|
# already loaded from multipart parse earlier
|
||
|
|
||
|
} elsif ($POST{'src'} eq "url") {
|
||
|
require LWPx::ParanoidAgent;
|
||
|
my $ua = LWPx::ParanoidAgent->new(
|
||
|
timeout => 10,
|
||
|
max_size => $MAX_UPLOAD + 1024,
|
||
|
);
|
||
|
my $res = $ua->get($POST{urlpic});
|
||
|
$POST{userpic} = $res->content if $res && $res->is_success;
|
||
|
return $err->($ML{'.error.urlerror'}) unless $POST{userpic};
|
||
|
}
|
||
|
|
||
|
if (length($POST{'userpic'}) > $MAX_UPLOAD) {
|
||
|
return $err->(BML::ml('.error.filetoolarge',
|
||
|
{ 'maxsize' => int($MAX_UPLOAD / 1024) .
|
||
|
$ML{'.kilobytes'} }));
|
||
|
}
|
||
|
|
||
|
my ($sx, $sy, $filetype) = Image::Size::imgsize(\$POST{'userpic'});
|
||
|
unless (defined $sx) {
|
||
|
return $err->($ML{'.error.invalidimage'});
|
||
|
}
|
||
|
|
||
|
unless ($filetype eq "GIF" || $filetype eq "JPG" || $filetype eq "PNG") {
|
||
|
return $err->(BML::ml(".error.unsupportedtype",
|
||
|
{ 'filetype' => $filetype }));
|
||
|
}
|
||
|
|
||
|
if ($sx > 100 || $sy > 100) {
|
||
|
return $err->( BML::ml(".error.imagetoolarge",
|
||
|
{ 'imagesize' => "${sx}$ML{'.imagesize.by'}${sy}",
|
||
|
'maxsize' => "100$ML{'.imagesize.by'}100" }) );
|
||
|
}
|
||
|
|
||
|
my $base64 = Digest::MD5::md5_base64($POST{'userpic'});
|
||
|
|
||
|
## see if they have too many pictures uploaded
|
||
|
if ($count >= $max) {
|
||
|
return $err->( BML::ml(".error.toomanypics2",
|
||
|
{ 'maxpics' => $max }) .
|
||
|
LJ::help_icon('userpics', " ", ""));
|
||
|
}
|
||
|
|
||
|
# see if it's a duplicate
|
||
|
my $picid;
|
||
|
my $contenttype;
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
if ($filetype eq "GIF") { $contenttype = 'G'; }
|
||
|
elsif ($filetype eq "PNG") { $contenttype = 'P'; }
|
||
|
elsif ($filetype eq "JPG") { $contenttype = 'J'; }
|
||
|
|
||
|
$picid = $dbcr->selectrow_array("SELECT picid FROM userpic2 " .
|
||
|
"WHERE userid=? AND fmt=? " .
|
||
|
"AND md5base64=?",
|
||
|
undef, $u->{'userid'}, $contenttype, $base64);
|
||
|
} else {
|
||
|
if ($filetype eq "GIF") { $contenttype = "image/gif"; }
|
||
|
elsif ($filetype eq "PNG") { $contenttype = "image/png"; }
|
||
|
elsif ($filetype eq "JPG") { $contenttype = "image/jpeg"; }
|
||
|
|
||
|
$picid = $dbh->selectrow_array("SELECT picid FROM userpic " .
|
||
|
"WHERE userid=? AND contenttype=? " .
|
||
|
"AND md5base64=?",
|
||
|
undef, $u->{'userid'}, $contenttype, $base64);
|
||
|
}
|
||
|
# if picture isn't a duplicate, insert it
|
||
|
if ($picid == 0) {
|
||
|
|
||
|
# insert the meta-data
|
||
|
# Make a new global picid
|
||
|
$picid = LJ::alloc_global_counter('P') or
|
||
|
return $err->('Unable to allocate new picture id');
|
||
|
|
||
|
# see where we're inserting this
|
||
|
my $target;
|
||
|
if ($u->{dversion} > 6 && $LJ::USERPIC_MOGILEFS) {
|
||
|
$target = 'mogile';
|
||
|
} elsif ($LJ::USERPIC_BLOBSERVER) {
|
||
|
$target = 'blob';
|
||
|
}
|
||
|
|
||
|
my $dberr = 0;
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("INSERT INTO userpic2 (picid, userid, fmt, width, height, " .
|
||
|
"picdate, md5base64, location) VALUES (?, ?, ?, ?, ?, NOW(), ?, ?)",
|
||
|
undef, $picid, $u->{'userid'}, $contenttype, $sx, $sy, $base64, $target);
|
||
|
if ($u->err) {
|
||
|
push @errors, $err->($u->errstr);
|
||
|
$dberr = 1;
|
||
|
}
|
||
|
} else {
|
||
|
$dbh->do("INSERT INTO userpic (picid, userid, contenttype, width, height, " .
|
||
|
"picdate, md5base64) VALUES (?, ?, ?, ?, ?, NOW(), ?)",
|
||
|
undef, $picid, $u->{'userid'}, $contenttype, $sx, $sy, $base64);
|
||
|
if ($dbh->err) {
|
||
|
push @errors, $err->($dbh->errstr);
|
||
|
$dberr = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $clean_err = sub {
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("DELETE FROM userpic2 WHERE userid=? AND picid=?",
|
||
|
undef, $u->{'userid'}, $picid) if $picid;
|
||
|
} else {
|
||
|
$dbh->do("DELETE FROM userpic WHERE picid=?", undef, $picid) if $picid;
|
||
|
}
|
||
|
return $err->(@_);
|
||
|
};
|
||
|
|
||
|
### insert the blob
|
||
|
if ($target eq 'mogile' && !$dberr) {
|
||
|
my $fh = LJ::mogclient()->new_file($u->mogfs_userpic_key($picid), 'userpics');
|
||
|
if (defined $fh) {
|
||
|
$fh->print($POST{'userpic'});
|
||
|
my $rv = $fh->close;
|
||
|
push @errors, $clean_err->("Error saving to storage server: $@") unless $rv;
|
||
|
} else {
|
||
|
# fatal error, we couldn't get a filehandle to use
|
||
|
push @errors, $clean_err->("Unable to contact storage server. Your picture has not been saved.");
|
||
|
}
|
||
|
} elsif ($target eq 'blob' && !$dberr) {
|
||
|
my $et;
|
||
|
my $fmt = lc($filetype);
|
||
|
my $rv = LJ::Blob::put($u, "userpic", $fmt, $picid, $POST{'userpic'}, \$et);
|
||
|
push @errors, $clean_err->("Error saving to media server: $et") unless $rv;
|
||
|
} elsif (!$dberr) {
|
||
|
my $dbcm = LJ::get_cluster_master($u);
|
||
|
return $err->($ML{'error.nodb'}) unless $dbcm;
|
||
|
$u->do("INSERT INTO userpicblob2 (userid, picid, imagedata) " .
|
||
|
"VALUES (?, ?, ?)",
|
||
|
undef, $u->{'userid'}, $picid, $POST{'userpic'});
|
||
|
push @errors, $clean_err->($u->errstr) if $u->err;
|
||
|
} else { # We should never get here!
|
||
|
push @errors, "User picture uploading failed for unknown reason";
|
||
|
}
|
||
|
|
||
|
# Not a duplicate, so increment $count
|
||
|
$count++;
|
||
|
}
|
||
|
|
||
|
# make it their default pic?
|
||
|
if ($POST{'make_default'}) {
|
||
|
LJ::update_user($u, { defaultpicid => $picid });
|
||
|
$u->{'defaultpicid'} = $picid;
|
||
|
}
|
||
|
|
||
|
# set default keywords?
|
||
|
if ($POST{'keywords'} ne '') {
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$sth = $dbcr->prepare("SELECT kwid, picid FROM userpicmap2 WHERE userid=?");
|
||
|
} else {
|
||
|
$sth = $dbh->prepare("SELECT kwid, picid FROM userpicmap WHERE userid=?");
|
||
|
}
|
||
|
$sth->execute($u->{'userid'});
|
||
|
|
||
|
my @exist_kwids;
|
||
|
while (my ($kwid, $picid) = $sth->fetchrow_array) {
|
||
|
$exist_kwids[$kwid] = $picid;
|
||
|
}
|
||
|
|
||
|
my @keywords = split(/\s*,\s*/, $POST{'keywords'});
|
||
|
@keywords = grep { s/^\s+//; s/\s+$//; $_; } @keywords;
|
||
|
|
||
|
my (@bind, @data, @kw_errors);
|
||
|
my $c = 0;
|
||
|
|
||
|
foreach my $kw (@keywords) {
|
||
|
my $kwid = ($u->{'dversion'} > 6) ? LJ::get_keyword_id($u, $kw) : LJ::get_keyword_id($kw);
|
||
|
next unless $kwid; # Houston we have a problem! This should always return an id.
|
||
|
|
||
|
if ($c > $LJ::MAX_USERPIC_KEYWORDS) {
|
||
|
my $ekw = LJ::ehtml($kw);
|
||
|
push @kw_errors, $ekw;
|
||
|
next;
|
||
|
}
|
||
|
|
||
|
if ($exist_kwids[$kwid]) { # Already used on another picture
|
||
|
my $ekw = LJ::ehtml($kw);
|
||
|
push @errors, BML::ml(".error.keywords", {'ekw' => $ekw});
|
||
|
next;
|
||
|
} else { # New keyword, so save it
|
||
|
push @bind, '(?, ?, ?)';
|
||
|
push @data, $u->{'userid'}, $kwid, $picid;
|
||
|
}
|
||
|
$c++;
|
||
|
}
|
||
|
|
||
|
# Let the user know about any we didn't save
|
||
|
if (@kw_errors) {
|
||
|
my $num_words = scalar(@kw_errors);
|
||
|
my $kws = join (", ", @kw_errors);
|
||
|
push @errors, BML::ml(".error.toomanykeywords", {'numwords' => $num_words, 'words' => $kws, 'max' => $LJ::MAX_USERPIC_KEYWORDS});
|
||
|
}
|
||
|
|
||
|
if (@data && @bind) {
|
||
|
my $bind = join(',', @bind);
|
||
|
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$u->do("INSERT INTO userpicmap2 (userid, kwid, picid) VALUES $bind",
|
||
|
undef, @data);
|
||
|
} else {
|
||
|
$dbh->do("INSERT INTO userpicmap (userid, kwid, picid) VALUES $bind",
|
||
|
undef, @data);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# set default comments and the url
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
my (@data, @set);
|
||
|
if ($POST{'comments'} ne '') {
|
||
|
push @set, 'comment=?';
|
||
|
push @data, LJ::text_trim($POST{'comments'}, LJ::BMAX_UPIC_COMMENT, LJ::CMAX_UPIC_COMMENT);
|
||
|
}
|
||
|
|
||
|
if ($POST{'url'} ne '') {
|
||
|
push @set, 'url=?';
|
||
|
push @data, $POST{'url'};
|
||
|
}
|
||
|
|
||
|
if (@set) {
|
||
|
my $set = join(',', @set);
|
||
|
|
||
|
$u->do("UPDATE userpic2 SET $set WHERE userid=? AND picid=?",
|
||
|
undef, @data, $u->{'userid'}, $picid);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $memkey = [$u->{'userid'},"upicinf:$u->{'userid'}"];
|
||
|
LJ::MemCache::delete($memkey);
|
||
|
|
||
|
$returl = LJ::CleanHTML::canonical_url($POST{'ret'});
|
||
|
if ($returl) {
|
||
|
my $redir_host = $1 if $returl =~ m#^http://([\.:\w-]+)#i;
|
||
|
return BML::redirect($returl) if $LJ::REDIRECT_ALLOWED{$redir_host};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# now fall through to edit page and show the updated userpic info
|
||
|
}
|
||
|
|
||
|
if ($fotobilder && $POST{'md5sum'}) {
|
||
|
my $id;
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$id = $dbcm->selectrow_array("SELECT picid FROM userpic2 WHERE userid=? " .
|
||
|
"AND md5base64=?", undef, $u->{'userid'}, $POST{'md5sum'});
|
||
|
} else {
|
||
|
$id = $dbh->selectrow_array("SELECT picid FROM userpic WHERE userid=? " .
|
||
|
"AND md5base64=?", undef, $u->{'userid'}, $POST{'md5sum'});
|
||
|
}
|
||
|
|
||
|
$fotobilder = 0 if $id;
|
||
|
}
|
||
|
|
||
|
# show the form to let people edit
|
||
|
$title = "Edit User Pictures";
|
||
|
|
||
|
# Fixme: Make this work with Fotobilder
|
||
|
if (!$fotobilder) {
|
||
|
# authas switcher form
|
||
|
$body .= "<form method='get' action='editpics.bml'>\n";
|
||
|
$body .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
|
||
|
$body .= "</form>\n\n";
|
||
|
}
|
||
|
|
||
|
if (@errors) {
|
||
|
$body .= LJ::error_list(@errors);
|
||
|
}
|
||
|
|
||
|
if (!$fotobilder) {
|
||
|
my %keywords = ();
|
||
|
my $dbcr = LJ::get_cluster_def_reader($u);
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$sth = $dbcr->prepare("SELECT m.picid, k.keyword FROM userpicmap2 m, userkeywords k ".
|
||
|
"WHERE m.userid=? AND m.kwid=k.kwid AND m.userid=k.userid");
|
||
|
} else {
|
||
|
$sth = $dbh->prepare("SELECT m.picid, k.keyword FROM userpicmap m, keywords k ".
|
||
|
"WHERE m.userid=? AND m.kwid=k.kwid");
|
||
|
}
|
||
|
$sth->execute($u->{'userid'});
|
||
|
while (my ($pic, $keyword) = $sth->fetchrow_array) {
|
||
|
LJ::text_out(\$keyword);
|
||
|
push @{$keywords{$pic}}, $keyword;
|
||
|
}
|
||
|
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$sth = $dbcr->prepare("SELECT picid, width, height, state, comment " .
|
||
|
"FROM userpic2 WHERE userid=?");
|
||
|
} else {
|
||
|
$sth = $dbh->prepare("SELECT picid, width, height, state " .
|
||
|
"FROM userpic WHERE userid=?");
|
||
|
}
|
||
|
$sth->execute($u->{'userid'});
|
||
|
my @sortedpics;
|
||
|
push @sortedpics, $_ while $_ = $sth->fetchrow_hashref;
|
||
|
|
||
|
|
||
|
# See if they have any without keywords before we output the display table
|
||
|
foreach (@sortedpics) {
|
||
|
unless ($keywords{$_->{'picid'}}) {
|
||
|
my @w;
|
||
|
if (defined $LJ::HELPURL{'upic_keywords'}) {
|
||
|
push @w, BML::ml('.warning.keywords.faq', {'aopts' => "href='$LJ::HELPURL{'upic_keywords'}'"});
|
||
|
} else {
|
||
|
push @w, $ML{'.warning.keywords'};
|
||
|
}
|
||
|
|
||
|
$body .= LJ::warning_list(@w);
|
||
|
last;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
my $piccount = 0;
|
||
|
foreach my $pic (sort { $a->{picid} <=> $b->{picid} } @sortedpics)
|
||
|
{
|
||
|
my $pid = $pic->{'picid'};
|
||
|
|
||
|
if ($piccount++ == 0) {
|
||
|
$body .= "<?h1 $ML{'.curpics'} h1?><?p $ML{'.curpics.desc'} p?>";
|
||
|
$body .= "<?p <strong>". BML::ml('.piclimitstatus', {current => $count, max => $max}) . "</strong> p?>";
|
||
|
|
||
|
$body .= "<form method='post' action='editpics.bml$getextra'>";
|
||
|
$body .= "<table cellpadding='5' border='0' cellspacing='1' " .
|
||
|
"style='margin-left: 30px'>";
|
||
|
}
|
||
|
$body .= "<tr valign='middle'>";
|
||
|
$body .= "<td align='center'><img src='$LJ::USERPIC_ROOT/$pid/$u->{'userid'}' width='$pic->{'width'}' height='$pic->{'height'}'></td>";
|
||
|
$body .= "<td>\n<table>";
|
||
|
|
||
|
my ($dis, $distxt);
|
||
|
{
|
||
|
$body .= "<tr><td align='right'><b><label for='$pid-def'>$ML{'.label.default'}</label></b></td><td> ";
|
||
|
$body .= LJ::html_check({ 'type' => 'radio', 'name' => 'defaultpic', 'value' => $pid,
|
||
|
'selected' => $u->{'defaultpicid'} == $pid,
|
||
|
'disabled' => $pic->{'state'} eq 'I' });
|
||
|
|
||
|
$body .= " <b><label for='$pid-del'>$ML{'.label.delete'}</label></b> ";
|
||
|
$body .= LJ::html_check({ 'type' => 'checkbox', 'name' => "delete_$pid",
|
||
|
'id' => "$pid-del", 'value' => 1 });
|
||
|
|
||
|
if ($pic->{'state'} eq 'I') {
|
||
|
$body .= " <i>[$ML{'userpic.inactive'}]</i> " . LJ::help_icon('userpic_inactive');
|
||
|
}
|
||
|
|
||
|
$body .= "</td></tr>\n";
|
||
|
}
|
||
|
|
||
|
{
|
||
|
my $keywords;
|
||
|
$keywords = join(", ", sort { lc($a) cmp lc($b) } @{$keywords{$pic->{'picid'}}})
|
||
|
if $keywords{$pid};
|
||
|
|
||
|
$body .= "<tr><td align='right'><b><label for='$pid-key'>$ML{'.label.keywords'}</label></b></td><td> ";
|
||
|
$body .= LJ::html_text({'name' => "kw_$pid", 'id' => "$pid-key",
|
||
|
'size' => '30', 'value' => $keywords,
|
||
|
'disabled' => $pic->{'state'} eq 'I' });
|
||
|
|
||
|
$body .= "</td></tr>\n";
|
||
|
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$body .= "<tr><td align='right'><b><label for='$pid-com'>$ML{'.label.comment'}</label></b></td><td> ";
|
||
|
$body .= LJ::html_text({ 'name' => "com_$pid", 'id' => "$pid-com",
|
||
|
'size' => '30', 'value' => $pic->{'comment'},
|
||
|
'maxlength' => LJ::CMAX_UPIC_COMMENT,
|
||
|
'disabled' => $pic->{'state'} eq 'I' });
|
||
|
|
||
|
$body .= "</td></tr>\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$body .= "</table>\n</td></tr>\n";
|
||
|
}
|
||
|
|
||
|
if ($piccount) {
|
||
|
$body .= "<tr><td></td><td align=left> <b><label for='nodefpic'>$ML{'.nodefault'}</label></b> ";
|
||
|
$body .= LJ::html_check({ 'name' => 'defaultpic',
|
||
|
'value' => 0,
|
||
|
'type' => 'radio',
|
||
|
'selected' => ! $u->{'defaultpicid'},
|
||
|
'raw' => "id='nodefpic'" });
|
||
|
|
||
|
$body .= "</td><td> </td></tr>\n";
|
||
|
$body .= "<tr><td></td><td> " . LJ::html_submit('action:save', $ML{'.btn.save'}) . "</td></tr>\n";
|
||
|
$body .= "</table>";
|
||
|
$body .= "</form>";
|
||
|
} else {
|
||
|
$body .= "<?h1 $ML{'.nopics'} h1?><?p $ML{'.noneupload'} p?>";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# let users upload more pics
|
||
|
$body .= "<a name='upload'></a>";
|
||
|
|
||
|
if ($count < $max) {
|
||
|
if ($fotobilder) {
|
||
|
$body .= "<?h1 $ML{'.uploadheader.fb'} h1?>\n";
|
||
|
$body .= "<?p " . BML::ml('.uploaddesc.fb', {'aopts' => "href='$LJ::FB_SITEROOT'", 'sitename' => $LJ::FB_SITENAME}) . " p?>\n\n";
|
||
|
} else {
|
||
|
$body .= "<?h1 $ML{'.uploadheader'} h1?>\n";
|
||
|
$body .= "<?p $ML{'.uploaddesc'} p?>\n\n";
|
||
|
|
||
|
$body .= "<ul>\n";
|
||
|
foreach (qw(filesize imagesize fileformat)) {
|
||
|
$body .= "<li>" . $ML{".restriction.$_"} . "</li>\n";
|
||
|
}
|
||
|
|
||
|
# Keywords is a little different
|
||
|
$body .= "<li>";
|
||
|
if (defined $LJ::HELPURL{'upic_keywords'}) {
|
||
|
$body .= BML::ml('.restriction.keywords.faq', {'aopts' => "href='$LJ::HELPURL{'upic_keywords'}'"});
|
||
|
} else {
|
||
|
$body .= $ML{'.restriction.keywords'};
|
||
|
}
|
||
|
|
||
|
$body .= "</li>";
|
||
|
$body .= "</ul>\n";
|
||
|
}
|
||
|
|
||
|
# upload form
|
||
|
$body .= "<?standout \n";
|
||
|
$body .= "<form action='editpics.bml$getextra' method='post' " .
|
||
|
"enctype='multipart/form-data' style='display: inline;'>\n";
|
||
|
|
||
|
$body .= "<table>\n";
|
||
|
|
||
|
if ($fotobilder) {
|
||
|
$body .= "<tr><td colspan='3' align='center'>\n";
|
||
|
$body .= "<img src='$picurl' />";
|
||
|
my $url = LJ::CleanHTML::canonical_url($POST{'url'});
|
||
|
$body .= LJ::html_hidden('src', 'url', 'urlpic', $picurl, 'url', $url, 'ret' => $returl);
|
||
|
} else {
|
||
|
$body .= "<tr><td align='right'>\n";
|
||
|
$body .= LJ::html_check({ 'type' => 'radio', 'name' => 'src', 'id' => 'radio_file',
|
||
|
'value' => 'file', 'selected' => '1',
|
||
|
'accesskey' => $ML{'.fromfile.key'} });
|
||
|
$body .= "</td><td align='right'>";
|
||
|
$body .= "<label for='radio_file'>$ML{'.fromfile'}</label></td>";
|
||
|
$body .= "<td align='left'><input type='file' name='userpic' size='28' /></td></tr>\n";
|
||
|
|
||
|
$body .= "<tr><td align='right'>";
|
||
|
$body .= LJ::html_check({ 'type' => 'radio', 'name' => 'src', 'value' => 'url',
|
||
|
'id' => 'radio_url', 'accesskey' => $ML{'.fromurl.key'} });
|
||
|
$body .= "</td><td align='right'>";
|
||
|
$body .= "<label for='radio_url'>$ML{'.fromurl'}</label></td><td align='left'>";
|
||
|
$body .= LJ::html_text({ 'name' => 'urlpic', 'size' => '40' }) . "</td></tr>\n";
|
||
|
}
|
||
|
|
||
|
$body .= "<tr><td colspan='3' align='center'><hr></td></tr>";
|
||
|
|
||
|
$body .= "<tr><td align='right'>";
|
||
|
$body .= LJ::help_icon('upic_keywords');
|
||
|
$body .= "</td><td align='right'><label for='keywords'>";
|
||
|
$body .= "$ML{'.label.keywords'}</label></td><td align='left'>";
|
||
|
$body .= LJ::html_text({ 'name' => 'keywords', 'size' => '40' });
|
||
|
$body .= "</td></tr>";
|
||
|
|
||
|
if ($u->{'dversion'} > 6) {
|
||
|
$body .= "<tr><td align='right'>";
|
||
|
$body .= LJ::help_icon('upic_comments');
|
||
|
$body .= "</td><td align='right'><label for='comments'>$ML{'.label.comment'}</label></td><td align='left'>";
|
||
|
my $comments = $POST{'comments'} if $fotobilder;
|
||
|
$body .= LJ::html_text({ 'name' => 'comments', 'size' => '40', 'maxlength' => LJ::CMAX_UPIC_COMMENT, 'value', $comments });
|
||
|
$body .= "</td></tr>";
|
||
|
}
|
||
|
|
||
|
$body .= "<tr><td colspan='2'> </td><td align='left'>";
|
||
|
$body .= LJ::html_check({ 'type' => 'checkbox',
|
||
|
'name' => 'make_default',
|
||
|
'id' => 'make_default',
|
||
|
'selected' => '1', 'value' => '1',
|
||
|
'accesskey' => $ML{'.makedefault.key'} });
|
||
|
|
||
|
$body .= "<label for='make_default'>$ML{'.makedefault'}</label></td></tr>\n";
|
||
|
|
||
|
$body .= "<tr><td colspan='3' align='center'><br />" .LJ::html_submit(undef, $ML{'.btn.proceed'}) . "</td></tr>\n";
|
||
|
$body .= "</table>\n</form>\n";
|
||
|
} else {
|
||
|
$body .= "<?standout \n";
|
||
|
$body .= BML::ml(".error.toomanypics3", { 'max' => $max });
|
||
|
}
|
||
|
|
||
|
$body .= " standout?>\n\n";
|
||
|
|
||
|
|
||
|
|
||
|
return;
|
||
|
|
||
|
}
|
||
|
_code?><?page
|
||
|
title=><?_code return $title; _code?>
|
||
|
body=><?_code return $body; _code?>
|
||
|
page?><?_c <LJDEP>
|
||
|
link: htdocs/login.bml, htdocs/allpics.bml
|
||
|
post: htdocs/editpics.bml
|
||
|
</LJDEP> _c?>
|