mirror of
https://github.com/openvk/openvk
synced 2024-11-11 01:19:53 +03:00
Merge branch 'master' of github.com:openvk/openvk
This commit is contained in:
commit
8a373faba0
26 changed files with 277 additions and 464 deletions
18
README.md
18
README.md
|
@ -31,17 +31,23 @@ If you want, you can add your instance to the list above so that people can regi
|
|||
### Installation procedure
|
||||
|
||||
1. Install PHP 7.4, web-server, Composer, Node.js, Yarn and [Chandler](https://github.com/openvk/chandler)
|
||||
* PHP 8 has **not** yet been tested, so you should not expect it to work.
|
||||
|
||||
* PHP 8 has **not** yet been tested, so you should not expect it to work.
|
||||
|
||||
2. Install [commitcaptcha](https://github.com/openvk/commitcaptcha) and OpenVK as Chandler extensions like this:
|
||||
```
|
||||
|
||||
```bash
|
||||
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
|
||||
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
|
||||
```
|
||||
|
||||
3. And enable them:
|
||||
```
|
||||
|
||||
```bash
|
||||
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
|
||||
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
||||
```
|
||||
|
||||
4. Import `install/init-static-db.sql` to **same database** you installed Chandler to
|
||||
5. Import `install/init-event-db.sql` to **separate database**
|
||||
6. Copy `openvk-example.yml` to `openvk.yml` and change options
|
||||
|
@ -50,11 +56,12 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
9. Set `openvk` as your root app in `chandler.yml`
|
||||
|
||||
Once you are done, you can login as a system administrator on the network itself (no registration required):
|
||||
|
||||
* **Login**: `admin@localhost.localdomain6`
|
||||
* **Password**: `admin`
|
||||
* It is recommended to change the password before using the built-in account.
|
||||
* It is recommended to change the password before using the built-in account.
|
||||
|
||||
Full example installation instruction for CentOS 8 is also available [here](docs/centos8_install.md).
|
||||
Full example installation instruction for CentOS 8 is also available [here](https://docs.openvk.su/openvk_engine/centos8_installation/).
|
||||
|
||||
### If my website uses OpenVK, should I publish it's sources?
|
||||
|
||||
|
@ -65,6 +72,7 @@ You also not required to publish source texts of your themepacks and plugins.
|
|||
## Where can I get assistance?
|
||||
|
||||
You may reach out to us via:
|
||||
|
||||
* [Bug-tracker](https://github.com/openvk/openvk/projects/1)
|
||||
* [Ticketing system](https://openvk.su/support?act=new)
|
||||
* Telegram chat: Go to [our channel](https://t.me/openvkch) and open discussion in our channel menu.
|
||||
|
|
18
README_RU.md
18
README_RU.md
|
@ -31,17 +31,23 @@ _[English](README.md)_
|
|||
### Процедура установки
|
||||
|
||||
1. Установите PHP 7.4, веб-сервер, Composer, Node.js, Yarn и [Chandler](https://github.com/openvk/chandler)
|
||||
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать.
|
||||
|
||||
* PHP 8 еще **не** тестировался, поэтому не стоит ожидать, что он будет работать.
|
||||
|
||||
2. Установите [commitcaptcha](https://github.com/openvk/commitcaptcha) и OpenVK в качестве расширений Chandler следующим образом:
|
||||
```
|
||||
|
||||
```bash
|
||||
git clone https://github.com/openvk/openvk /path/to/chandler/extensions/available/openvk
|
||||
git clone https://github.com/openvk/commitcaptcha /path/to/chandler/extensions/available/commitcaptcha
|
||||
```
|
||||
|
||||
3. И включите их:
|
||||
```
|
||||
|
||||
```bash
|
||||
ln -s /path/to/chandler/extensions/available/commitcaptcha /path/to/chandler/extensions/enabled/
|
||||
ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions/enabled/
|
||||
```
|
||||
|
||||
4. Импортируйте `install/init-static-db.sql` в **ту же базу данных**, в которую вы установили Chandler
|
||||
5. Импортируйте `install/init-event-db.sql` в **отдельную базу данных**
|
||||
6. Скопируйте `openvk-example.yml` в `openvk.yml` и измените параметры
|
||||
|
@ -50,11 +56,12 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
9. Установите `openvk` в качестве корневого приложения в файле `chandler.yml`
|
||||
|
||||
После этого вы можете войти как системный администратор в саму сеть (регистрация не требуется):
|
||||
|
||||
* **Логин**: `admin@localhost.localdomain6`
|
||||
* **Пароль**: `admin`
|
||||
* Перед использованием встроенной учетной записи рекомендуется сменить пароль.
|
||||
* Перед использованием встроенной учетной записи рекомендуется сменить пароль.
|
||||
|
||||
Полный пример инструкции по установке CentOS 8 также доступен [здесь](docs/centos8_install.md).
|
||||
Полный пример инструкции по установке CentOS 8 также доступен [здесь](https://docs.openvk.su/openvk_engine/centos8_installation/).
|
||||
|
||||
### Если мой сайт использует OpenVK, должен ли я публиковать его исходные тексты?
|
||||
|
||||
|
@ -65,6 +72,7 @@ ln -s /path/to/chandler/extensions/available/openvk /path/to/chandler/extensions
|
|||
## Где я могу получить помощь?
|
||||
|
||||
Вы можете связаться с нами через:
|
||||
|
||||
* [Баг-трекер](https://github.com/openvk/openvk/projects/1)
|
||||
* [Помощь в OVK](https://openvk.su/support?act=new)
|
||||
* Telegram-чат: Перейдите на [наш канал](https://t.me/openvkch) и откройте обсуждение в меню нашего канала.
|
||||
|
|
|
@ -94,4 +94,9 @@ class Note extends Postable
|
|||
|
||||
return $cached;
|
||||
}
|
||||
|
||||
function getSource(): string
|
||||
{
|
||||
return $this->getRecord()->source;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,5 +127,10 @@ class TicketComment extends RowModel
|
|||
return $mark === 1;
|
||||
}
|
||||
|
||||
function isDeleted(): bool
|
||||
{
|
||||
return (bool) $this->getRecord()->deleted;
|
||||
}
|
||||
|
||||
use Traits\TRichText;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace openvk\Web\Models\Repositories;
|
|||
// use openvk\Web\Models\Entities\User;
|
||||
// use openvk\Web\Models\Repositories\Users;
|
||||
use openvk\Web\Models\Entities\TicketComment;
|
||||
use Nette\Database\Table\ActiveRow;
|
||||
use Chandler\Database\DatabaseConnection;
|
||||
|
||||
class TicketComments
|
||||
|
@ -20,7 +19,7 @@ class TicketComments
|
|||
|
||||
function getCommentsById(int $ticket_id): \Traversable
|
||||
{
|
||||
foreach($this->comments->where(['ticket_id' => $ticket_id]) as $comment) yield new TicketComment($comment);
|
||||
foreach($this->comments->where(['ticket_id' => $ticket_id, 'deleted' => 0]) as $comment) yield new TicketComment($comment);
|
||||
}
|
||||
|
||||
// private function toTicket(?ActiveRow $ar): ?Ticket
|
||||
|
|
|
@ -39,7 +39,7 @@ class Users
|
|||
function find(string $query): Util\EntityStream
|
||||
{
|
||||
$query = "%$query%";
|
||||
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name) LIKE ?", $query);
|
||||
$result = $this->users->where("CONCAT_WS(' ', first_name, last_name) LIKE ?", $query)->where("deleted", 0);
|
||||
|
||||
return new Util\EntityStream("User", $result);
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ final class AboutPresenter extends OpenVKPresenter
|
|||
$this->template->usersStats = (new Users)->getStatistics();
|
||||
$this->template->clubsCount = (new Clubs)->getCount();
|
||||
$this->template->postsCount = (new Posts)->getCount();
|
||||
$this->template->popularClubs = (new Clubs)->getPopularClubs();
|
||||
$this->template->popularClubs = iterator_to_array((new Clubs)->getPopularClubs());
|
||||
$this->template->admins = iterator_to_array((new Users)->getInstanceAdmins());
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,10 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
if(!$this->authenticator->verifyCredentials($user->id, $this->postParam("password")))
|
||||
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
||||
|
||||
$ovkUser = new User($user->related("profiles.user")->fetch());
|
||||
if($ovkUser->isDeleted())
|
||||
$this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password"));
|
||||
|
||||
$secret = $user->related("profiles.user")->fetch()["2fa_secret"];
|
||||
$code = $this->postParam("code");
|
||||
if(!is_null($secret)) {
|
||||
|
@ -136,7 +140,6 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
if(is_null($code))
|
||||
return;
|
||||
|
||||
$ovkUser = new User($user->related("profiles.user")->fetch());
|
||||
if(!($code === (new Totp)->GenerateToken(Base32::decode($secret)) || $ovkUser->use2faBackupCode((int) $code))) {
|
||||
$this->flash("err", tr("login_failed"), tr("incorrect_2fa_code"));
|
||||
return;
|
||||
|
@ -229,7 +232,7 @@ final class AuthPresenter extends OpenVKPresenter
|
|||
}
|
||||
|
||||
$user = $this->users->getByChandlerUser(new ChandlerUser($uRow));
|
||||
if(!$user)
|
||||
if(!$user || $user->isDeleted())
|
||||
$this->flashFail("err", tr("error"), tr("password_reset_error"));
|
||||
|
||||
$request = $this->restores->getLatestByUser($user);
|
||||
|
|
|
@ -207,6 +207,7 @@ final class GroupPresenter extends OpenVKPresenter
|
|||
$club->setShortcode(empty($this->postParam("shortcode")) ? NULL : $this->postParam("shortcode"));
|
||||
$club->setWall(empty($this->postParam("wall")) ? 0 : 1);
|
||||
$club->setAdministrators_List_Display(empty($this->postParam("administrators_list_display")) ? 0 : $this->postParam("administrators_list_display"));
|
||||
$club->setEveryone_Can_Create_Topics(empty($this->postParam("everyone_can_create_topics")) ? 0 : 1);
|
||||
$club->setDisplay_Topics_Above_Wall(empty($this->postParam("display_topics_above_wall")) ? 0 : 1);
|
||||
$club->setHide_From_Global_Feed(empty($this->postParam("hide_from_global_feed")) ? 0 : 1);
|
||||
|
||||
|
|
|
@ -67,6 +67,35 @@ final class NotesPresenter extends OpenVKPresenter
|
|||
$note->setCreated(time());
|
||||
$note->setName($this->postParam("name"));
|
||||
$note->setSource($this->postParam("html"));
|
||||
$note->setEdited(time());
|
||||
$note->save();
|
||||
|
||||
$this->redirect("/note" . $this->user->id . "_" . $note->getVirtualId());
|
||||
}
|
||||
}
|
||||
|
||||
function renderEdit(int $owner, int $note_id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->willExecuteWriteAction();
|
||||
|
||||
$note = $this->notes->getNoteById($owner, $note_id);
|
||||
|
||||
if(!$note || $note->getOwner()->getId() !== $owner || $note->isDeleted())
|
||||
$this->notFound();
|
||||
if(is_null($this->user) || !$note->canBeModifiedBy($this->user->identity))
|
||||
$this->flashFail("err", "Ошибка доступа", "Недостаточно прав для модификации данного ресурса.");
|
||||
$this->template->note = $note;
|
||||
|
||||
if($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
if(empty($this->postParam("name"))) {
|
||||
$this->flashFail("err", tr("error"), tr("error_segmentation"));
|
||||
}
|
||||
|
||||
$note->setName($this->postParam("name"));
|
||||
$note->setSource($this->postParam("html"));
|
||||
$note->setCached_Content(NULL);
|
||||
$note->setEdited(time());
|
||||
$note->save();
|
||||
|
||||
$this->redirect("/note" . $this->user->id . "_" . $note->getVirtualId());
|
||||
|
|
|
@ -210,12 +210,20 @@ abstract class OpenVKPresenter extends SimplePresenter
|
|||
$this->user->id = $this->user->identity->getId();
|
||||
$this->template->thisUser = $this->user->identity;
|
||||
$this->template->userTainted = $user->isTainted();
|
||||
|
||||
if($this->user->identity->isDeleted()) {
|
||||
Authenticator::i()->logout();
|
||||
Session::i()->set("_su", NULL);
|
||||
$this->flashFail("err", tr("error"), tr("profile_not_found"));
|
||||
$this->redirect("/", static::REDIRECT_TEMPORARY);
|
||||
}
|
||||
|
||||
if($this->user->identity->isBanned() && !$this->banTolerant) {
|
||||
header("HTTP/1.1 403 Forbidden");
|
||||
$this->getTemplatingEngine()->render(__DIR__ . "/templates/@banned.xml", [
|
||||
"thisUser" => $this->user->identity,
|
||||
"csrfToken" => $GLOBALS["csrfToken"],
|
||||
"isTimezoned" => Session::i()->get("_timezoneOffset"),
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
|
|
@ -226,6 +226,29 @@ final class SupportPresenter extends OpenVKPresenter
|
|||
$this->template->content = $parser->text($content);
|
||||
}
|
||||
|
||||
function renderDeleteComment(int $id): void
|
||||
{
|
||||
$this->assertUserLoggedIn();
|
||||
$this->assertNoCSRF();
|
||||
|
||||
$comment = $this->comments->get($id);
|
||||
if(is_null($comment))
|
||||
$this->notFound();
|
||||
|
||||
$ticket = $comment->getTicket();
|
||||
|
||||
if($ticket->isDeleted())
|
||||
$this->notFound();
|
||||
|
||||
if(!($ticket->getUserId() === $this->user->id && $comment->getUType() === 0))
|
||||
$this->assertPermission("openvk\Web\Models\Entities\TicketReply", "write", 0);
|
||||
|
||||
$this->willExecuteWriteAction();
|
||||
$comment->delete();
|
||||
|
||||
$this->flashFail("succ", tr("ticket_changed"), tr("ticket_changed_comment"));
|
||||
}
|
||||
|
||||
function renderRateAnswer(int $id, int $mark): void
|
||||
{
|
||||
$this->willExecuteWriteAction();
|
||||
|
|
|
@ -190,7 +190,11 @@
|
|||
<img src="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['src']}" alt="{php echo OPENVK_ROOT_CONF['openvk']['preferences']['adPoster']['caption']}" class="psa-poster" style="max-width: 100%; margin-top: 50px;" />
|
||||
</a>
|
||||
{else}
|
||||
<a href="/support" class="link">{_menu_support}</a>
|
||||
<a href="/support" class="link">{_menu_support}
|
||||
{if $ticketAnsweredCount > 0}
|
||||
(<b>{$ticketAnsweredCount}</b>)
|
||||
{/if}
|
||||
</a>
|
||||
<a href="/logout?hash={urlencode($csrfToken)}" class="link">{_menu_logout}</a>
|
||||
{/if}
|
||||
{else}
|
||||
|
|
|
@ -42,15 +42,17 @@
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
<h4>{_most_popular_groups}</h4>
|
||||
<ol>
|
||||
<li n:foreach="$popularClubs as $entry" style="margin-top: 5px;">
|
||||
<a href="{$entry->club->getURL()}">{$entry->club->getName()}</a>
|
||||
<div>
|
||||
{tr("participants", $entry->subscriptions)}
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
{if sizeof($popularClubs) !== 0}
|
||||
<h4>{_most_popular_groups}</h4>
|
||||
<ol>
|
||||
<li n:foreach="$popularClubs as $entry" style="margin-top: 5px;">
|
||||
<a href="{$entry->club->getURL()}">{$entry->club->getName()}</a>
|
||||
<div>
|
||||
{tr("participants", $entry->subscriptions)}
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
{/if}
|
||||
|
||||
<h4>{_rules}</h4>
|
||||
<div style="margin-top: 16px;">
|
||||
|
|
49
Web/Presenters/templates/Notes/Edit.xml
Normal file
49
Web/Presenters/templates/Notes/Edit.xml
Normal file
|
@ -0,0 +1,49 @@
|
|||
{extends "../@layout.xml"}
|
||||
|
||||
{block title}{_edit_note}{/block}
|
||||
|
||||
{block header}
|
||||
{var author = $note->getOwner()}
|
||||
<a href="{$author->getURL()}">{$author->getCanonicalName()}</a>
|
||||
»
|
||||
<a href="/notes{$author->getId()}">{_notes}</a>
|
||||
»
|
||||
<a href="/note{$author->getId()}_{$note->getVirtualId()}">{$note->getName()}</a>
|
||||
{/block}
|
||||
|
||||
{block content}
|
||||
<form id="noteFactory" method="POST">
|
||||
<input type="text" name="name" placeholder="{_name_note}" style="width:603px;" value="{$note->getName()}" />
|
||||
<br/><br/>
|
||||
<textarea name="html" style="display:none;"></textarea>
|
||||
<div id="editor" style="width:600px;height:300px;border:1px solid grey"></div>
|
||||
|
||||
<p><i><a href="/kb/notes">Кое-что</a> из (X)HTML поддерживается.</i></p>
|
||||
|
||||
<input type="hidden" name="hash" value="{$csrfToken}" />
|
||||
<button class="button">{_save}</button>
|
||||
|
||||
<a href="/note{$note->getOwner()->getId()}_{$note->getVirtualId()}" class="button">{_cancel}</a>
|
||||
</form>
|
||||
|
||||
{script "js/node_modules/monaco-editor/min/vs/loader.js"}
|
||||
{script "js/node_modules/requirejs/bin/r.js"}
|
||||
<script>
|
||||
require.config({
|
||||
paths: {
|
||||
'vs': '/assets/packages/static/openvk/js/node_modules/monaco-editor/min/vs'
|
||||
}
|
||||
});
|
||||
require(['vs/editor/editor.main'], function() {
|
||||
window._editor = monaco.editor.create(document.getElementById('editor'), {
|
||||
value: {$note->getSource()},
|
||||
lineNumbers: "off",
|
||||
language: "html"
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelector("#noteFactory").addEventListener("submit", function() {
|
||||
document.querySelector("textarea").value = window._editor.getValue();
|
||||
});
|
||||
</script>
|
||||
{/block}
|
|
@ -18,53 +18,61 @@
|
|||
max-width: 245pt;
|
||||
max-height: 200pt;
|
||||
}
|
||||
|
||||
|
||||
#userContent blockquote {
|
||||
background-color: #f3f3f3;
|
||||
border-bottom: 5px solid #969696;
|
||||
padding: 1;
|
||||
}
|
||||
|
||||
|
||||
#userContent cite {
|
||||
margin-top: 1em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
#userContent cite::before {
|
||||
content: "— ";
|
||||
}
|
||||
</style>
|
||||
|
||||
<article id="userContent" style="min-height: 300pt;margin: 10px;">
|
||||
<div class="note_header">
|
||||
<div class="note_title">
|
||||
<div class="note_title">
|
||||
<a>{$note->getName()}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="byline">
|
||||
<span><a href="{$author->getURL()}">{$author->getCanonicalName()}</a></span> {$note->getPublicationTime()}
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: 6px;">
|
||||
{$note->getText()|noescape}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div style="width: 100%; min-height: 100px;">
|
||||
<div style="float: left; min-height: 100px; width: 70%;">
|
||||
{include "../components/comments.xml",
|
||||
comments => $comments,
|
||||
count => $cCount,
|
||||
page => $cPage,
|
||||
model => "notes",
|
||||
parent => $note}
|
||||
</div>
|
||||
<div style="float: right; min-height: 100px; width: 30%;">
|
||||
<h4>{_actions}</h4>
|
||||
<div n:if="isset($thisUser) && $thisUser->getId() === $note->getOwner()->getId()">
|
||||
<a id="_noteDelete" href="/note{$note->getOwner()->getId()}_{$note->getId()}/delete" class="profile_link" style="display:block;width:96%;">{_delete}</a>
|
||||
|
||||
<article id="userContent" style="margin: 10px 10px 0;">
|
||||
<div class="note_header">
|
||||
<div class="note_title">
|
||||
<div class="note_title">
|
||||
<a>{$note->getName()}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="byline">
|
||||
<span><a href="{$author->getURL()}">{$author->getCanonicalName()}</a></span> {$note->getPublicationTime()}
|
||||
<span n:if="$note->getEditTime() > $note->getPublicationTime()">({_edited} {$note->getEditTime()})</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-left: 6px; width: 535px;">
|
||||
{$note->getText()|noescape}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div class="note_footer" style="margin: 10px 10px 0;">
|
||||
<div class="comments_count">
|
||||
{if sizeof($comments) > 0}
|
||||
{_comments} ({$note->getCommentsCount()})
|
||||
{else}
|
||||
{_no_comments}
|
||||
{/if}
|
||||
<span n:if="isset($thisUser) && $thisUser->getId() === $note->getOwner()->getId()"> |
|
||||
<a id="_noteDelete" href="/note{$note->getOwner()->getId()}_{$note->getId()}/delete">{_delete}</a>
|
||||
|
|
||||
<a href="/note{$note->getOwner()->getId()}_{$note->getVirtualId()}/edit">{_edit}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin: 6px 10px 10px;border-top: 1px solid #ddd;">
|
||||
{include "../components/comments.xml",
|
||||
comments => $comments,
|
||||
count => $cCount,
|
||||
page => $cPage,
|
||||
model => "notes",
|
||||
parent => $note,
|
||||
showTitle => false}
|
||||
</div>
|
||||
{/block}
|
||||
|
|
|
@ -28,11 +28,9 @@
|
|||
{var cover = $x->getCoverPhoto()}
|
||||
{var preview = is_null($cover) ? "/assets/packages/static/openvk/img/camera_200.png" : $cover->getURL()}
|
||||
|
||||
<center style="height: 54pt; width: 140px;">
|
||||
<a href="/album{$x->getPrettyId()}">
|
||||
<img src="{$preview}" alt="{$x->getName()}" style="max-height: 100%; max-width: 100%;" />
|
||||
</a>
|
||||
</center>
|
||||
<a href="/album{$x->getPrettyId()}">
|
||||
<img src="{$preview}" alt="{$x->getName()}" style="height: 130px; width: 170px; object-fit: cover" />
|
||||
</a>
|
||||
{/block}
|
||||
|
||||
{block name}
|
||||
|
@ -40,8 +38,8 @@
|
|||
{/block}
|
||||
|
||||
{block description}
|
||||
<span>{$x->getDescription() ?? $x->getName()}</span><br/>
|
||||
<span style="color: grey;">{$x->getPhotosCount()} фотографий</span><br/>
|
||||
<span style="color: grey;">Создан {$x->getCreationTime()}</span><br/>
|
||||
<span style="color: grey;">Изменён {$x->getEditTime() ?? $x->getCreationTime()}</span>
|
||||
<span>{$x->getDescription() ?? $x->getName()}</span><br />
|
||||
<span style="color: grey;">{$x->getPhotosCount()} фотографий</span><br />
|
||||
<span style="color: grey;">Обновлен {$x->getEditTime() ?? $x->getCreationTime()}</span><br />
|
||||
<span style="color: grey;">Создан {$x->getCreationTime()}</span><br />
|
||||
{/block}
|
||||
|
|
|
@ -101,11 +101,9 @@
|
|||
{/if}
|
||||
</div>
|
||||
|
||||
{if $comment->getUType() === 0}
|
||||
<div class="post-menu">
|
||||
<a href="/support/comment/{$comment->getId()}/delete">{_delete}</a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="post-menu">
|
||||
<a href="/support/comment/{$comment->getId()}/delete?hash={urlencode($csrfToken)}">{_delete}</a>
|
||||
</div>
|
||||
|
||||
{if $comment->getUType() === 1 && !is_null($comment->isLikedByUser())}
|
||||
<div class="post-menu">
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
|
||||
{if $comment->getUType() === 0}
|
||||
<div class="post-menu">
|
||||
<a href="/support/comment/{$comment->getId()}/delete">{_delete}</a>
|
||||
<a href="/support/comment/{$comment->getId()}/delete?hash={urlencode($csrfToken)}">{_delete}</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ routes:
|
|||
handler: "Support->makeComment"
|
||||
- url: "/al_comments/create/support/reply/{num}"
|
||||
handler: "Support->AnswerTicketReply"
|
||||
- url: "/support/comment/{num}/delete"
|
||||
handler: "Support->deleteComment"
|
||||
- url: "/al_comments/create/{text}/{num}"
|
||||
handler: "Comment->makeComment"
|
||||
- url: "/support/delete/{num}"
|
||||
|
@ -223,6 +225,8 @@ routes:
|
|||
handler: "Notes->view"
|
||||
- url: "/notes/create"
|
||||
handler: "Notes->create"
|
||||
- url: "/note{num}_{num}/edit"
|
||||
handler: "Notes->edit"
|
||||
- url: "/note{num}_{num}/delete"
|
||||
handler: "Notes->delete"
|
||||
- url: "/invite"
|
||||
|
|
|
@ -214,7 +214,7 @@ a {
|
|||
}
|
||||
|
||||
.page_yellowheader a {
|
||||
color: #C8BF85;
|
||||
color: #696029;
|
||||
}
|
||||
|
||||
.page_content {
|
||||
|
@ -794,9 +794,9 @@ table.User {
|
|||
}
|
||||
|
||||
.tabs {
|
||||
border-bottom: 1px solid #707070;
|
||||
margin-right: -12px;
|
||||
margin-left: -12px;
|
||||
border-bottom: 1px solid #707070;
|
||||
margin-right: -12px;
|
||||
margin-left: -12px;
|
||||
}
|
||||
|
||||
#activetabs {
|
||||
|
@ -1581,11 +1581,10 @@ body.scrolled .toTop:hover {
|
|||
}
|
||||
|
||||
.postFeedWrapper {
|
||||
margin: -10px;
|
||||
width: 611px;
|
||||
padding: 4px 8px;
|
||||
background-color: rgb(240, 240, 240);
|
||||
border-bottom: 1px solid #ccc;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.user-alert {
|
||||
|
@ -1786,38 +1785,49 @@ body.scrolled .toTop:hover {
|
|||
.hover-box:hover {
|
||||
background-color: #C0CAD5;
|
||||
}
|
||||
|
||||
.summaryBar {
|
||||
border-bottom: 1px solid #DAE2E8;
|
||||
clear: both;
|
||||
padding: 0 10px;
|
||||
padding-top: 11px;
|
||||
padding-top: 11px;
|
||||
color: black;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
margin-left: -12px;
|
||||
margin-right: -12px;
|
||||
border-bottom: 1px solid #DAE2E8;
|
||||
clear: both;
|
||||
padding: 11px 10px;
|
||||
color: black;
|
||||
font-weight: normal;
|
||||
line-height: normal;
|
||||
margin-left: -12px;
|
||||
margin-right: -12px;
|
||||
}
|
||||
|
||||
.summaryBar .summary {
|
||||
color: #45688E;
|
||||
font-weight: bold;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 4px;
|
||||
color: #45688E;
|
||||
font-weight: bold;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.note_header {
|
||||
background: #f7f7f7;
|
||||
border-bottom: solid 1px #DAE1E8;
|
||||
border-top: solid 1px #45688E;
|
||||
padding: 4px 6px 5px 6px;
|
||||
background: #f7f7f7;
|
||||
border-bottom: solid 1px #DAE1E8;
|
||||
border-top: solid 1px #45688E;
|
||||
padding: 4px 6px 5px 6px;
|
||||
}
|
||||
|
||||
.note_header .note_title {
|
||||
color: #45688E;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 15px;
|
||||
margin: 0px;
|
||||
padding: 0px 0px 1px 0px;
|
||||
color: #45688E;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 15px;
|
||||
margin: 0;
|
||||
padding: 0 0 1px 0;
|
||||
}
|
||||
.page_yellowheader a {
|
||||
color: #696029;
|
||||
|
||||
.note_footer {
|
||||
border-top: 1px solid #ddd;
|
||||
clear: both;
|
||||
margin-top: 10px;
|
||||
padding: 0px 2px 0px 6px;
|
||||
}
|
||||
|
||||
.comments_count {
|
||||
padding: 5px 0px 0px 0px;
|
||||
}
|
|
@ -1,357 +0,0 @@
|
|||
# Installing OpenVK
|
||||
|
||||
Based on [@rem-pai](https://github.com/rem-pai)'s way to install OpenVK modified using my experience.
|
||||
|
||||
!!WARNING!!
|
||||
|
||||
CentOS 8 is reaching it's end-of-life soon. There are other supported similar distributions like Rocky Linux or AlmaLinux.
|
||||
|
||||
## SELinux
|
||||
|
||||
🖥Run the command:
|
||||
|
||||
```bash
|
||||
sestatus
|
||||
```
|
||||
|
||||
If it says `SELinux status: enabled` then SELinux will disturb us. Let's disable it.
|
||||
|
||||
_ℹNote: I know that it's not most secured solution but I don't know any proper way that will work._
|
||||
|
||||
📝Edit file `/etc/sysconfig/selinux` and change the line `SELinux=enforcing` to `SELinux=disabled`, then 🔌reboot your machine. `sestatus` should tell `SELinux status: disabled` right now.
|
||||
|
||||
## Dependencies
|
||||
|
||||
🖥Let's install EPEL and Remi repos for PHP 7.4:
|
||||
|
||||
```bash
|
||||
dnf -y install epel-release
|
||||
dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
|
||||
```
|
||||
|
||||
🖥Then enable modules that we need:
|
||||
|
||||
```bash
|
||||
dnf -y module enable php:remi-7.4
|
||||
dnf -y module enable nodejs:14
|
||||
```
|
||||
|
||||
🖥And install dependencies:
|
||||
|
||||
```bash
|
||||
dnf -y install php php-cli php-common unzip php-zip php-yaml php-gd php-pdo_mysql nodejs git
|
||||
```
|
||||
|
||||
🖥Don't forget about Yarn and Composer:
|
||||
|
||||
```bash
|
||||
npm i -g yarn
|
||||
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
php composer-setup.php --filename=composer2 --install-dir=/bin --snapshot
|
||||
rm composer-setup.php
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
🖥We will use Percona Server for DB:
|
||||
|
||||
```bash
|
||||
dnf -y install https://repo.percona.com/yum/percona-release-latest.noarch.rpm
|
||||
percona-release setup -y ps80
|
||||
dnf -y install percona-server-server percona-toolkit
|
||||
systemctl start mysql
|
||||
```
|
||||
|
||||
🖥And then look up for temporary password:
|
||||
|
||||
```bash
|
||||
cat /var/log/mysqld.log | grep password
|
||||
```
|
||||
|
||||
It should look like this:
|
||||
|
||||
2021-01-11T12:56:09.203991Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: >b?Q.fDXJ4fk
|
||||
|
||||
🖥Then run `mysql_secure_installation`, set new password and answer like this:
|
||||
|
||||
Change the password for root ? ((Press y|Y for Yes, any other key for No) : n
|
||||
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
|
||||
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
|
||||
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
|
||||
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
|
||||
|
||||
### ffmpeg
|
||||
|
||||
Additionally, you can install ffmpeg for processing videos.
|
||||
|
||||
🖥You will need to use RPMFusion repo to install it:
|
||||
|
||||
```bash
|
||||
dnf -y localinstall --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
|
||||
dnf -y install --nogpgcheck https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm
|
||||
```
|
||||
|
||||
🖥Then install SDL2 and ffmpeg:
|
||||
|
||||
```bash
|
||||
dnf -y install http://rpmfind.net/linux/epel/7/x86_64/Packages/s/SDL2-2.0.10-1.el7.x86_64.rpm
|
||||
dnf -y install ffmpeg
|
||||
```
|
||||
|
||||
## Chandler and OpenVK installation
|
||||
|
||||
🖥Install Chandler in `/opt`:
|
||||
|
||||
```bash
|
||||
cd /opt
|
||||
git clone https://github.com/openvk/chandler.git
|
||||
cd chandler/
|
||||
composer2 install
|
||||
```
|
||||
|
||||
🖥You will need a secret key. You can generate it using:
|
||||
|
||||
```bash
|
||||
cat /dev/random | tr -dc 'a-z0-9' | fold -w 128 | head -n 1
|
||||
```
|
||||
|
||||
📝Now edit config file `chandler-example.yml` like this:
|
||||
|
||||
```yaml
|
||||
chandler:
|
||||
debug: true
|
||||
websiteUrl: null
|
||||
rootApp: "openvk"
|
||||
|
||||
preferences:
|
||||
appendExtension: "xhtml"
|
||||
adminUrl: "/chandlerd"
|
||||
exposeChandler: true
|
||||
|
||||
database:
|
||||
dsn: "mysql:unix_socket=/var/lib/mysql/mysql.sock;dbname=db"
|
||||
user: "root"
|
||||
password: "DATABASE_PASSWORD"
|
||||
|
||||
security:
|
||||
secret: "SECRET_KEY_HERE"
|
||||
csrfProtection: "permissive"
|
||||
sessionDuration: 14
|
||||
```
|
||||
|
||||
🖥And rename it to `chandler.yml`:
|
||||
|
||||
```bash
|
||||
mv chandler-example.yml chandler.yml
|
||||
```
|
||||
|
||||
🖥Now let's install CommitCaptcha extension. It is mandatory for OpenVK.
|
||||
|
||||
```bash
|
||||
cd extensions/available/
|
||||
git clone https://github.com/openvk/commitcaptcha.git
|
||||
cd commitcaptcha/
|
||||
composer2 install
|
||||
```
|
||||
|
||||
🖥And now download OpenVK:
|
||||
|
||||
```bash
|
||||
cd ..
|
||||
git clone https://github.com/openvk/openvk.git
|
||||
cd openvk/
|
||||
composer2 install
|
||||
cd Web/static/js
|
||||
yarn install
|
||||
```
|
||||
|
||||
📝Now edit config file `openvk-example.yml` like this:
|
||||
|
||||
```yaml
|
||||
openvk:
|
||||
debug: true
|
||||
appearance:
|
||||
name: "OpenVK"
|
||||
motd: "Yet another OpenVK instance"
|
||||
preferences:
|
||||
femaleGenderPriority: true
|
||||
uploads:
|
||||
disableLargeUploads: false
|
||||
mode: "basic"
|
||||
shortcodes:
|
||||
forbiddenNames:
|
||||
- "index.php"
|
||||
security:
|
||||
requireEmail: false
|
||||
requirePhone: false
|
||||
forcePhoneVerification: false
|
||||
forceEmailVerification: false
|
||||
enableSu: true
|
||||
rateLimits:
|
||||
actions: 5
|
||||
time: 20
|
||||
maxViolations: 50
|
||||
maxViolationsAge: 120
|
||||
autoban: true
|
||||
support:
|
||||
supportName: "Moderator"
|
||||
adminAccount: 1 # Change this ok
|
||||
messages:
|
||||
strict: false
|
||||
wall:
|
||||
postSizes:
|
||||
maxSize: 60000
|
||||
processingLimit: 3000
|
||||
emojiProcessingLimit: 1000
|
||||
menu:
|
||||
links:
|
||||
|
||||
adPoster:
|
||||
enable: false
|
||||
src: "https://example.org/ad_poster.jpeg"
|
||||
caption: "Ad caption"
|
||||
link: "https://example.org/product.aspx?id=10&from=ovk"
|
||||
bellsAndWhistles:
|
||||
fartscroll: false
|
||||
testLabel: false
|
||||
credentials:
|
||||
smsc:
|
||||
enable: false
|
||||
client: ""
|
||||
secret: ""
|
||||
eventDB:
|
||||
enable: true # Better enable this
|
||||
database:
|
||||
dsn: "mysql:unix_socket=/var/lib/mysql/mysql.sock;dbname=openvk_eventdb"
|
||||
user: "root"
|
||||
password: "DATABASE_PASSWORD"
|
||||
```
|
||||
|
||||
Please note `eventDB` section because it's better to enable event database.
|
||||
|
||||
🖥And rename it to `openvk.yml`:
|
||||
|
||||
```bash
|
||||
mv openvk-example.yml openvk.yml
|
||||
```
|
||||
|
||||
🖥Then enable CommitCaptcha and OpenVK for Chandler:
|
||||
|
||||
```bash
|
||||
ln -s /opt/chandler/extensions/available/commitcaptcha/ /opt/chandler/extensions/enabled/commitcaptcha
|
||||
ln -s /opt/chandler/extensions/available/openvk/ /opt/chandler/extensions/enabled/openvk
|
||||
```
|
||||
|
||||
### DB configuration
|
||||
|
||||
_ℹNote: it's better to create another user for SQL but I won't cover that._
|
||||
|
||||
🖥Enter MySQL shell:
|
||||
|
||||
```bash
|
||||
mysql -p
|
||||
```
|
||||
|
||||
🖥And create main and event databases:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE openvk;
|
||||
CREATE DATABASE openvk_eventdb;
|
||||
exit
|
||||
```
|
||||
|
||||
🖥Go to `/opt/chandler`:
|
||||
|
||||
```bash
|
||||
cd /opt/chandler
|
||||
```
|
||||
|
||||
📝We need to import Chandler database but for some reason it's not ready for use so we need to edit dump `install/init-db.sql`:
|
||||
1\. Remove ` PAGE_CHECKSUM=1` everywhere.
|
||||
2\. Replace `Aria` with `InnoDB` everywhere.
|
||||
|
||||
🖥Now database dump can be imported:
|
||||
|
||||
```bash
|
||||
mysql -p'DATABASE_PASSWORD' openvk < install/init-db.sql
|
||||
```
|
||||
|
||||
🖥Go to `extensions/available/openvk/`:
|
||||
|
||||
```bash
|
||||
cd extensions/available/openvk/
|
||||
```
|
||||
|
||||
📝We also need to import OpenVK database. Unless you use MariaDB (we are using Percona here) you should edit `install/init-static-db.sql`:
|
||||
1\. Replace `utf8mb4_unicode_nopad_ci` with `utf8mb4_unicode_520_ci` everywhere.
|
||||
|
||||
🖥Now database dump can be imported:
|
||||
|
||||
```bash
|
||||
mysql -p'DATABASE_PASSWORD' openvk < install/init-static-db.sql
|
||||
```
|
||||
|
||||
🖥Also import event database:
|
||||
|
||||
```bash
|
||||
mysql -p'DATABASE_PASSWORD' openvk_eventdb < install/init-event-db.sql
|
||||
```
|
||||
|
||||
### Webserver configuration
|
||||
|
||||
Apache is already installed so we will use it.
|
||||
|
||||
🖥Make the user `apache` owner of the `chandler` folder:
|
||||
|
||||
```bash
|
||||
cd /opt
|
||||
chown -R apache: chandler/
|
||||
```
|
||||
|
||||
📝Now let's create config file `/etc/httpd/conf.d/10-openvk.conf`:
|
||||
|
||||
```apache
|
||||
<VirtualHost *:80>
|
||||
ServerName openvk.local
|
||||
DocumentRoot /opt/chandler/htdocs
|
||||
|
||||
<Directory /opt/chandler/htdocs>
|
||||
AllowOverride All
|
||||
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
ErrorLog /var/log/openvk/error.log
|
||||
CustomLog /var/log/openvk/access.log combinedio
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
📝Also enable rewrite_module by creating `/etc/httpd/conf.modules.d/02-rewrite.conf`:
|
||||
|
||||
```apache
|
||||
LoadModule rewrite_module modules/mod_rewrite.so
|
||||
```
|
||||
|
||||
🖥Make directory for OpenVK logs and make the user `apache` owner of it:
|
||||
|
||||
```bash
|
||||
mkdir /var/log/openvk
|
||||
chown apache: /var/log/openvk/
|
||||
```
|
||||
|
||||
🖥Make the firewall exception for port 80:
|
||||
|
||||
```bash
|
||||
firewall-cmd --permanent --add-port=80/tcp
|
||||
firewall-cmd --reload
|
||||
```
|
||||
|
||||
🖥And start Apache:
|
||||
|
||||
```bash
|
||||
systemctl start httpd
|
||||
```
|
||||
|
||||
OpenVK should work right now!
|
||||
|
||||
Also you can raise 2MB the file limit through editing `/etc/php.ini`. And it's also better to install PHPMyAdmin but I won't cover that.
|
|
@ -1 +1,3 @@
|
|||
--- if you haven't used helpdesk before nov 25, 2021 - you will not need it.
|
||||
|
||||
UPDATE `tickets_comments` SET `text`=REGEXP_REPLACE(`text`, "(?:Здравствуйте, [^!]*!<br><\/br>|<br><\/br>С уважением,<br\/> Команда поддержки OpenVK.)", "") WHERE 1=1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Locales for OpenVK
|
||||
So, there is a locales contained here for [OpenVK](../../../openvk).
|
||||
So, there is a locales contained here for [OpenVK](../../../).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -295,8 +295,11 @@
|
|||
"name_note" = "Title";
|
||||
"text_note" = "Content";
|
||||
"create_note" = "Create note";
|
||||
"edit_note" = "Edit note";
|
||||
"actions" = "Actions";
|
||||
|
||||
"edited" = "Edited";
|
||||
|
||||
"notes_zero" = "No notes";
|
||||
"notes_one" = "$1 note";
|
||||
"notes_other" = "$1 notes";
|
||||
|
|
|
@ -313,8 +313,11 @@
|
|||
"name_note" = "Название";
|
||||
"text_note" = "Содержание";
|
||||
"create_note" = "Создать заметку";
|
||||
"edit_note" = "Редактировать заметку";
|
||||
"actions" = "Действия";
|
||||
|
||||
"edited" = "Отредактировано";
|
||||
|
||||
"notes_zero" = "Ни одной заметки";
|
||||
"notes_one" = "Одна заметка";
|
||||
"notes_few" = "$1 заметки";
|
||||
|
|
Loading…
Reference in a new issue