template->usersStats = (new Users)->getStatistics();
$this->template->clubsCount = (new Clubs)->getCount();
$this->template->postsCount = (new Posts)->getCount();
- $this->template->popularClubs = iterator_to_array((new Clubs)->getPopularClubs());
+ $this->template->popularClubs = [];
$this->template->admins = iterator_to_array((new Users)->getInstanceAdmins());
}
@@ -76,6 +79,9 @@ final class AboutPresenter extends OpenVKPresenter
$this->assertNoCSRF();
setLanguage($_GET['lg']);
}
+
+ if(!is_null($_GET['jReturnTo']))
+ $this->redirect(rawurldecode($_GET['jReturnTo']));
}
function renderExportJSLanguage($lg = NULL): void
@@ -135,6 +141,6 @@ final class AboutPresenter extends OpenVKPresenter
function renderDev(): void
{
- $this->redirect("https://docs.openvk.su/");
+ $this->redirect("https://docs.openvk.uk/");
}
}
diff --git a/Web/Presenters/AdminPresenter.php b/Web/Presenters/AdminPresenter.php
index ceda6f6b..ff21612b 100644
--- a/Web/Presenters/AdminPresenter.php
+++ b/Web/Presenters/AdminPresenter.php
@@ -1,7 +1,7 @@
users = $users;
$this->clubs = $clubs;
$this->vouchers = $vouchers;
$this->gifts = $gifts;
$this->bannedLinks = $bannedLinks;
+ $this->chandlerGroups = $chandlerGroups;
parent::__construct();
}
@@ -62,7 +64,9 @@ final class AdminPresenter extends OpenVKPresenter
$this->notFound();
$this->template->user = $user;
-
+ $this->template->c_groups_list = (new ChandlerGroups)->getList();
+ $this->template->c_memberships = $this->chandlerGroups->getUsersMemberships($user->getChandlerGUID());
+
if($_SERVER["REQUEST_METHOD"] !== "POST")
return;
@@ -78,8 +82,16 @@ final class AdminPresenter extends OpenVKPresenter
$user->changeEmail($this->postParam("email"));
if($user->onlineStatus() != $this->postParam("online")) $user->setOnline(intval($this->postParam("online")));
$user->setVerified(empty($this->postParam("verify") ? 0 : 1));
+ if($this->postParam("add-to-group")) {
+ $query = "INSERT INTO `ChandlerACLRelations` (`user`, `group`) VALUES ('" . $user->getChandlerGUID() . "', '" . $this->postParam("add-to-group") . "')";
+ DatabaseConnection::i()->getConnection()->query($query);
+ }
+ if($this->postParam("password")) {
+ $user->getChandlerUser()->updatePassword($this->postParam("password"));
+ }
$user->save();
+
break;
}
}
@@ -447,4 +459,95 @@ final class AdminPresenter extends OpenVKPresenter
$this->redirect("/admin/bannedLinks");
}
+
+ function renderChandlerGroups(): void
+ {
+ $this->template->groups = (new ChandlerGroups)->getList();
+
+ if($_SERVER["REQUEST_METHOD"] !== "POST")
+ return;
+
+ $req = "INSERT INTO `ChandlerGroups` (`name`) VALUES ('" . $this->postParam("name") . "')";
+ DatabaseConnection::i()->getConnection()->query($req);
+ }
+
+ function renderChandlerGroup(string $UUID): void
+ {
+ $DB = DatabaseConnection::i()->getConnection();
+
+ if(is_null($DB->query("SELECT * FROM `ChandlerGroups` WHERE `id` = '$UUID'")->fetch()))
+ $this->flashFail("err", tr("error"), tr("c_group_not_found"));
+
+ $this->template->group = (new ChandlerGroups)->get($UUID);
+ $this->template->mode = in_array(
+ $this->queryParam("act"),
+ [
+ "main",
+ "members",
+ "permissions",
+ "removeMember",
+ "removePermission",
+ "delete"
+ ]) ? $this->queryParam("act") : "main";
+ $this->template->members = (new ChandlerGroups)->getMembersById($UUID);
+ $this->template->perms = (new ChandlerGroups)->getPermissionsById($UUID);
+
+ if($this->template->mode == "removeMember") {
+ $where = "`user` = '" . $this->queryParam("uid") . "' AND `group` = '$UUID'";
+
+ if(is_null($DB->query("SELECT * FROM `ChandlerACLRelations` WHERE " . $where)->fetch()))
+ $this->flashFail("err", tr("error"), tr("c_user_is_not_in_group"));
+
+ $DB->query("DELETE FROM `ChandlerACLRelations` WHERE " . $where);
+ $this->flashFail("succ", tr("changes_saved"), tr("c_user_removed_from_group"));
+ } elseif($this->template->mode == "removePermission") {
+ $where = "`model` = '" . trim(addslashes($this->queryParam("model"))) . "' AND `permission` = '". $this->queryParam("perm") ."' AND `group` = '$UUID'";
+
+ if(is_null($DB->query("SELECT * FROM `ChandlerACLGroupsPermissions WHERE $where`")))
+ $this->flashFail("err", tr("error"), tr("c_permission_not_found"));
+
+ $DB->query("DELETE FROM `ChandlerACLGroupsPermissions` WHERE $where");
+ $this->flashFail("succ", tr("changes_saved"), tr("c_permission_removed_from_group"));
+ } elseif($this->template->mode == "delete") {
+ $DB->query("DELETE FROM `ChandlerGroups` WHERE `id` = '$UUID'");
+ $DB->query("DELETE FROM `ChandlerACLGroupsPermissions` WHERE `group` = '$UUID'");
+ $DB->query("DELETE FROM `ChandlerACLRelations` WHERE `group` = '$UUID'");
+
+ $this->flashFail("succ", tr("changes_saved"), tr("c_group_removed"));
+ }
+
+ if ($_SERVER["REQUEST_METHOD"] !== "POST") return;
+
+ $req = "";
+
+ if($this->template->mode == "main")
+ if($this->postParam("delete"))
+ $req = "DELETE FROM `ChandlerGroups` WHERE `id`='$UUID'";
+ else
+ $req = "UPDATE `ChandlerGroups` SET `name`='". $this->postParam('name') ."' , `color`='". $this->postParam("color") ."' WHERE `id`='$UUID'";
+
+ if($this->template->mode == "members")
+ if($this->postParam("uid"))
+ if(!is_null($DB->query("SELECT * FROM `ChandlerACLRelations` WHERE `user` = '" . $this->postParam("uid") . "'")))
+ $this->flashFail("err", tr("error"), tr("c_user_is_already_in_group"));
+
+ $req = "INSERT INTO `ChandlerACLRelations` (`user`, `group`, `priority`) VALUES ('". $this->postParam("uid") ."', '$UUID', 32)";
+
+ if($this->template->mode == "permissions")
+ $req = "INSERT INTO `ChandlerACLGroupsPermissions` (`group`, `model`, `permission`, `context`) VALUES ('$UUID', '". trim(addslashes($this->postParam("model"))) ."', '". $this->postParam("permission") ."', 0)";
+
+ $DB->query($req);
+ $this->flashFail("succ", tr("changes_saved"));
+ }
+
+ function renderChandlerUser(string $UUID): void
+ {
+ if(!$UUID) $this->notFound();
+
+ $c_user = (new ChandlerUsers())->getById($UUID);
+ $user = $this->users->getByChandlerUser($c_user);
+ if(!$user) $this->notFound();
+
+ $this->redirect("/admin/users/id" . $user->getId());
+ }
}
diff --git a/Web/Presenters/AppsPresenter.php b/Web/Presenters/AppsPresenter.php
index 02fb8922..8dcfb8a4 100644
--- a/Web/Presenters/AppsPresenter.php
+++ b/Web/Presenters/AppsPresenter.php
@@ -6,7 +6,7 @@ use openvk\Web\Models\Repositories\Applications;
final class AppsPresenter extends OpenVKPresenter
{
private $apps;
-
+ protected $presenterName = "apps";
function __construct(Applications $apps)
{
$this->apps = $apps;
diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php
index f934f7fe..2f178900 100644
--- a/Web/Presenters/AuthPresenter.php
+++ b/Web/Presenters/AuthPresenter.php
@@ -80,10 +80,17 @@ final class AuthPresenter extends OpenVKPresenter
if(!Validator::i()->emailValid($this->postParam("email")))
$this->flashFail("err", tr("invalid_email_address"), tr("invalid_email_address_comment"));
-
+
+ if(OPENVK_ROOT_CONF['openvk']['preferences']['security']['forceStrongPassword'])
+ if(!Validator::i()->passwordStrong($this->postParam("password")))
+ $this->flashFail("err", tr("error"), tr("error_weak_password"));
+
if (strtotime($this->postParam("birthday")) > time())
$this->flashFail("err", tr("invalid_birth_date"), tr("invalid_birth_date_comment"));
+ if (!$this->postParam("confirmation"))
+ $this->flashFail("err", tr("error"), tr("checkbox_in_registration_unchecked"));
+
try {
$user = new User;
$user->setFirst_Name($this->postParam("first_name"));
@@ -200,6 +207,9 @@ final class AuthPresenter extends OpenVKPresenter
function renderFinishRestoringPassword(): void
{
+ if(OPENVK_ROOT_CONF['openvk']['preferences']['security']['disablePasswordRestoring'])
+ $this->notFound();
+
$request = $this->restores->getByToken(str_replace(" ", "+", $this->queryParam("key")));
if(!$request || !$request->isStillValid()) {
$this->flash("err", tr("token_manipulation_error"), tr("token_manipulation_error_comment"));
@@ -234,6 +244,9 @@ final class AuthPresenter extends OpenVKPresenter
function renderRestore(): void
{
+ if(OPENVK_ROOT_CONF['openvk']['preferences']['security']['disablePasswordRestoring'])
+ $this->notFound();
+
if(!is_null($this->user))
$this->redirect($this->user->identity->getURL());
diff --git a/Web/Presenters/CommentPresenter.php b/Web/Presenters/CommentPresenter.php
index cbdac84e..dad79ac4 100644
--- a/Web/Presenters/CommentPresenter.php
+++ b/Web/Presenters/CommentPresenter.php
@@ -1,11 +1,12 @@
"openvk\\Web\\Models\\Repositories\\Posts",
"photos" => "openvk\\Web\\Models\\Repositories\\Photos",
@@ -46,6 +47,9 @@ final class CommentPresenter extends OpenVKPresenter
$club = (new Clubs)->get(abs($entity->getTargetWall()));
else if($entity instanceof Topic)
$club = $entity->getClub();
+
+ if($_FILES["_vid_attachment"] && OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
+ $this->flashFail("err", tr("error"), "Video uploads are disabled by the system administrator.");
$flags = 0;
if($this->postParam("as_group") === "on" && !is_null($club) && $club->canBeModifiedBy($this->user->identity))
@@ -73,7 +77,7 @@ final class CommentPresenter extends OpenVKPresenter
}
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
- $video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"]);
+ $video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"]);
}
} catch(ISE $ex) {
$this->flashFail("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
@@ -104,6 +108,15 @@ final class CommentPresenter extends OpenVKPresenter
if($entity->getOwner()->getId() !== $this->user->identity->getId())
if(($owner = $entity->getOwner()) instanceof User)
(new CommentNotification($owner, $comment, $entity, $this->user->identity))->emit();
+
+ $excludeMentions = [$this->user->identity->getId()];
+ if(($owner = $entity->getOwner()) instanceof User)
+ $excludeMentions[] = $owner->getId();
+
+ $mentions = iterator_to_array($comment->resolveMentions($excludeMentions));
+ foreach($mentions as $mentionee)
+ if($mentionee instanceof User)
+ (new MentionNotification($mentionee, $entity, $comment->getOwner(), strip_tags($comment->getText())))->emit();
$this->flashFail("succ", "Комментарий добавлен", "Ваш комментарий появится на странице.");
}
diff --git a/Web/Presenters/GiftsPresenter.php b/Web/Presenters/GiftsPresenter.php
index b99e5ba9..8f59bdcb 100644
--- a/Web/Presenters/GiftsPresenter.php
+++ b/Web/Presenters/GiftsPresenter.php
@@ -7,6 +7,7 @@ final class GiftsPresenter extends OpenVKPresenter
{
private $gifts;
private $users;
+ protected $presenterName = "gifts";
function __construct(Gifts $gifts, Users $users)
{
diff --git a/Web/Presenters/GroupPresenter.php b/Web/Presenters/GroupPresenter.php
index a83386db..4f671df3 100644
--- a/Web/Presenters/GroupPresenter.php
+++ b/Web/Presenters/GroupPresenter.php
@@ -1,6 +1,7 @@
clubs = $clubs;
@@ -190,7 +192,7 @@ final class GroupPresenter extends OpenVKPresenter
$this->willExecuteWriteAction();
$club = $this->clubs->get($id);
- if(!$club->canBeModifiedBy($this->user->identity))
+ if(!$club || !$club->canBeModifiedBy($this->user->identity))
$this->notFound();
else
$this->template->club = $club;
@@ -249,6 +251,88 @@ final class GroupPresenter extends OpenVKPresenter
}
}
+ function renderSetAvatar(int $id)
+ {
+ $photo = new Photo;
+ $club = $this->clubs->get($id);
+ if($_SERVER["REQUEST_METHOD"] === "POST" && $_FILES["ava"]["error"] === UPLOAD_ERR_OK) {
+ try {
+ $anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
+ if($anon && $this->user->id === $club->getOwner()->getId())
+ $anon = $club->isOwnerHidden();
+ else if($anon)
+ $anon = $club->getManager($this->user->identity)->isHidden();
+ $photo->setOwner($this->user->id);
+ $photo->setDescription("Club image");
+ $photo->setFile($_FILES["ava"]);
+ $photo->setCreated(time());
+ $photo->setAnonymous($anon);
+ $photo->save();
+
+ (new Albums)->getClubAvatarAlbum($club)->addPhoto($photo);
+
+ $flags = 0;
+ $flags |= 0b00010000;
+ $flags |= 0b10000000;
+
+ $post = new Post;
+ $post->setOwner($this->user->id);
+ $post->setWall($club->getId()*-1);
+ $post->setCreated(time());
+ $post->setContent("");
+ $post->setFlags($flags);
+ $post->save();
+ $post->attach($photo);
+
+ } catch(ISE $ex) {
+ $name = $album->getName();
+ $this->flashFail("err", "Неизвестная ошибка", "Не удалось сохранить фотографию.");
+ }
+ }
+ $this->returnJson([
+ "url" => $photo->getURL(),
+ "id" => $photo->getPrettyId()
+ ]);
+ }
+ function renderEditBackdrop(int $id): void
+ {
+ $this->assertUserLoggedIn();
+ $this->willExecuteWriteAction();
+
+ $club = $this->clubs->get($id);
+ if(!$club || !$club->canBeModifiedBy($this->user->identity))
+ $this->notFound();
+ else
+ $this->template->club = $club;
+
+ if($_SERVER["REQUEST_METHOD"] !== "POST")
+ return;
+
+ if($this->postParam("subact") === "remove") {
+ $club->unsetBackDropPictures();
+ $club->save();
+ $this->flashFail("succ", tr("backdrop_succ_rem"), tr("backdrop_succ_desc")); # will exit
+ }
+
+ $pic1 = $pic2 = NULL;
+ try {
+ if($_FILES["backdrop1"]["error"] !== UPLOAD_ERR_NO_FILE)
+ $pic1 = Photo::fastMake($this->user->id, "Profile backdrop (system)", $_FILES["backdrop1"]);
+
+ if($_FILES["backdrop2"]["error"] !== UPLOAD_ERR_NO_FILE)
+ $pic2 = Photo::fastMake($this->user->id, "Profile backdrop (system)", $_FILES["backdrop2"]);
+ } catch(InvalidStateException $e) {
+ $this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
+ }
+
+ if($pic1 == $pic2 && is_null($pic1))
+ $this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
+
+ $club->setBackDropPictures($pic1, $pic2);
+ $club->save();
+ $this->flashFail("succ", tr("backdrop_succ"), tr("backdrop_succ_desc"));
+ }
+
function renderStatistics(int $id): void
{
$this->assertUserLoggedIn();
diff --git a/Web/Presenters/MaintenancePresenter.php b/Web/Presenters/MaintenancePresenter.php
new file mode 100644
index 00000000..d4a5a6ef
--- /dev/null
+++ b/Web/Presenters/MaintenancePresenter.php
@@ -0,0 +1,35 @@
+flashFail("err", tr("error"), tr("forbidden"));
+
+ $this->template->name = [
+ "photos" => tr("my_photos"),
+ "videos" => tr("my_videos"),
+ "messenger" => tr("my_messages"),
+ "user" => tr("users"),
+ "group" => tr("my_groups"),
+ "comment" => tr("comments"),
+ "gifts" => tr("gifts"),
+ "apps" => tr("apps"),
+ "notes" => tr("my_notes"),
+ "notification" => tr("my_feedback"),
+ "support" => tr("menu_support"),
+ "topics" => tr("topics")
+ ][$name] ?? $name;
+ }
+
+ function renderAll(): void
+ {
+
+ }
+}
diff --git a/Web/Presenters/MessengerPresenter.php b/Web/Presenters/MessengerPresenter.php
index cea440ba..d5ffb988 100644
--- a/Web/Presenters/MessengerPresenter.php
+++ b/Web/Presenters/MessengerPresenter.php
@@ -9,11 +9,13 @@ final class MessengerPresenter extends OpenVKPresenter
{
private $messages;
private $signaler;
-
+ protected $presenterName = "messenger";
+
function __construct(Messages $messages)
{
$this->messages = $messages;
$this->signaler = SignalManager::i();
+
parent::__construct();
}
@@ -30,7 +32,7 @@ final class MessengerPresenter extends OpenVKPresenter
function renderIndex(): void
{
$this->assertUserLoggedIn();
-
+
if(isset($_GET["sel"]))
$this->pass("openvk!Messenger->app", $_GET["sel"]);
@@ -55,6 +57,11 @@ final class MessengerPresenter extends OpenVKPresenter
$correspondent = $this->getCorrespondent($sel);
if(!$correspondent)
$this->notFound();
+
+ if(!$this->user->identity->getPrivacyPermission('messages.write', $correspondent))
+ {
+ $this->flash("err", tr("warning"), tr("user_may_not_reply"));
+ }
$this->template->selId = $sel;
$this->template->correspondent = $correspondent;
@@ -93,6 +100,13 @@ final class MessengerPresenter extends OpenVKPresenter
}
$legacy = $this->queryParam("version") < 3;
+
+ $time = intval($this->queryParam("wait"));
+
+ if($time > 60)
+ $time = 60;
+ elseif($time == 0)
+ $time = 25; // default
$this->signaler->listen(function($event, $eId) use ($id) {
exit(json_encode([
@@ -101,7 +115,7 @@ final class MessengerPresenter extends OpenVKPresenter
$event->getVKAPISummary($id),
],
]));
- }, $id);
+ }, $id, $time);
}
function renderApiGetMessages(int $sel, int $lastMsg): void
diff --git a/Web/Presenters/NotesPresenter.php b/Web/Presenters/NotesPresenter.php
index 363d814c..50437ad7 100644
--- a/Web/Presenters/NotesPresenter.php
+++ b/Web/Presenters/NotesPresenter.php
@@ -6,7 +6,8 @@ use openvk\Web\Models\Entities\Note;
final class NotesPresenter extends OpenVKPresenter
{
private $notes;
-
+ protected $presenterName = "notes";
+
function __construct(Notes $notes)
{
$this->notes = $notes;
diff --git a/Web/Presenters/NotificationPresenter.php b/Web/Presenters/NotificationPresenter.php
index d12f27f0..3bd7a321 100644
--- a/Web/Presenters/NotificationPresenter.php
+++ b/Web/Presenters/NotificationPresenter.php
@@ -3,6 +3,8 @@ namespace openvk\Web\Presenters;
final class NotificationPresenter extends OpenVKPresenter
{
+ protected $presenterName = "notification";
+
function renderFeed(): void
{
$this->assertUserLoggedIn();
diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php
index 2a19fa03..710713e5 100755
--- a/Web/Presenters/OpenVKPresenter.php
+++ b/Web/Presenters/OpenVKPresenter.php
@@ -17,7 +17,8 @@ abstract class OpenVKPresenter extends SimplePresenter
protected $deactivationTolerant = false;
protected $errorTemplate = "@error";
protected $user = NULL;
-
+ protected $presenterName;
+
private function calculateQueryString(array $data): string
{
$rawUrl = "tcp+stratum://fakeurl.net$_SERVER[REQUEST_URI]"; #HTTP_HOST can be tainted
@@ -196,12 +197,13 @@ abstract class OpenVKPresenter extends SimplePresenter
function onStartup(): void
{
$user = Authenticator::i()->getUser();
-
+
$this->template->isXmas = intval(date('d')) >= 1 && date('m') == 12 || intval(date('d')) <= 15 && date('m') == 1 ? true : false;
$this->template->isTimezoned = Session::i()->get("_timezoneOffset");
-
+
$userValidated = 0;
$cacheTime = OPENVK_ROOT_CONF["openvk"]["preferences"]["nginxCacheTime"] ?? 0;
+
if(!is_null($user)) {
$this->user = (object) [];
$this->user->raw = $user;
@@ -226,7 +228,7 @@ abstract class OpenVKPresenter extends SimplePresenter
}
exit;
}
-
+
if($this->user->identity->isBanned() && !$this->banTolerant) {
header("HTTP/1.1 403 Forbidden");
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@banned.xml", [
@@ -247,23 +249,34 @@ abstract class OpenVKPresenter extends SimplePresenter
]);
exit;
}
-
+
$userValidated = 1;
$cacheTime = 0; # Force no cache
if($this->user->identity->onlineStatus() == 0 && !($this->user->identity->isDeleted() || $this->user->identity->isBanned())) {
$this->user->identity->setOnline(time());
+ $this->user->identity->setClient_name(NULL);
$this->user->identity->save();
}
-
+
$this->template->ticketAnsweredCount = (new Tickets)->getTicketsCountByUserId($this->user->id, 1);
if($user->can("write")->model("openvk\Web\Models\Entities\TicketReply")->whichBelongsTo(0))
$this->template->helpdeskTicketNotAnsweredCount = (new Tickets)->getTicketCount(0);
}
-
+
header("X-OpenVK-User-Validated: $userValidated");
header("X-Accel-Expires: $cacheTime");
setlocale(LC_TIME, ...(explode(";", tr("__locale"))));
-
+
+ if (!OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"]["all"]) {
+ if (OPENVK_ROOT_CONF["openvk"]["preferences"]["maintenanceMode"][$this->presenterName]) {
+ $this->pass("openvk!Maintenance->section", $this->presenterName);
+ }
+ } else {
+ if ($this->presenterName != "maintenance") {
+ $this->redirect("/maintenances/");
+ }
+ }
+
parent::onStartup();
}
@@ -272,10 +285,14 @@ abstract class OpenVKPresenter extends SimplePresenter
parent::onBeforeRender();
$whichbrowser = new WhichBrowser\Parser(getallheaders());
+ $featurephonetheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultFeaturePhoneTheme"];
$mobiletheme = OPENVK_ROOT_CONF["openvk"]["preferences"]["defaultMobileTheme"];
- if($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == NULL)
+
+ if($featurephonetheme && $this->isOldThing($whichbrowser) && Session::i()->get("_tempTheme") == NULL) {
+ $this->setSessionTheme($featurephonetheme);
+ } elseif($mobiletheme && $whichbrowser->isType('mobile') && Session::i()->get("_tempTheme") == NULL)
$this->setSessionTheme($mobiletheme);
-
+
$theme = NULL;
if(Session::i()->get("_tempTheme")) {
$theme = Themepacks::i()[Session::i()->get("_tempTheme", "ovk")];
@@ -306,4 +323,33 @@ abstract class OpenVKPresenter extends SimplePresenter
header("Content-Length: $size");
exit($payload);
}
+
+ protected function isOldThing($whichbrowser) {
+ if($whichbrowser->isOs('Series60') ||
+ $whichbrowser->isOs('Series40') ||
+ $whichbrowser->isOs('Series80') ||
+ $whichbrowser->isOs('Windows CE') ||
+ $whichbrowser->isOs('Windows Mobile') ||
+ $whichbrowser->isOs('Nokia Asha Platform') ||
+ $whichbrowser->isOs('UIQ') ||
+ $whichbrowser->isEngine('NetFront') || // PSP and other japanese portable systems
+ $whichbrowser->isOs('Android') ||
+ $whichbrowser->isOs('iOS') ||
+ $whichbrowser->isBrowser('Internet Explorer', '<=', '8')) {
+ // yeah, it's old, but ios and android are?
+ if($whichbrowser->isOs('iOS') && $whichbrowser->isOs('iOS', '<=', '9'))
+ return true;
+ elseif($whichbrowser->isOs('iOS') && $whichbrowser->isOs('iOS', '>', '9'))
+ return false;
+
+ if($whichbrowser->isOs('Android') && $whichbrowser->isOs('Android', '<=', '5'))
+ return true;
+ elseif($whichbrowser->isOs('Android') && $whichbrowser->isOs('Android', '>', '5'))
+ return false;
+
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/Web/Presenters/PhotosPresenter.php b/Web/Presenters/PhotosPresenter.php
index eacf76d4..02d6ae46 100644
--- a/Web/Presenters/PhotosPresenter.php
+++ b/Web/Presenters/PhotosPresenter.php
@@ -9,7 +9,8 @@ final class PhotosPresenter extends OpenVKPresenter
private $users;
private $photos;
private $albums;
-
+ protected $presenterName = "photos";
+
function __construct(Photos $photos, Albums $albums, Users $users)
{
$this->users = $users;
@@ -184,6 +185,18 @@ final class PhotosPresenter extends OpenVKPresenter
$this->renderPhoto($photo->getOwner(true)->getId(), $photo->getVirtualId());
}
+ function renderThumbnail($id, $size): void
+ {
+ $photo = $this->photos->get($id);
+ if(!$photo || $photo->isDeleted())
+ $this->notFound();
+
+ if(!$photo->forceSize($size))
+ chandler_http_panic(588, "Gone", "This thumbnail cannot be generated due to server misconfiguration");
+
+ $this->redirect($photo->getURLBySizeId($size), 8);
+ }
+
function renderEditPhoto(int $ownerId, int $photoId): void
{
$this->assertUserLoggedIn();
diff --git a/Web/Presenters/PollPresenter.php b/Web/Presenters/PollPresenter.php
new file mode 100644
index 00000000..9c75e3bf
--- /dev/null
+++ b/Web/Presenters/PollPresenter.php
@@ -0,0 +1,75 @@
+polls = $polls;
+
+ parent::__construct();
+ }
+
+ function renderView(int $id): void
+ {
+ $poll = $this->polls->get($id);
+ if(!$poll)
+ $this->notFound();
+
+ $this->template->id = $poll->getId();
+ $this->template->title = $poll->getTitle();
+ $this->template->isAnon = $poll->isAnonymous();
+ $this->template->multiple = $poll->isMultipleChoice();
+ $this->template->unlocked = $poll->isRevotable();
+ $this->template->until = $poll->endsAt();
+ $this->template->votes = $poll->getVoterCount();
+ $this->template->meta = $poll->getMetaDescription();
+ $this->template->ended = $ended = $poll->hasEnded();
+ if((is_null($this->user) || $poll->canVote($this->user->identity)) && !$ended) {
+ $this->template->options = $poll->getOptions();
+
+ $this->template->_template = "Poll/Poll.xml";
+ return;
+ }
+
+ if(is_null($this->user)) {
+ $this->template->voted = false;
+ $this->template->results = $poll->getResults();
+ } else {
+ $this->template->voted = $poll->hasVoted($this->user->identity);
+ $this->template->results = $poll->getResults($this->user->identity);
+ }
+
+ $this->template->_template = "Poll/PollResults.xml";
+ }
+
+ function renderVoters(int $pollId): void
+ {
+ $poll = $this->polls->get($pollId);
+ if(!$poll)
+ $this->notFound();
+
+ if($poll->isAnonymous())
+ $this->flashFail("err", tr("forbidden"), tr("poll_err_anonymous"));
+
+ $options = $poll->getOptions();
+ $option = (int) base_convert($this->queryParam("option"), 32, 10);
+ if(!in_array($option, array_keys($options)))
+ $this->notFound();
+
+ $page = (int) ($this->queryParam("p") ?? 1);
+ $voters = $poll->getVoters($option, $page);
+
+ $this->template->pollId = $pollId;
+ $this->template->options = $options;
+ $this->template->option = [$option, $options[$option]];
+ $this->template->tabs = $options;
+ $this->template->iterator = $voters;
+ $this->template->count = $poll->getVoterCount($option);
+ $this->template->page = $page;
+ }
+}
\ No newline at end of file
diff --git a/Web/Presenters/SearchPresenter.php b/Web/Presenters/SearchPresenter.php
index 2171297c..fadf9954 100644
--- a/Web/Presenters/SearchPresenter.php
+++ b/Web/Presenters/SearchPresenter.php
@@ -1,18 +1,28 @@
users = $users;
- $this->clubs = $clubs;
+ $this->users = $users;
+ $this->clubs = $clubs;
+ $this->posts = new Posts;
+ $this->comments = new Comments;
+ $this->videos = new Videos;
+ $this->apps = new Applications;
+ $this->notes = new Notes;
parent::__construct();
}
@@ -21,6 +31,8 @@ final class SearchPresenter extends OpenVKPresenter
{
$query = $this->queryParam("query") ?? "";
$type = $this->queryParam("type") ?? "users";
+ $sorter = $this->queryParam("sort") ?? "id";
+ $invert = $this->queryParam("invert") == 1 ? "ASC" : "DESC";
$page = (int) ($this->queryParam("p") ?? 1);
$this->willExecuteWriteAction();
@@ -28,11 +40,58 @@ final class SearchPresenter extends OpenVKPresenter
$this->assertUserLoggedIn();
# https://youtu.be/pSAWM5YuXx8
-
- $repos = [ "groups" => "clubs", "users" => "users" ];
+
+ $repos = [
+ "groups" => "clubs",
+ "users" => "users",
+ "posts" => "posts",
+ "comments" => "comments",
+ "videos" => "videos",
+ "audios" => "posts",
+ "apps" => "apps",
+ "notes" => "notes"
+ ];
+
+ switch($sorter) {
+ default:
+ case "id":
+ $sort = "id " . $invert;
+ break;
+ case "name":
+ $sort = "first_name " . $invert;
+ break;
+ case "rating":
+ $sort = "rating " . $invert;
+ break;
+ }
+
+ $parameters = [
+ "type" => $this->queryParam("type"),
+ "city" => $this->queryParam("city") != "" ? $this->queryParam("city") : NULL,
+ "maritalstatus" => $this->queryParam("maritalstatus") != 0 ? $this->queryParam("maritalstatus") : NULL,
+ "with_photo" => $this->queryParam("with_photo"),
+ "status" => $this->queryParam("status") != "" ? $this->queryParam("status") : NULL,
+ "politViews" => $this->queryParam("politViews") != 0 ? $this->queryParam("politViews") : NULL,
+ "email" => $this->queryParam("email"),
+ "telegram" => $this->queryParam("telegram"),
+ "site" => $this->queryParam("site") != "" ? "https://".$this->queryParam("site") : NULL,
+ "address" => $this->queryParam("address"),
+ "is_online" => $this->queryParam("is_online") == 1 ? 1 : NULL,
+ "interests" => $this->queryParam("interests") != "" ? $this->queryParam("interests") : NULL,
+ "fav_mus" => $this->queryParam("fav_mus") != "" ? $this->queryParam("fav_mus") : NULL,
+ "fav_films" => $this->queryParam("fav_films") != "" ? $this->queryParam("fav_films") : NULL,
+ "fav_shows" => $this->queryParam("fav_shows") != "" ? $this->queryParam("fav_shows") : NULL,
+ "fav_books" => $this->queryParam("fav_books") != "" ? $this->queryParam("fav_books") : NULL,
+ "fav_quote" => $this->queryParam("fav_quote") != "" ? $this->queryParam("fav_quote") : NULL,
+ "hometown" => $this->queryParam("hometown") != "" ? $this->queryParam("hometown") : NULL,
+ "before" => $this->queryParam("datebefore") != "" ? strtotime($this->queryParam("datebefore")) : NULL,
+ "after" => $this->queryParam("dateafter") != "" ? strtotime($this->queryParam("dateafter")) : NULL,
+ "gender" => $this->queryParam("gender") != "" && $this->queryParam("gender") != 2 ? $this->queryParam("gender") : NULL
+ ];
+
$repo = $repos[$type] or $this->throwError(400, "Bad Request", "Invalid search entity $type.");
- $results = $this->{$repo}->find($query);
+ $results = $this->{$repo}->find($query, $parameters, $sort);
$iterator = $results->page($page);
$count = $results->size();
diff --git a/Web/Presenters/SupportPresenter.php b/Web/Presenters/SupportPresenter.php
index 22f09201..c4d729ea 100644
--- a/Web/Presenters/SupportPresenter.php
+++ b/Web/Presenters/SupportPresenter.php
@@ -1,7 +1,7 @@
notFound();
} else {
if($ticket->getUserId() !== $this->user->id && $this->hasPermission('openvk\Web\Models\Entities\TicketReply', 'write', 0))
- $this->redirect("/support/tickets");
+ $_redirect = "/support/tickets";
else
- $this->redirect("/support");
+ $_redirect = "/support?act=list";
$ticket->delete();
+ $this->redirect($_redirect);
}
}
}
@@ -340,4 +342,58 @@ final class SupportPresenter extends OpenVKPresenter
$user->save();
$this->returnJson([ "success" => true ]);
}
+
+ function renderAgent(int $id): void
+ {
+ $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
+
+ $support_names = new SupportAgents;
+
+ if(!$support_names->isExists($id))
+ $this->template->mode = "edit";
+
+ $this->template->agent_id = $id;
+ $this->template->mode = in_array($this->queryParam("act"), ["info", "edit"]) ? $this->queryParam("act") : "info";
+ $this->template->agent = $support_names->get($id) ?? NULL;
+ $this->template->counters = [
+ "all" => (new TicketComments)->getCountByAgent($id),
+ "good" => (new TicketComments)->getCountByAgent($id, 1),
+ "bad" => (new TicketComments)->getCountByAgent($id, 2)
+ ];
+
+ if($id != $this->user->identity->getId())
+ if ($support_names->isExists($id))
+ $this->template->mode = "info";
+ else
+ $this->redirect("/support/agent" . $this->user->identity->getId());
+ }
+
+ function renderEditAgent(int $id): void
+ {
+ $this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
+ $this->assertNoCSRF();
+
+ $support_names = new SupportAgents;
+ $agent = $support_names->get($id);
+
+ if($agent)
+ if($agent->getAgentId() != $this->user->identity->getId()) $this->flashFail("err", tr("error"), tr("forbidden"));
+
+ if ($support_names->isExists($id)) {
+ $agent = $support_names->get($id);
+ $agent->setName($this->postParam("name") ?? tr("helpdesk_agent"));
+ $agent->setNumerate((int) $this->postParam("number") ?? NULL);
+ $agent->setIcon($this->postParam("avatar"));
+ $agent->save();
+ $this->flashFail("succ", "Успех", "Профиль отредактирован.");
+ } else {
+ $agent = new SupportAgent;
+ $agent->setAgent($this->user->identity->getId());
+ $agent->setName($this->postParam("name") ?? tr("helpdesk_agent"));
+ $agent->setNumerate((int) $this->postParam("number") ?? NULL);
+ $agent->setIcon($this->postParam("avatar"));
+ $agent->save();
+ $this->flashFail("succ", "Успех", "Профиль создан. Теперь пользователи видят Ваши псевдоним и аватарку вместо стандартных аватарки и номера.");
+ }
+ }
}
diff --git a/Web/Presenters/TopicsPresenter.php b/Web/Presenters/TopicsPresenter.php
index 6dd1ec6c..e7b08ac3 100644
--- a/Web/Presenters/TopicsPresenter.php
+++ b/Web/Presenters/TopicsPresenter.php
@@ -7,7 +7,8 @@ final class TopicsPresenter extends OpenVKPresenter
{
private $topics;
private $clubs;
-
+ protected $presenterName = "topics";
+
function __construct(Topics $topics, Clubs $clubs)
{
$this->topics = $topics;
@@ -83,6 +84,9 @@ final class TopicsPresenter extends OpenVKPresenter
if($this->postParam("as_group") === "on" && $club->canBeModifiedBy($this->user->identity))
$flags |= 0b10000000;
+ if($_FILES["_vid_attachment"] && OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
+ $this->flashFail("err", tr("error"), "Video uploads are disabled by the system administrator.");
+
$topic = new Topic;
$topic->setGroup($club->getId());
$topic->setOwner($this->user->id);
@@ -104,7 +108,7 @@ final class TopicsPresenter extends OpenVKPresenter
}
if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
- $video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"]);
+ $video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"]);
}
} catch(ISE $ex) {
$this->flash("err", "Не удалось опубликовать комментарий", "Файл медиаконтента повреждён или слишком велик.");
diff --git a/Web/Presenters/UserPresenter.php b/Web/Presenters/UserPresenter.php
index bfda79e8..9cfa3654 100644
--- a/Web/Presenters/UserPresenter.php
+++ b/Web/Presenters/UserPresenter.php
@@ -1,5 +1,6 @@
users = $users;
-
+
parent::__construct();
}
@@ -28,7 +30,7 @@ final class UserPresenter extends OpenVKPresenter
{
$user = $this->users->get($id);
if(!$user || $user->isDeleted()) {
- if($user->isDeactivated()) {
+ if(!is_null($user) && $user->isDeactivated()) {
$this->template->_template = "User/deactivated.xml";
$this->template->user = $user;
@@ -37,6 +39,7 @@ final class UserPresenter extends OpenVKPresenter
}
} else {
$this->template->albums = (new Albums)->getUserAlbums($user);
+ $this->template->avatarAlbum = (new Albums)->getUserAvatarAlbum($user);
$this->template->albumsCount = (new Albums)->getUserAlbumsCount($user);
$this->template->videos = (new Videos)->getByUser($user, 1, 2);
$this->template->videosCount = (new Videos)->getUserVideosCount($user);
@@ -207,6 +210,30 @@ final class UserPresenter extends OpenVKPresenter
$user->setFav_Books(empty($this->postParam("fav_books")) ? NULL : ovk_proc_strtr($this->postParam("fav_books"), 300));
$user->setFav_Quote(empty($this->postParam("fav_quote")) ? NULL : ovk_proc_strtr($this->postParam("fav_quote"), 300));
$user->setAbout(empty($this->postParam("about")) ? NULL : ovk_proc_strtr($this->postParam("about"), 300));
+ } elseif($_GET["act"] === "backdrop") {
+ if($this->postParam("subact") === "remove") {
+ $user->unsetBackDropPictures();
+ $user->save();
+ $this->flashFail("succ", tr("backdrop_succ_rem"), tr("backdrop_succ_desc")); # will exit
+ }
+
+ $pic1 = $pic2 = NULL;
+ try {
+ if($_FILES["backdrop1"]["error"] !== UPLOAD_ERR_NO_FILE)
+ $pic1 = Photo::fastMake($user->getId(), "Profile backdrop (system)", $_FILES["backdrop1"]);
+
+ if($_FILES["backdrop2"]["error"] !== UPLOAD_ERR_NO_FILE)
+ $pic2 = Photo::fastMake($user->getId(), "Profile backdrop (system)", $_FILES["backdrop2"]);
+ } catch(InvalidStateException $e) {
+ $this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
+ }
+
+ if($pic1 == $pic2 && is_null($pic1))
+ $this->flashFail("err", tr("backdrop_error_title"), tr("backdrop_error_no_media"));
+
+ $user->setBackDropPictures($pic1, $pic2);
+ $user->save();
+ $this->flashFail("succ", tr("backdrop_succ"), tr("backdrop_succ_desc"));
} elseif($_GET['act'] === "status") {
if(mb_strlen($this->postParam("status")) > 255) {
$statusLength = (string) mb_strlen($this->postParam("status"));
@@ -234,7 +261,7 @@ final class UserPresenter extends OpenVKPresenter
}
$this->template->mode = in_array($this->queryParam("act"), [
- "main", "contacts", "interests", "avatar"
+ "main", "contacts", "interests", "avatar", "backdrop"
]) ? $this->queryParam("act")
: "main";
@@ -275,7 +302,7 @@ final class UserPresenter extends OpenVKPresenter
$this->redirect($user->getURL());
}
- function renderSetAvatar(): void
+ function renderSetAvatar()
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
@@ -295,8 +322,26 @@ final class UserPresenter extends OpenVKPresenter
$album->addPhoto($photo);
$album->setEdited(time());
$album->save();
-
- $this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
+
+ $flags = 0;
+ $flags |= 0b00010000;
+
+ $post = new Post;
+ $post->setOwner($this->user->id);
+ $post->setWall($this->user->id);
+ $post->setCreated(time());
+ $post->setContent("");
+ $post->setFlags($flags);
+ $post->save();
+ $post->attach($photo);
+ if($this->postParam("ava", true) == (int)1) {
+ $this->returnJson([
+ "url" => $photo->getURL(),
+ "id" => $photo->getPrettyId()
+ ]);
+ } else {
+ $this->flashFail("succ", tr("photo_saved"), tr("photo_saved_comment"));
+ }
}
function renderSettings(): void
diff --git a/Web/Presenters/VKAPIPresenter.php b/Web/Presenters/VKAPIPresenter.php
index a26a25b9..431379c5 100644
--- a/Web/Presenters/VKAPIPresenter.php
+++ b/Web/Presenters/VKAPIPresenter.php
@@ -6,6 +6,7 @@ use openvk\VKAPI\Exceptions\APIErrorException;
use openvk\Web\Models\Entities\{User, APIToken};
use openvk\Web\Models\Repositories\{Users, APITokens};
use lfkeitel\phptotp\{Base32, Totp};
+use WhichBrowser;
final class VKAPIPresenter extends OpenVKPresenter
{
@@ -98,20 +99,21 @@ final class VKAPIPresenter extends OpenVKPresenter
function renderPhotoUpload(string $signature): void
{
- $secret = CHANDLER_ROOT_CONF["security"]["secret"];
- $computedSignature = hash_hmac("sha3-224", $_SERVER["QUERY_STRING"], $secret);
+ $secret = CHANDLER_ROOT_CONF["security"]["secret"];
+ $queryString = rawurldecode($_SERVER["QUERY_STRING"]);
+ $computedSignature = hash_hmac("sha3-224", $queryString, $secret);
if(!(strlen($signature) == 56 && sodium_memcmp($signature, $computedSignature) == 0)) {
header("HTTP/1.1 422 Unprocessable Entity");
exit("Try harder <3");
}
- $data = unpack("vDOMAIN/Z10FIELD/vMF/vMP/PTIME/PUSER/PGROUP", base64_decode($_SERVER["QUERY_STRING"]));
+ $data = unpack("vDOMAIN/Z10FIELD/vMF/vMP/PTIME/PUSER/PGROUP", base64_decode($queryString));
if((time() - $data["TIME"]) > 600) {
header("HTTP/1.1 422 Unprocessable Entity");
exit("Expired");
}
- $folder = __DIR__ . "../../tmp/api-storage/photos";
+ $folder = __DIR__ . "/../../tmp/api-storage/photos";
$maxSize = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["api"]["maxFileSize"];
$maxFiles = OPENVK_ROOT_CONF["openvk"]["preferences"]["uploads"]["api"]["maxFilesPerDomain"];
$usrFiles = sizeof(glob("$folder/$data[USER]_*.oct"));
@@ -195,19 +197,24 @@ final class VKAPIPresenter extends OpenVKPresenter
$identity = NULL;
} else {
$token = (new APITokens)->getByCode($this->requestParam("access_token"));
- if(!$token)
+ if(!$token) {
$identity = NULL;
- else
+ } else {
$identity = $token->getUser();
+ $platform = $token->getPlatform();
+ }
}
}
+ if(!is_null($identity) && $identity->isBanned())
+ $this->fail(18, "User account is deactivated", $object, $method);
+
$object = ucfirst(strtolower($object));
$handlerClass = "openvk\\VKAPI\\Handlers\\$object";
if(!class_exists($handlerClass))
$this->badMethod($object, $method);
- $handler = new $handlerClass($identity);
+ $handler = new $handlerClass($identity, $platform);
if(!is_callable([$handler, $method]))
$this->badMethod($object, $method);
@@ -274,8 +281,11 @@ final class VKAPIPresenter extends OpenVKPresenter
$this->fail(28, "Invalid 2FA code", "internal", "acquireToken");
}
+ $platform = $this->requestParam("client_name");
+
$token = new APIToken;
$token->setUser($user);
+ $token->setPlatform($platform ?? (new WhichBrowser\Parser(getallheaders()))->toString());
$token->save();
$payload = json_encode([
diff --git a/Web/Presenters/VideosPresenter.php b/Web/Presenters/VideosPresenter.php
index e7b24344..4e4d484a 100644
--- a/Web/Presenters/VideosPresenter.php
+++ b/Web/Presenters/VideosPresenter.php
@@ -8,7 +8,8 @@ final class VideosPresenter extends OpenVKPresenter
{
private $videos;
private $users;
-
+ protected $presenterName = "videos";
+
function __construct(Videos $videos, Users $users)
{
$this->videos = $videos;
@@ -55,6 +56,9 @@ final class VideosPresenter extends OpenVKPresenter
{
$this->assertUserLoggedIn();
$this->willExecuteWriteAction();
+
+ if(OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
+ $this->flashFail("err", tr("error"), "Video uploads are disabled by the system administrator.");
if($_SERVER["REQUEST_METHOD"] === "POST") {
if(!empty($this->postParam("name"))) {
diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php
index 55c90518..727101ff 100644
--- a/Web/Presenters/WallPresenter.php
+++ b/Web/Presenters/WallPresenter.php
@@ -1,8 +1,9 @@
get(abs($user));
if(is_null($this->user)) {
$canPost = false;
@@ -65,7 +63,10 @@ final class WallPresenter extends OpenVKPresenter
}
if ($embedded == true) $this->template->_template = "components/wall.xml";
- $this->template->oObj = $owner;
+ $this->template->oObj = $owner;
+ if($user < 0)
+ $this->template->club = $owner;
+
$this->template->owner = $user;
$this->template->canPost = $canPost;
$this->template->count = $this->posts->getPostCountOnUserWall($user);
@@ -88,9 +89,6 @@ final class WallPresenter extends OpenVKPresenter
function renderRSS(int $user): void
{
- if(false)
- exit(tr("forbidden") . ": " . (string) random_int(0, 255));
-
$owner = ($user < 0 ? (new Clubs) : (new Users))->get(abs($user));
if(is_null($this->user)) {
$canPost = false;
@@ -231,6 +229,9 @@ final class WallPresenter extends OpenVKPresenter
if(!$canPost)
$this->flashFail("err", tr("not_enough_permissions"), tr("not_enough_permissions_comment"));
+ if($_FILES["_vid_attachment"] && OPENVK_ROOT_CONF['openvk']['preferences']['videos']['disableUploading'])
+ $this->flashFail("err", tr("error"), "Video uploads are disabled by the system administrator.");
+
$anon = OPENVK_ROOT_CONF["openvk"]["preferences"]["wall"]["anonymousPosting"]["enable"];
if($wallOwner instanceof Club && $this->postParam("as_group") === "on" && $this->postParam("force_sign") !== "on" && $anon) {
$manager = $wallOwner->getManager($this->user->identity);
@@ -259,16 +260,40 @@ final class WallPresenter extends OpenVKPresenter
$photo = Photo::fastMake($this->user->id, $this->postParam("text"), $_FILES["_pic_attachment"], $album, $anon);
}
- if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK) {
- $video = Video::fastMake($this->user->id, $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
- }
+ if($_FILES["_vid_attachment"]["error"] === UPLOAD_ERR_OK)
+ $video = Video::fastMake($this->user->id, $_FILES["_vid_attachment"]["name"], $this->postParam("text"), $_FILES["_vid_attachment"], $anon);
} catch(\DomainException $ex) {
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted"));
} catch(ISE $ex) {
$this->flashFail("err", tr("failed_to_publish_post"), tr("media_file_corrupted_or_too_large"));
}
- if(empty($this->postParam("text")) && !$photo && !$video)
+ try {
+ $poll = NULL;
+ $xml = $this->postParam("poll");
+ if (!is_null($xml) && $xml != "none")
+ $poll = Poll::import($this->user->identity, $xml);
+ } catch(TooMuchOptionsException $e) {
+ $this->flashFail("err", tr("failed_to_publish_post"), tr("poll_err_to_much_options"));
+ } catch(\UnexpectedValueException $e) {
+ $this->flashFail("err", tr("failed_to_publish_post"), "Poll format invalid");
+ }
+
+ $note = NULL;
+
+ if(!is_null($this->postParam("note")) && $this->postParam("note") != "none") {
+ $note = (new Notes)->get((int)$this->postParam("note"));
+
+ if(!$note || $note->isDeleted() || $note->getOwner()->getId() != $this->user->id) {
+ $this->flashFail("err", tr("error"), tr("error_attaching_note"));
+ }
+
+ if($note->getOwner()->getPrivacySetting("notes.read") < 1) {
+ $this->flashFail("err", " ");
+ }
+ }
+
+ if(empty($this->postParam("text")) && !$photo && !$video && !$poll && !$note)
$this->flashFail("err", tr("failed_to_publish_post"), tr("post_is_empty_or_too_big"));
try {
@@ -291,9 +316,24 @@ final class WallPresenter extends OpenVKPresenter
if(!is_null($video))
$post->attach($video);
+ if(!is_null($poll))
+ $post->attach($poll);
+
+ if(!is_null($note))
+ $post->attach($note);
+
if($wall > 0 && $wall !== $this->user->identity->getId())
(new WallPostNotification($wallOwner, $post, $this->user->identity))->emit();
+ $excludeMentions = [$this->user->identity->getId()];
+ if($wall > 0)
+ $excludeMentions[] = $wall;
+
+ $mentions = iterator_to_array($post->resolveMentions($excludeMentions));
+ foreach($mentions as $mentionee)
+ if($mentionee instanceof User)
+ (new MentionNotification($mentionee, $post, $post->getOwner(), strip_tags($post->getText())))->emit();
+
$this->redirect($wallOwner->getURL());
}
@@ -343,21 +383,52 @@ final class WallPresenter extends OpenVKPresenter
$this->assertNoCSRF();
$post = $this->posts->getPostById($wall, $post_id);
- if(!$post || $post->isDeleted()) $this->notFound();
+
+ if(!$post || $post->isDeleted())
+ $this->notFound();
+ $where = $this->postParam("type") ?? "wall";
+ $groupId = NULL;
+ $flags = 0;
+
+ if($where == "group")
+ $groupId = $this->postParam("groupId");
+
if(!is_null($this->user)) {
$nPost = new Post;
- $nPost->setOwner($this->user->id);
- $nPost->setWall($this->user->id);
+
+ if($where == "wall") {
+ $nPost->setOwner($this->user->id);
+ $nPost->setWall($this->user->id);
+ } elseif($where == "group") {
+ $nPost->setOwner($this->user->id);
+ $club = (new Clubs)->get((int)$groupId);
+
+ if(!$club || !$club->canBeModifiedBy($this->user->identity))
+ $this->notFound();
+
+ if($this->postParam("asGroup") == 1)
+ $flags |= 0b10000000;
+
+ if($this->postParam("signed") == 1)
+ $flags |= 0b01000000;
+
+ $nPost->setWall($groupId * -1);
+ }
+
$nPost->setContent($this->postParam("text"));
+ $nPost->setFlags($flags);
$nPost->save();
+
$nPost->attach($post);
if($post->getOwner(false)->getId() !== $this->user->identity->getId() && !($post->getOwner() instanceof Club))
(new RepostNotification($post->getOwner(false), $post, $this->user->identity))->emit();
};
-
- $this->returnJson(["wall_owner" => $this->user->identity->getId()]);
+
+ $this->returnJson([
+ "wall_owner" => $where == "wall" ? $this->user->identity->getId() : $groupId * -1
+ ]);
}
function renderDelete(int $wall, int $post_id): void
diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml
index 2c8c9e63..047050ad 100644
--- a/Web/Presenters/templates/@layout.xml
+++ b/Web/Presenters/templates/@layout.xml
@@ -17,62 +17,19 @@
{script "js/l10n.js"}
{script "js/openvk.cls.js"}
+ {css "js/node_modules/tippy.js/dist/backdrop.css"}
+ {css "js/node_modules/tippy.js/dist/border.css"}
+ {css "js/node_modules/tippy.js/dist/svg-arrow.css"}
+ {css "js/node_modules/tippy.js/themes/light.css"}
+ {script "js/node_modules/@popperjs/core/dist/umd/popper.min.js"}
+ {script "js/node_modules/tippy.js/dist/tippy-bundle.umd.min.js"}
+ {script "js/node_modules/handlebars/dist/handlebars.min.js"}
+
{if $isTimezoned == NULL}
{script "js/timezone.js"}
{/if}
- {ifset $thisUser}
- {if $thisUser->getNsfwTolerance() < 2}
- {css "css/nsfw-posts.css"}
- {/if}
-
- {if $theme !== NULL}
- {if $theme->inheritDefault()}
- {css "css/style.css"}
- {css "css/dialog.css"}
- {css "css/notifications.css"}
-
- {if $isXmas}
- {css "css/xmas.css"}
- {/if}
- {/if}
-
-
-
- {if $isXmas}
-
- {/if}
- {else}
- {css "css/style.css"}
- {css "css/dialog.css"}
- {css "css/notifications.css"}
-
- {if $isXmas}
- {css "css/xmas.css"}
- {/if}
- {/if}
-
- {if $thisUser->getStyleAvatar() == 1}
- {css "css/avatar.1.css"}
- {/if}
-
- {if $thisUser->getStyleAvatar() == 2}
- {css "css/avatar.2.css"}
- {/if}
-
- {if $thisUser->hasMicroblogEnabled() == 1}
- {css "css/microblog.css"}
- {/if}
- {else}
- {css "css/style.css"}
- {css "css/dialog.css"}
- {css "css/nsfw-posts.css"}
- {css "css/notifications.css"}
-
- {if $isXmas}
- {css "css/xmas.css"}
- {/if}
- {/ifset}
+ {include "_includeCSS.xml"}
{ifset headIncludes}
{include headIncludes}
@@ -92,6 +49,34 @@
+
+ {_close}
+
+
+
+ {_aw_legacy_ui}
+
+
+
+
+
+
+
+
+
+
+ {if isset($backdrops) && !is_null($backdrops)}
+
+
+
+ {/if}
+
⬆ {_to_top}
@@ -107,28 +92,66 @@
{_header_log_out}
{else}
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+ {var $atSearch = str_contains($_SERVER['REQUEST_URI'], "/search")}
+
+
+ {if !$atSearch}
+
+
+
+
+
+
+
+ {else}
+
+
+ {/if}
{/if}
{else}
@@ -182,7 +205,7 @@
{var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')}
{_admin}
- Helpdesk
+ {_helpdesk}
{if $helpdeskTicketNotAnsweredCount > 0}
({$helpdeskTicketNotAnsweredCount})
{/if}
@@ -210,7 +233,7 @@