This commit is contained in:
lalka2016 2023-09-09 22:48:01 +03:00
parent 245f8690c6
commit dd37321d42
6 changed files with 229 additions and 53 deletions

View file

@ -221,39 +221,71 @@ final class PhotosPresenter extends OpenVKPresenter
function renderUploadPhoto(): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$this->willExecuteWriteAction(true);
if(is_null($this->queryParam("album")))
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>DELETED</b>.");
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>DELETED</b>.", 500, true);
[$owner, $id] = explode("_", $this->queryParam("album"));
$album = $this->albums->get((int) $id);
if(!$album)
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>DELETED</b>.");
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>DELETED</b>.", 500, true);
if(is_null($this->user) || !$album->canBeModifiedBy($this->user->identity))
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.", 500, true);
if($_SERVER["REQUEST_METHOD"] === "POST") {
if(!isset($_FILES["blob"]))
$this->flashFail("err", "Нету фотографии", "Выберите файл.");
try {
$photo = new Photo;
$photo->setOwner($this->user->id);
$photo->setDescription($this->postParam("desc"));
$photo->setFile($_FILES["blob"]);
$photo->setCreated(time());
$photo->save();
} catch(ISE $ex) {
$name = $album->getName();
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>$name</b>.");
}
$album->addPhoto($photo);
$album->setEdited(time());
$album->save();
if($this->queryParam("act") == "finish") {
$result = json_decode($this->postParam("photos"), true);
foreach($result as $photoId => $description) {
$phot = $this->photos->get($photoId);
$this->redirect("/photo" . $photo->getPrettyId() . "?from=album" . $album->getId());
if(!$phot || $phot->isDeleted() || $phot->getOwner()->getId() != $this->user->id)
continue;
$phot->setDescription($description);
$phot->save();
$album = $phot->getAlbum();
}
$this->returnJson(["success" => true,
"album" => $album->getId(),
"owner" => $album->getOwner() instanceof User ? $album->getOwner()->getId() : $album->getOwner()->getId() * -1]);
}
if(!isset($_FILES))
$this->flashFail("err", "Нету фотографии", "Выберите файл.", 500, true);
$photos = [];
for($i = 0; $i < $this->postParam("count"); $i++) {
try {
$photo = new Photo;
$photo->setOwner($this->user->id);
$photo->setDescription("");
$photo->setFile($_FILES["photo_".$i]);
$photo->setCreated(time());
$photo->save();
$photos[] = [
"url" => $photo->getURLBySizeId("tiny"),
"id" => $photo->getId(),
"vid" => $photo->getVirtualId(),
"owner" => $photo->getOwner()->getId(),
"link" => $photo->getURL()
];
} catch(ISE $ex) {
$name = $album->getName();
$this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию в <b>$name</b>.", 500, true);
}
$album->addPhoto($photo);
$album->setEdited(time());
$album->save();
}
$this->returnJson(["success" => true,
"photos" => $photos]);
} else {
$this->template->album = $album;
}
@ -285,7 +317,7 @@ final class PhotosPresenter extends OpenVKPresenter
function renderDeletePhoto(int $ownerId, int $photoId): void
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
$this->willExecuteWriteAction($_SERVER["REQUEST_METHOD"] === "POST");
$this->assertNoCSRF();
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
@ -298,6 +330,9 @@ final class PhotosPresenter extends OpenVKPresenter
$photo->isolate();
$photo->delete();
if($_SERVER["REQUEST_METHOD"] === "POST")
$this->returnJson(["success" => true]);
$this->flash("succ", "Фотография удалена", "Эта фотография была успешно удалена.");
$this->redirect($redirect);
}

View file

