Image Endpoint

This commit is contained in:
Kilian Hofmann 2024-07-27 20:43:57 +02:00
parent 5ebdee09d8
commit 42529a66d4
6 changed files with 207 additions and 22 deletions

View File

@ -0,0 +1,57 @@
<?php
namespace Api\Users\Image;
use Exception;
use Khofmann\Api\Api;
use Khofmann\Input\Input;
use Khofmann\Models\User\User;
use Khofmann\Response\Response;
use Khofmann\ApiError\ApiError;
use Khofmann\Request\Request;
class Image extends Api
{
public function post($id): void
{
// Fetch all inputs.
$image = Input::file("image");
$predefined = Input::post("predefined");
// Try and update user image.
// Throw errors according to situation.
try {
Response::json(User::getByID($id)->updateImage($image, $predefined));
} catch (Exception $err) {
switch ($err->getMessage()) {
case "NotFound":
throw ApiError::notFound("user");
default:
// Due to how the failed field is handled, it's ApiError is inside the models update
throw $err;
}
}
}
public function postSelf(): void
{
// Fetch all inputs.
$token = Request::token();
$image = Input::file("image");
$predefined = Input::post("predefined");
// Try and update user image.
// Throw errors according to situation.
try {
Response::json(User::getByToken($token)->updateImage($image, $predefined));
} catch (Exception $err) {
switch ($err->getMessage()) {
case "NotFound":
throw ApiError::notFound("user");
default:
// Due to how the failed field is handled, it's ApiError is inside the models update
throw $err;
}
}
}
}

View File

@ -491,7 +491,7 @@ paths:
$ref: "#/components/schemas/NotFoundResponse"
examples:
User not found:
value: { "code": "NotFound", "entity": "username" }
value: { "code": "NotFound", "entity": "user" }
500:
description: Update failed.
content:
@ -539,6 +539,60 @@ paths:
value: { "code": "NotFound", "entity": "user" }
tags:
- User
/users/{id}/image:
post:
summary: Update user image
description: Update user image with ID. <br>
Use special ID <code>self</code> to update logged in user. <br>
Requires logged in user to have admin permissions for any ID other than <code>self</code>.
security:
- BasicAuth: []
- BasicAuth: [isAdmin]
parameters:
- name: id
in: path
description: User ID
required: true
schema:
type: integer
format: int14
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/UserImageUpdateRequest"
responses:
200:
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/UserResponse"
404:
description: User not found.
content:
application/json:
schema:
$ref: "#/components/schemas/NotFoundResponse"
examples:
User not found:
value: { "code": "NotFound", "entity": "user" }
500:
description: Update failed.
content:
application/json:
schema:
$ref: "#/components/schemas/FailedUpdateResponse"
examples:
Failed username:
value:
{
"code": "FailedUpdate",
"fields": ["image", "predefined"],
"reasons": ["string", "string"],
}
tags:
- User
externalDocs:
url: https://khofmann.userpage.fu-berlin.de/phpCourse/exam/api/docs/
@ -658,6 +712,14 @@ components:
type: string
email:
type: string
UserImageUpdateRequest:
type: object
properties:
image:
type: string
format: binary
predefined:
type: string
RegisterRequest:
type: object
required:

File diff suppressed because one or more lines are too long

View File

@ -31,6 +31,6 @@ class Input
public static function file(string $index, $defaultValue = null)
{
$value = Request::request()->getInputHandler()->file($index, $defaultValue);
return !is_object($value) ? $value : $value->getValue();
return $value;
}
}

View File

