[fotobilder] r1456: LJSUP-10497: Security mapping supported,...
Committer: vtroitsky
LJSUP-10497: Security mapping supported, video formats eliminated, UploadTempFile/UploadPrepare/UploadPic/GU trunk/lib/FB/Protocol/Fotki/CreateGals.pm U trunk/lib/FB/Protocol/Fotki/GetGals.pm U trunk/lib/FB/Protocol/Fotki/GetGalsTree.pm U trunk/lib/FB/Protocol/Fotki/GetPics.pm U trunk/lib/FB/Protocol/Fotki/Login.pm U trunk/lib/FB/Protocol/Fotki/UploadPic.pm A trunk/lib/FB/Protocol/Fotki/UploadPrepare.pm A trunk/lib/FB/Protocol/Fotki/UploadTempFile.pm A trunk/lib/FB/Protocol/Fotki.pm U trunk/lib/FB/Protocol/Response.pm
Modified: trunk/lib/FB/Protocol/Fotki/CreateGals.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/CreateGals.pm 2011-11-28 15:35:57 UTC (rev 1455)
+++ trunk/lib/FB/Protocol/Fotki/CreateGals.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -2,6 +2,8 @@
package FB::Protocol::Fotki::CreateGals;
+use FB::Protocol::Fotki;
+
use strict;
use LJ::Fotki::Album;
@@ -47,11 +49,18 @@
return $err->(211 => "Malformed gallery name: $galname")
unless FB::valid_gallery_name($galname);
-# warn "Creating gallery...";
+ # check that GalSec was valid, if it was specified
+ my $galsec = exists $gvar->{GalSec} ? $gvar->{GalSec} : 255;
+ return $err->(211 => "Invalid GalSec value")
+ unless defined $galsec && FB::valid_security_value($u, \$galsec);
- my $album = LJ::Fotki::Album->create(userid => $lj_userid, album_title => $galname, album_desc => '');
+ my ($security, $allowmask) = FB::Protocol::Fotki->fb2lj_security($galsec);
-# warn "AID:".$album->album_id;
+ my $album;
+ eval {
+ $album = LJ::Fotki::Album->create(userid => $lj_userid, album_title => $galname, album_desc => '', security => $security, allowmask => $allowmask);
+ };
+ return $err->(512 => 'Error creation LJ Fotki album' ) if $@;
return $err->(512 => 'Error creation LJ Fotki album' ) unless($album);
@@ -67,199 +76,4 @@
return 1;
}
-
-# FIXME: perhaps add support for adding multiple
-# parents/children by ParentID and/or Path?
-
-sub old_handler {
- my $resp = shift or return undef;
- my $req = $resp->{req};
- my $vars = $req->{vars}->{CreateGals};
- my $u = $resp->{u};
-
- my $ret = { Gallery => [] };
-
- my $err = sub {
- $resp->add_method_error(CreateGals => @_);
- return undef;
- };
-
- return $err->(212 => 'Gallery')
- unless defined $vars->{Gallery};
-
- return $err->(211 => 'CreateGals')
- unless ref $vars->{Gallery} eq 'ARRAY' && @{$vars->{Gallery}};
-
- # to which galleries should this picture be added?
- my @gals;
- GALLERY:
- foreach my $gvar (@{$vars->{Gallery}}) {
-
- # FIXME: make sure that gallery doesn't already exist,
- # case is different from uploadpic
-
- # existence of GalName is required
- return $err->(212 => 'GalName')
- unless exists $gvar->{GalName};
-
- # exists but not defined?
- my $galname = $gvar->{GalName};
- return $err->(211 => 'GalName')
- unless defined $galname;
-
- # defined but not valid?
- return $err->(211 => "Malformed gallery name: $galname")
- unless FB::valid_gallery_name($galname);
-
- # check for invalid argument interactions
- return $err->(211 => "Can't specify both ParentID and Path when adding to gallery")
- if exists $gvar->{ParentID} && exists $gvar->{Path};
-
- # check that GalSec was valid, if it was specified
- my $galsec = exists $gvar->{GalSec} ? $gvar->{GalSec} : 255;
- return $err->(211 => "Invalid GalSec value")
- unless defined $galsec && FB::valid_security_value($u, \$galsec);
-
- # check against existence of undefined values:
- foreach (qw(ParentID GalDate)) {
- return $err->(211 => $_)
- if exists $gvar->{$_} && ! defined $gvar->{$_};
- }
-
- # check that ParentID was valid, if it was specified
- my $parentid = exists $gvar->{ParentID} ? $gvar->{ParentID} : 0;
- return $err->(211 => "ParentID must be a non-negative integer")
- if ! defined $parentid || $parentid =~ /\D/ || $parentid < 0;
-
- # check gallery names in Path
- my @path = @{$gvar->{Path}||[]};
- foreach (@path) {
- next if defined $_ && FB::valid_gallery_name($_);
- return $err->(211 => [ "Malformed gallery name in Path" => $_ ]);
- }
-
- # if no path was specified, and the parentid is 0 only because
- # it defaulted to that, then the gallery we create will be
- # top-level
- my $top_level = ! @path && $parentid == 0 ? 1 : 0;
-
- # check that GalDate was valid, if it was specified
- my $galdate = FB::date_from_user($gvar->{GalDate});
- return $err->(211 => "Malformed date: $galdate")
- if exists $gvar->{GalDate} && ! defined $galdate;
-
- # goal from here on is to find what gals this 'Gallery' struct refers to,
- # we'll create those galleries as needed
-
- my $udbh = FB::get_user_db_writer($u)
- or return $err->(501 => "Cluster $u->{clusterid}");
-
- # if a GalName was specified in conjunction with a path, it is a
- # special case and means that we should attempt to create galleries
- # down the path, starting at the root, then create a new gallery
- # (if it doesn't exist) of the given GalName at the end of the path
- if (@path) {
-
- # add GalName to the end of the path since it will be the final
- # destination gallery and follows the same rules for creation as
- # the rest of the path.
- push @path, $galname;
-
- # for error reporting if necessary later
- my $pathstr = join(" / ", @path);
-
- my $pid = 0;
- PATH:
- while (@path) {
- my $currname = shift @path;
-
- # FIXME: pretty sure this could be further optimized
-
- # see if the parent of the path thus far exists
- my $gal = $udbh->selectrow_hashref
- ("SELECT g.* FROM gallery g, galleryrel gr ".
- "WHERE g.userid=? AND g.name=? AND gr.userid=g.userid ".
- "AND gr.gallid2=g.gallid AND gr.gallid=? AND gr.type='C' ".
- "ORDER BY gr.sortorder LIMIT 1",
- undef, $u->{userid}, $currname, $pid);
- return $err->(502) if $udbh->err;
-
- # if we've reached the end of the path and the gallery being
- # referenced already exists, then error.
- return $err->(211 => "Gallery already exists: $pathstr")
- if @path == 0 && $gal;
-
- # gal didn't exist, create and set that as parent
- unless ($gal) {
- $gal = FB::create_gallery
- ($u, $currname, $galsec, $pid,
- @path == 0 ? { dategal => $galdate } : {})
- or return $err->(512 => FB::last_error());
-
- if (@path == 0) {
- push @{$ret->{Gallery}}, { GalID => [ $gal->{gallid} ],
- GalName => [ $galname ],
- GalURL => [ FB::url_gallery($u, $gal) ] };
- }
- }
-
- # parent is either the gallery we just looked up or the
- # one we just created
- $pid = $gal->{gallid};
-
- next PATH;
- }
-
- # move on to the next gallery record
- next GALLERY;
- }
-
- # if a name was specified with a ParentID, then create a gallery
- # named GalName that is also a child of $parentid. it is possible
- # that the parentid was set to 0 because no parentid was specified,
- # meaning that the gallery should be created top-level
- if (defined $parentid && $parentid > 0 || $top_level) {
-
- # does the specified parent gallery even exist?
- my $pgal = undef;
- unless ($top_level) {
- $pgal = FB::load_gallery_id($u, $parentid)
- or return $err->(211 => "Parent gallery does not exist: $parentid");
- }
-
- my $rows = $udbh->selectrow_array
- ("SELECT COUNT(*) FROM gallery g, galleryrel gr ".
- "WHERE g.userid=? AND g.name=? AND gr.userid=g.userid ".
- "AND gr.gallid2=g.gallid AND gr.gallid=? AND gr.type='C'",
- undef, $u->{userid}, $galname, $parentid);
- return $err->(502) if $udbh->err;
-
- # gallery already existed?
- if ($rows) {
- my @galpath = ($galname);
- unshift @galpath, $pgal->{name} if $pgal;
- return $err->(512 => "Gallery aready exists: " . join('/', @galpath));
- }
-
- # create a new gallery
- my $gal = FB::create_gallery
- ($u, $galname, $galsec, $parentid, { dategal => $galdate })
- or return $err->(512 => FB::last_error());
-
- push @{$ret->{Gallery}}, { GalID => [ $gal->{gallid} ],
- GalName => [ $galname ],
- GalURL => [ FB::url_gallery($u, $gal) ] };
-
-
- next GALLERY;
- }
-
- next GALLERY;
- }
-
- # register return value with parent Request
- $resp->add_method_vars(CreateGals => $ret);
-
- return 1;
-}
1;
Modified: trunk/lib/FB/Protocol/Fotki/GetGals.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/GetGals.pm 2011-11-28 15:35:57 UTC (rev 1455)
+++ trunk/lib/FB/Protocol/Fotki/GetGals.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -2,6 +2,8 @@
package FB::Protocol::Fotki::GetGals;
+use FB::Protocol::Fotki;
+
use strict;
use LJ::Fotki::Album;
@@ -18,7 +20,6 @@
my $lj_userid = FB::get_domain_userid($u);
my $lj_user = LJ::load_userid($lj_userid);
-# warn "userid: ".$u->userid." -> ljuserid: $lj_userid # $lj_user" ;
# TODO: eval to catch all errors
my $albums = LJ::Fotki::Album->get_albums($lj_userid, $lj_user);
@@ -29,14 +30,14 @@
next unless($album);
my $album_ret = {
id => $album->album_id,
- Name => [ $album->title ],
- Sec => [ 255 ], # default security: public
- # Date => [ $album->createtime ], # gallery creation date in 2004-01-01 01:01:01 format
- # TimeUpdate => [ $album->updatetime ], # update timestamp
+ Name => [ FB::transform_gal_name($album->title) ],
+ Sec => [ FB::Protocol::Fotki->lj2fb_security($album->get_security, $album->get_mask) ],
+ Date => [ FB::date_unix_to_mysql($album->timecreate) ],
+ ($album->timeupdate ? (TimeUpdate => [ $album->timeupdate ]) : ()),
URL => [ $album->url ],
};
# is this the incoming gallery?
-# $gal_ret->{incoming} = 1 if $album->is_unsorted;
+ $album_ret->{incoming} = 1 if $album->is_default;
# GalMembers
my $photos = $album->get_all_photos($lj_user);
@@ -58,66 +59,4 @@
return 1;
}
-sub handler_old {
- my $resp = shift or return undef;
- my $req = $resp->{req};
- my $vars = $req->{vars};
- my $u = $resp->{u};
-
- my $err = sub {
- $resp->add_method_error(GetGals => @_);
- return undef;
- };
-
- my $gals = FB::gals_of_user($u);
- return $err->(500) unless ref $gals;
-
- my $ret = { Gal => [] };
-
- if (%$gals) {
-
- # load gallery rels and pic rels for use later
- my @gal_rel = FB::user_galleryrel($u);
- my @pic_rel = FB::user_gallerypics($u);
-
- while (my ($gallid, $gal) = each %$gals) {
- my $gal_ret = { id => $gallid,
- Name => [ FB::transform_gal_name($gal->{name}) ],
- Sec => [ $gal->{secid} ],
- Date => [ $gal->{dategal} ],
- TimeUpdate => [ $gal->{timeupdate} ],
- URL => [ FB::url_gallery($u, $gal) ],
- };
-
- # is this the incoming gallery?
- $gal_ret->{incoming} = 1 if FB::gal_is_unsorted($gal);
-
- # GalMembers
- $gal_ret->{GalMembers}->{GalMember} =
- [ map { { id => $_->{upicid} } }
- grep { $_->{gallid} == $gallid }
- @pic_rel ];
-
- # ParentGals
- $gal_ret->{ParentGals}->{ParentGal} =
- [ map { { id => $_->{gallid}, sortorder => $_->{sortorder} } }
- grep { $_->{gallid2} == $gallid && $_->{type} eq 'C' }
- @gal_rel ];
-
- # ChildGals
- $gal_ret->{ChildGals}->{ChildGal} =
- [ map { { id => $_->{gallid2}, sortorder => $_->{sortorder} } }
- grep { $_->{gallid} == $gallid && $_->{type} eq 'C' }
- @gal_rel ];
-
- push @{$ret->{Gal}}, $gal_ret;
- }
- }
-
- # register return value with parent Request
- $resp->add_method_vars(GetGals => $ret);
-
- return 1;
-}
-
1;
Modified: trunk/lib/FB/Protocol/Fotki/GetGalsTree.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/GetGalsTree.pm 2011-11-28 15:35:57 UTC (rev 1455)
+++ trunk/lib/FB/Protocol/Fotki/GetGalsTree.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -2,6 +2,7 @@
package FB::Protocol::Fotki::GetGalsTree;
+use FB::Protocol::Fotki;
use strict;
use LJ::Fotki::Album;
@@ -34,13 +35,13 @@
my $album_ret = {
id => $album->album_id,
Name => [ $album->title ],
- Sec => [ 255 ], # default security: public
- # Date => [ $album->createtime ], # gallery creation date in 2004-01-01 01:01:01 format
- # TimeUpdate => [ $album->updatetime ], # update timestamp
+ Sec => [ FB::Protocol::Fotki->lj2fb_security($album->get_security, $album->get_mask) ],
+ Date => [ FB::date_unix_to_mysql($album->timecreate) ], # gallery creation date in 2004-01-01 01:01:01 format
+ ($album->timeupdate ? (TimeUpdate => [ $album->timeupdate ]) : ()), # update timestamp
URL => [ $album->url ],
};
# is this the incoming gallery?
-# $gal_ret->{incoming} = 1 if $album->is_unsorted;
+ $album_ret->{incoming} = 1 if $album->is_default;
# GalMembers
my $photos = $album->get_all_photos($lj_user);
@@ -58,108 +59,6 @@
$resp->add_method_vars(GetGalsTree => $ret);
return 1;
-
-
}
-sub handler_old {
- my $resp = shift or return undef;
- my $req = $resp->{req};
- my $vars = $req->{vars};
- my $u = $resp->{u};
-
- my $err = sub {
- $resp->add_method_error(GetGalsTree => @_);
- return undef;
- };
-
- my $gals = FB::gals_of_user($u);
- return $err->(500) unless ref $gals;
-
- my $ret = {
- RootGals => [ { Gal => [ ] } ],
- UnreachableGals => [ { Gal => [ ] } ],
- };
-
- if (%$gals) {
-
- # load gallery rels and pic rels for use later
- my @gal_rel = FB::user_galleryrel($u);
- my @pic_rel = FB::user_gallerypics($u);
-
- # build a data structure of parent gallids => array of their children
- my %parents = ();
- my %children = ();
- foreach (grep { $_->{type} eq 'C' } @gal_rel) {
- my ($pid, $cid) = ($_->{gallid}, $_->{gallid2});
- push @{$children{$pid}}, $gals->{$cid};
- push @{$parents{$cid}}, $gals->{$pid};
- $gals->{$cid}->{sortorder} = $_->{sortorder};
- }
-
- # resets every visit to top-level (0)
- my %seen = ();
- my %unreachable = map { $_ => 1 } keys %$gals;
-
- my $recurse;
- $recurse = sub {
- my $gal = shift;
- my $gallid = $gal->{gallid};
-
- # since we've visited this gallery, it's not unreachable
- delete $unreachable{$gallid};
-
- my $node = { id => $gallid,
- sortorder => $gal->{sortorder}+0,
- Name => [ FB::transform_gal_name($gal->{name}) ],
- Sec => [ $gal->{secid} ],
- Date => [ $gal->{dategal} ],
- TimeUpdate => [ $gal->{timeupdate} ],
- URL => [ FB::url_gallery($u, $gal) ],
- };
-
- # is this the incoming gallery?
- $node->{incoming} = 1 if FB::gal_is_unsorted($gal);
-
- # GalMembers
- $node->{GalMembers}->{GalMember} =
- [ map { { id => $_->{upicid} } }
- grep { $_->{gallid} == $gallid }
- @pic_rel ];
-
- # now the hard part: ChildGals
- $node->{ChildGals}->{Gal} =
- [ map { $recurse->($_) }
- sort { $a->{sortorder} <=> $b->{sortorder} || $a->{gallid} <=> $b->{gallid} }
- grep { ! $seen{$_->{gallid}}++ }
- @{$children{$gallid}} ];
-
- return $node;
- };
-
- # start at parent (top-level) node and built tree
- # of all its children
- foreach my $child (@{$children{0}}) {
- %seen = ( $child->{gallid} => 1 );
- push @{$ret->{RootGals}->[0]->{Gal}}, $recurse->($child);
- }
-
- # represent any galleries that were unreachable, recursing down
- # from each gallery that has no parents
- foreach my $gal (map { $gals->{$_} }
- sort { $gals->{$a}->{sortorder} <=> $gals->{$b}->{sortorder} ||
- $gals->{$a}->{gallid} <=> $gals->{$b}->{gallid} }
- keys %unreachable) {
-
- %seen = ( $gal->{gallid} => 1 );
- push @{$ret->{UnreachableGals}->[0]->{Gal}}, $recurse->($gal);
- }
- }
-
- # register return value with parent Request
- $resp->add_method_vars(GetGalsTree => $ret);
-
- return 1;
-}
-
1;
Modified: trunk/lib/FB/Protocol/Fotki/GetPics.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/GetPics.pm 2011-11-28 15:35:57 UTC (rev 1455)
+++ trunk/lib/FB/Protocol/Fotki/GetPics.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -2,6 +2,8 @@
package FB::Protocol::Fotki::GetPics;
+use FB::Protocol::Fotki;
+
use strict;
use LJ::Fotki::Photo;
@@ -30,10 +32,10 @@
push @{$ret->{Pic}}, {
id => $photo->photo_id,
- Sec => [ $photo->get_security ], # TODO: convert mask!!!
-# Width => [ $pic->{width} ], # TODO: necessary to support original photo sizes
-# Height => [ $pic->{height} ],
-# Bytes => [ $pic->{bytes} ], # TODO: original photo size
+ Sec => [ FB::Protocol::Fotki->lj2fb_security($photo->get_security, $photo->get_mask) ], # TODO: convert mask to FB format
+ Width => [ $photo->orig_width ],
+ Height => [ $pic->orig_height ],
+ Bytes => [ $pic->orig_size ],
# Format => [ FB::fmtid_to_mime($pic->{fmtid}) ], # TODO: Format of the original photo
# MD5 => [ FB::bin_to_hex($gpic_md5->{$pic->{gpicid}}) ],
URL => [ $photo->orig_url ],
@@ -55,57 +57,4 @@
return 1;
}
-
-sub handler_old {
- my $resp = shift or return undef;
- my $req = $resp->{req};
- my $vars = $req->{vars};
- my $u = $resp->{u};
-
- my $err = sub {
- $resp->add_method_error(GetPics => @_);
- return undef;
- };
-
- my $ret = { Pic => [] };
- my $upics = FB::upics_of_user($u, { props => [ qw(filename pictitle) ] });
- return $err->(500 => FB::last_error) unless ref $upics eq 'HASH';
-
- if (%$upics) {
-
- # get md5s of all the gpics
- my $gpic_md5 = FB::get_gpic_md5_multi([ map { $_->{gpicid} } values %$upics ]);
- return $err->(500 => FB::last_error()) unless ref $gpic_md5 eq 'HASH';
-
- my @pics_with_des = FB::get_des_multi($u, 'P', [ values %$upics ]);
- return $err->(500 => FB::last_error()) unless ref $pics_with_des[0] eq 'HASH';
-
- foreach my $pic (sort { $a->{upicid} <=> $b->{upicid} } @pics_with_des) {
-
- push @{$ret->{Pic}}, {
- id => $pic->{upicid},
- Sec => [ $pic->{secid} ],
- Width => [ $pic->{width} ],
- Height => [ $pic->{height} ],
- Bytes => [ $pic->{bytes} ],
- Format => [ FB::fmtid_to_mime($pic->{fmtid}) ],
- MD5 => [ FB::bin_to_hex($gpic_md5->{$pic->{gpicid}}) ],
- URL => [ FB::url_picture($u, $pic) ],
- Meta => [ map {
- { name => $_->[0],
- content => $pic->{$_->[1]} }
- } (['filename' => 'filename' ],
- ['title' => 'pictitle' ],
- ['description' => 'des' ])
- ],
- };
- }
- }
-
- # register return value with parent Request
- $resp->add_method_vars(GetPics => $ret);
-
- return 1;
-}
-
1;
Modified: trunk/lib/FB/Protocol/Fotki/Login.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/Login.pm 2011-11-28 15:35:57 UTC (rev 1455)
+++ trunk/lib/FB/Protocol/Fotki/Login.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -3,6 +3,7 @@
package FB::Protocol::Fotki::Login;
use strict;
+
use LJ::Fotki::UserSpace;
sub handler {
@@ -49,45 +50,4 @@
return 1;
}
-sub handler_old {
- my $resp = shift or return undef;
- my $req = $resp->{req};
- my $vars = $req->{vars}->{Login};
- my $u = $resp->{u};
-
- my $err = sub {
- $resp->add_method_error(Login => @_);
- return undef;
- };
-
- my $ret = { ServerTime => [ FB::date_unix_to_mysql() ]};
-
- # store client version in $r->notes so we can log it optionally
- # to keep stats
- if (defined $vars->{ClientVersion}) {
- LJ::Request->notes(ProtocolClientVersion => $vars->{ClientVersion});
- }
-
- # look up quota and usage information to return with this request
- if (FB::are_hooks('disk_usage_info')) {
-
- my $qinf = FB::run_hook('disk_usage_info', $u);
- if (ref $qinf eq 'HASH') {
- $ret->{Quota} = {
- Total => [ $qinf->{quota} * (1 << 10) ], # kb -> bytes
- Used => [ $qinf->{used} * (1 << 10) ],
- Remaining => [ $qinf->{free} * (1 << 10) ],
- };
- }
- }
-
- # are there any current system messages applying to this user?
- $ret->{Message} = [ FB::get_system_message($u) . '' ];
-
- # register return value with parent Request
- $resp->add_method_vars( Login => $ret );
-
- return 1;
-}
-
1;
Modified: trunk/lib/FB/Protocol/Fotki/UploadPic.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/UploadPic.pm 2011-11-28 15:35:57 UTC (rev 1455)
+++ trunk/lib/FB/Protocol/Fotki/UploadPic.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -2,6 +2,8 @@
package FB::Protocol::Fotki::UploadPic;
+use FB::Protocol::Fotki;
+
use strict;
use LJ::Fotki;
use LJ::Fotki::Album;
@@ -36,135 +38,9 @@
return $err->(201 => "Cannot specify both ImageLength and Receipt")
if exists $vars->{ImageLength} && exists $vars->{Receipt};
- my $gpic;
+# my $photo;
my ($fmtid, $length, $md5_hex);
- # did they specify an ImageData variable?
- return $err->(212 => "ImageData")
- unless $img && ref $img eq 'HASH';
-
- return $err->(212 => "ImageLength")
- unless exists $vars->{ImageLength};
-
- $length = $vars->{ImageLength};
-
- return $err->(211 => "ImageLength")
- unless defined $length;
-
- # did we count bytes?
- return $err->(213 => "No data sent")
- unless $img->{bytes};
-
- # did they match the declared length?
- return $err->(211 => "ImageLength does not match data length")
- unless $img->{bytes} == $length;
-
- # check that it's a valid fmtid
- $fmtid = $img->{fmtid};
- return $err->(213 => "Unknown format")
- unless $fmtid;
-
- # valid filehandle -- not applicable to $img from receipt
- return $err->(500 => "No spool filehandle")
- unless $img->{spool_fh};
-
- # valid md5 sum?
- return $err->(500 => "Could not calculate MD5 sum")
- unless $img->{md5sum};
-
- # if an md5 is supplied, check that it matches the image's actual
- # calculated md5
- $md5_hex = FB::bin_to_hex($img->{md5sum});
- if ($vars->{MD5} && $vars->{MD5} ne $md5_hex) {
- return $err->(211 => "Supplied MD5 does not match data MD5");
- }
-
- # check PicSec if specified
-
- # TODO: Support
- my $picsec = exists $vars->{PicSec} ? $vars->{PicSec} : 255;
- return $err->(211 => "PicSec")
- unless defined $picsec && FB::valid_security_value($u, $picsec);
-
- # Meta information
- if (exists $vars->{Meta}) {
- my $meta = $vars->{Meta};
- return $err->(211 => "Meta")
- unless ref $meta eq 'HASH';
-
- foreach (qw(Filename Title Description)) {
- next unless exists $meta->{$_};
- return $err->(211 => "Meta-$_")
- unless defined $meta->{$_};
-
- # Description is a BLOB (2^16-1 bytes)
- my $maxlen = $_ eq 'Description' ? 65535 : 255;
- return $err->(211 => [ "Meta-$_" => "Too long, maximum length is $maxlen" ])
- if length($meta->{$_}) > $maxlen;
- }
- }
-
- # call hook to check if user has disk space for picture before uploading
- my $spaces = LJ::Fotki::UserSpace->get_spaces($lj_user);
- return $err->(401) if $spaces->[3] <= 0;
- return $err->(402) if $spaces->[3] < $length;
-
-
- # TODO: process Galleries: add uploaded photo into specified galleries (albums)
-
-
-
-
- # use default upload album
- my $album = LJ::Fotki::Album->get_default_album($lj_user);
-
- # upload photo to fotki and create
-
- my $content = '';
- seek $img->{spool_fh}, 0,0;
- read $img->{spool_fh}, $content, $length;
-
- my $photo = LJ::Fotki::Photo->create(userid => $lj_userid, album_id => $album->album_id, photo_data => $content);
-
- # register return value with parent Request
- $resp->add_method_vars(
- UploadPic => {
- PicID => [ $photo->photo_id ],
- URL => [ $photo->orig_url ],
- Width => [ $up->width ],
- Height => [ $up->height ],
- Bytes => [ $length ],
- });
-
- return 1;
-}
-
-sub handler_old {
- my $resp = shift or return undef;
- my $req = $resp->{req};
- my $vars = $req->{vars}->{UploadPic};
-
- my $u = $resp->{u};
-
- my $err = sub {
- $resp->add_method_error(UploadPic => @_);
- return undef;
- };
-
- # is the user allowed to upload?
- return $err->(303)
- unless FB::get_cap($u, 'can_upload') && $u->{statusvis} eq 'V';
-
- # specifying two data sources makes no sense, error
- my $img = $vars->{ImageData};
- return $err->(201 => "Cannot specify both ImageData and Receipt")
- if $img && exists $vars->{Receipt};
- return $err->(201 => "Cannot specify both ImageLength and Receipt")
- if exists $vars->{ImageLength} && exists $vars->{Receipt};
-
- my $gpic;
- my ($fmtid, $length, $md5_hex);
-
# are they supplying a receipt for their upload data?
if (exists $vars->{Receipt}) {
return $err->(211 => 'Receipt')
@@ -183,19 +59,19 @@
return $err->(211 => [ 'Receipt' => "Expired" ])
unless $rcpt->{timecreate} > time() - $rcpt_exp->{$rcpt->{type}};
- # UploadPrepare receipt
- if ($rcpt->{type} eq 'P') {
+ # UploadPrepare receipt: there no such type at all at the moment
+# if ($rcpt->{type} eq 'P') {
+#
+# eval { $gpic = FB::Gpic->load($rcpt->{val}) };
+# return $err->(500 => $@) if $@;
+#
+# # still have no gpic from receipt?
+# return $err->(211 => 'Receipt')
+# unless $gpic;
+ # UploadTempFile receipt
+# }
+ if ($rcpt->{type} eq 'T') {
- eval { $gpic = FB::Gpic->load($rcpt->{val}) };
- return $err->(500 => $@) if $@;
-
- # still have no gpic from receipt?
- return $err->(211 => 'Receipt')
- unless $gpic;
-
- # UploadTempFile receipt
- } elsif ($rcpt->{type} eq 'T') {
-
my $inf = $rcpt->{val_hash};
return $err->(211 => 'Receipt')
unless ref $inf eq 'HASH';
@@ -231,13 +107,11 @@
}
}
}
-
# so now we know that no receipt was specified, else we'd have a $gpic or error by now
# error check data submission so we can attempt to create a new gpic later after the
# rest of the request is error checked
+ # unless ($photo) {
- unless ($gpic) {
-
# did they specify an ImageData variable?
return $err->(212 => "ImageData")
unless $img && ref $img eq 'HASH';
@@ -259,10 +133,6 @@
return $err->(211 => "ImageLength")
unless defined $length;
- # valid pclustertype / pclusterid
- return $err->(500 => "Could not determine pclustertype/id")
- unless $img->{pclustertype} && $img->{pclusterid};
-
# did we count bytes?
return $err->(213 => "No data sent")
unless $img->{bytes};
@@ -276,9 +146,12 @@
return $err->(213 => "Unknown format")
unless $fmtid;
+ return $err->(213 => "Format doesn't supported")
+ unless FB::Protocol::Fotki->accepted_fmtid($fmtid);
+
# valid filehandle -- not applicable to $img from receipt
return $err->(500 => "No spool filehandle")
- unless $img->{_from_rcpt} || $img->{spool_fh};
+ unless $img->{spool_fh};
# valid md5 sum?
return $err->(500 => "Could not calculate MD5 sum")
@@ -290,20 +163,22 @@
if ($vars->{MD5} && $vars->{MD5} ne $md5_hex) {
return $err->(211 => "Supplied MD5 does not match data MD5");
}
- }
-
+ # }
# check PicSec if specified
+ # TODO: Support security groups
my $picsec = exists $vars->{PicSec} ? $vars->{PicSec} : 255;
return $err->(211 => "PicSec")
- unless defined $picsec && FB::valid_security_value($u, $picsec);
+ unless defined $picsec && FB::valid_security_value($u, $picsec); # TODO check it!
+ my ($security, $allowmask) = FB::Protocol::Fotki->fb2lj_security($picsec);
+
# Meta information
if (exists $vars->{Meta}) {
my $meta = $vars->{Meta};
return $err->(211 => "Meta")
unless ref $meta eq 'HASH';
- foreach (qw(Filename Title Description)) {
+ foreach (qw(Title Description)) {
next unless exists $meta->{$_};
return $err->(211 => "Meta-$_")
unless defined $meta->{$_};
@@ -316,386 +191,124 @@
}
# call hook to check if user has disk space for picture before uploading
- my $Kibfree = FB::run_hook("disk_remaining", $u);
- if (defined $Kibfree) {
- return $err->(401) if $Kibfree <= 0;
- return $err->(402) if $Kibfree < $length>>10;
- }
+ my $spaces = LJ::Fotki::UserSpace->get_spaces($lj_user);
+ return $err->(401) if $spaces->[3] <= 0;
+ return $err->(402) if $spaces->[3] < $length;
+ # TODO: process Galleries: add uploaded photo into specified galleries (albums)
+
+
# to which galleries should this picture be added?
- my @gals;
+ my @albums;
GALLERY:
foreach my $gvar (@{$vars->{Gallery}}) {
- # check for invalid argument interactions
- return $err->(211 => "Can't specify both GalName and GalID when adding to gallery")
- if exists $gvar->{GalName} && exists $gvar->{GalID};
+ # TODO here
- return $err->(212 => "Must specify either GalName or GalID when adding to gallery")
- unless exists $gvar->{GalName} || exists $gvar->{GalID};
- return $err->(211 => "Can't specify both ParentID and Path when adding to gallery")
- if exists $gvar->{ParentID} && exists $gvar->{Path};
-
- # check that GalSec was valid, if it was specified
- my $galsec = exists $gvar->{GalSec} ? $gvar->{GalSec} : 255;
- return $err->(211 => "Invalid GalSec value")
- unless defined $galsec && FB::valid_security_value($u, \$galsec);
-
- # check against existence of undefined values:
- foreach (qw(ParentID GalDate GalName)) {
- return $err->(211 => $_)
- if exists $gvar->{$_} && ! defined $gvar->{$_};
- }
-
- # check that ParentID was valid, if it was specified
- my $parentid = exists $gvar->{ParentID} ? $gvar->{ParentID} : 0;
- return $err->(211 => "ParentID must be a non-negative integer")
- if ! defined $parentid || $parentid =~ /\D/ || $parentid < 0;
-
- # check that GalDate was valid, if it was specified
- my $galdate = FB::date_from_user($gvar->{GalDate});
- return $err->(211 => "Malformed date: $galdate")
- if exists $gvar->{GalDate} && ! defined $galdate;
-
- # check GalName, as well as any names in @path
- my $galname = $gvar->{GalName};
- return $err->(211 => "Malformed gallery name: $galname")
- if defined $galname && ! FB::valid_gallery_name($galname);
-
- # check gallery names in Path
- my @path = @{$gvar->{Path}||[]};
- foreach (@path) {
- next if defined $_ && FB::valid_gallery_name($_);
- return $err->(211 => [ "Malformed gallery name in Path" => $galname ]);
- }
-
- # goal from here on is to find what gals this 'Gallery' struct refers to,
- # we'll push those to the @gals array and add the picture to each of them
-
- # simple if they've specified a gallid
- if (exists $gvar->{GalID}) {
- my $gallid = $gvar->{GalID};
- return $err->(211 => "GalID must be a positive integer")
- unless defined $gallid && $gallid =~ /^\d+$/ && $gallid > 0;
-
- my $gal = $u->load_gallery_id($gallid)
- or return $err->(211 => "Gallery '$gallid' does not exist");
-
- push @gals, $gal;
- next GALLERY;
- }
-
- # more complicated if specified by name, need to check / create
- # gallery based on GalName, Path and ParentID
- if ($galname) {
-
- my $udbh = FB::get_user_db_writer($u)
- or return $err->(501 => "Cluster $u->{clusterid}");
-
- # if a GalName was specified in conjunction with a path, it is a
- # special case and means that we should attempt to create galleries
- # down the path, starting at the root, then create a new gallery
- # (if it doesn't exist) of the given GalName at the end of the path
- if (@path) {
-
- # add GalName to the end of the path since it will be the final
- # destination gallery and follows the same rules for creation as
- # the rest of the path.
- push @path, $galname;
-
- my $pid = 0;
- PATH:
- while (@path) {
- my $currname = shift @path;
-
- # FIXME: pretty sure this could be further optimized
-
- # see if the parent of the path thus far exists
- my $galrow = $u->selectrow_hashref
- ("SELECT g.* FROM gallery g, galleryrel gr ".
- "WHERE g.userid=? AND g.name=? AND gr.userid=g.userid ".
- "AND gr.gallid2=g.gallid AND gr.gallid=? AND gr.type='C' ".
- "ORDER BY gr.sortorder LIMIT 1",
- $u->{userid}, $currname, $pid);
- return $err->(502) if $u->err;
-
- my $gal;
- # gal didn't exist, create and set that as parent
- if ($galrow) {
- $gal = FB::Gallery->from_gallery_row($u, $galrow)
- or return $err->(512 => FB::last_error());
- } else {
- $gal = FB::Gallery->create($u, name => $currname, secid => $galsec)
- or return $err->(512 => FB::last_error());
- $gal->link_from($pid);
- $gal->set_date($galdate) if @path == 0 && $galdate;
- }
-
- # if we've worn the path list completely away, we've found
- # the target to add the picture to... it's the result of the
- # traversal of @path from the root, then finding/creating
- # GalName at the end of that traversal.
- if (@path == 0) {
- push @gals, $gal;
- last PATH;
- }
-
- # parent is either the gallery we just looked up or the
- # one we just created
- $pid = $gal->id;
- next PATH;
- }
-
- # move on to the next gallery record
- next GALLERY;
- }
-
- # if a name was specified with a ParentID, then add to galleries
- # named GalName that are also children of $parentid. find those now.
- if ($parentid) {
-
- my $sth = $u->prepare
- ("SELECT g.* FROM gallery g, galleryrel gr ".
- "WHERE g.userid=? AND g.name=? AND gr.userid=g.userid ".
- "AND gr.gallid2=g.gallid AND gr.gallid=? AND gr.type='C'",
- $u->{userid}, $galname, $parentid);
- $sth->execute;
- return $err->(502) if $u->err;
- while (my $grow = $sth->fetchrow_hashref) {
- my $gal = FB::Gallery->from_gallery_row($u, $grow) or die;
- push @gals, $gal;
- }
-
- # gal didn't exist, create and set that as parent
- unless (@gals) {
- my $gal = FB::Gallery->create($u, name => $galname, secid => $galsec)
- or return $err->(512 => FB::last_error());
- $gal->link_from($parentid);
- push @gals, $gal;
- }
-
- next GALLERY;
- }
-
- # otherwise we have a GalName but no constraining parentid, so we just
- # add to any galleries having that name
- my $sth = $u->prepare("SELECT * FROM gallery WHERE userid=? AND name=?",
- $u->{userid}, $galname);
- $sth->execute;
- return $err->(502) if $udbh->err;
- while (my $grow = $sth->fetchrow_hashref) {
- my $gal = FB::Gallery->from_gallery_row($u, $grow) or die;
- push @gals, $gal;
- }
-
- # but if there were no galleries by this name, create a new one
- # under the root
- unless (grep { $_->{name} eq $galname } @gals) {
- my $newgal = FB::Gallery->create($u, name => $galname, secid => $galsec)
- or return $err->(512 => FB::last_error());
- $newgal->link_from(0);
- $newgal->set_date($galdate) if $galdate;
- push @gals, $newgal;
- }
-
- next GALLERY;
- }
-
- # end processing of Gallery array
}
- # internally, a minimum of one gallery. use ":FB_in" which means
- # "unsorted" or "incoming" or something equivalent in user's native language.
- unless (@gals) {
- my $g = $u->incoming_gallery
- or return $err->(502 => "Cannot load incoming gallery");
- push @gals, $g;
+ # use default upload album if no albums specified
+ unless (@albums) {
+ my $a = LJ::Fotki::Album->get_default_album($lj_user)
+ or return $err->(502 => "Cannot load default album");
+ push @albums, $a;
}
# now we're finished with all input error checking, and we know that all the
# destination galleries exist... time to start processing the data, either from
# ImageData or from an upload receipt (tempfile or prepare)
- # already have a gpic if an existing one was specified via UploadPrepare receipt
- unless ($gpic) {
+ my $content = '';
+
+ # see if we have image data from a UploadTempFile receipt, if so we need to
+ # handle things a bit differently
+ if ($img->{_from_rcpt}) {
+ if ($img->{pclustertype} eq 'mogilefs') {
- # need to get an existing gpic, or start making one.
+ # Get content from Mogile FS
+ my $fh = $FB::MogileFS->read_file($img->{_rcpt_pathkey})
+ or return $err->(510 => "Unable to read MogileFS temp file");
+ eval {
+ seek $fh, 0,0;
+ read $fh, $content, $length;
+ };
+ return $err->(510 => $@) if $@;
+ } elsif ($img->{pclustertype} eq 'disk') {
+ eval {
+ seek $img->{spool_fh}, 0,0;
+ read $img->{spool_fh}, $content, $length;
+ };
+ return $err->(510 => $@) if $@;
- if ( my $gpicid = FB::find_equal_gpicid($md5_hex, $length, $fmtid, 'verify_paths') ) {
-
- # found an existing gpic for this fingerprint
- $gpic = FB::Gpic->load($gpicid)
- or return $err->(500);
-
- # note that we could have TempFiles to clean up at this point,
- # in the case that the fingerprint above was that of a receipt
- # tempfile. in any case, it will be cleaned up later.
-
+ } else {
+ return $err->(510 => [ "Unknown pclustertype" => $img->{pclustertype} ]);
}
- # still no gpic? time to create anew
- unless ($gpic) {
-
- # create a new gpic from $img hashref (defined and validated above)
- $gpic = FB::Gpic->new
- ( map { $_ => $img->{$_} } qw(pclustertype pclusterid md5sum fmtid bytes) )
- or return $err->(510 => $@);
-
- # errors from now until $gpic->save require the gpic to be discarded
- my $err_discard = sub {
- my $errcode = shift;
- my @errmsg = @_;
-
- # $gpic->discard will croak on err, catch it
- eval { $gpic->discard };
- push @errmsg, $@ if $@;
-
- return @errmsg ? $err->($errcode => \@errmsg) : $err->($errcode);
- };
-
-
- # swap in the spoolfile
-
- # see if we have image data from a UploadTempFile receipt, if so we need to
- # handle things a bit differently
- if ($img->{_from_rcpt}) {
-
- if ($img->{pclustertype} eq 'mogilefs') {
-
- # rename the old TempFile MogileFS key for this to
- # be a permanent one of the mogfs_key form
- $FB::MogileFS->rename($img->{_rcpt_pathkey}, FB::Gpic::mogfs_key($gpic->{gpicid}))
- or return $err_discard->(510 => "Unable to rename MogileFS temp file");
-
- } elsif ($img->{pclustertype} eq 'disk') {
-
- # swap in (hard link) pathkey to the final gpic disk path via API
- eval { $gpic->file_from_spool($img->{spool_fh}, $img->{_rcpt_pathkey}) };
- return $err_discard->(510 => $@) if $@;
-
- } else {
- return $err_discard->(510 => [ "Unknown pclustertype" => $img->{pclustertype} ]);
- }
-
# otherwise we're working on a spool filehandle for data uploaded in
# this request and collected in Request.pm
- } else {
+ } else {
+ eval {
+ seek $img->{spool_fh}, 0,0;
+ read $img->{spool_fh}, $content, $length;
+ };
+ return $err->(510 => $@) if $@;
+ }
- # swap in (hard link) pathkey to the final gpic disk path via API
- eval { $gpic->file_from_spool($img->{spool_fh}, $img->{spool_path}) };
- return $err_discard->(510 => $@) if $@;
- }
-
- # save gpic in database
- # 1) in case of all disk uploads, this only saves gpic row
- # 2) in case of mogilefs uploads not via receipt, this gives
- # them a key and makes them permanent
- # 3) in case of mogilefs uploads via receipt, this only saves
- # gpic row since mogilefs file already has a key (was renamed above)
- eval { $gpic->save('remote' => $u) };
- return $err_discard->(510 => $@) if $@;
- }
-
- # now need to clean up any receipt tempfiles that have now been made into
- # permanent gpics
- # -- but don't need to do this if it was a mogilefs TempFile, since
- # we did a rename and there's nothing to delete. 'twould be redundant
- if ($img->{pclustertype} ne 'mogilefs' &&
- $img->{_from_rcpt} && $img->{_rcpt_pathkey}) {
-
- FB::clean_receipt_tempfile($img->{pclustertype}, $img->{_rcpt_pathkey})
- or return $err->(500 => FB::last_error());
- }
-
+ # now need to clean up any receipt tempfiles that have now been made into
+ # permanent gpics
+ # -- but don't need to do this if it was a mogilefs TempFile, since
+ # we did a rename and there's nothing to delete. 'twould be redundant
+ if ($img->{pclustertype} ne 'mogilefs' &&
+ $img->{_from_rcpt} && $img->{_rcpt_pathkey}) {
+ FB::clean_receipt_tempfile($img->{pclustertype}, $img->{_rcpt_pathkey})
+ or return $err->(500 => FB::last_error());
}
# definitely have a $gpic now, either from above or from an existing receipt
- return $err->(510) unless $gpic; # should never happen, but be safe
+ return $err->(510) unless $content; # should never happen, but be safe
- # allocate new upic
- my $pre_existing = 0;
- my $up = FB::Upic->create($u, $gpic->{gpicid},
- secid => $picsec,
- exist_flag => \$pre_existing)
- or return $err->(511 => $@);
+ # upload photo to fotki and create
+ my $upload_res;
+ eval {
+ $upload_res = LJ::Fotki->upload_photo($lj_user, $content, debug => 1);
+ };
+ return $err->(510 => $@) if $@;
- # only need to re-check disk quota if the upic returned wasn't an
- # already existing and accounted for upic
- unless ($pre_existing) {
- # call hook again to check if user has disk space for picture
- # AFTER uploading (rather than try to hold some sort of lock over
- # some indefinite period of time)
- my $Kibfree = FB::run_hook("disk_remaining", $u);
- if (defined $Kibfree && $Kibfree < 0) {
- # need to delete this picture now because apparently two pics
- # were uploading at once.
- $up->delete;
- return $err->(401);
- }
- }
+ my $photo_data = $upload_res->{'photo_data'};
+ my $version = $upload_res->{'api_version'};
- # parse EXIF data from image and store it if necessary
- if ($FB::EXTRACT_EXIF_ON_UPLOAD && $up->fmtid == FB::fmtid_from_ext('jpg')) {
- $up->exif_header($gpic->data)
- or return $err->(511 => "Couldn't extract EXIF Header" => FB::last_error());
- }
+ # add photo to all necessary albums
+ my $photo;
+ foreach my $album (@albums) {
+ $photo = LJ::Fotki::Photo->create(userid => $lj_userid, album_id => $album->album_id, photo_data => $photo_data, version => $version, security => $security, allowmask => $allowmask);
+ return $err->(513 => 'Error adding photo to album '.$album->album_id) unless $photo;
+ # Meta information
+ # -- existence vs definition checked at top
+ if (defined $vars->{Meta}) {
+ my $meta = $vars->{Meta};
- # auto-rotate picture
- {
- my $handle_dup = sub {
- my $exist_upicid = shift;
- # delete the one we'd been working with,
- # and keep working with the original one
- $up->delete;
- $up = FB::Upic->new($u, $exist_upicid);
- };
- $up->add_event_listener("set_gpic_failed_dup", $handle_dup);
- $up->autorotate;
- $up->remove_event_listener("set_gpic_failed_dup", $handle_dup);
- }
+ # set photo title
+ if (defined $meta->{Title}) {
+ $photo->set_title($meta->{Title}) or return $err->(511 => "Couldn't set title prop");
+ }
-
- if (! $FB::NO_UPLOAD_PRESCALING && ($gpic->{width} > 640 || $gpic->{height} > 640)) {
- # load the scaled version, creating unless necessary... just to make sure it's there
- eval { $gpic->load_scaled(640, 640, { create => 1 }) };
- return $err->(510 => [ "Unable to scale Gpic" => $@ ]) if $@;
- }
-
- # add to galleries
- foreach my $gal (@gals) {
- $gal->add_picture($up)
- or return $err->(513 => FB::last_error());
- }
-
- # Meta information
- # -- existence vs definition checked at top
- if (defined $vars->{Meta}) {
- my $meta = $vars->{Meta};
-
- # set upc props if they're present
- foreach ([Filename => 'filename'], [Title => 'pictitle']) {
- my $val = $meta->{$_->[0]};
- next unless defined $val;
- $up->set_text_prop($_->[1] => $val)
- or return $err->(511 => "Couldn't set $_->[0] prop");
+ # set photo description
+ if (defined $meta->{Description}) {
+ $photo->set_desc($meta->{Description}) or return $err->(511 => "Couldn't set Description");
+ }
}
-
- # set picture description if it's present
- if (defined $meta->{Description}) {
- $up->set_des($meta->{Description})
- or return $err->(511 => [ "Couldn't set Description" => FB::last_error() ]);
- }
}
+ # return the last returned photo_id
# register return value with parent Request
$resp->add_method_vars(
UploadPic => {
- PicID => [ $up->id ],
- URL => [ $up->url_full ],
- Width => [ $up->width ],
- Height => [ $up->height ],
- Bytes => [ $up->bytes ],
+ PicID => [ $photo->photo_id ],
+ URL => [ $photo->orig_url ],
+ Width => [ $photo->orig_width ],
+ Height => [ $photo->orig_height ],
+ Bytes => [ $length ],
});
return 1;
Added: trunk/lib/FB/Protocol/Fotki/UploadPrepare.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/UploadPrepare.pm (rev 0)
+++ trunk/lib/FB/Protocol/Fotki/UploadPrepare.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -0,0 +1,108 @@
+#!/usr/bin/perl
+
+package FB::Protocol::Fotki::UploadPrepare;
+
+use FB::Protocol::Fotki;
+
+use strict;
+
+use LJ::Fotki::UserSpace;
+
+sub handler {
+ my $resp = shift or return undef;
+ my $req = $resp->{req};
+ my $vars = $req->{vars}->{UploadPrepare};
+ my $u = $resp->{u};
+
+ my $err = sub {
+ $resp->add_method_error(UploadPrepare => @_);
+ return undef;
+ };
+
+ my $lj_userid = FB::get_domain_userid($u);
+ my $lj_user = LJ::load_userid($lj_userid);
+
+ return $err->(212 => "Pic") unless exists $vars->{Pic};
+
+ my $picarr = $vars->{Pic};
+ return $err->(211 => "Pic") unless ref $picarr eq 'ARRAY';
+
+ my $ret = {};
+
+# Get available space for the user
+ my $spaces = LJ::Fotki::UserSpace->get_spaces($lj_user);
+
+ if (ref $spaces eq 'ARRAY') {
+ my $free_space = $spaces->[3] - $spaces->[0];
+ $free_space = 0 if $free_space < 0;
+ $ret->{Quota} = {
+ Total => [ $spaces->[3] ], # kb -> bytes
+ Used => [ $spaces->[0] ],
+ Remaining => [ $free_space ],
+ };
+ }
+
+ PIC:
+ foreach my $pic (@$picarr) {
+
+ # default values to return, override later
+ my $picret = {
+ MD5 => [ $pic->{MD5} ],
+ known => 0,
+ };
+
+ # err subref, notes error in $picret and goes to next PIC in array
+ my $picerr = sub {
+
+ $picret->{Error} = {
+ code => $_[0],
+ content => $resp->error_msg(@_),
+ };
+
+ # add to final return structure
+ push @{$ret->{Pic}}, $picret;
+
+ next PIC;
+ };
+
+ # check existence of required vars
+ foreach (qw(Size MD5 Magic)) {
+ $picerr->(212 => $_) unless exists $pic->{$_};
+ }
+
+ # validate Size argument
+ my $size = $pic->{Size};
+ $picerr->(211 => "Size")
+ unless $size =~ /^\d+$/ && $size > 0;
+
+ # valid MD5 argument
+ my $md5 = $pic->{MD5};
+ $picerr->(211 => "MD5")
+ unless $md5 =~ /^[a-f0-9]{32}$/;
+
+ # validate Magic argument
+ my $magic = $pic->{Magic};
+ $picerr->(211 => "Magic")
+ unless $magic =~ /^[a-f0-9]{20}$/;
+
+ my $fmtid = FB::fmtid_from_magic(FB::hex_to_bin($magic))
+ or $picerr->(211 => [ "Magic" => "Invalid Image Format" ]);
+
+ return $err->(213 => "Format doesn't supported")
+ unless FB::Protocol::Fotki->accepted_fmtid($fmtid);
+
+ ### everything's validated now, make a response
+
+ ### nothing to do due to we don't store md5 sums of photos
+
+ # add to final return structure
+ push @{$ret->{Pic}}, $picret;
+ }
+
+ # register return value with parent Request
+ $resp->add_method_vars(UploadPrepare => $ret);
+
+ return 1;
+}
+
+1;
Added: trunk/lib/FB/Protocol/Fotki/UploadTempFile.pm
===================================================================
--- trunk/lib/FB/Protocol/Fotki/UploadTempFile.pm (rev 0)
+++ trunk/lib/FB/Protocol/Fotki/UploadTempFile.pm 2011-11-30 18:37:38 UTC (rev 1456)
@@ -0,0 +1,136 @@
+#!/usr/bin/perl
+
+package FB::Protocol::Fotki::UploadTempFile;
+
+use FB::Protocol::Fotki;
+
+use strict;
+use LJ::Fotki::UserSpace;
+
+sub handler {
+ my $resp = shift or return undef;
+ my $req = $resp->{req};
+ my $vars = $req->{vars}->{UploadTempFile};
+
+ my $u = $resp->{u};
+
+ my $err = sub {
+ $resp->add_method_error(UploadTempFile => @_);
+ return undef;
+ };
+
+ my $lj_userid = FB::get_domain_userid($u);
+ my $lj_user = LJ::load_userid($lj_userid);
+
+ # is the user allowed to upload?
+ return $err->(303)
+ unless FB::get_cap($u, 'can_upload') && $u->{statusvis} eq 'V';
+
+ # did they specify an ImageData variable?
+ my $img = $vars->{ImageData};
+ return $err->(212 => "ImageData")
+ unless $img;
+
+ # valid pclustertype / pclusterid
+ return $err->(500 => "Could not determine pclustertype/id")
+ unless $img->{pclustertype} && $img->{pclusterid};
+
+ # did we count bytes?
+ return $err->(213 => "No data sent")
+ unless $img->{bytes};
+
+ # check the declared imagelength
+ return $err->(212 => "ImageLength")
+ unless exists $vars->{ImageLength};
+
+ my $length = $vars->{ImageLength};
+ return $err->(211 => "ImageLength")
+ unless defined $length;
+ return $err->(211 => "ImageLength does not match data length")
+ unless $length == $img->{bytes};
+
+ # check that it's a valid fmtid
+ my $fmtid = $img->{fmtid};
+ return $err->(213 => "Unknown format")
+ unless $fmtid;
+
+
+ return $err->(213 => "Format doesn't supported")
+ unless FB::Protocol::Fotki->accepted_fmtid($fmtid);
+
+
+ # valid filehandle -- can't count on path
+ return $err->(500 => "No spool filehandle")
+ unless $img->{spool_fh};
+
+ # valid md5 sum?
+ return $err->(500 => "Could not calculate MD5 sum")
+ unless $img->{md5sum};
+
+ # if an md5 is supplied, check that it matches the image's actual
+ # calculated md5
+ my $md5_hex = FB::bin_to_hex($img->{md5sum});
+ if ($vars->{MD5} && $vars->{MD5} ne ...
(truncated) 