init
This commit is contained in:
679
ljcom/htdocs/manage/files.bml
Normal file
679
ljcom/htdocs/manage/files.bml
Normal file
@@ -0,0 +1,679 @@
|
||||
<?page
|
||||
title=>File Manager
|
||||
body<=
|
||||
<?_code
|
||||
{
|
||||
use strict;
|
||||
use vars qw(%GET %POST);
|
||||
|
||||
LJ::set_active_crumb('filemanager');
|
||||
|
||||
my $remote = LJ::get_remote();
|
||||
return LJ::bad_input($ML{'error.noremote'})
|
||||
unless $remote;
|
||||
|
||||
my $authas = $GET{'authas'} || $remote->{'user'};
|
||||
my $u = LJ::get_authas_user($authas);
|
||||
return LJ::bad_input($ML{'error.invalidauth'})
|
||||
unless $u;
|
||||
|
||||
# KiB vs MiB byte conversions / printing
|
||||
my %shift = ( MiB => 1 << 20, KiB => 1 << 10 );
|
||||
my $size = sub {
|
||||
my $bytes = shift;
|
||||
# Display in Mb or Kb?
|
||||
return sprintf("%.2f MiB", $bytes / $shift{MiB}) if $bytes >= $shift{MiB};
|
||||
return sprintf("%.2f KiB", $bytes / $shift{KiB});
|
||||
};
|
||||
|
||||
# for reporting error
|
||||
my $err = sub { return "<?h1 $ML{'Error'} h1?><?p $_[0] p?>" };
|
||||
|
||||
# what type of blob to show
|
||||
my $showtype = $GET{'showtype'};
|
||||
|
||||
# extra arguments for get requests
|
||||
# how to make links back to this page
|
||||
my $self_link = sub {
|
||||
my $page = shift || $GET{'page'};
|
||||
my $sort = shift || $GET{'sort'};
|
||||
|
||||
my $uri = "files.bml?";
|
||||
$uri .= "authas=$authas&" if $authas ne $remote->{'user'};
|
||||
$uri .= "showtype=$showtype&" if $showtype;
|
||||
$uri .= "page=$page&" if $page > 1;
|
||||
$uri .= "sort=$sort&" if $sort;
|
||||
chop $uri;
|
||||
|
||||
return $uri;
|
||||
};
|
||||
|
||||
# how to make a sort link back to this page,
|
||||
# given a sort type and name
|
||||
my $sort_link = sub {
|
||||
my ($sort, $name) = @_;
|
||||
return $name unless $sort;
|
||||
|
||||
my $type = $GET{'sort'} eq "${sort}_asc"
|
||||
? "${sort}_desc" : "${sort}_asc";
|
||||
return "<a href='" . $self_link->(undef, $type) . "'>$name</a>";
|
||||
};
|
||||
|
||||
# declare these up here so closures below can use them
|
||||
my %blobs = (); # { 'blobid' => blob object }, references into @blobs
|
||||
my @blobs = (); # [ { blob object }, { ... }, ... ]
|
||||
my ($domain, $domainid); # blob domain/id
|
||||
my ($dbh, $dbcm);
|
||||
|
||||
my %btype = ();
|
||||
|
||||
###
|
||||
### Userpic handler functions
|
||||
###
|
||||
$btype{'userpic'} = {
|
||||
'name' => "Userpics",
|
||||
|
||||
# how to sort various columns
|
||||
'sort' => sub {
|
||||
my $sort = $GET{'sort'};
|
||||
my $cmp = sub { $b->{'length'} <=> $a->{'length'} };
|
||||
|
||||
# numeric <=> comparison
|
||||
if ($sort =~ /^(kw_ct|width|height|length)_(asc|desc)$/) {
|
||||
my ($meth, $dir) = ($1, $2);
|
||||
|
||||
if ($dir eq 'desc') {
|
||||
$cmp = sub { $b->{$meth} <=> $a->{$meth} };
|
||||
} elsif ($dir eq 'asc') {
|
||||
$cmp = sub { $a->{$meth} <=> $b->{$meth} };
|
||||
}
|
||||
|
||||
# string 'cmp' comparison
|
||||
} elsif ($sort =~ /^(picdate|ext)_(asc|desc)$/) {
|
||||
my ($meth, $dir) = ($1, $2);
|
||||
|
||||
if ($dir eq 'desc') {
|
||||
$cmp = sub { $b->{$meth} cmp $a->{$meth} };
|
||||
} elsif ($dir eq 'asc') {
|
||||
$cmp = sub { $a->{$meth} cmp $b->{$meth} };
|
||||
}
|
||||
}
|
||||
|
||||
return sort $cmp @blobs;
|
||||
},
|
||||
|
||||
# how to fetch userpic objects from the database
|
||||
'fetch' => sub {
|
||||
my @ids = map { $_->{'blobid'} } @blobs;
|
||||
my $bind = join(",", map { "?" } @ids);
|
||||
my $sth;
|
||||
if ($u->{'dversion'} > 6) {
|
||||
my $dbcr = LJ::get_cluster_def_reader($u);
|
||||
$sth = $dbcr->prepare("SELECT picid, fmt, width, height, " .
|
||||
"state, picdate FROM userpic2 " .
|
||||
"WHERE userid=$u->{'userid'} AND picid IN ($bind)");
|
||||
} else {
|
||||
$sth = $dbh->prepare("SELECT picid, contenttype, width, height, " .
|
||||
"state, picdate FROM userpic " .
|
||||
"WHERE picid IN ($bind)");
|
||||
}
|
||||
$sth->execute(@ids);
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
my $picid = $row->{'picid'};
|
||||
$row->{'length'} = $blobs{$picid}->{'length'};
|
||||
$blobs{$picid} = $row;
|
||||
}
|
||||
@blobs = values %blobs;
|
||||
|
||||
# add in keywords
|
||||
my $upicinf = LJ::get_userpic_info($u);
|
||||
while (my ($k, $v) = each %{$upicinf->{'kw'}}) {
|
||||
push @{$blobs{$v->{'picid'}}->{'kw'}}, $k;
|
||||
}
|
||||
|
||||
# don't need keyword array though,
|
||||
# 'kw_str' => comma separated keywords
|
||||
# 'kw_ct' => count of keywords, for sorting
|
||||
foreach my $bl (@blobs) {
|
||||
$bl->{'kw_str'} = join(", ", @{$bl->{'kw'}||[]});
|
||||
$bl->{'kw_ct'} = scalar(@{$bl->{'kw'}||[]});
|
||||
delete $bl->{'kw'};
|
||||
|
||||
# convert mime type to filetype (ext)
|
||||
if ($u->{'dversion'} > 6) {
|
||||
$bl->{'ext'} = {
|
||||
'G' => 'gif',
|
||||
'J' => 'jpg',
|
||||
'P' => 'png',
|
||||
}->{$bl->{'contenttype'}};
|
||||
} else {
|
||||
$bl->{'ext'} = {
|
||||
'image/gif' => 'gif',
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png',
|
||||
}->{$bl->{'contenttype'}};
|
||||
}
|
||||
delete $bl->{'contenttype'};
|
||||
}
|
||||
},
|
||||
|
||||
# deletes blobs which need to be deleted based on %POST
|
||||
'delete' => sub {
|
||||
|
||||
# find picids to delete
|
||||
my @del = ();
|
||||
foreach my $id (map { $_->{'picid'} } @blobs) {
|
||||
push @del, $id if $POST{"del_${id}"};
|
||||
}
|
||||
return 0 unless @del;
|
||||
|
||||
# try and delete from either the blob server or database,
|
||||
my $deleted = 0;
|
||||
my $bind = join(",", map { "?" } @del);
|
||||
if ($LJ::USERPIC_BLOBSERVER) {
|
||||
|
||||
# delete blobs from blobserver
|
||||
foreach my $picid (@del) {
|
||||
LJ::Blob::delete($u, $domain, $blobs{$picid}->{'ext'}, $picid);
|
||||
}
|
||||
$deleted = 1;
|
||||
|
||||
} elsif ($u->do("DELETE FROM userpicblob2 WHERE ".
|
||||
"userid=? AND picid IN ($bind)", undef,
|
||||
$u->{userid}, @del) > 0) {
|
||||
$deleted = 1;
|
||||
}
|
||||
if ($deleted) {
|
||||
if ($u->{'dversion'} > 6) {
|
||||
$u->do("DELETE FROM userpic2 WHERE userid=? IN ($bind)",
|
||||
undef, $u->{'userid'}, @del);
|
||||
} else {
|
||||
$dbh->do("DELETE FROM userpic WHERE picid IN ($bind)",
|
||||
undef, @del);
|
||||
}
|
||||
$u->do("DELETE FROM userblob WHERE journalid=? AND domain=? " .
|
||||
"AND blobid IN ($bind)", undef, $u->{'userid'},
|
||||
$domain, @del);
|
||||
|
||||
# userpics changed, need to reactivate
|
||||
LJ::activate_userpics($u);
|
||||
}
|
||||
|
||||
return scalar(@del);
|
||||
},
|
||||
|
||||
# renders userpic rows in the table (including column headings)
|
||||
'render' => sub {
|
||||
my $ret;
|
||||
|
||||
$ret .= "<tr><td class='tablehead'> </td>";
|
||||
|
||||
my $eff_sort =
|
||||
$GET{'sort'} =~ /^(kw_ct|picdate|width|height|length|ext)_(asc|desc)$/
|
||||
? $GET{'sort'} : "length_desc";
|
||||
|
||||
# display column headings
|
||||
foreach ([undef, "Image"], ['kw_ct', "Keywords"], ['picdate', "Date Uploaded"],
|
||||
['width', "Width"], ['height', "Height"], ['length', "Filesize"],
|
||||
['ext', "Type"]) {
|
||||
|
||||
$ret .= "<td class='tablehead'";
|
||||
$ret .= " width='40%'" if $_->[0] eq 'subject';
|
||||
$ret .= ">" . $sort_link->(@$_);
|
||||
|
||||
if ($eff_sort =~ /^$_->[0]_(asc|desc)$/) {
|
||||
my $pref = $1 eq 'asc' ? "down" : "up";
|
||||
$ret .= "<img src='$LJ::IMGPREFIX/${pref}arrow.gif' width='16' ";
|
||||
$ret .= "height='15' alt='' border='0' />";
|
||||
}
|
||||
|
||||
$ret .= "</td>";
|
||||
}
|
||||
|
||||
$ret .= "<td class='tablehead'> </td></tr>";
|
||||
|
||||
# fill in rows
|
||||
foreach my $bl (@blobs) {
|
||||
my $picid = $bl->{'picid'};
|
||||
|
||||
# delete checkbox
|
||||
$ret .= "<tr><td class='tablecontent'>";
|
||||
$ret .= LJ::html_check({ 'type' => 'check', 'name' => "del_${picid}",
|
||||
'id' => "del_${picid}", 'value' => 1 }) . "</td>";
|
||||
|
||||
# display userpic
|
||||
$ret .= "<td class='tablecontent'><label for='del_${picid}'>";
|
||||
$ret .= "<img src='$LJ::USERPIC_ROOT/$bl->{'picid'}/$u->{'userid'}'";
|
||||
$ret .= " width='$bl->{'width'}' height='$bl->{'height'}' alt='$bl->{'kw_str'}'";
|
||||
$ret .= " title='$bl->{'kw_str'}'></label></td>";
|
||||
|
||||
# keywords, date/time
|
||||
$bl->{'kw_str'} ||= "<i>none</i>";
|
||||
foreach (qw(kw_str picdate)) {
|
||||
$ret .= "<td class='tablecontent'>$bl->{$_}</td>";
|
||||
}
|
||||
|
||||
# width/height
|
||||
foreach (qw(width height)) {
|
||||
$ret .= "<td class='tablecontent'>$bl->{$_}px</td>";
|
||||
}
|
||||
|
||||
# file size
|
||||
my $len = sprintf("%.1fk", $bl->{'length'} / 1000);
|
||||
$ret .= "<td class='tablecontent' align='center'>$len</td>";
|
||||
|
||||
# typs
|
||||
$ret .= "<td class='tablecontent' align='center'>";
|
||||
$ret .= uc($bl->{'ext'}) . "</td></tr>";
|
||||
}
|
||||
|
||||
# delete button
|
||||
$ret .= "<tr><td colspan='4' align='left'>";
|
||||
$ret .= LJ::html_submit('action:delete', "Delete Selected") . "</td>";
|
||||
$ret .= "<td colspan='4' align='right'>[<a href='$LJ::SITEROOT/editpics.bml#upload'>";
|
||||
$ret .= "Upload new userpics</a>]";
|
||||
|
||||
return $ret;
|
||||
},
|
||||
};
|
||||
|
||||
###
|
||||
### PhonePost handler functions
|
||||
###
|
||||
$btype{'phonepost'} = {
|
||||
'name' => "Phone Posts",
|
||||
|
||||
# how to sort phonepost rows, for each column type
|
||||
'sort' => sub {
|
||||
my $sort = $GET{'sort'};
|
||||
my $cmp = sub { $b->{'length'} <=> $a->{'length'} };
|
||||
|
||||
# numeric <=> comparison
|
||||
if ($sort =~ /^(length|lengthsecs|posttime)_(asc|desc)$/) {
|
||||
my ($meth, $dir) = ($1, $2);
|
||||
|
||||
if ($dir eq 'desc') {
|
||||
$cmp = sub { $b->{$meth} <=> $a->{$meth} };
|
||||
} elsif ($dir eq 'asc') {
|
||||
$cmp = sub { $a->{$meth} <=> $b->{$meth} };
|
||||
}
|
||||
|
||||
# string 'cmp' comparison
|
||||
} elsif ($sort =~ /^subject_(asc|desc)$/) {
|
||||
if ($1 eq 'desc') {
|
||||
$cmp = sub { $b->{'subject'} cmp $a->{'subject'} };
|
||||
} else {
|
||||
$cmp = sub { $a->{'subject'} cmp $b->{'subject'} };
|
||||
}
|
||||
}
|
||||
|
||||
return sort $cmp @blobs;
|
||||
},
|
||||
|
||||
# populates @/%blobs from database
|
||||
'fetch' => sub {
|
||||
|
||||
# get data from phonepostentry
|
||||
my $bind = join(",", map { "?" } @blobs);
|
||||
my $sth = $dbcm->prepare("SELECT blobid, jitemid, anum AS pp_anum, " .
|
||||
"lengthsecs, posttime, filetype FROM phonepostentry " .
|
||||
"WHERE userid=? AND blobid IN ($bind)");
|
||||
$sth->execute($u->{'userid'}, map { $_->{'blobid'} } @blobs);
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
my $bid = $row->{'blobid'};
|
||||
$row->{'length'} = $blobs{$bid}->{'length'};
|
||||
|
||||
# convert filetype to extension
|
||||
$row->{'ext'} = $row->{'filetype'} == 1 ? "ogg" : "mp3";
|
||||
delete $row->{'filetype'};
|
||||
|
||||
$blobs{$bid} = $row;
|
||||
}
|
||||
@blobs = values %blobs;
|
||||
|
||||
# now get subject from logtext2
|
||||
my $logtext = LJ::get_logtext2($u, map { $_->{'jitemid'} } @blobs);
|
||||
foreach my $bl (@blobs) {
|
||||
my $jitemid = $bl->{'jitemid'};
|
||||
next unless ref $logtext->{$jitemid} eq 'ARRAY';
|
||||
|
||||
# subject and has_entry keys
|
||||
$bl->{'subject'} = $logtext->{$jitemid}->[0];
|
||||
$bl->{'has_entry'} = 1;
|
||||
|
||||
# also get log2 row so we can see security
|
||||
my $log = LJ::get_log2_row($u, $jitemid);
|
||||
if (ref $log eq 'HASH') {
|
||||
$bl->{'security'} = $log->{'security'};
|
||||
$bl->{'l_anum'} = $log->{'anum'};
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
# deletes blobs which need to be deleted based on %POST
|
||||
'delete' => sub {
|
||||
|
||||
# find picids to delete
|
||||
my @del = ();
|
||||
foreach my $id (map { $_->{'blobid'} } @blobs) {
|
||||
push @del, $id if $POST{"del_${id}"};
|
||||
}
|
||||
return 0 unless @del;
|
||||
|
||||
return 0 unless $u->writer;
|
||||
|
||||
# delete from userblob (journalid, domain, blobid)
|
||||
my $bind = join(",", map { "?" } @del);
|
||||
$u->do("DELETE FROM userblob WHERE journalid=? AND domain=? " .
|
||||
"AND blobid IN ($bind)", undef, $u->{'userid'},
|
||||
$domainid, @del);
|
||||
|
||||
# delete blobs from blobserver
|
||||
foreach my $bid (@del) {
|
||||
my $ppe = LJ::PhonePost::get_phonepost_entry($u, $bid);
|
||||
if ($ppe->{location} eq 'mogile') {
|
||||
LJ::mogclient()->delete("pp:$u->{userid}:$bid");
|
||||
} else {
|
||||
LJ::Blob::delete($u, $domain, $blobs{$bid}->{'ext'}, $bid);
|
||||
}
|
||||
}
|
||||
|
||||
# update phonepost entry locations to be 'none'
|
||||
$u->do("UPDATE phonepostentry SET location='none' WHERE userid=? AND blobid IN ($bind)",
|
||||
undef, $u->{userid}, @del);
|
||||
|
||||
return scalar(@del);
|
||||
},
|
||||
|
||||
# generate phonepost table rows
|
||||
'render' => sub {
|
||||
my $ret;
|
||||
|
||||
$ret .= "<tr><td class='tablehead'> </td>";
|
||||
|
||||
my $eff_sort =
|
||||
$GET{'sort'} =~ /^(subject|length|lengthsecs|posttime)_(asc|desc)$/
|
||||
? $GET{'sort'} : "length_desc";
|
||||
|
||||
# table heading
|
||||
foreach ([undef, "Audio"], ['subject', "Subject"], ['posttime', "Date/Time"],
|
||||
['lengthsecs', "Duration"], ['length', "Filesize"]) {
|
||||
|
||||
$ret .= "<td class='tablehead'";
|
||||
$ret .= " width='40%'" if $_->[0] eq 'subject';
|
||||
$ret .= ">" . $sort_link->(@$_);
|
||||
|
||||
if ($eff_sort =~ /^$_->[0]_(asc|desc)$/) {
|
||||
my $pref = $1 eq 'asc' ? "down" : "up";
|
||||
$ret .= "<img src='$LJ::IMGPREFIX/${pref}arrow.gif' width='16' ";
|
||||
$ret .= "height='15' alt='' border='0' />";
|
||||
}
|
||||
|
||||
$ret .= "</td>";
|
||||
}
|
||||
|
||||
$ret .= "<td class='tablehead'> </td></tr>";
|
||||
|
||||
# table rows
|
||||
foreach my $bl (@blobs) {
|
||||
my $blobid = $bl->{'blobid'};
|
||||
|
||||
# delete checkbox
|
||||
$ret .= "<tr><td class='tablecontent'>";
|
||||
$ret .= LJ::html_check({ 'type' => 'check', 'name' => "del_${blobid}",
|
||||
'value' => 1, 'selected' => 0 }) . "</td>";
|
||||
|
||||
# link to phonepost
|
||||
{
|
||||
$ret .= "<td class='tablecontent'>";
|
||||
$ret .= LJ::PhonePost::make_link($remote, $u, $bl->{'blobid'}, 'bare');
|
||||
}
|
||||
|
||||
# link to original entry
|
||||
my $subject = "<i>No associated journal entry</i>";
|
||||
if ($bl->{'has_entry'}) {
|
||||
$subject = "<a href='" . LJ::item_link($u, $bl->{'jitemid'}, $bl->{'l_anum'});
|
||||
$subject .= "'>" . ($bl->{'subject'} || "<i>no subject</i>") . "</a>";
|
||||
}
|
||||
$ret .= "<td class='tablecontent'>$subject</td>";
|
||||
|
||||
# date/time
|
||||
my $datetime = LJ::mysql_time($bl->{'posttime'});
|
||||
$ret .= "<td class='tablecontent'>$datetime</td>";
|
||||
|
||||
# length
|
||||
my $secs = int($bl->{'lengthsecs'} / 60) . ":";
|
||||
$secs .= sprintf("%02ds", $bl->{'lengthsecs'} % 60);
|
||||
$ret .= "<td class='tablecontent' align='center'>$secs</td>";
|
||||
|
||||
# file size
|
||||
my $len = sprintf("%.1fk", $bl->{'length'} / 1000);
|
||||
$ret .= "<td class='tablecontent' align='center'>$len</td>";
|
||||
|
||||
# security
|
||||
$ret .= "<td class='tablecontent' align='center'>";
|
||||
if ($bl->{'security'} && $bl->{'security'} ne 'public') {
|
||||
$ret .= "<img src='$LJ::IMGPREFIX/icon_protected.gif' width='14' ";
|
||||
$ret .= "height='15' border='0'alt='Protected' />";
|
||||
}
|
||||
$ret .= "</td></tr>";
|
||||
}
|
||||
|
||||
# delete button
|
||||
$ret .= "<tr><td colspan='6' align='left'>";
|
||||
$ret .= LJ::html_submit('action:delete', "Delete Selected") . "</td>";
|
||||
|
||||
return $ret;
|
||||
}
|
||||
};
|
||||
|
||||
# All of this is managed on the FotoBilder side of things, so just give total
|
||||
# usage info, and a link to where they can manage it.
|
||||
if (LJ::get_cap($u, 'fb_account')) {
|
||||
$btype{'fotobilder'} = {
|
||||
'name' => "Photo Hosting",
|
||||
'sort' => sub {},
|
||||
'delete' => sub {},
|
||||
'fetch' => sub {},
|
||||
'render' => sub
|
||||
{
|
||||
my $ret;
|
||||
|
||||
my $pp_bytes = LJ::Blob::get_disk_usage($u, 'fotobilder');
|
||||
my $pp_display = $size->($pp_bytes);
|
||||
|
||||
my $max_size = LJ::get_cap($u, "disk_quota") * $shift{MiB};
|
||||
my $ret;
|
||||
|
||||
$ret .= '<tr>';
|
||||
foreach (' ', 'Images', 'Filesize Totals') {
|
||||
$ret .= "<td class='tablehead'>$_</td>";
|
||||
}
|
||||
$ret .= '</tr>';
|
||||
|
||||
$ret .= "<tr><td class='tablecontent'> </td>";
|
||||
$ret .= "<td class='tablecontent' valign='top'>";
|
||||
$ret .= "<img src='$LJ::IMGPREFIX/imageplaceholder2.png' width='35' ";
|
||||
$ret .= "height='35' alt='' border='0' /></td>";
|
||||
|
||||
$ret .= "<td class='tablecontent' valign='top'>";
|
||||
$ret .= "$pp_display (";
|
||||
$ret .= sprintf("%.2f%%", ($pp_bytes / $max_size) * 100);
|
||||
$ret .= " of your total) <br />";
|
||||
|
||||
$ret .= "Please visit <a href='$LJ::FB_SITEROOT'>$LJ::FB_DOMAIN</a> to manage your images.";
|
||||
$ret .= '</td></tr>';
|
||||
return $ret;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
###
|
||||
### START OF OUTPUT
|
||||
###
|
||||
my $ret;
|
||||
|
||||
# authas switcher form
|
||||
$ret .= "<form method='get' action='files.bml'>\n";
|
||||
$ret .= LJ::html_hidden('showtype' => $showtype) if $showtype;
|
||||
$ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }) . "\n";
|
||||
$ret .= "</form>\n\n";
|
||||
|
||||
# domain type selector
|
||||
$ret .= "<form method='get' action='files.bml'>File Type: ";
|
||||
$ret .= LJ::html_hidden('authas' => $authas) if $authas ne $remote->{'user'};
|
||||
$ret .= LJ::html_select({ 'name' => 'showtype', 'selected' => $showtype },
|
||||
'' => '---',
|
||||
map { $_ => $btype{$_}->{'name'} } sort keys %btype) . " ";
|
||||
$ret .= LJ::html_submit("Show") . "</form>";
|
||||
|
||||
# show quota info
|
||||
my $used_size = LJ::Blob::get_disk_usage($u);
|
||||
my $max_size = LJ::get_cap($u, "disk_quota") * $shift{MiB};
|
||||
|
||||
if ($max_size) {
|
||||
|
||||
$ret .= "<?h2 Quota Usage h2?>";
|
||||
$ret .= "<p>You are currently using " . $size->($used_size) . " (";
|
||||
$ret .= sprintf("%.2f%%", ($used_size / $max_size) * 100);
|
||||
$ret .= ") of your " . $size->($max_size) . " quota.</p>";
|
||||
}
|
||||
|
||||
return $ret unless defined $btype{$showtype};
|
||||
|
||||
###
|
||||
### LOAD DATA
|
||||
###
|
||||
|
||||
# now we have a showtype
|
||||
$domain = $showtype;
|
||||
$domainid = LJ::get_blob_domainid($domain);
|
||||
my $bobj = $btype{$showtype};
|
||||
|
||||
# get db handle now
|
||||
$dbh = LJ::get_db_writer();
|
||||
$dbcm = LJ::get_cluster_master($u);
|
||||
return $err->($ML{'error.nodb'}) unless $dbh && $dbcm;
|
||||
|
||||
# fetch data from userblob
|
||||
my $sth = $dbcm->prepare("SELECT blobid, length FROM userblob " .
|
||||
"WHERE journalid=? AND domain=?");
|
||||
$sth->execute($u->{'userid'}, $domainid);
|
||||
while (my $row = $sth->fetchrow_hashref) {
|
||||
push @blobs, $row;
|
||||
}
|
||||
|
||||
# no blobs?
|
||||
unless (@blobs) {
|
||||
$ret .= "<?h1 No Files h1?>";
|
||||
$ret .= "<?p You do not have any files of the specified type. Please select a ";
|
||||
$ret .= "different type from the list above and try again. p?>";
|
||||
return $ret;
|
||||
}
|
||||
|
||||
# generate paging object and make a navbar
|
||||
my $page_size = 25;
|
||||
my %items = BML::paging(\@blobs, $GET{'page'}, $page_size);
|
||||
my $navbar = LJ::paging_bar($items{'page'}, $items{'pages'},
|
||||
{ 'self_link' => $self_link });
|
||||
@blobs = @{$items{'items'}};
|
||||
|
||||
# get only this page of blobids
|
||||
$blobs{$_->{'blobid'}} = $_ foreach @blobs;
|
||||
|
||||
# call data-getter to fill in the rest of blob data
|
||||
$bobj->{'fetch'}->();
|
||||
|
||||
# sort blobs into specified order
|
||||
@blobs = $bobj->{'sort'}->();
|
||||
|
||||
|
||||
# if a blob's id is in the blobid list, but we got nothing from the
|
||||
# database, then we'll remove its entry from userblob because we
|
||||
# forgot to remove the row in editpics.bml
|
||||
if ($showtype eq 'userpic') {
|
||||
my @del;
|
||||
foreach my $bl (@blobs) {
|
||||
|
||||
# see if required 'picdate' column was added in
|
||||
push @del, $bl->{'blobid'} unless
|
||||
$bl->{'picdate'};
|
||||
}
|
||||
if (@del) {
|
||||
return $err->($ML{'error.nodb'}) unless $u->writer;
|
||||
|
||||
my $bind = join(",", map { "?" } @del);
|
||||
$u->do("DELETE FROM userblob WHERE journalid=? AND domain=? " .
|
||||
"AND blobid IN ($bind)", undef, $u->{'userid'}, $domainid, @del);
|
||||
|
||||
return BML::redirect($self_link->());
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
### Perform actions
|
||||
###
|
||||
if (LJ::did_post() && $POST{'action:delete'}) {
|
||||
|
||||
my $res = $bobj->{'delete'}->();
|
||||
if ($res) {
|
||||
# now the database has been modified and deleted, but our current
|
||||
# memory state isn't accurate, so we'll have to redirect and start
|
||||
# over before displaying anything below
|
||||
return BML::redirect($self_link->());
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
### Generate page
|
||||
###
|
||||
|
||||
# output table
|
||||
$ret .= $navbar;
|
||||
$ret .= "<form method='post' action='" . $self_link->() . "'>";
|
||||
|
||||
$ret .= "<table border='0' width='100%' cellspacing='1' cellpadding='4'>";
|
||||
$ret .= $bobj->{'render'}->();
|
||||
$ret .= "</table></form>";
|
||||
|
||||
$ret .= $navbar;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
_code?>
|
||||
<=body
|
||||
head<=
|
||||
<style type='text/css'>
|
||||
dt { font-weight: bold }
|
||||
.tablecontent {
|
||||
border-top: 1px solid #dfdfdf;
|
||||
border-bottom: 1px solid #dfdfdf;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.tablehead {
|
||||
border-bottom: 1px solid #dfdfdf;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tablehead A {
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
.tablebottom {
|
||||
border-top: 1px solid #dfdfdf;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
<=head
|
||||
page?>
|
||||
138
ljcom/htdocs/manage/phonepost.bml
Normal file
138
ljcom/htdocs/manage/phonepost.bml
Normal file
@@ -0,0 +1,138 @@
|
||||
<?page
|
||||
title=><?_ml .title _ml?>
|
||||
body<=
|
||||
<?_code
|
||||
{
|
||||
use strict;
|
||||
use vars qw/ %POST /;
|
||||
|
||||
return LJ::server_down_html() if $LJ::SERVER_DOWN;
|
||||
|
||||
LJ::set_active_crumb('phonepostsettings');
|
||||
|
||||
my $remote = LJ::get_remote();
|
||||
|
||||
return "<?h1 Error h1?><?p Only personal journals are allowed to use the post by phone system. p?>"
|
||||
if $remote && $remote->{journaltype} ne 'P';
|
||||
|
||||
return $LJ::MSG_READONLY_USER if LJ::get_cap($remote, "readonly");
|
||||
|
||||
my ($ret, $saved);
|
||||
my %errors;
|
||||
my $error_msg = sub {
|
||||
my $key = shift;
|
||||
my $msg = $errors{$key};
|
||||
return unless $msg;
|
||||
return "<tr><th align='right'><?inerr $ML{'Error'}: inerr?></th><td colspan='2'><?inerr $msg inerr?></td></tr>";
|
||||
};
|
||||
|
||||
my %formats = (
|
||||
'ogg', 'Ogg Vorbis',
|
||||
'wav', 'Wav (GSM encoded)'
|
||||
);
|
||||
$formats{'mp3'} = 'Mp3' if $LJ::PHONEPOST_MP3;
|
||||
|
||||
POST:
|
||||
while ($remote && LJ::did_post()) {
|
||||
my $phone = $POST{phone};
|
||||
my $trans = $POST{trans};
|
||||
my $format = $POST{format};
|
||||
my $pin = $POST{pin};
|
||||
|
||||
if ($POST{delete}) {
|
||||
my $dbh = LJ::get_db_writer();
|
||||
$dbh->do("DELETE FROM phonepostlogin WHERE userid=?", undef, $remote->{userid});
|
||||
return "<?h1 $ML{'.deleted.header'} h1?><?p $ML{'.deleted'} p?>";
|
||||
}
|
||||
|
||||
$phone =~ s/\D//g;
|
||||
$errors{'.phone'} = $ML{'.error.phone.length'}
|
||||
unless length $phone >= 10;
|
||||
|
||||
$errors{'.pin'} = $ML{'.error.pin'} if $pin =~ /\D/ or
|
||||
length $pin < 1;
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
my $prevuserid = $dbh->selectrow_array("SELECT userid FROM phonepostlogin ".
|
||||
"WHERE phone=? AND pin=?", undef,
|
||||
$phone, $pin);
|
||||
$errors{'.pin'} = $ML{'.error.inuse'} if $prevuserid && $prevuserid != $remote->{userid};
|
||||
|
||||
my $grouplist = LJ::get_friend_group($remote);
|
||||
$errors{'.transcribers'} = $ML{'.error.transcription'}
|
||||
unless $trans == -1 || $trans == 0 || defined $grouplist->{$trans};
|
||||
|
||||
$errors{'.format'} = "Bad format selected." unless $formats{$format};
|
||||
|
||||
last POST if %errors;
|
||||
|
||||
$dbh->do("REPLACE INTO phonepostlogin ".
|
||||
"(phone, pin, userid) VALUES (?, ?, ?)", undef,
|
||||
$phone, $pin, $remote->{userid});
|
||||
|
||||
LJ::set_userprop($remote, 'pp_transallow', $trans);
|
||||
LJ::set_userprop($remote, 'pp_format', $format);
|
||||
|
||||
$saved .= "<?h1 $ML{'.saved'} h1?>";
|
||||
$saved .= "<?p $ML{'.success.text'} p?>";
|
||||
$saved .= "<?p $ML{'.success.moreinfo'} p?>";
|
||||
last;
|
||||
}
|
||||
|
||||
my $grouplist = LJ::get_friend_group($remote);
|
||||
|
||||
my $tableline = sub {
|
||||
my ($mlcaption, $content) = @_;
|
||||
my $err = $error_msg->($mlcaption);
|
||||
return "<tr><th align='right' nowrap='1'>$ML{$mlcaption}</th><td>$content</td><td><?de " . $ML{"$mlcaption.help"} . " de?></td></tr>\n$err";
|
||||
};
|
||||
|
||||
my $dbr = LJ::get_db_reader();
|
||||
my ($phone, $pin);
|
||||
|
||||
if ($remote) {
|
||||
($phone, $pin) = $dbr->selectrow_array(
|
||||
"SELECT phone, pin FROM phonepostlogin ".
|
||||
"WHERE userid=?", undef,
|
||||
$remote->{userid});
|
||||
LJ::load_user_props($remote, qw/ pp_transallow pp_format /);
|
||||
$ret .= $ML{'.intro.loggedin'};
|
||||
} else {
|
||||
$ret .= "<?p $ML{'.intro.loggedout'} p?>";
|
||||
}
|
||||
|
||||
$phone = $POST{'phone'} ? $POST{'phone'} : $phone;
|
||||
$pin = $POST{'pin'} ? $POST{'pin'} : $pin;
|
||||
|
||||
$ret .= "<form method='post' action='phonepost.bml' style='margin-left: 40px'>\n";
|
||||
$ret .= "<table cellpadding='3' cellspacing='0'>";
|
||||
$ret .= $tableline->('.phone',
|
||||
LJ::html_text({name => 'phone', value => $phone,
|
||||
maxlength => 25, disabled => !$remote}));
|
||||
|
||||
$ret .= $tableline->('.pin',
|
||||
LJ::html_text({name => 'pin', value => $pin, type => 'password',
|
||||
maxlength => 8, disabled => !$remote}));
|
||||
|
||||
my $default_format = $remote->{pp_format} || ($LJ::PHONEPOST_MP3 ? 'mp3' : 'ogg');
|
||||
|
||||
$ret .= $tableline->('.format',
|
||||
LJ::html_select({ name => 'format', selected => $default_format }, %formats));
|
||||
|
||||
$ret .= $tableline->('.transcribers',
|
||||
LJ::html_select({ name=>'trans', selected=>$remote->{pp_transallow} },
|
||||
0,'All friends',-1,'No one but you',
|
||||
map { $_, $grouplist->{$_}->{groupname} }
|
||||
sort {$grouplist->{$a}->{groupname} cmp $grouplist->{$b}->{groupname}}
|
||||
keys %$grouplist));
|
||||
|
||||
$ret .= '<tr><td> </td><td>' . LJ::html_submit('save', $ML{'.save'}, { disabled => !$remote }) . '</td><td>';
|
||||
$ret .= LJ::html_submit('delete', $ML{'.delete'}, { disabled => !$remote}) . '</td></tr></table><br />';
|
||||
$ret .= "</form>";
|
||||
|
||||
$ret .= $saved if $saved;
|
||||
return $ret;
|
||||
}
|
||||
_code?>
|
||||
<=body
|
||||
page?>
|
||||
Reference in New Issue
Block a user