@ -319,9 +319,6 @@ class User implements JsonSerializable
}
if (!empty($email)) {
// $destinationFilename = sprintf('%s.%s', uniqid(), $image->getExtension());
// $image->move(Config::getStoragePath() . "profilbilder/$destinationFilename");
$stmt = $db->prepare("UPDATE egb_benutzer SET email = :EMA WHERE id = :ID");
$stmt->bindValue(":EMA", $email);
$stmt->bindValue(":ID", $this->id);
@ -339,6 +336,76 @@ class User implements JsonSerializable
} else array_push($reasons, "{$e->getCode()}");
}
}
if (count($failed) > 0) {
$db->rollBack();
throw ApiError::failedUpdate($failed, $reasons);
}
$db->commit();
return User::getByID($this->id);
}
public function updateImage($image, ?string $predefined): User
{
$db = Database::getInstance();
$db->beginTransaction();
$failed = [];
$reasons = [];
try {
$stmt = $db->prepare("SELECT image FROM egb_benutzer WHERE id = :ID");
$stmt->bindValue(":ID", $this->id);
$stmt->execute();
$oldImage = $stmt->fetch(PDO::FETCH_COLUMN, 0);
if (strpos($oldImage, "default") === false) unlink(Config::getStoragePath() . $oldImage);
} catch (Exception $e) {
}
if (!empty($image)) {
$destinationFilename = sprintf('%s.%s', uniqid(), $image->getExtension());
$image->move(Config::getStoragePath() . "profilbilder/$destinationFilename");
try {
$stmt = $db->prepare("UPDATE egb_benutzer SET image = :IMG WHERE id = :ID");
$stmt->bindValue(":IMG", "profilbilder/$destinationFilename");
$stmt->bindValue(":ID", $this->id);
if (!$stmt->execute()) {
array_push($failed, "image");
array_push($reasons, "generic");
}
} catch (Exception $e) {
array_push($failed, "image");
if ($e->getCode() === "23000") {
$pdoErr = $stmt->errorInfo()[1];
if ($pdoErr === 1062) array_push($reasons, "Duplicate");
else array_push($reasons, "SQL: $pdoErr");
} else array_push($reasons, "{$e->getCode()}");
}
} else if (!empty($predefined)) {
$stmt = $db->prepare("UPDATE egb_benutzer SET image = :IMG WHERE id = :ID");
$stmt->bindValue(":IMG", "profilbilder/default/$predefined.svg");
$stmt->bindValue(":ID", $this->id);
try {
if (!$stmt->execute()) {
array_push($failed, "image");
array_push($reasons, "generic");
}
} catch (Exception $e) {
array_push($failed, "image");
if ($e->getCode() === "23000") {
$pdoErr = $stmt->errorInfo()[1];
if ($pdoErr === 1062) array_push($reasons, "Duplicate");
else array_push($reasons, "SQL: $pdoErr");
} else array_push($reasons, "{$e->getCode()}");
}
}
if (count($failed) > 0) {
$db->rollBack();

View File

@ -58,20 +58,7 @@ SimpleRouter::group(["middleware" => Khofmann\Auth\Auth::class], function () {
// Update self
SimpleRouter::patch("/users/self", [Api\Users\Users::class, "patchSelf"]);
// Update image self
SimpleRouter::post("/users/self/image", function () {
Response::response()
->header("Cache-control: no-cache")
->header("Access-Control-Allow-Origin: *")
->header("Access-Control-Allow-Methods: *")
->header("Access-Control-Allow-Headers: *");
echo "<pre>";
print_r(RequestRequest::request()->getInputHandler());
echo "</pre>";
$pre = Input::post("predefined");
echo $pre;
echo "\n";
echo Input::file("image");
}); //[Api\Users\Users::class, "patchImageSelf"]);
SimpleRouter::post("/users/self/image", [Api\Users\Image\Image::class, "postSelf"]);
// Update post
SimpleRouter::patch("/posts/{id}", [Api\Posts\Posts::class, "patch"]);
// Create post
@ -87,6 +74,8 @@ SimpleRouter::group(["middleware" => Khofmann\Auth\AdminAuth::class], function (
SimpleRouter::get("/users", [Api\Users\Users::class, "list"]);
// Update user
SimpleRouter::patch("/users/{id}", [Api\Users\Users::class, "patch"]);
// Update image
SimpleRouter::post("/users/{id}/image", [Api\Users\Image\Image::class, "post"]);
// Delete user
SimpleRouter::delete("/users/{id}", [Api\Users\Users::class, "delete"]);
// Delete post