@ -12,32 +12,22 @@
{/block}
{block content}
<form action="/photos/upload?album={$album->getPrettyId()}" method="post" enctype="multipart/form-data">
<table cellspacing="6">
<tbody>
<tr>
<td width="120" valign="top"><span class="nobold">{_description}:</span></td>
<td><textarea style="margin: 0px; height: 50px; width: 159px; resize: none;" name="desc"></textarea></td>
</tr>
<tr>
<td width="120" valign="top"><span class="nobold">{_photo}:</span></td>
<td>
<label class="button" style="">{_browse}
<input type="file" id="blob" name="blob" style="display: none;" onchange="filename.innerHTML=blob.files[0].name" />
</label>
<div id="filename" style="margin-top: 10px;"></div>
</td>
</tr>
<tr>
<td width="120" valign="top"></td>
<td>
<input type="hidden" name="hash" value="{$csrfToken}" />
<input type="submit" class="button" name="submit" value="Загрузить" />
</td>
</tr>
</tbody>
</table>
<input n:ifset="$_GET['album']" type="hidden" name="album" value="{$_GET['album']}" />
</form>
<div class="uploadPhotos">
<input type="file" accept=".jpg,.png,.gif" name="files[]" multiple class="button" id="uploadButton" style="display:none">
<input type="button" class="button" onclick="uploadButton.click()" value="{_upload_picts}">
</div>
<table style="border-spacing: 6px 10px;">
<tbody id="photos"></tbody>
</table>
<input n:ifset="$_GET['album']" type="hidden" id="album" value="{$_GET['album']}" />
<input type="button" class="button" style="display:none;" id="endUploading" value="{_end_uploading}">
<script>
uploadButton.value = ''
</script>
{/block}
{block bodyScripts}
{script "js/al_photos.js"}
{/block}

View file

@ -2700,4 +2700,19 @@ body.article .floating_sidebar, body.article .page_content {
position: absolute;
right: 22px;
font-size: 12px;
}
}
.uploadedImage img {
max-height: 76px;
object-fit: cover;
}
.lagged {
filter: opacity(0.5);
cursor: progress;
user-select: none;
}
.lagged * {
pointer-events: none;
}

120
Web/static/js/al_photos.js Normal file
View file

