From de82eb87929ac99227b5498724be207c25f0e734 Mon Sep 17 00:00:00 2001 From: mrilyew <99399973+mrilyew@users.noreply.github.com> Date: Fri, 27 Dec 2024 17:35:38 +0300 Subject: [PATCH] create document entity --- VKAPI/Handlers/Docs.php | 91 +++++++++ Web/Models/Entities/Document.php | 205 ++++++++++++++++++++ Web/Models/Repositories/Documents.php | 69 +++++++ Web/Presenters/DocumentsPresenter.php | 19 ++ Web/Presenters/templates/Documents/List.xml | 11 ++ Web/di.yml | 2 + Web/routes.yml | 4 + install/sqls/00054-docs.sql | 28 +++ 8 files changed, 429 insertions(+) create mode 100644 VKAPI/Handlers/Docs.php create mode 100644 Web/Models/Entities/Document.php create mode 100644 Web/Models/Repositories/Documents.php create mode 100644 Web/Presenters/DocumentsPresenter.php create mode 100644 Web/Presenters/templates/Documents/List.xml create mode 100644 install/sqls/00054-docs.sql diff --git a/VKAPI/Handlers/Docs.php b/VKAPI/Handlers/Docs.php new file mode 100644 index 00000000..a7abc842 --- /dev/null +++ b/VKAPI/Handlers/Docs.php @@ -0,0 +1,91 @@ +requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function delete(int $owner_id, int $doc_id): int + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function restore(int $owner_id, int $doc_id): int + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function edit(int $owner_id, int $doc_id, ?string $title, ?string $tags, ?int $folder_id): int + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function get(int $count = 30, int $offset = 0, int $type = 0, int $owner_id = NULL, int $return_tags = 0): int + { + $this->requireUser(); + + return 0; + } + + function getById(string $docs, int $return_tags = 0): int + { + $this->requireUser(); + + return 0; + } + + function getTypes(?int $owner_id) + { + $this->requireUser(); + + return []; + } + + function getUploadServer(?int $group_id = NULL) + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function getWallUploadServer(?int $group_id = NULL) + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function save(string $file, string $title, string $tags, ?int $return_tags = 0) + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + return 0; + } + + function search(string $q, int $search_own = 0, int $count = 30, int $offset = 0, int $return_tags = 0, int $type = 0, ?string $tags = NULL): object + { + $this->requireUser(); + + return 0; + } +} diff --git a/Web/Models/Entities/Document.php b/Web/Models/Entities/Document.php new file mode 100644 index 00000000..4a3fdc42 --- /dev/null +++ b/Web/Models/Entities/Document.php @@ -0,0 +1,205 @@ +getBaseDir() . substr($hash, 0, 2); + if(!is_dir($dir)) + mkdir($dir); + + return "$dir/$hash." . $this->getFileExtension(); + } + + protected function saveFile(string $filename, string $hash): bool + { + + return true; + } + + function getURL(): string + { + $hash = $this->getRecord()->hash; + $filetype = $this->getFileExtension(); + + switch(OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["mode"]) { + default: + case "default": + case "basic": + return "http://" . $_SERVER['HTTP_HOST'] . "/blob_" . substr($hash, 0, 2) . "/$hash.$filetype"; + break; + case "accelerated": + return "http://" . $_SERVER['HTTP_HOST'] . "/openvk-datastore/$hash.$filetype"; + break; + case "server": + $settings = (object) OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["server"]; + return ( + $settings->protocol ?? ovk_scheme() . + "://" . $settings->host . + $settings->path . + substr($hash, 0, 2) . "/$hash.$filetype" + ); + break; + } + } + + function hasPreview(): bool + { + return $this->getRecord()->preview != NULL; + } + + function isOwnerHidden(): bool + { + return (bool) $this->getRecord()->owner_hidden; + } + + function isCopy(): bool + { + return $this->getRecord()->copy_of != NULL; + } + + function isLicensed(): bool + { + return false; + } + + function isUnsafe(): bool + { + return false; + } + + function getFileExtension(): string + { + return $this->getRecord()->format; + } + + function getPrettyId(): string + { + return $this->getVirtualId() . "_" . $this->getId(); + } + + function getOriginal(): Document + { + return $this->getRecord()->copy_of; + } + + function getName(): string + { + return $this->getRecord()->name; + } + + function getOriginalName(): string + { + return $this->getRecord()->original_name; + } + + function getVKAPIType(): int + { + return $this->getRecord()->type; + } + + function getFolder(): int + { + return $this->getRecord()->folder_id; + } + + function getTags(): array + { + return explode(",", $this->getRecord()->tags); + } + + function getFilesize(): int + { + return $this->getRecord()->filesize; + } + + function getPreview(): ?RowModel + { + $preview_array = $this->getRecord()->preview; + $preview = explode(",", $this->getRecord()->preview)[0]; + $model = NULL; + $exploded = explode("_", $preview); + + switch($exploded[0]) { + case "photo": + $model = (new Photos)->get((int)$exploded[1]); + break; + } + + return $model; + } + + function getOwnerID(): int + { + return $this->getRecord()->owner; + } + + function toApiPreview(): object + { + $preview = $this->getPreview(); + if($preview instanceof Photo) { + return (object)[ + "photo" => [ + "sizes" => array_values($preview->getVkApiSizes()), + ], + ]; + } + } + + function canBeModifiedBy(User $user = NULL): bool + { + if(!$user) + return false; + + if($this->getOwnerID() < 0) + return (new Clubs)->get(abs($this->getOwnerID()))->canBeModifiedBy($user); + + return $this->getOwnerID() === $user->getId(); + } + + function toVkApiStruct(?User $user = NULL): object + { + $res = new \stdClass; + $res->id = $this->getId(); + $res->owner_id = $this->getVirtualId(); + $res->title = $this->getName(); + $res->size = $this->getFilesize(); + $res->ext = $this->getFileExtension(); + $res->url = $this->getURL(); + $res->date = $this->getPublicationTime()->timestamp(); + $res->type = $this->getVKAPIType(); + $res->is_licensed = (int) $this->isLicensed(); + $res->is_unsafe = (int) $this->isUnsafe(); + $res->folder_id = (int) $this->getFolder(); + $res->private_url = ""; + if($user) { + $res->can_manage = $this->canBeModifiedBy($user); + } + + if($this->hasPreview()) { + $res->preview = $this->toApiPreview(); + } + + return $res; + } +} diff --git a/Web/Models/Repositories/Documents.php b/Web/Models/Repositories/Documents.php new file mode 100644 index 00000000..a03afb2d --- /dev/null +++ b/Web/Models/Repositories/Documents.php @@ -0,0 +1,69 @@ +context = DatabaseConnection::i()->getContext(); + $this->documents = $this->context->table("documents"); + } + + private function toDocument(?ActiveRow $ar): ?Document + { + return is_null($ar) ? NULL : new Document($ar); + } + + function get(int $id): ?Comment + { + return $this->toDocument($this->documents->get($id)); + } + + # By "Virtual ID" and "Absolute ID" (to not leak owner's id). + function getDocumentById(int $virtual_id, int $real_id, ?string $access_key = NULL): ?Post + { + $doc = $this->documents->where(['virtual_id' => $virtual_id, 'id' => $real_id]); + + if($access_key) { + $doc->where("access_key", $access_key); + } + + $doc = $doc->fetch(); + if(!is_null($doc)) + return new Document($doc); + else + return NULL; + + } + + function find(string $query, array $params = [], array $order = ['type' => 'id', 'invert' => false]): Util\EntityStream + { + $result = $this->documents->where("title LIKE ?", "%$query%")->where("deleted", 0); + $order_str = 'id'; + + switch($order['type']) { + case 'id': + $order_str = 'created ' . ($order['invert'] ? 'ASC' : 'DESC'); + break; + } + + foreach($params as $paramName => $paramValue) { + switch($paramName) { + case "before": + $result->where("created < ?", $paramValue); + break; + } + } + + if($order_str) + $result->order($order_str); + + return new Util\EntityStream("Document", $result); + } +} diff --git a/Web/Presenters/DocumentsPresenter.php b/Web/Presenters/DocumentsPresenter.php new file mode 100644 index 00000000..da39f48d --- /dev/null +++ b/Web/Presenters/DocumentsPresenter.php @@ -0,0 +1,19 @@ +template->_template = "Documents/List.xml"; + } + + function renderListGroup(?int $gid) + { + $this->renderList($gid); + } +} diff --git a/Web/Presenters/templates/Documents/List.xml b/Web/Presenters/templates/Documents/List.xml new file mode 100644 index 00000000..edad9241 --- /dev/null +++ b/Web/Presenters/templates/Documents/List.xml @@ -0,0 +1,11 @@ +{extends "../@layout.xml"} + +{block title} + +{/block} + +{block header}{/block} + +{block content} + загрузить +{/block} diff --git a/Web/di.yml b/Web/di.yml index 81e06117..b9821fec 100644 --- a/Web/di.yml +++ b/Web/di.yml @@ -27,6 +27,7 @@ services: - openvk\Web\Presenters\VKAPIPresenter - openvk\Web\Presenters\PollPresenter - openvk\Web\Presenters\BannedLinkPresenter + - openvk\Web\Presenters\DocumentsPresenter - openvk\Web\Models\Repositories\Users - openvk\Web\Models\Repositories\Posts - openvk\Web\Models\Repositories\Polls @@ -52,5 +53,6 @@ services: - openvk\Web\Models\Repositories\Aliases - openvk\Web\Models\Repositories\BannedLinks - openvk\Web\Models\Repositories\ChandlerGroups + - openvk\Web\Models\Repositories\Documents - openvk\Web\Presenters\MaintenancePresenter - openvk\Web\Presenters\NoSpamPresenter diff --git a/Web/routes.yml b/Web/routes.yml index 7fd0cfe7..f7150670 100644 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -311,6 +311,10 @@ routes: handler: "Poll->view" - url: "/poll{num}/voters" handler: "Poll->voters" + - url: "/docs" + handler: "Documents->list" + - url: "/docs{num}" + handler: "Documents->listGroup" - url: "/admin" handler: "Admin->index" - url: "/admin/users" diff --git a/install/sqls/00054-docs.sql b/install/sqls/00054-docs.sql new file mode 100644 index 00000000..69059b4c --- /dev/null +++ b/install/sqls/00054-docs.sql @@ -0,0 +1,28 @@ +CREATE TABLE `documents` ( + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + `owner` BIGINT(20) UNSIGNED NOT NULL, + `virtual_id` BIGINT(20) UNSIGNED NOT NULL, + `hash` CHAR(128) NOT NULL, + `owner_hidden` TINYINT(1) UNSIGNED NOT NULL DEFAULT '1', + `copy_of` BIGINT(20) UNSIGNED NULL DEFAULT NULL, + `created` BIGINT(20) UNSIGNED NOT NULL, + `edited` BIGINT(20) UNSIGNED NULL DEFAULT NULL, + `name` VARCHAR(256) NOT NULL, + `original_name` VARCHAR(500) NULL DEFAULT NULL, + `access_key` VARCHAR(100) NULL DEFAULT NULL, + `format` VARCHAR(20) NOT NULL DEFAULT 'gif', + `type` TINYINT(10) UNSIGNED NOT NULL DEFAULT '0', + `folder_id` TINYINT(10) UNSIGNED NOT NULL DEFAULT '0', + `preview` VARCHAR(200) NULL DEFAULT NULL, + `tags` VARCHAR(500) NULL DEFAULT NULL, + `filesize` BIGINT(20) UNSIGNED NOT NULL, + `deleted` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `unlisted` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE = InnoDB COLLATE=utf8mb4_unicode_520_ci; + +ALTER TABLE `documents` ADD INDEX (`deleted`); +ALTER TABLE `documents` ADD INDEX (`unlisted`); +ALTER TABLE `documents` ADD INDEX `virtual_id_id` (`virtual_id`, `id`); +ALTER TABLE `documents` ADD INDEX `folder_id` (`folder_id`); +ALTER TABLE `photos` ADD `system` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `anonymous`, ADD `private` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `system`;