Skip to content

Commit

Permalink
Add photos.save, photos.saveWallPhoto, photos.saveOwnerPhoto, photos.…
Browse files Browse the repository at this point in the history
…getUploadServer

Didn't test, but shouldn't be really tough to fix afterwards if it'll break.
  • Loading branch information
celestora committed Mar 29, 2022
1 parent f7a2da2 commit 1a2a080
Show file tree
Hide file tree
Showing 10 changed files with 367 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ update.pid.old
Web/static/js/node_modules

tmp/*
!tmp/.gitkeep
!tmp/api-storage
!tmp/themepack_artifacts/.gitkeep
themepacks/*
!themepacks/.gitkeep
Expand Down
230 changes: 230 additions & 0 deletions VKAPI/Handlers/Photos.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
<?php declare(strict_types=1);
namespace openvk\VKAPI\Handlers;

use Nette\InvalidStateException;
use Nette\Utils\ImageException;
use openvk\Web\Models\Entities\Photo;
use openvk\Web\Models\Repositories\Albums;
use openvk\Web\Models\Repositories\Clubs;

final class Photos extends VKAPIRequestHandler
{
private function getPhotoUploadUrl(string $field, int $group = 0, bool $multifile = false): string
{
$secret = CHANDLER_ROOT_CONF["security"]["secret"];
$uploadInfo = [
1,
$field,
(int) $multifile,
0,
time(),
$this->getUser()->getId(),
$group,
0, # this is unused but stays here base64 reasons (X2 doesn't work, so there's dummy value for short)
];
$uploadInfo = pack("vZ10v2P3S", ...$uploadInfo);
$uploadInfo = base64_encode($uploadInfo);
$uploadHash = hash_hmac("sha3-224", $uploadInfo, $secret);
$uploadInfo = rawurlencode($uploadInfo);

return ovk_scheme(true) . $_SERVER["HTTP_HOST"] . "/upload/photo/$uploadHash?$uploadInfo";
}

private function getImagePath(string $photo, string $hash, ?string& $up = NULL, ?string& $group = NULL): string
{
$secret = CHANDLER_ROOT_CONF["security"]["secret"];
if(!hash_equals(hash_hmac("sha3-224", $photo, $secret), $hash))
$this->fail(121, "Incorrect hash");

[$up, $image, $group] = explode("|", $photo);

$imagePath = __DIR__ . "/../../tmp/api-storage/photos/$up" . "_$image.oct";
if(!file_exists($imagePath))
$this->fail(10, "Invalid image");

return $imagePath;
}

function getOwnerPhotoUploadServer(int $owner_id = 0): object
{
$this->requireUser();

if($owner_id < 0) {
$club = (new Clubs)->get(abs($owner_id));
if(!$club)
$this->fail(0404, "Club not found");
else if(!$club->canBeModifiedBy($this->getUser()))
$this->fail(200, "Access: Club can't be 'written' by user");
}

return (object) [
"upload_url" => $this->getPhotoUploadUrl("photo", isset($club) ? 0 : $club->getId()),
];
}

function saveOwnerPhoto(string $photo, string $hash): object
{
$imagePath = $this->getImagePath($photo, $hash, $uploader, $group);
if($group == 0) {
$user = (new \openvk\Web\Models\Repositories\Users)->get((int) $uploader);
$album = (new Albums)->getUserAvatarAlbum($user);
} else {
$club = (new Clubs)->get((int) $group);
$album = (new Albums)->getClubAvatarAlbum($club);
}

try {
$avatar = new Photo;
$avatar->setOwner((int) $uploader);
$avatar->setDescription("Profile photo");
$avatar->setCreated(time());
$avatar->setFile([
"tmp_name" => $imagePath,
"error" => 0,
]);
$avatar->save();
$album->addPhoto($avatar);
unlink($imagePath);
} catch(ImageException | InvalidStateException $e) {
unlink($imagePath);
$this->fail(129, "Invalid image file");
}

return (object) [
"photo_hash" => NULL,
"photo_src" => $avatar->getURL(),
];
}

function getWallUploadServer(?int $group_id = NULL): object
{
$this->requireUser();

$album = NULL;
if(!is_null($group_id)) {
$club = (new Clubs)->get(abs($group_id));
if(!$club)
$this->fail(0404, "Club not found");
else if(!$club->canBeModifiedBy($this->getUser()))
$this->fail(200, "Access: Club can't be 'written' by user");
} else {
$album = (new Albums)->getUserWallAlbum($this->getUser());
}

return (object) [
"upload_url" => $this->getPhotoUploadUrl("photo", $group_id ?? 0),
"album_id" => $album,
"user_id" => $this->getUser()->getId(),
];
}

function saveWallPhoto(string $photo, string $hash, int $group_id = 0, ?string $caption = NULL): array
{
$imagePath = $this->getImagePath($photo, $hash, $uploader, $group);
if($group_id != $group)
$this->fail(8, "group_id doesn't match");

$album = NULL;
if($group_id != 0) {
$uploader = (new \openvk\Web\Models\Repositories\Users)->get((int) $uploader);
$album = (new Albums)->getUserWallAlbum($uploader);
}

try {
$photo = new Photo;
$photo->setOwner((int) $uploader);
$photo->setCreated(time());
$photo->setFile([
"tmp_name" => $imagePath,
"error" => 0,
]);

if (!is_null($caption))
$photo->setDescription($caption);

$photo->save();
unlink($imagePath);
} catch(ImageException | InvalidStateException $e) {
unlink($imagePath);
$this->fail(129, "Invalid image file");
}

if(!is_null($album))
$album->addPhoto($photo);

return [
$photo->toVkApiStruct(),
];
}

function getUploadServer(?int $album_id = NULL): object
{
$this->requireUser();

# Not checking rights to album because save() method will do so anyways
return (object) [
"upload_url" => $this->getPhotoUploadUrl("photo", 0, true),
"album_id" => $album_id,
"user_id" => $this->getUser()->getId(),
];
}

function save(string $photos_list, string $hash, int $album_id = 0, ?string $caption = NULL): object
{
$this->requireUser();

$secret = CHANDLER_ROOT_CONF["security"]["secret"];
if(!hash_equals(hash_hmac("sha3-224", $photos_list, $secret), $hash))
$this->fail(121, "Incorrect hash");

$album = NULL;
if($album_id != 0) {
$album_ = (new Albums)->get($album_id);
if(!$album_)
$this->fail(0404, "Invalid album");
else if(!$album_->canBeModifiedBy($this->getUser()))
$this->fail(15, "Access: Album can't be 'written' by user");

$album = $album_;
}

$pList = json_decode($photos_list);
$imagePaths = [];
foreach($pList as $pDesc)
$imagePaths[] = __DIR__ . "/../../tmp/api-storage/photos/$pDesc->keyholder" . "_$pDesc->resource.oct";

$images = [];
try {
foreach($imagePaths as $imagePath) {
$photo = new Photo;
$photo->setOwner($this->getUser()->getId());
$photo->setCreated(time());
$photo->setFile([
"tmp_name" => $imagePath,
"error" => 0,
]);

if (!is_null($caption))
$photo->setDescription($caption);

$photo->save();
unlink($imagePath);

if(!is_null($album))
$album->addPhoto($photo);

$images[] = $photo->toVkApiStruct();
}
} catch(ImageException | InvalidStateException $e) {
foreach($imagePaths as $imagePath)
unlink($imagePath);

$this->fail(129, "Invalid image file");
}

return (object) [
"count" => sizeof($images),
"items" => $images,
];
}
}
64 changes: 45 additions & 19 deletions Web/Models/Entities/Photo.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Photo extends Media
protected $fileExtension = "jpeg";

const ALLOWED_SIDE_MULTIPLIER = 7;

protected function saveFile(string $filename, string $hash): bool
{
$image = Image::fromFile($filename);
Expand All @@ -24,7 +24,7 @@ protected function saveFile(string $filename, string $hash): bool
return true;
}

function crop(real $left, real $top, real $width, real $height): bool
function crop(real $left, real $top, real $width, real $height): void
{
if(isset($this->changes["hash"]))
$hash = $this->changes["hash"];
Expand All @@ -35,7 +35,7 @@ function crop(real $left, real $top, real $width, real $height): bool

$image = Image::fromFile($this->pathFromHash($hash));
$image->crop($left, $top, $width, $height);
return $image->save($this->pathFromHash($hash));
$image->save($this->pathFromHash($hash));
}

function isolate(): void
Expand All @@ -45,8 +45,46 @@ function isolate(): void

DB::i()->getContext()->table("album_relations")->where("media", $this->getRecord()->id)->delete();
}

static function fastMake(int $owner, string $description = "", array $file, ?Album $album = NULL, bool $anon = false): Photo

function getDimensions(): array
{
$hash = $this->getRecord()->hash;

return array_slice(getimagesize($this->pathFromHash($hash)), 0, 2);
}

function getDimentions(): array
{
trigger_error("getDimentions is deprecated, use Photo::getDimensions instead.");

return $this->getDimensions();
}

function getAlbum(): ?Album
{
return (new Albums)->getAlbumByPhotoId($this);
}

function toVkApiStruct(): object
{
$res = (object) [];

$res->id = $res->pid = $this->getId();
$res->owner_id = $res->user_id = $this->getOwner()->getId()->getId();
$res->aid = $res->album_id = NULL;
$res->width = $this->getDimensions()[0];
$res->height = $this->getDimensions()[1];
$res->date = $res->created = $this->getPublicationTime()->timestamp();

$res->src =
$res->src_small = $res->src_big = $res->src_xbig = $res->src_xxbig =
$res->src_xxxbig = $res->photo_75 = $res->photo_130 = $res->photo_604 =
$res->photo_807 = $res->photo_1280 = $res->photo_2560 = $this->getURL();

return $res;
}

static function fastMake(int $owner, array $file, string $description = "", ?Album $album = NULL, bool $anon = false): Photo
{
$photo = new static;
$photo->setOwner($owner);
Expand All @@ -55,22 +93,10 @@ static function fastMake(int $owner, string $description = "", array $file, ?Alb
$photo->setCreated(time());
$photo->setFile($file);
$photo->save();

if(!is_null($album))
$album->addPhoto($photo);

return $photo;
}

function getDimentions()
{
$hash = $this->getRecord()->hash;

return getimagesize($this->pathFromHash($hash));
}

function getAlbum(): ?Album
{
return (new Albums)->getAlbumByPhotoId($this);
return $photo;
}
}
1 change: 0 additions & 1 deletion Web/Presenters/UserPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ function renderSetAvatar(): void
$photo->setCreated(time());
$photo->save();
} catch(ISE $ex) {
$name = $album->getName();
$this->flashFail("err", tr("error"), tr("error_upload_failed"));
}

Expand Down
Loading

0 comments on commit 1a2a080

Please sign in to comment.