@ -0,0 +1,120 @@
$(document).on("change", "#uploadButton", (e) => {
let iterator = 0
if(e.currentTarget.files.length > 10) {
MessageBox(tr("error"), tr("too_many_pictures"), [tr("ok")], [() => {Function.noop}])
return;
}
let photos = new FormData()
for(file of e.currentTarget.files) {
photos.append("photo_"+iterator, file)
iterator += 1
}
photos.append("count", e.currentTarget.files.length)
photos.append("hash", u("meta[name=csrf]").attr("value"))
let xhr = new XMLHttpRequest()
xhr.open("POST", "/photos/upload?album="+document.getElementById("album").value)
xhr.onloadstart = () => {
document.getElementById("photos").insertAdjacentHTML("beforeend", `<img id="loader" src="/assets/packages/static/openvk/img/loading_mini.gif">`)
}
xhr.onload = () => {
let result = JSON.parse(xhr.responseText)
if(result.success) {
u("#loader").remove()
let photosArr = result.photos
for(photo of photosArr) {
let table = document.querySelector("#photos")
table.insertAdjacentHTML("beforeend", `
<tr id="photo" data-id="${photo.id}">
<td width="120" valign="top">
<div class="uploadedImage">
<a href="${photo.link}" target="_blank"><img width="125" src="${photo.url}"></a>
</div>
<a style="float:right" id="deletePhoto" data-id="${photo.vid}" data-owner="${photo.owner}">${tr("delete")}</a>
</td>
<td>
<textarea style="margin: 0px; height: 50px; width: 259px; resize: none;" maxlength="255"></textarea>
</td>
</tr>
`)
}
document.getElementById("endUploading").style.display = "block"
} else {
u("#loader").remove()
MessageBox(tr("error"), result.flash.message ?? tr("error_uploading_photo"), [tr("ok")], [() => {Function.noop}])
}
}
xhr.send(photos)
})
$(document).on("click", "#endUploading", (e) => {
let table = document.querySelector("#photos")
let data = new FormData()
let arr = new Map();
for(el of table.querySelectorAll("tr#photo")) {
arr.set(el.dataset.id, el.querySelector("textarea").value)
}
data.append("photos", JSON.stringify(Object.fromEntries(arr)))
data.append("hash", u("meta[name=csrf]").attr("value"))
let xhr = new XMLHttpRequest()
// в самом вк на каждое изменение описания отправляется свой запрос, но тут мы экономим запросы
xhr.open("POST", "/photos/upload?act=finish&album="+document.getElementById("album").value)
xhr.onloadstart = () => {
e.currentTarget.setAttribute("disabled", "disabled")
}
xhr.onerror = () => {
MessageBox(tr("error"), tr("error_uploading_photo"), [tr("ok")], [() => {Function.noop}])
}
xhr.onload = () => {
let result = JSON.parse(xhr.responseText)
e.currentTarget.removeAttribute("disabled")
document.querySelector(".page_content tbody").innerHTML = ""
document.getElementById("endUploading").style.display = "none"
NewNotification(tr("photos_successfully_uploaded"), tr("click_to_go_to_album"), null, () => {window.location.assign(`/album${result.owner}_${result.album}`)})
}
xhr.send(data)
})
$(document).on("click", "#deletePhoto", (e) => {
let data = new FormData()
data.append("hash", u("meta[name=csrf]").attr("value"))
let xhr = new XMLHttpRequest()
xhr.open("POST", `/photo${e.currentTarget.dataset.owner}_${e.currentTarget.dataset.id}/delete`)
xhr.onloadstart = () => {
e.currentTarget.closest("tr#photo").classList.add("lagged")
}
xhr.onerror = () => {
MessageBox(tr("error"), tr("unknown_error"), [tr("ok")], [() => {Function.noop}])
}
xhr.onload = () => {
u(e.currentTarget.closest("tr#photo")).remove()
if(document.querySelectorAll("tr#photo").length < 1) {
document.getElementById("endUploading").style.display = "none"
}
}
xhr.send(data)
})

View file

@ -381,6 +381,13 @@
"upd_f" = "updated her profile picture";
"upd_g" = "updated group's picture";
"upload_picts" = "Upload photos";
"end_uploading" = "Finish uploading";
"photos_successfully_uploaded" = "Photos successfully uploaded";
"click_to_go_to_album" = "Click here to go to album.";
"error_uploading_photo" = "Error when uploading photo";
"too_many_pictures" = "No more than 10 pictures";
/* Notes */
"notes" = "Notes";
@ -1066,6 +1073,7 @@
"error_data_too_big" = "Attribute '$1' must be at most $2 $3 long";
"forbidden" = "Access error";
"unknown_error" = "Unknown error";
"forbidden_comment" = "This user's privacy settings do not allow you to look at his page.";
"changes_saved" = "Changes saved";

View file

@ -364,6 +364,13 @@
"upd_f" = "обновила фотографию на своей странице";
"upd_g" = "обновило фотографию группы";
"upload_picts" = "Загрузить фотографии";
"end_uploading" = "Завершить загрузку";
"photos_successfully_uploaded" = "Фотографии успешно загружены";
"click_to_go_to_album" = "Нажмите, чтобы перейти к альбому.";
"error_uploading_photo" = "Не удалось загрузить фотографию";
"too_many_pictures" = "Не больше 10 фотографий";
/* Notes */
"notes" = "Заметки";
@ -982,6 +989,7 @@
"error_repost_fail" = "Не удалось поделиться записью";
"error_data_too_big" = "Аттрибут '$1' не может быть длиннее $2 $3";
"forbidden" = "Ошибка доступа";
"unknown_error" = "Неизвестная ошибка";
"forbidden_comment" = "Настройки приватности этого пользователя не разрешают вам смотреть на его страницу.";
"changes_saved" = "Изменения сохранены";
"changes_saved_comment" = "Новые данные появятся на вашей странице";