Compare commits

...

13 commits

Author SHA1 Message Date
n1rwana
19dee0eb05
Merge a16e15eaef into 3ceb27e532 2024-11-03 08:09:14 +00:00
3ceb27e532
build(composer.lock): update dependencies 2024-11-03 00:20:54 +03:00
99a2e3a8e6
fix(docker): set openvk dir as workdir
So that opening a shell with `docker compose exec openvk bash` would lead to openvk dir instead of ~/html which is not used
2024-11-03 00:05:40 +03:00
mrilyew
341226cac5 wall: fix 500 when no user 2024-11-02 16:31:35 +03:00
9b53839192
ci(build-base): add ability to manually dispatch builds 2024-11-02 12:43:11 +03:00
mrilyew
fab39bd7fd
Posts: add source param (#934)
* Chopin

- Полностью переписана та часть где про источник поста
- Исправлен метод video.search
- Сокращено число запросов в БД у шаблона поста
- Удалена ссылка на прикреплятор заметок потому что low quality
- Исправлен баг с прикреплённой заметкой в api, но только если ты указал версию.
- Исправлены проблемы с кешированными спрайтшитами

* Chopin 2
2024-11-01 14:46:41 +03:00
ayato
9b220a88db
locales/en.strings: Rephrasing some strings and grammar check (#1098)
* locales: English: fix grammar

* locales: English: fix confusing labels in the repost modal

Clarified modal phrasing when reposting a user's post. The previous wording, 'Share to user's wall,' was ambiguous and could be interpreted as either sharing to your own wall or the original user's wall. Updated the language to make it clear that the post will be shared to your wall.

---------

Co-authored-by: Vladimir Barinov <veselcraft@icloud.com>
2024-11-01 14:00:09 +03:00
ayato
d1bcdaf7d7
Link directly to interests section of the edit page in completeness gauge (#1113) 2024-11-01 13:58:14 +03:00
f83c45ead9
build(docker): remove version from compose file and add name 2024-10-31 12:58:10 +03:00
Jillian Österreich
96dad033ba
fix(theme-midnight): bump version to 0.0.3.0 2024-10-30 18:59:03 +07:00
b557f42daa
build: add additional compose file for devs 2024-10-29 22:11:06 +03:00
Jillian Österreich
250c022bde
docs(docker): improve instructions 2024-10-30 00:16:06 +07:00
n1rwana
a16e15eaef
Фикс проверки заблокированных ссылок 2023-08-05 14:49:41 +03:00
40 changed files with 739 additions and 422 deletions

View file

@ -2,7 +2,8 @@ name: Build base images
on:
schedule:
- cron: '0 0 * * *'
- cron: "0 0 * * *"
workflow_dispatch:
env:
BASE_IMAGE_NAME: php

View file

@ -74,7 +74,7 @@ final class Video extends VKAPIRequestHandler
$return_items = [];
$profiles = [];
$groups = [];
foreach($items as $item)
foreach($items as $item) {
$return_item = $item->getApiStructure($this->getUser());
$return_item = $return_item->video;
$return_items[] = $return_item;
@ -85,6 +85,7 @@ final class Video extends VKAPIRequestHandler
else
$groups[] = abs($return_item['owner_id']);
}
}
if($extended) {
$profiles = array_unique($profiles);

View file

@ -102,7 +102,14 @@ final class Wall extends VKAPIRequestHandler
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
$attachments[] = $attachment->getApiStructure($this->getUser());
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
if(VKAPI_DECL_VER === '4.100') {
$attachments[] = $attachment->toVkApiStruct();
} else {
$attachments[] = [
'type' => 'note',
'note' => $attachment->toVkApiStruct()
];
}
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
$attachments[] = [
"type" => "audio",
@ -188,6 +195,9 @@ final class Wall extends VKAPIRequestHandler
]
];
if($post->hasSource())
$post_temp_obj->copyright = $post->getVkApiCopyright();
if($signerId)
$post_temp_obj->signer_id = $signerId;
@ -291,7 +301,14 @@ final class Wall extends VKAPIRequestHandler
} else if ($attachment instanceof \openvk\Web\Models\Entities\Video) {
$attachments[] = $attachment->getApiStructure($this->getUser());
} else if ($attachment instanceof \openvk\Web\Models\Entities\Note) {
if(VKAPI_DECL_VER === '4.100') {
$attachments[] = $attachment->toVkApiStruct();
} else {
$attachments[] = [
'type' => 'note',
'note' => $attachment->toVkApiStruct()
];
}
} else if ($attachment instanceof \openvk\Web\Models\Entities\Audio) {
$attachments[] = [
"type" => "audio",
@ -373,6 +390,9 @@ final class Wall extends VKAPIRequestHandler
]
];
if($post->hasSource())
$post_temp_obj->copyright = $post->getVkApiCopyright();
if($signerId)
$post_temp_obj->signer_id = $signerId;
@ -543,6 +563,12 @@ final class Wall extends VKAPIRequestHandler
$post->setFlags($flags);
$post->setApi_Source_Name($this->getPlatform());
if(!is_null($copyright) && !empty($copyright)) {
try {
$post->setSource($copyright);
} catch(\Throwable) {}
}
if($owner_id < 0 && !$wallOwner->canBeModifiedBy($this->getUser()) && $wallOwner->getWallType() == 2)
$post->setSuggested(1);
@ -558,11 +584,11 @@ final class Wall extends VKAPIRequestHandler
# Пример: photo1_1
if(sizeof($attachmentsArr) > 10)
$this->fail(50, "Error: too many attachments");
$this->fail(50, "Too many attachments");
preg_match_all("/poll/m", $attachments, $matches, PREG_SET_ORDER, 0);
if(sizeof($matches) > 1)
$this->fail(85, "Error: too many polls");
$this->fail(85, "Too many polls");
foreach($attachmentsArr as $attac) {
$attachmentType = NULL;
@ -993,7 +1019,7 @@ final class Wall extends VKAPIRequestHandler
}
}
function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "") {
function edit(int $owner_id, int $post_id, string $message = "", string $attachments = "", string $copyright = NULL) {
$this->requireUser();
$this->willExecuteWriteAction();
@ -1002,9 +1028,6 @@ final class Wall extends VKAPIRequestHandler
if(!$post || $post->isDeleted())
$this->fail(102, "Invalid post");
if(empty($message) && empty($attachments))
$this->fail(100, "Required parameter 'message' missing.");
if(!$post->canBeEditedBy($this->getUser()))
$this->fail(7, "Access to editing denied");
@ -1012,6 +1035,12 @@ final class Wall extends VKAPIRequestHandler
$post->setContent($message);
$post->setEdited(time());
if(!is_null($copyright) && !empty($copyright)) {
try {
$post->setSource($copyright);
} catch(\Throwable) {}
}
$post->save(true);
# todo добавить такое в веб версию
@ -1082,6 +1111,63 @@ final class Wall extends VKAPIRequestHandler
return 1;
}
function checkCopyrightLink(string $link): int
{
$this->requireUser();
try {
$result = check_copyright_link($link);
} catch(\InvalidArgumentException $e) {
$this->fail(3102, "Specified link is incorrect (can't find source)");
} catch(\LengthException $e) {
$this->fail(3103, "Specified link is incorrect (too long)");
} catch(\LogicException $e) {
$this->fail(3104, "Link is suspicious");
} catch(\Throwable $e) {
$this->fail(3102, "Specified link is incorrect");
}
return 1;
}
function pin(int $owner_id, int $post_id)
{
$this->requireUser();
$this->willExecuteWriteAction();
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
if(!$post || $post->isDeleted())
$this->fail(100, "One of the parameters specified was missing or invalid: post_id is undefined");
if(!$post->canBePinnedBy($this->getUser()))
return 0;
if($post->isPinned())
return 1;
$post->pin();
return 1;
}
function unpin(int $owner_id, int $post_id)
{
$this->requireUser();
$this->willExecuteWriteAction();
$post = (new PostsRepo)->getPostById($owner_id, $post_id);
if(!$post || $post->isDeleted())
$this->fail(100, "One of the parameters specified was missing or invalid: post_id is undefined");
if(!$post->canBePinnedBy($this->getUser()))
return 0;
if(!$post->isPinned())
return 1;
$post->unpin();
return 1;
}
private function getApiPhoto($attachment) {
return [
"type" => "photo",

View file

@ -39,7 +39,7 @@ class BannedLink extends RowModel
function getRegexpRule(): string
{
return addslashes("/" . $this->getDomain() . $this->getRawRegexp() . "/");
return "/^" . $this->getDomain() . "\/" . $this->getRawRegexp() . "$/i";
}
function getRawRegexp(): string

View file

@ -46,8 +46,11 @@ class Comment extends Post
return parent::getOwner($honourFlags, $real);
}
function canBeDeletedBy(User $user): bool
function canBeDeletedBy(User $user = NULL): bool
{
if(!$user)
return false;
return $this->getOwner()->getId() == $user->getId() ||
$this->getTarget()->getOwner()->getId() == $user->getId() ||
$this->getTarget() instanceof Post && $this->getTarget()->getTargetWall() < 0 && (new Clubs)->get(abs($this->getTarget()->getTargetWall()))->canBeModifiedBy($user) ||

View file

@ -79,6 +79,40 @@ class Post extends Postable
return (bool) $this->getRecord()->pinned;
}
function hasSource(): bool
{
return $this->getRecord()->source != NULL;
}
function getSource(bool $format = false)
{
$orig_source = $this->getRecord()->source;
if(!str_contains($orig_source, "https://") && !str_contains($orig_source, "http://"))
$orig_source = "https://" . $orig_source;
if(!$format)
return $orig_source;
return $this->formatLinks($orig_source);
}
function setSource(string $source)
{
$result = check_copyright_link($source);
$this->stateChanges("source", $source);
}
function getVkApiCopyright(): object
{
return (object)[
'id' => 0,
'link' => $this->getSource(false),
'name' => $this->getSource(false),
'type' => 'link',
];
}
function isAd(): bool
{
return (bool) $this->getRecord()->ad;
@ -226,16 +260,22 @@ class Post extends Postable
$this->save();
}
function canBePinnedBy(User $user): bool
function canBePinnedBy(User $user = NULL): bool
{
if(!$user)
return false;
if($this->getTargetWall() < 0)
return (new Clubs)->get(abs($this->getTargetWall()))->canBeModifiedBy($user);
return $this->getTargetWall() === $user->getId();
}
function canBeDeletedBy(User $user): bool
function canBeDeletedBy(User $user = NULL): bool
{
if(!$user)
return false;
if($this->getTargetWall() < 0 && !$this->getWallOwner()->canBeModifiedBy($user) && $this->getWallOwner()->getWallType() != 1 && $this->getSuggestionType() == 0)
return false;

View file

@ -38,9 +38,20 @@ trait TRichText
$href = str_replace("#", "&num;", $matches[1]);
$href = rawurlencode(str_replace(";", "&#59;", $href));
$link = str_replace("#", "&num;", $matches[3]);
# this string breaks ampersands
$link = str_replace(";", "&#59;", $link);
$rel = $this->isAd() ? "sponsored" : "ugc";
$server_domain = str_replace(':' . $_SERVER['SERVER_PORT'], '', $_SERVER['HTTP_HOST']);
if(str_contains($link, $server_domain)) {
$replaced_link = str_replace(':' . $_SERVER['SERVER_PORT'], '', $link);
$replaced_link = str_replace($server_domain, '', $replaced_link);
return "<a href='$replaced_link' rel='$rel'>$link</a>" . htmlentities($matches[4]);
}
$link = htmlentities(urldecode($link));
return "<a href='/away.php?to=$href' rel='$rel' target='_blank'>$link</a>" . htmlentities($matches[4]);
}),
$text

View file

@ -3,6 +3,7 @@ namespace openvk\Web\Models\Repositories;
use Chandler\Database\DatabaseConnection as DB;
use Nette\Database\Table\{ActiveRow, Selection};
use openvk\Web\Models\Entities\BannedLink;
use function Symfony\Component\Translation\t;
class BannedLinks
{
@ -43,7 +44,7 @@ class BannedLinks
function isDomainBanned(string $domain): bool
{
return sizeof($this->bannedLinks->where(["link" => $domain, "regexp_rule" => ""])) > 0;
return sizeof($this->bannedLinks->where(["domain" => $domain, "regexp_rule" => ""])) > 0;
}
function genLinks($rules): \Traversable
@ -57,12 +58,14 @@ class BannedLinks
foreach($links as $link)
if (preg_match($link->getRegexpRule(), $uri))
yield $link->getId();
else if ($this->isDomainBanned($link->getDomain()))
yield $link->getId();
}
function check(string $url): ?array
{
$uri = strstr(str_replace(["https://", "http://"], "", $url), "/", true);
$domain = str_replace("www.", "", $uri);
$uri = str_replace(["https://", "http://"], "", $url);
$domain = explode("/", str_replace("www.", "", $uri))[0];
$rules = $this->getByDomain($domain);
if (is_null($rules))

View file

@ -481,7 +481,7 @@ final class AdminPresenter extends OpenVKPresenter
if ($link) {
$link->setDomain($new_domain ?? $this->postParam("link"));
$link->setReason($new_reason);
$link->setRegexp_rule($this->postParam("regexp"));
$link->setRegexp_rule(mb_strlen(trim($this->postParam("regexp"))) > 0 ? $this->postParam("regexp") : "");
$link->save();
} else {
if (!$new_domain)
@ -490,7 +490,7 @@ final class AdminPresenter extends OpenVKPresenter
$link = new BannedLink;
$link->setDomain($new_domain);
$link->setReason($new_reason);
$link->setRegexp_rule($this->postParam("regexp"));
$link->setRegexp_rule(mb_strlen(trim($this->postParam("regexp"))) > 0 ? $this->postParam("regexp") : "");
$link->setInitiator($this->user->identity->getId());
$link->save();

View file

@ -7,7 +7,7 @@ final class AwayPresenter extends OpenVKPresenter
{
function renderAway(): void
{
$checkBanEntries = (new BannedLinks)->check($this->queryParam("to") . "/");
$checkBanEntries = (new BannedLinks)->check($this->queryParam("to"));
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["susLinks"]["warnings"])
if (sizeof($checkBanEntries) > 0)
$this->pass("openvk!Away->view", $checkBanEntries[0]);

View file

@ -367,6 +367,12 @@ final class WallPresenter extends OpenVKPresenter
$post->setFlags($flags);
$post->setNsfw($this->postParam("nsfw") === "on");
if(!empty($this->postParam("source")) && $this->postParam("source") != 'none') {
try {
$post->setSource($this->postParam("source"));
} catch(\Throwable) {}
}
if($wall < 0 && !$wallOwner->canBeModifiedBy($this->user->identity) && $wallOwner->getWallType() == 2)
$post->setSuggested(1);

View file

@ -18,7 +18,7 @@
{else}
<a href="{$owner->getURL()}">{$owner->getCanonicalName()}</a>
»
<a href="/playlists{$ownerId}">{_playlists}</a>
<a href="/playlists{$owner->getRealId()}">{_playlists}</a>
»
<a href="/playlist{$playlist->getPrettyId()}">{_playlist}</a>
{/if}

View file

@ -17,7 +17,7 @@
<a n:if="!$isMy" n:attr="id => $mode === 'list' ? 'used' : 'ki'" href="/audios{$ownerId}">{if $ownerId > 0}{_music_user}{else}{_music_club}{/if}</a>
<a href="/player/upload?gid={abs($ownerId)}" n:if="isset($thisUser) && isset($club) && $club->canUploadAudio($thisUser)">{_upload_audio}</a>
<a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a>
<a n:attr="id => $mode === 'playlists' && $ownerId != $thisUser->getId() ? 'used' : 'ki'" class='noOverflow' href="/playlists{$ownerId}" n:if="isset($thisUser) && isset($ownerId) && !$isMy">{if $ownerId > 0}{_playlists_user}{else}{_playlists_club}{/if}</a>
<a href="/audios/newPlaylist{if $isMyClub}?gid={abs($ownerId)}{/if}" n:if="isset($thisUser) && $isMyClub">{_new_playlist}</a>
{/if}
</div>

View file

@ -202,7 +202,7 @@
{if isset($thisUser) && $user->getId() === $thisUser->getId() && sizeof($completeness->unfilled) > 0}
<br/>
<a n:if="in_array('interests', $completeness->unfilled)" href="/edit">
<a n:if="in_array('interests', $completeness->unfilled)" href="/edit?act=interests">
<img src="/assets/packages/static/openvk/img/icon1.gif" />
{_interests} (+20%)
</a>

View file

@ -18,7 +18,7 @@
</div>
<div n:class="postFeedWrapper, $thisUser->hasMicroblogEnabled() ? postFeedWrapperMicroblog">
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true}
{include "../components/textArea.xml", route => "/wall" . $thisUser->getId() . "/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
</div>
{foreach $posts as $post}

View file

@ -28,7 +28,7 @@
</div>
<div n:if="$canPost && $type == 'all'" class="content_subtitle">
{include "../components/textArea.xml", route => "/wall$owner/makePost"}
{include "../components/textArea.xml", route => "/wall$owner/makePost", hasSource => true}
</div>
<div class="content">

View file

@ -1,9 +1,11 @@
{var $author = $comment->getOwner()}
{var $Club = openvk\Web\Models\Entities\Club::class}
{var $postId = $comment->getTarget() instanceof \openvk\Web\Models\Entities\Post ? $comment->getTarget()->getId() : NULL}
{var $likesCount = $comment->getLikesCount()}
{var $target = $comment->getTarget()}
{var $postId = $target instanceof \openvk\Web\Models\Entities\Post ? $target->getId() : NULL}
<a name="cid={$comment->getId()}"></a>
<table border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$comment->getOwner() instanceof $Club}" n:attr="data-post-id => $postId">
<table border="0" style="font-size: 11px;" class="post comment" id="_comment{$comment->getId()}" data-comment-id="{$comment->getId()}" data-owner-id="{$author->getId()}" data-from-group="{$author instanceof $Club}" n:attr="data-post-id => $postId">
<tbody>
<tr>
<td width="30" valign="top">
@ -40,8 +42,8 @@
<span n:if="$comment->getEditTime()" class="edited editedMark">({_edited_short})</span>
</a>
{if !$timeOnly}
&nbsp;|
{if $comment->canBeDeletedBy($thisUser)}
|
<a href="/comment{$comment->getId()}/delete">{_delete}</a>
{/if}
{if $comment->canBeEditedBy($thisUser)}
@ -60,7 +62,7 @@
<div style="float: right; font-size: .7rem;">
<a class="post-like-button" href="/comment{$comment->getId()}/like?hash={rawurlencode($csrfToken)}">
<div class="heart" style="{if $comment->hasLikeFrom($thisUser)}opacity: 1;{else}opacity: 0.4;{/if}"></div>
<span class="likeCnt">{if $comment->getLikesCount() > 0}{$comment->getLikesCount()}{/if}</span>
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
</a>
</div>
{/if}

View file

@ -3,6 +3,11 @@
{var $commentsCount = $post->getCommentsCount()}
{var $platform = $post->getPlatform()}
{var $platformDetails = $post->getPlatformDetails()}
{var $likesCount = $post->getLikesCount()}
{var $repostsCount = $post->getRepostCount()}
{var $canBePinned = $post->canBePinnedBy($thisUser ?? NULL)}
{var $canBeDeleted = $post->canBeDeletedBy($thisUser)}
{var $wallOwner = $post->getWallOwner()}
{if $post->isDeactivationMessage() && $post->getText()}
{var $deac = "post_deact"}
{else}
@ -30,7 +35,6 @@
{$post->isUpdateAvatarMessage() && !$post->isPostedOnBehalfOfGroup() ? ($author->isFemale() ? tr("upd_f") : ($author->isNeutral() ? tr("upd_n") : tr("upd_m")))}
{$post->isUpdateAvatarMessage() && $post->isPostedOnBehalfOfGroup() ? tr("upd_g") : ""}
{if ($onWallOf ?? false) &&!$post->isPostedOnBehalfOfGroup() && $post->getOwnerPost() !== $post->getTargetWall()}
{var $wallOwner = $post->getWallOwner()}
<a href="{$wallOwner->getURL()}" class="mention" data-mention-ref="{$post->getTargetWall()}">
<b>
{if isset($thisUser) && $thisUser->getId() === $post->getTargetWall()}
@ -53,9 +57,9 @@
<span n:if="$post->isPinned()" class="nobold">{_pinned}</span>
<a n:if="$post->canBeDeletedBy($thisUser) && !($forceNoDeleteLink ?? false) && $compact == false" class="delete" href="/wall{$post->getPrettyId()}/delete"></a>
<a n:if="$canBeDeleted && !($forceNoDeleteLink ?? false) && $compact == false" class="delete" href="/wall{$post->getPrettyId()}/delete"></a>
{if $post->canBePinnedBy($thisUser) && !($forceNoPinLink ?? false) && $compact == false}
{if $canBePinned && !($forceNoPinLink ?? false) && $compact == false}
{if $post->isPinned()}
<a class="pin" href="/wall{$post->getPrettyId()}/pin?act=unpin&hash={rawurlencode($csrfToken)}"></a>
{else}
@ -67,7 +71,7 @@
<a class="edit" id="editPost"
data-id="{$post->getId()}"
data-nsfw="{(int)$post->isExplicit()}"
{if $post->getTargetWall() < 0 && $post->getWallOwner()->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}></a>
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}></a>
{/if}
</div>
<div class="post-content" id="{$post->getPrettyId()}">
@ -95,6 +99,9 @@
<br/>
&nbsp;! {_post_is_ad}
</div>
<div n:if="$post->hasSource()" class="sourceDiv">
<span>{_source}: {$post->getSource(true)|noescape}</span>
</div>
<div n:if="$post->isSigned()" class="post-signature">
{var $actualAuthor = $post->getOwner(false)}
<span>
@ -121,14 +128,14 @@
<div class="like_wrap">
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')">
<div class="repost-icon" style="opacity: 0.4;"></div>
<span class="likeCnt" id="repostsCount{$post->getPrettyId()}">{if $post->getRepostCount() > 0}{$post->getRepostCount()}{/if}</span>
<span class="likeCnt" id="repostsCount{$post->getPrettyId()}">{if $repostsCount > 0}{$repostsCount}{/if}</span>
</a>
{if !($forceNoLike ?? false)}
{var $liked = $post->hasLikeFrom($thisUser)}
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$post->getLikesCount()}">
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$likesCount}">
<div class="heart" id="{if $liked}liked{/if}"></div>
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
</a>
{/if}
</div>
@ -145,7 +152,7 @@
{include "../textArea.xml", route => $commentsURL, postOpts => false, graffiti => (bool) ovkGetQuirk("comments.allow-graffiti"), post => $post, club => $club}
</div>
</div>
<div n:if="$suggestion && $post->canBePinnedBy($thisUser ?? NULL)" class="suggestionControls">
<div n:if="$suggestion && $canBePinned" class="suggestionControls">
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
</div>

View file

@ -1,6 +1,12 @@
{var $author = $post->getOwner()}
{var $platform = $post->getPlatform()}
{var $platformDetails = $post->getPlatformDetails()}
{var $wallOwner = $post->getWallOwner()}
{var $likesCount = $post->getLikesCount()}
{var $repostsCount = $post->getRepostCount()}
{var $commentsCount = $post->getCommentsCount()}
{var $canBePinned = $post->canBePinnedBy($thisUser ?? NULL)}
{var $canBeDeleted = $post->canBeDeletedBy($thisUser)}
{if $post->isDeactivationMessage() && $post->getText()}
{var $deac = "post_deact"}
{else}
@ -40,7 +46,6 @@
{/if}
{/if}
{if ($onWallOf ?? false) &&!$post->isPostedOnBehalfOfGroup() && $post->getOwnerPost() !== $post->getTargetWall()}
{var $wallOwner = $post->getWallOwner()}
<a href="{$wallOwner->getURL()}" class="mention" data-mention-ref="{$post->getTargetWall()}">
<b>
{if isset($thisUser) && $thisUser->getId() === $post->getTargetWall()}
@ -85,7 +90,7 @@
</div>
</div>
</div>
<div n:if="$suggestion && $post->canBePinnedBy($thisUser ?? NULL)" class="suggestionControls" style="margin-bottom: 7px;">
<div n:if="$suggestion && $canBePinned" class="suggestionControls" style="margin-bottom: 7px;">
<input type="button" class="button" id="publish_post" data-id="{$post->getId()}" value="{_publish_suggested}">
<input type="button" class="button" id="decline_post" data-id="{$post->getId()}" value="{_decline_suggested}">
</div>
@ -93,6 +98,9 @@
<br/>
&nbsp;! {_post_is_ad}
</div>
<div n:if="$post->hasSource()" class="sourceDiv">
<span>{_source}: {$post->getSource(true)|noescape}</span>
</div>
<div n:if="$post->isSigned()" class="post-signature">
{var $actualAuthor = $post->getOwner(false)}
<span>
@ -113,14 +121,14 @@
<a id="editPost"
data-id="{$post->getId()}"
data-nsfw="{(int)$post->isExplicit()}"
{if $post->getTargetWall() < 0 && $post->getWallOwner()->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}>{_edit}</a> &nbsp;|&nbsp;
{if $post->getTargetWall() < 0 && $wallOwner->canBeModifiedBy($thisUser)}data-fromgroup="{(int)$post->isPostedOnBehalfOfGroup()}"{/if}>{_edit}</a> &nbsp;|&nbsp;
{/if}
{if !($forceNoDeleteLink ?? false) && $post->canBeDeletedBy($thisUser)}
{if !($forceNoDeleteLink ?? false) && $canBeDeleted}
<a href="/wall{$post->getPrettyId()}/delete">{_delete}</a> &nbsp;|&nbsp;
{/if}
{if !($forceNoPinLink ?? false) && $post->canBePinnedBy($thisUser)}
{if !($forceNoPinLink ?? false) && $canBePinned}
{if $post->isPinned()}
<a href="/wall{$post->getPrettyId()}/pin?act=unpin&hash={rawurlencode($csrfToken)}">{_unpin}</a>
{else}
@ -131,8 +139,8 @@
<a n:if="!($forceNoCommentsLink ?? false)" href="/wall{$post->getPrettyId()}#comments">
{_comments}
{if $post->getCommentsCount() > 0}
(<b>{$post->getCommentsCount()}</b>)
{if $commentsCount > 0}
(<b>{$commentsCount}</b>)
{/if}
</a>
@ -142,22 +150,22 @@
<a n:if="!($forceNoShareLink ?? false)" id="reposts{$post->getPrettyId()}" class="post-share-button" {ifset $thisUser} href="javascript:repostPost('{$post->getPrettyId()}', '{rawurlencode($csrfToken)}')"{/ifset}>
{_share}
{if $post->getRepostCount() > 0}
(<b id="repostsCount{$post->getPrettyId()}">{$post->getRepostCount()}</b>)
{if $repostsCount > 0}
(<b id="repostsCount{$post->getPrettyId()}">{$repostsCount}</b>)
{/if}
</a>
<div n:if="!($forceNoLike ?? false)" class="like_wrap">
{ifset $thisUser}
{var $liked = $post->hasLikeFrom($thisUser)}
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$post->getLikesCount()}">
<a href="/wall{$post->getPrettyId()}/like?hash={rawurlencode($csrfToken)}" class="post-like-button" data-liked="{(int) $liked}" data-likes="{$likesCount}">
<div class="heart" id="{if $liked}liked{/if}"></div>
<span class="likeCnt">{if $post->getLikesCount() > 0}{$post->getLikesCount()}{/if}</span>
<span class="likeCnt">{if $likesCount > 0}{$likesCount}{/if}</span>
</a>
{else}
<a n:if="$post->getLikesCount() > 0" class="post-like-button">
<a n:if="$likesCount > 0" class="post-like-button">
<div class="heart"></div>
<span class="likeCnt">{$post->getLikesCount()}</span>
<span class="likeCnt">{$likesCount}</span>
</a>
{/ifset}
</div>

View file

@ -18,14 +18,15 @@
<div class="post-has-poll">
{_poll}
</div>
<div class="post-has-note">
<div class="post-has-note"></div>
</div>
<div class="post-has-videos"></div>
<div class="post-has-audios"></div>
<div class="post-source"></div>
<div n:if="$postOpts ?? true" class="post-opts">
{var $anonEnabled = OPENVK_ROOT_CONF['openvk']['preferences']['wall']['anonymousPosting']['enable']}
{if !is_null($thisUser) && !is_null($club ?? NULL) && $owner < 0}
{if $club->canBeModifiedBy($thisUser)}
<script>
@ -66,6 +67,7 @@
<input type="hidden" name="audios" value="" />
<input type="hidden" name="poll" value="none" />
<input type="hidden" id="note" name="note" value="none" />
<input type="hidden" id="source" name="source" value="none" />
<input type="hidden" name="type" value="1" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<br/>
@ -91,10 +93,6 @@
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/audio-ac3.png" />
{_audio}
</a>
<a n:if="$notes ?? false" href="javascript:attachNote({$textAreaId})">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/mimetypes/application-x-srt.png" />
{_note}
</a>
<a n:if="$graffiti ?? false" href="javascript:initGraffiti({$textAreaId});">
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/draw-brush.png" />
{_graffiti}
@ -103,6 +101,10 @@
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/office-chart-bar-stacked.png" />
{_poll}
</a>
<a n:if="$hasSource ?? false" id='__sourceAttacher'>
<img src="/assets/packages/static/openvk/img/oxygen-icons/16x16/actions/insert-link.png" />
{_source}
</a>
</div>
</div>
</div>

View file

@ -10,7 +10,7 @@
<div class="insertThere" id="postz"></div>
<div id="underHeader">
<div n:if="$canPost" class="content_subtitle">
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true}
{include "../components/textArea.xml", route => "/wall$owner/makePost", graffiti => true, polls => true, notes => true, hasSource => true}
</div>
<div class="content">

View file

@ -70,7 +70,7 @@ class Makima
$result->colSizes = [1];
$result->rowSizes = [1, 1];
$result->width = ceil($maxWidth);
$result->height = $computedHeight;
$result->height = $computedHeight * 2;
$result->tiles = [new ThumbTile(1, 1, $maxWidth, $computedHeight), new ThumbTile(1, 1, $maxWidth, $computedHeight)];
} else if(
$orients == [Makima::ORIENT_WIDE, Makima::ORIENT_WIDE]

View file

@ -9,7 +9,7 @@
}
.musicIcon {
background-image: url('/assets/packages/static/openvk/img/audios_controls.png');
background-image: url('/assets/packages/static/openvk/img/audios_controls.png?v=2');
background-repeat: no-repeat;
cursor: pointer;
}
@ -185,6 +185,7 @@
width: 81%;
height: 13px;
display: inline-block;
line-height: 14px;
}
.bigPlayer .paddingLayer .trackInfo .timer span {
@ -345,6 +346,7 @@
.audioEntry .status .mediaInfo {
cursor: pointer;
display: flex;
line-height: 14px;
width: 100%;
}

View file

@ -44,7 +44,7 @@
._add_image::before {
margin-top: 2px;
content: ' ';
background: url('/assets/packages/static/openvk/img/upload.png');
background: url('/assets/packages/static/openvk/img/upload.png?v=2');
width: 10px;
height: 10px;
display: inline-block;
@ -65,7 +65,7 @@
.avatarDelete::before {
content: ' ';
background: url('/assets/packages/static/openvk/img/upload.png');
background: url('/assets/packages/static/openvk/img/upload.png?v=2');
background-position: -10px 2px;
background-repeat: no-repeat;
width: 12px;

View file

@ -1454,6 +1454,24 @@ body.scrolled .toTop:hover {
color: #3c3c3c;
}
.post-source #remove_source_button {
display: inline-block;
background-repeat: no-repeat;
background: url('/assets/packages/static/openvk/img/arrows.png?v=2');
margin-bottom: -2px;
background-position: -18px 0px;
height: 11px;
width: 11px;
opacity: 0.6;
transition-duration: 0.3s;
cursor: pointer;
}
.post-source #remove_source_button:hover {
opacity: 0.8;
}
.post-upload::before, .post-has-poll::before, .post-has-note::before {
content: " ";
width: 8px;
@ -3019,6 +3037,26 @@ body.article .floating_sidebar, body.article .page_content {
font-size: 12px;
}
.post .sourceDiv {
margin-top: 3px;
margin-left: 4px;
}
.post .sourceDiv span {
color: grey;
font-size: 10px;
}
.post .sourceDiv a:hover {
text-decoration: underline;
}
#source_flex_kunteynir {
display: flex;
flex-direction: column;
gap: 22px;
}
.sugglist {
padding-bottom: 5px;
padding-top: 5px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

After

Width:  |  Height:  |  Size: 316 B

View file

@ -66,16 +66,16 @@ u(`#search_box input[type='search']`).on('input', async (e) => {
switch(section) {
case 'users':
results = await fetch(`/method/users.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&fields=photo_50,status,nickname`)
results = await fetch(`/method/users.search?auth_mechanism=roaming&q=${encodeURIComponent(query)}&count=10&sort=4&fields=photo_50,status,nickname`)
break
case 'groups':
results = await fetch(`/method/groups.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&fields=photo_50,description`)
results = await fetch(`/method/groups.search?auth_mechanism=roaming&q=${encodeURIComponent(query)}&count=10&sort=4&fields=photo_50,description`)
break
case 'videos':
results = await fetch(`/method/video.search?auth_mechanism=roaming&q=${query}&count=10&sort=4&extended=1`)
results = await fetch(`/method/video.search?auth_mechanism=roaming&q=${encodeURIComponent(query)}&count=10&sort=4&extended=1`)
break
case 'audios_playlists':
results = await fetch(`/method/audio.searchAlbums?auth_mechanism=roaming&query=${query}&limit=10`)
results = await fetch(`/method/audio.searchAlbums?auth_mechanism=roaming&query=${encodeURIComponent(query)}&limit=10`)
break
}

View file

@ -1145,7 +1145,7 @@ $(document).on("click", "#editPost", (e) => {
}
post.querySelector(".post-avatar").setAttribute("src", result.author.avatar)
post.querySelector(".post-author-name").innerHTML = result.author.name
post.querySelector(".post-author-name").innerHTML = result.author.name.escapeHtml()
post.querySelector(".really_text").setAttribute("data-text", result.new_text)
} else {
MessageBox(tr("error"), result.error, [tr("ok")], [Function.noop])
@ -1626,7 +1626,7 @@ $(document).on("click", ".avatarDelete", (e) => {
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
u(".ovk-diag-cont").remove();
u(".ovk-diag-cont").remove()
document.querySelector("#bigAvatar").src = response.url
document.querySelector("#bigAvatar").parentNode.href = response.new_photo ? ("/photo" + response.new_photo) : "javascript:void(0)"
@ -1643,3 +1643,77 @@ $(document).on("click", ".avatarDelete", (e) => {
}),
]);
})
u(document).on('click', '#__sourceAttacher', (e) => {
MessageBox(tr('add_source'), `
<div id='source_flex_kunteynir'>
<span>${tr('set_source_tip')}</span>
<!-- давай, копируй ссылку и переходи по ней -->
<input type='text' maxlength='400' placeholder='https://www.youtube.com/watch?v=lkWuk_nzzVA'>
</div>
`, [tr('cancel')], [
() => {Function.noop}
])
__removeDialog = () => {
u("body").removeClass("dimmed");
document.querySelector("html").style.overflowY = "scroll"
u(".ovk-diag-cont").remove()
}
u('.ovk-diag-action').append(`
<button class='button' id='__setsrcbutton'>${tr('set_source')}</button>
`)
u('.ovk-diag-action #__setsrcbutton').on('click', async (ev) => {
// Consts
const _u_target = u(e.target)
const nearest_textarea = _u_target.closest('#write')
const source_output = nearest_textarea.find(`input[name='source']`)
const source_input = u(`#source_flex_kunteynir input[type='text']`)
const source_value = source_input.nodes[0].value ?? ''
if(source_value.length < 1) {
return
}
ev.target.classList.add('lagged')
// Checking link
const __checkCopyrightLinkRes = await fetch(`/method/wall.checkCopyrightLink?auth_mechanism=roaming&link=${encodeURIComponent(source_value)}`)
const checkCopyrightLink = await __checkCopyrightLinkRes.json()
// todo переписать блять мессенджбоксы чтоб они классами были
if(checkCopyrightLink.error_code) {
__removeDialog()
switch(checkCopyrightLink.error_code) {
default:
case 3102:
fastError(tr('error_adding_source_regex'))
return
case 3103:
fastError(tr('error_adding_source_long'))
return
case 3104:
fastError(tr('error_adding_source_sus'))
return
}
}
// Making indicator
__removeDialog()
source_output.attr('value', source_value)
nearest_textarea.find('.post-source').html(`
<span>${tr('source')}: <a target='_blank' href='${source_value.escapeHtml()}'>${ovk_proc_strtr(source_value.escapeHtml(), 50)}</a></span>
<div id='remove_source_button'></div>
`)
nearest_textarea.find('.post-source #remove_source_button').on('click', () => {
nearest_textarea.find('.post-source').html('')
source_output.attr('value', 'none')
})
})
u('.ovk-diag-body').attr('style', `padding:8px;`)
u('.ovk-diag-cont').attr('style', 'width: 325px;')
u('#source_flex_kunteynir input').nodes[0].focus()
})

View file

@ -286,6 +286,31 @@ function ovk_scheme(bool $with_slashes = false): string
return $scheme;
}
function check_copyright_link(string $link = ''): bool
{
if(!str_contains($link, "https://") && !str_contains($link, "http://"))
$link = "https://" . $link;
# Existability
if(is_null($link) || empty($link))
throw new \InvalidArgumentException("Empty link");
# Length
if(iconv_strlen($link) < 2 || iconv_strlen($link) > 400)
throw new \LengthException("Link is too long");
# Match URL regex
# stolen from http://urlregex.com/
if (!preg_match("%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+|xn--[a-z\d-]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.(?:xn--[a-z\d-]+|[a-z\x{00a1}-\x{ffff}]{2,6})))(?::\d+)?(?:[^\s]*)?$%iu", $link))
throw new \InvalidArgumentException("Invalid link format");
$banEntries = (new openvk\Web\Models\Repositories\BannedLinks)->check($link);
if(sizeof($banEntries) > 0)
throw new \LogicException("Suspicious link");
return true;
}
return (function() {
_ovk_check_environment();
require __DIR__ . "/vendor/autoload.php";

373
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0d3b0eb1916eaf088444ef637743284a",
"content-hash": "987e26c5520b71fccd0cd31de00eead2",
"packages": [
{
"name": "al/emoji-detector",
@ -197,16 +197,16 @@
},
{
"name": "chillerlan/php-settings-container",
"version": "3.2.0",
"version": "3.2.1",
"source": {
"type": "git",
"url": "https://github.com/chillerlan/php-settings-container.git",
"reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6"
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/8f93648fac8e6bacac8e00a8d325eba4950295e6",
"reference": "8f93648fac8e6bacac8e00a8d325eba4950295e6",
"url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
"reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681",
"shasum": ""
},
"require": {
@ -214,15 +214,16 @@
"php": "^8.1"
},
"require-dev": {
"phan/phan": "^5.4",
"phpmd/phpmd": "^2.15",
"phpstan/phpstan": "^1.11",
"phpstan/phpstan-deprecation-rules": "^1.2",
"phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "^3.9"
"squizlabs/php_codesniffer": "^3.10"
},
"type": "library",
"autoload": {
"psr-4": {
"chillerlan\\Settings\\": "src/"
"chillerlan\\Settings\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
@ -258,7 +259,7 @@
"type": "ko_fi"
}
],
"time": "2024-03-02T20:07:15+00:00"
"time": "2024-07-16T11:13:48+00:00"
},
{
"name": "erusev/parsedown",
@ -266,20 +267,20 @@
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "1ff038273949df7d6a455352659a878f3c89b29c"
"reference": "582f9f9cd12a894a0901bef1652854a3c5a1d874"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/1ff038273949df7d6a455352659a878f3c89b29c",
"reference": "1ff038273949df7d6a455352659a878f3c89b29c",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/582f9f9cd12a894a0901bef1652854a3c5a1d874",
"reference": "582f9f9cd12a894a0901bef1652854a3c5a1d874",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
"phpunit/phpunit": "^7.5|^8.5|^9.6"
},
"default-branch": true,
"type": "library",
@ -309,7 +310,7 @@
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/master"
},
"time": "2024-03-12T05:27:45+00:00"
"time": "2024-10-12T07:06:08+00:00"
},
{
"name": "ezyang/htmlpurifier",
@ -317,12 +318,12 @@
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "4828fdf45a93eeeacfcbcc855f96f9a7e6b4ed44"
"reference": "cb56001e54359df7ae76dc522d08845dc741621b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/4828fdf45a93eeeacfcbcc855f96f9a7e6b4ed44",
"reference": "4828fdf45a93eeeacfcbcc855f96f9a7e6b4ed44",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
"reference": "cb56001e54359df7ae76dc522d08845dc741621b",
"shasum": ""
},
"require": {
@ -369,9 +370,9 @@
],
"support": {
"issues": "https://github.com/ezyang/htmlpurifier/issues",
"source": "https://github.com/ezyang/htmlpurifier/tree/master"
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
},
"time": "2024-03-13T03:41:45+00:00"
"time": "2024-11-01T03:51:45+00:00"
},
{
"name": "guzzlehttp/guzzle",
@ -678,12 +679,12 @@
"source": {
"type": "git",
"url": "https://github.com/JamesHeinrich/getID3.git",
"reference": "143af3325ee40e77c5d041d3f674c8bdd4762dc7"
"reference": "eb358a0d4943c0cc23e783f1a72141f46153c13a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/143af3325ee40e77c5d041d3f674c8bdd4762dc7",
"reference": "143af3325ee40e77c5d041d3f674c8bdd4762dc7",
"url": "https://api.github.com/repos/JamesHeinrich/getID3/zipball/eb358a0d4943c0cc23e783f1a72141f46153c13a",
"reference": "eb358a0d4943c0cc23e783f1a72141f46153c13a",
"shasum": ""
},
"require": {
@ -738,7 +739,7 @@
"issues": "https://github.com/JamesHeinrich/getID3/issues",
"source": "https://github.com/JamesHeinrich/getID3/tree/master"
},
"time": "2024-03-26T12:26:30+00:00"
"time": "2024-09-20T19:45:51+00:00"
},
{
"name": "league/uri",
@ -1099,20 +1100,20 @@
},
{
"name": "psr/http-factory",
"version": "1.0.2",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "e616d01114759c4c489f93b099585439f795fe35"
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"php": ">=7.1",
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
@ -1136,7 +1137,7 @@
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
"description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
"keywords": [
"factory",
"http",
@ -1148,9 +1149,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
"source": "https://github.com/php-fig/http-factory"
},
"time": "2023-04-10T20:10:41+00:00"
"time": "2024-04-15T12:06:14+00:00"
},
{
"name": "psr/http-message",
@ -1318,21 +1319,22 @@
"source": {
"type": "git",
"url": "https://github.com/scssphp/scssphp.git",
"reference": "5659341b5da400dafd5672171215f4534c06236b"
"reference": "12d3cdf0fc2a73e9438ded5a5a82fb353b68d718"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/5659341b5da400dafd5672171215f4534c06236b",
"reference": "5659341b5da400dafd5672171215f4534c06236b",
"url": "https://api.github.com/repos/scssphp/scssphp/zipball/12d3cdf0fc2a73e9438ded5a5a82fb353b68d718",
"reference": "12d3cdf0fc2a73e9438ded5a5a82fb353b68d718",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-json": "*",
"league/uri": "^7.4@dev",
"league/uri-interfaces": "^7.3",
"league/uri": "^7.4",
"league/uri-interfaces": "^7.4",
"php": ">=8.1",
"symfony/filesystem": "^5.4 || ^6.0 || ^7.0"
"symfony/filesystem": "^5.4 || ^6.0 || ^7.0",
"symfony/polyfill-mbstring": "^1.30"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
@ -1347,8 +1349,7 @@
"zurb/foundation": "~6.7.0"
},
"suggest": {
"ext-iconv": "Can be used as fallback when ext-mbstring is not available",
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv"
"ext-mbstring": "For best performance, mbstring should be installed as it is faster than the polyfill"
},
"default-branch": true,
"type": "library",
@ -1392,7 +1393,7 @@
"issues": "https://github.com/scssphp/scssphp/issues",
"source": "https://github.com/scssphp/scssphp/tree/main"
},
"time": "2024-01-13T13:17:46+00:00"
"time": "2024-10-24T15:03:30+00:00"
},
{
"name": "symfony/console",
@ -1400,12 +1401,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e"
"reference": "108d436c2af470858bdaba3257baab3a74172017"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e",
"url": "https://api.github.com/repos/symfony/console/zipball/108d436c2af470858bdaba3257baab3a74172017",
"reference": "108d436c2af470858bdaba3257baab3a74172017",
"shasum": ""
},
"require": {
@ -1491,20 +1492,20 @@
"type": "tidelift"
}
],
"time": "2024-02-20T16:33:57+00:00"
"time": "2024-10-08T07:27:17+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v3.4.0",
"version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
"reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
"shasum": ""
},
"require": {
@ -1513,7 +1514,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -1542,7 +1543,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
},
"funding": [
{
@ -1558,27 +1559,30 @@
"type": "tidelift"
}
],
"time": "2023-05-23T14:45:45+00:00"
"time": "2024-04-18T09:32:20+00:00"
},
{
"name": "symfony/filesystem",
"version": "v6.4.3",
"version": "v7.2.0-BETA1",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb"
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb",
"reference": "7f3b1755eb49297a0827a7575d5d2b2fd11cc9fb",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
"shasum": ""
},
"require": {
"php": ">=8.1",
"php": ">=8.2",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
"symfony/process": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
@ -1605,7 +1609,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v6.4.3"
"source": "https://github.com/symfony/filesystem/tree/v7.2.0-BETA1"
},
"funding": [
{
@ -1621,24 +1625,24 @@
"type": "tidelift"
}
],
"time": "2024-01-23T14:51:35+00:00"
"time": "2024-10-25T15:15:23+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
"reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
@ -1684,7 +1688,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
@ -1700,24 +1704,24 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
@ -1762,7 +1766,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
},
"funding": [
{
@ -1778,26 +1782,25 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
"reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/c36586dcf89a12315939e00ec9b4474adcb1d773",
"reference": "c36586dcf89a12315939e00ec9b4474adcb1d773",
"shasum": ""
},
"require": {
"php": ">=7.1",
"symfony/polyfill-intl-normalizer": "^1.10",
"symfony/polyfill-php72": "^1.10"
"php": ">=7.2",
"symfony/polyfill-intl-normalizer": "^1.10"
},
"suggest": {
"ext-intl": "For best performance"
@ -1846,7 +1849,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.31.0"
},
"funding": [
{
@ -1862,24 +1865,24 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
"reference": "3833d7255cc303546435cb650316bff708a1c75c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
"reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
"reference": "3833d7255cc303546435cb650316bff708a1c75c",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"suggest": {
"ext-intl": "For best performance"
@ -1927,7 +1930,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
},
"funding": [
{
@ -1943,24 +1946,24 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"provide": {
"ext-mbstring": "*"
@ -2007,7 +2010,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
},
"funding": [
{
@ -2023,97 +2026,24 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.29.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25",
"reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php72\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2"
"reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2",
"reference": "21bd091060673a1177ae842c0ef8fe30893114d2",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
"reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"type": "library",
"extra": {
@ -2156,7 +2086,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0"
},
"funding": [
{
@ -2172,24 +2102,24 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.29.0",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"shasum": ""
},
"require": {
"php": ">=7.1"
"php": ">=7.2"
},
"type": "library",
"extra": {
@ -2236,7 +2166,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
},
"funding": [
{
@ -2252,25 +2182,26 @@
"type": "tidelift"
}
],
"time": "2024-01-29T20:11:03+00:00"
"time": "2024-09-09T11:45:10+00:00"
},
{
"name": "symfony/service-contracts",
"version": "v3.4.1",
"version": "v3.5.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0"
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0",
"reference": "fe07cbc8d837f60caf7018068e350cc5163681a0",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
"shasum": ""
},
"require": {
"php": ">=8.1",
"psr/container": "^1.1|^2.0"
"psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3"
},
"conflict": {
"ext-psr": "<1.1|>=2"
@ -2278,7 +2209,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.4-dev"
"dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -2318,7 +2249,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.4.1"
"source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
},
"funding": [
{
@ -2334,20 +2265,20 @@
"type": "tidelift"
}
],
"time": "2023-12-26T14:02:43+00:00"
"time": "2024-04-18T09:32:20+00:00"
},
{
"name": "symfony/string",
"version": "v6.4.4",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9"
"reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9",
"url": "https://api.github.com/repos/symfony/string/zipball/38371c60c71c72b3d64d8d76f6b1bb81a2cc3627",
"reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627",
"shasum": ""
},
"require": {
@ -2404,7 +2335,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.4.4"
"source": "https://github.com/symfony/string/tree/v6.4.13"
},
"funding": [
{
@ -2420,7 +2351,7 @@
"type": "tidelift"
}
],
"time": "2024-02-01T13:16:41+00:00"
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "vearutop/php-obscene-censor-rus",
@ -2525,12 +2456,12 @@
"source": {
"type": "git",
"url": "https://github.com/wapmorgan/Morphos.git",
"reference": "302b56636cf604ad07e20020076d8a4880554286"
"reference": "d22876709756b538a52b30a50a3f37cd89efeb91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wapmorgan/Morphos/zipball/302b56636cf604ad07e20020076d8a4880554286",
"reference": "302b56636cf604ad07e20020076d8a4880554286",
"url": "https://api.github.com/repos/wapmorgan/Morphos/zipball/d22876709756b538a52b30a50a3f37cd89efeb91",
"reference": "d22876709756b538a52b30a50a3f37cd89efeb91",
"shasum": ""
},
"require": {
@ -2592,7 +2523,7 @@
"issues": "https://github.com/wapmorgan/Morphos/issues",
"source": "https://github.com/wapmorgan/Morphos/tree/master"
},
"time": "2024-03-26T07:24:27+00:00"
"time": "2024-09-26T12:41:09+00:00"
},
{
"name": "whichbrowser/parser",
@ -2600,12 +2531,12 @@
"source": {
"type": "git",
"url": "https://github.com/WhichBrowser/Parser-PHP.git",
"reference": "1044880bc792dbce5948fbff22ae731c43c280d9"
"reference": "581d614d686bfbec3529ad60562a5213ac5d8d72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/WhichBrowser/Parser-PHP/zipball/1044880bc792dbce5948fbff22ae731c43c280d9",
"reference": "1044880bc792dbce5948fbff22ae731c43c280d9",
"url": "https://api.github.com/repos/WhichBrowser/Parser-PHP/zipball/581d614d686bfbec3529ad60562a5213ac5d8d72",
"reference": "581d614d686bfbec3529ad60562a5213ac5d8d72",
"shasum": ""
},
"require": {
@ -2629,8 +2560,7 @@
"autoload": {
"psr-4": {
"WhichBrowser\\": [
"src/",
"tests/src/"
"src/"
]
}
},
@ -2655,28 +2585,28 @@
],
"support": {
"issues": "https://github.com/WhichBrowser/Parser-PHP/issues",
"source": "https://github.com/WhichBrowser/Parser-PHP/tree/v2.1.7"
"source": "https://github.com/WhichBrowser/Parser-PHP/tree/v2.1.8"
},
"time": "2022-04-19T20:14:54+00:00"
"time": "2024-04-17T12:47:41+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "beta",
"stability-flags": {
"whichbrowser/parser": 20,
"james-heinrich/getid3": 20,
"rybakit/msgpack": 20,
"wapmorgan/binary-stream": 20,
"al/emoji-detector": 20,
"ezyang/htmlpurifier": 20,
"scssphp/scssphp": 20,
"lfkeitel/phptotp": 20,
"vearutop/php-obscene-censor-rus": 20,
"erusev/parsedown": 20,
"bhaktaraz/php-rss-generator": 20,
"erusev/parsedown": 20,
"ezyang/htmlpurifier": 20,
"james-heinrich/getid3": 20,
"lfkeitel/phptotp": 20,
"rybakit/msgpack": 20,
"scssphp/scssphp": 20,
"symfony/console": 20,
"wapmorgan/morphos": 20
"vearutop/php-obscene-censor-rus": 20,
"wapmorgan/binary-stream": 20,
"wapmorgan/morphos": 20,
"whichbrowser/parser": 20
},
"prefer-stable": false,
"prefer-lowest": false,
@ -2684,8 +2614,9 @@
"php": "~7.3||~8.1",
"ext-openssl": "*",
"ext-simplexml": "*",
"ext-sodium": "*"
"ext-sodium": "*",
"ext-iconv": "*"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -1,51 +1,55 @@
# Docker
Note: `buildx` is required for building multi-arch images. See [Docker Buildx](https://docs.docker.com/buildx/working-with-buildx/) for more information.
Note: If you want to build images for multiple architectures, you must use `buildx`. See [Docker Buildx](https://docs.docker.com/buildx/working-with-buildx/) for more information.
If unsure, skip to single-arch image build instructions.
## Build
Note: commands below should be run from the root of the repository.
Note: **commands below must be run from the this directory** (`/install/automated/docker/`).
### Multi-arch (arm64, amd64)
Base images:
```
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/php:8.2-cli . --load -f install/automated/docker/base-php-cli.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/php:8.2-apache . --load -f install/automated/docker/base-php-apache.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/php:8.2-cli ../../.. --load -f base-php-cli.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/php:8.2-apache ../../.. --load -f base-php-apache.Dockerfile
```
DB images:
```
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/mariadb:10.9-primary . --load -f install/automated/docker/mariadb-primary.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/mariadb:10.9-eventdb . --load -f install/automated/docker/mariadb-eventdb.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/mariadb:10.9-primary ../../.. --load -f mariadb-primary.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/mariadb:10.9-eventdb ../../.. --load -f mariadb-eventdb.Dockerfile
```
OpenVK main image:
```
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/openvk:latest . --load -f install/automated/docker/openvk.Dockerfile
docker buildx build --platform linux/amd64,linux/arm64 -t ghcr.io/openvk/openvk/openvk:latest ../../.. --load -f openvk.Dockerfile
```
### Single-arch
Base images:
```
docker build -t ghcr.io/openvk/openvk/php:8.2-cli . -f install/automated/docker/base-php-cli.Dockerfile
docker build -t ghcr.io/openvk/openvk/php:8.2-apache . -f install/automated/docker/base-php-apache.Dockerfile
docker build -t ghcr.io/openvk/openvk/php:8.2-cli ../../.. -f base-php-cli.Dockerfile
docker build -t ghcr.io/openvk/openvk/php:8.2-apache ../../.. -f base-php-apache.Dockerfile
```
DB images:
```
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-primary . -f install/automated/docker/mariadb-primary.Dockerfile
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-eventdb . -f install/automated/docker/mariadb-eventdb.Dockerfile
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-primary ../../.. -f mariadb-primary.Dockerfile
docker build -t ghcr.io/openvk/openvk/mariadb:10.9-eventdb ../../.. --f mariadb-eventdb.Dockerfile
```
OpenVK main image:
```
docker build -t ghcr.io/openvk/openvk/openvk:latest . -f install/automated/docker/openvk.Dockerfile
docker build -t ghcr.io/openvk/openvk/openvk:latest ../../.. -f openvk.Dockerfile
```
## Run
If you have Docker Desktop installed, then you probably have `docker-compose` installed as well. If not, refer to [Docker Compose](https://docs.docker.com/compose/install/) for installation instructions.
If you have Docker Desktop installed, then you should have `docker compose` installed automatically. If not, refer to [Docker Compose](https://docs.docker.com/compose/install/) for installation instructions.
Before start, copy `openvk-example.yml` from the root of the repository to `openvk.yml` in this directory and edit it to your liking.
Example configurations are located in this directory for convenience. Before start, copy `openvk.example.yml` to `openvk.yml`, then `chandler.example.yml` to `chandler.yml` and edit them to your liking.
Then, obtain `chandler-example.yml` from [chandler repository](https://github.com/openvk/chandler/blob/master/chandler-example.yml) and place it in this directory as well.
Start is simple as `docker-compose up -d`. You can also use `docker-compose up` to see logs.
Start is simple as `docker compose up -d`. You can also use `docker compose up` to see logs.
- OpenVK will be available at `http://localhost:8080/`.
- PHPMyAdmin will be available at `http://localhost:8081/`.
- Adminer will be available at `http://localhost:8082/`.
### Running in development environment
By using additional `docker-compose.dev.yml` file you can develop OpenVK in Docker with automatic updates as you edit and save your code. Simply run:
```
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --watch
```

View file

@ -0,0 +1,20 @@
services:
openvk:
build:
context: ../../..
dockerfile: install/automated/docker/openvk.Dockerfile
develop:
watch:
- path: ../../..
action: sync
target: /opt/chandler/extensions/available/openvk
ignore:
- vendor/
- path: ../../../composer.json
action: rebuild
- path: ../../../composer.lock
action: rebuild
- path: ../../../Web/static/js/package-lock.json
action: rebuild
- path: ../../../Web/static/js/package.json
action: rebuild

View file

@ -1,4 +1,4 @@
version: '3.7'
name: openvk
services:
openvk:

View file

@ -58,3 +58,5 @@ VOLUME [ "/opt/chandler/extensions/available/openvk/tmp/api-storage/photos" ]
VOLUME [ "/opt/chandler/extensions/available/openvk/tmp/api-storage/videos" ]
USER www-data
WORKDIR /opt/chandler/extensions/available/openvk

View file

@ -0,0 +1,2 @@
ALTER TABLE `posts`
ADD COLUMN `source` TEXT NULL DEFAULT NULL AFTER `api_source_name`;

View file

@ -111,7 +111,7 @@
"relationship_4" = "Married";
"relationship_5" = "In a civil marriage";
"relationship_6" = "In love";
"relationship_7" = "Everything is complicated";
"relationship_7" = "It's complicated";
"relationship_8" = "Actively searching";
/* xd */
@ -122,7 +122,7 @@
"relationship_6_prefix" = "with";
"relationship_7_prefix" = "with";
"politViews" = "Polit. Views";
"politViews" = "Political views";
"politViews_0" = "Not Selected";
"politViews_1" = "Indifferent";
@ -156,7 +156,7 @@
"updated_at" = "Updated at $1";
"user_banned" = "Unfortunately, we had to block the <b>$1</b> user page.";
"user_banned" = "Unfortunately, we had to block <b>$1's</b> user page.";
"user_banned_comment" = "Moderator's comment:";
"verified_page" = "Verified page";
"user_is_blocked" = "User is blocked";
@ -201,11 +201,11 @@
"pin" = "Pin";
"unpin" = "Unpin";
"pinned" = "pinned";
"comments_tip" = "Be first, who leaves a comment at this post!";
"comments_tip" = "Be the first to leave a comment on this post!";
"your_comment" = "Your comment";
"auditory" = "Auditory";
"in_wall" = "to user's wall";
"in_group" = "to group";
"in_wall" = "to my wall";
"in_group" = "to a group";
"shown" = "Shown";
"x_out_of" = "$1 of";
"wall_zero" = "no posts";
@ -223,6 +223,12 @@
"attachment" = "Attachment";
"post_as_group" = "Post as group";
"comment_as_group" = "Comment as group";
"add_source" = "Add source";
"set_source" = "Apply source";
"source" = "Source";
"set_source_tip" = "If you are using content from other authors, it is important to provide a source to the original.<br>You can do it below.";
"add_signature" = "Add signature";
/* ^ can be translated as "author's signature". ^ */
"contains_nsfw" = "Contains NSFW content";
@ -236,7 +242,7 @@
"no_posts_abstract" = "Nobody wrote anything here... So far.";
"attach_no_longer_available" = "This attachment is no longer available.";
"open_post" = "Open post";
"version_incompatibility" = "This attachment could not be displayed. Probably the database is incompatible with the current version of OpenVK.";
"version_incompatibility" = "This attachment could not be displayed. Probably because the database is incompatible with the current version of OpenVK.";
"graffiti" = "Graffiti";
@ -317,8 +323,8 @@
"create_group" = "Create group";
"group_managers" = "Managers";
"group_type" = "Group type";
"group_type_open" = "This is an open group, anyone can enter it.";
"group_type_closed" = "This is an closed group. To enter, you must submit an request.";
"group_type_open" = "This is an open group. Anyone can enter it.";
"group_type_closed" = "This is a closed group. To enter, you must submit a request.";
"creator" = "Creator";
"administrators" = "Administrators";
"add_to_left_menu" = "Add to left menu";
@ -357,12 +363,12 @@
"suggested_by_everyone_many" = "$1 suggested posts";
"suggested_by_everyone_other" = "$1 suggested posts";
"group_hide_from_global_feed" = "Don't display posts in the global feed";
"suggested_posts_by_you" = "Suggested posts by you";
"group_hide_from_global_feed" = "Don't display posts in global feed";
"suggested_posts_by_you" = "Your suggested posts";
"suggested_posts_by_everyone" = "Suggested posts";
"suggested" = "Suggested";
"suggested_posts_everyone" = "Suggested by users posts";
"no_suggested_posts_by_you" = "You haven't suggested posts to this group yet.";
"suggested_posts_everyone" = "Posts suggested by users";
"no_suggested_posts_by_you" = "You haven't suggested any post to this group yet.";
"no_suggested_posts_by_people" = "No posts have been suggested to this group yet.";
"publish_suggested" = "Accept";
@ -377,23 +383,24 @@
"suggested_posts_in_group_many" = "This group has $1 suggested posts";
"suggested_posts_in_group_other" = "This group has $1 suggested posts";
"suggested_posts_in_group_by_you_zero" = "You haven't suggested any posts to this group";
"suggested_posts_in_group_by_you_zero" = "You haven't suggested any post to this group";
"suggested_posts_in_group_by_you_one" = "You suggested one post to this group";
"suggested_posts_in_group_by_you_few" = "You suggested $1 posts to this group";
"suggested_posts_in_group_by_you_many" = "You suggested $1 posts to this group";
"suggested_posts_in_group_by_you_other" = "You suggested $1 posts to this group";
"suggestion_succefully_published" = "Post successfully published";
"suggestion_succefully_declined" = "Post successfully declined";
"suggestion_press_to_go" = "Click to show it";
"suggestion_successfully_published" = "Post successfully published";
"suggestion_successfully_declined" = "Post successfully declined";
"suggestion_press_to_go" = "Go to post";
"error_declining_invalid_post" = "Error when declining post: post does not exists";
"error_declining_not_suggested_post" = "Error when declining post: post is not suggested";
"error_declining_declined_post" = "Error when declining post: post is already declined";
"error_declining_invalid_post" = "The suggested post you attempted to decline is invalid";
"error_declining_not_suggested_post" = "The post you attempted to decline is not suggested";
"error_declining_declined_post" = "This suggested post has already been declined";
"error_accepting_invalid_post" = "The suggested post you attempted to accept is invalid";
"error_accepting_not_suggested_post" = "The post you attempted to accept is not suggested";
"error_accepting_declined_post" = "This suggested post has already been declined";
"error_accepting_invalid_post" = "Error when accepting post: post does not exists";
"error_accepting_not_suggested_post" = "Error when accepting post: post is not suggested";
"error_accepting_declined_post" = "Error when accepting post: cant accept declined post";
"statistics" = "Statistics";
"group_administrators_list" = "Admins list";
"group_display_only_creator" = "Display only group creator";
@ -483,6 +490,7 @@
"deleting_avatar" = "Deleting photo";
"deleting_avatar_sure" = "Do you sure you want to delete avatar?";
"deleted_avatar_notification" = "Picture deleted successfully";
"save_changes" = "Save changes";
"upd_m" = "updated his profile picture";
@ -493,7 +501,7 @@
"add_photos" = "Add photos";
"upload_picts" = "Upload photos";
"end_uploading" = "Finish uploading";
"photos_successfully_uploaded" = "Photos successfully uploaded";
"photos_successfully_uploaded" = "Photos uploaded successfully";
"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";
@ -553,10 +561,10 @@
"error_attaching_note" = "Error when attaching note";
"select_or_create_new" = "Select existing note or <a href='/notes/create'>create new one</a>";
"select_or_create_new" = "Select an existing note or <a href='/notes/create'>create a new one</a>";
"notes_closed" = "You can't attach note to post, because only you can see them.<br> You can change it in <a href=\"/settings?act=privacy\">settings</a>.";
"do_not_attach_note" = "Do not attach note";
"notes_closed" = "You can't attach a note to the post because only you can see them.<br> You can change this in <a href=\"/settings?act=privacy\">settings</a>.";
"do_not_attach_note" = "Do not attach a note";
"something" = "Something";
"supports_xhtml" = "from (X)HTML supported.";
@ -579,11 +587,11 @@
"my_feed" = "My Feed";
"my_feedback" = "My Feedback";
"my_settings" = "My Settings";
"bug_tracker" = "Bug-tracker";
"bug_tracker" = "Bug Tracker";
"menu_settings" = "Settings";
"menu_login" = "Login";
"menu_registration" = "Registration";
"menu_registration" = "Register";
"menu_help" = "Help";
@ -834,6 +842,7 @@
/* Audios */
"my" = "My";
"audios" = "Audios";
"audio" = "Audio";
"playlist" = "Playlist";
@ -849,16 +858,16 @@
"limits" = "Limits";
"select_audio" = "Select audio from your computer";
"audio_requirements" = "Audio must be between $1 seconds to $2 minutes, weights to $3 MB and contain audio stream.";
"audio_requirements_2" = "Audio must not infringe copyright and related rights";
"you_can_also_add_audio_using" = "You can also add audio from among the files you have already downloaded using";
"audio_requirements" = "Audio must be between $1 seconds and $2 minutes, with a file size up to $3 MB, and contain an audio stream.";
"audio_requirements_2" = "Audio must not infringe copyright and related rights.";
"you_can_also_add_audio_using" = "You can also add audio from files you have already downloaded using";
"search_audio_inst" = "audios search";
"audio_embed_not_found" = "Audio not found";
"audio_embed_deleted" = "Audio was deleted";
"audio_embed_withdrawn" = "The audio was withdrawn at the request of the copyright holder";
"audio_embed_deleted" = "Audio has been deleted";
"audio_embed_withdrawn" = "The audio has been withdrawn at the request of the copyright holder";
"audio_embed_forbidden" = "The user's privacy settings do not allow this audio to be embedded";
"audio_embed_processing" = "Audio is still being processed, or has not been processed correctly.";
"audio_embed_processing" = "Audio is still being processed or has not been processed correctly.";
"audios_count_zero" = "No audios";
"audios_count_one" = "One audio";
@ -871,7 +880,7 @@
"my_music" = "My music";
"music_user" = "User's music";
"music_club" = "Club's music";
"music_club" = "Group's music";
"audio_new" = "New";
"audio_popular" = "Popular";
"audio_search" = "Search";
@ -914,19 +923,19 @@
"delete_playlist" = "Delete playlist";
"playlist_cover" = "Playlist cover";
"playlists_user" = "Users playlists";
"playlists_club" = "Groups playlists";
"playlists_user" = "User's playlists";
"playlists_club" = "Group's playlists";
"change_cover" = "Change cover";
"playlist_cover" = "Playlist's cover";
"minutes_count_zero" = "lasts no minutes";
"minutes_count_one" = "lasts one minute";
"minutes_count_few" = "lasts $1 minutes";
"minutes_count_many" = "lasts $1 minutes";
"minutes_count_other" = "lasts $1 minutes";
"minutes_count_zero" = "Lasts no minutes";
"minutes_count_one" = "Lasts one minute";
"minutes_count_few" = "Lasts $1 minutes";
"minutes_count_many" = "Lasts $1 minutes";
"minutes_count_other" = "Lasts $1 minutes";
"listens_count_zero" = "no listens";
"listens_count_one" = "one listen";
"listens_count_zero" = "No listens";
"listens_count_one" = "One listen";
"listens_count_few" = "$1 listens";
"listens_count_many" = "$1 listens";
"listens_count_other" = "$1 listens";
@ -949,7 +958,7 @@
"audio_successfully_uploaded" = "Audio has been successfully uploaded and is currently being processed.";
"broadcast_audio" = "Broadcast audio to status";
"sure_delete_playlist" = "Do you sure want to delete this playlist?";
"sure_delete_playlist" = "Are you sure you want to delete this playlist?";
"edit_audio" = "Edit audio";
"audios_group" = "Audios from group";
"playlists_group" = "Playlists from group";
@ -1057,7 +1066,7 @@
"coins_count" = "Number of votes";
"message" = "Message";
"failed_to_tranfer_points" = "Failed to transfer votes";
"failed_to_transfer_points" = "Failed to transfer votes";
"points_transfer_successful" = "You have successfully transferred <b>$1</b> to <b><a href=\"$2\">$3</a></b>.";
"not_all_information_has_been_entered" = "Not all information has been entered.";
@ -1076,8 +1085,8 @@
"apply_voucher" = "Apply voucher";
"failed_to_increase_rating" = "Failed to increase rating";
"rating_increase_successful" = "You have successfully increased rating of <b><a href=\"$1\">$2</a></b> by <b>$3%</b>.";
"negative_rating_value" = "We cannot steal rating from another person, sorry.";
"rating_increase_successful" = "You have successfully increased the rating of <b><a href=\"$1\">$2</a></b> by <b>$3%</b>.";
"negative_rating_value" = "You can't steal ratings from another person.";
"increased_your_rating_by" = "increased your rating by";
@ -1138,43 +1147,43 @@
"app_withdrawal_empty" = "Sorry, withdrawal of emptiness is not possible.";
"app_withdrawal_created" = "A request to withdraw $1 votes has been created. Awaiting crediting.";
"appjs_payment" = "Purchase payment";
"appjs_payment" = "Purchase Payment";
"appjs_payment_intro" = "You are about to pay for an order in the application";
"appjs_order_items" = "Order items";
"appjs_payment_total" = "Total amount payable";
"appjs_payment_confirm" = "Pay";
"appjs_err_funds" = "Failed to pay: insufficient funds.";
"appjs_wall_post" = "Publish a post";
"appjs_wall_post" = "Publish a Post";
"appjs_wall_post_desc" = "wants to publish a post on your wall";
"appjs_act_friends" = "your Friends";
"appjs_act_friends" = "Your Friends";
"appjs_act_friends_desc" = "add users as friends and read your friends list";
"appjs_act_wall" = "your Wall";
"appjs_act_wall" = "Your Wall";
"appjs_act_wall_desc" = "see your news, your wall and create posts on it";
"appjs_act_messages" = "your Messages";
"appjs_act_messages" = "Your Messages";
"appjs_act_messages_desc" = "read and write messages on your behalf";
"appjs_act_groups" = "your Groups";
"appjs_act_groups_desc" = "see a list of your groups and subscribe you to other";
"appjs_act_likes" = "Likes feature";
"appjs_act_groups" = "Your Groups";
"appjs_act_groups_desc" = "see a list of your groups and subscribe you to others";
"appjs_act_likes" = "Likes Feature";
"appjs_act_likes_desc" = "give and take away likes to posts";
"appjs_act_request" = "Access request";
"appjs_act_request" = "Access Request";
"appjs_act_requests" = "requests access to";
"appjs_act_can" = "The app will be able to";
"appjs_act_allow" = "Allow";
"appjs_act_disallow" = "Disallow";
"app_uninstalled" = "Application is disabled";
"app_uninstalled" = "Application Disabled";
"app_uninstalled_desc" = "It will no longer be able to perform actions on your behalf.";
"app_err_not_found" = "Application not found";
"app_err_not_found" = "Application Not Found";
"app_err_not_found_desc" = "Incorrect identifier or it has been disabled.";
"app_err_forbidden_desc" = "This application is not yours.";
"app_err_url" = "Incorrect address";
"app_err_url_desc" = "The address of the application did not pass the check, make sure it is correct.";
"app_err_ava" = "Unable to upload an avatar";
"app_err_ava_desc" = "Avatar too big or wrong: general error #$res.";
"app_err_note" = "Failed to attach a news note";
"app_err_forbidden_desc" = "This application does not belong to you.";
"app_err_url" = "Incorrect Address";
"app_err_url_desc" = "The address of the application did not pass the check; make sure it is correct.";
"app_err_ava" = "Unable to Upload an Avatar";
"app_err_ava_desc" = "Avatar is too big or incorrect: general error #$res.";
"app_err_note" = "Failed to Attach a News Note";
"app_err_note_desc" = "Make sure the link is correct and the note belongs to you.";
"learn_more" = "Learn more";
@ -1182,7 +1191,7 @@
/* Support */
"support_opened" = "Opened";
"support_answered" = "With a response";
"support_answered" = "Has a response";
"support_closed" = "Closed";
"support_ticket" = "Ticket";
"support_tickets" = "Tickets";
@ -1190,28 +1199,28 @@
"support_status_1" = "There's a response";
"support_status_2" = "Closed";
"support_greeting_hi" = "Greetings, $1!";
"support_greeting_regards" = "Best regards,<br/>$1 support team.";
"support_greeting_regards" = "Best regards,<br/>$1 Support Team.";
"support_faq" = "Frequently Asked Questions";
"support_list" = "List of tickets";
"support_new" = "New ticket";
"support_list" = "List of Tickets";
"support_new" = "New Ticket";
"support_new_title" = "Enter the topic of your ticket";
"support_new_content" = "Describe the issue or suggestion";
"reports" = "Reports";
"support_rate_good_answer" = "This is good answer";
"support_rate_bad_answer" = "This is bad answer";
"support_good_answer_user" = "You left a positive feedback.";
"support_bad_answer_user" = "You left a negative feedback.";
"support_good_answer_agent" = "User left a positive feedback.";
"support_bad_answer_agent" = "User left a negative feedback.";
"support_rated_good" = "You left a positive feedback about the answer.";
"support_rated_bad" = "You left a negative feedback about the answer.";
"support_rate_good_answer" = "This is a good answer";
"support_rate_bad_answer" = "This is a bad answer";
"support_good_answer_user" = "You left positive feedback.";
"support_bad_answer_user" = "You left negative feedback.";
"support_good_answer_agent" = "User left positive feedback.";
"support_bad_answer_agent" = "User left negative feedback.";
"support_rated_good" = "You left positive feedback about the answer.";
"support_rated_bad" = "You left negative feedback about the answer.";
"wrong_parameters" = "Invalid request parameters.";
"fast_answers" = "Fast answers";
"fast_answers" = "Quick Answers";
"ignore_report" = "Ignore report";
"report_number" = "Report #";
@ -1306,7 +1315,7 @@
"poll_editor_tips" = "Pressing backspace in empty option will remove it. Use Tab/Enter (in last option) to create new options faster.";
"poll_embed" = "Embed code";
"poll_voter_count_zero" = "Be <b>the first one</b> to vote!";
"poll_voter_count_zero" = "Be <b>the first</b> to vote!";
"poll_voter_count_one" = "<b>Only one</b> user voted.";
"poll_voter_count_few" = "<b>$1</b> users voted.";
"poll_voter_count_many" = "<b>$1</b> users voted.";
@ -1333,7 +1342,7 @@
"messages_other" = "$1 messages";
"topic_messages_count_zero" = "Topic has no messages";
"topic_messages_count_one" = "There are one message in the topic";
"topic_messages_count_one" = "There is one message in the topic";
"topic_messages_count_other" = "There are $1 messages in the topic";
"replied" = "replied";
@ -1399,7 +1408,7 @@
"photo_saved" = "Photo saved";
"photo_saved_comment" = "New profile picture will appear on your page";
"shared_succ" = "The post will appear on your wall. Click on the notification to go to your wall.";
"shared_succ" = "The post will appear on your wall. Click on this notification to go there.";
"invalid_email_address" = "Invalid Email address";
"invalid_email_address_comment" = "The Email you entered is not correct.";
@ -1553,6 +1562,10 @@
"ffmpeg_not_installed" = "Failed to proccess the file. It looks like ffmpeg is not installed on this server.";
"too_many_or_to_lack" = "Too few or too many sources.";
"error_adding_source_regex" = "Error adding source: incorrect link.";
"error_adding_source_long" = "Error adding source: link is too long.";
"error_adding_source_sus" = "Error adding source: suspicious link.";
/* Admin actions */
"login_as" = "Login as $1";
@ -1993,6 +2006,7 @@
/* Search */
"s_params" = "Search params";
"s_people" = "Users";
"s_groups" = "Clubs";
"s_apps" = "Applications";

View file

@ -207,6 +207,12 @@
"attachment" = "Вложение";
"post_as_group" = "От имени сообщества";
"comment_as_group" = "От имени сообщества";
"add_source" = "Добавление источника";
"set_source" = "Указать источник";
"source" = "Источник";
"set_source_tip" = "Если вы используете материалы других авторов, важно указывать ссылку на оригинал.<br>Сделать это вы можете ниже.";
"add_signature" = "Подпись автора";
"contains_nsfw" = "Содержит NSFW-контент";
"nsfw_warning" = "Данный пост может содержать 18+ контент";
@ -791,6 +797,7 @@
/* Audios */
"my" = "Моё";
"audios" = "Аудиозаписи";
"audio" = "Аудиозапись";
"playlist" = "Плейлист";
@ -870,7 +877,7 @@
"remove_from_playlist" = "Удалить из плейлиста";
"delete_playlist" = "Удалить плейлист";
"playlist_cover" = "Обложка плейлиста";
"playlists_user" = "Плейлисты польз.";
"playlists_user" = "Плейлисты пользователя";
"playlists_club" = "Плейлисты группы";
"change_cover" = "Сменить обложку";
"playlist_cover" = "Обложка плейлиста";
@ -1455,6 +1462,10 @@
"ffmpeg_not_installed" = "Не удалось обработать файл. Похоже, на сервере не установлен ffmpeg.";
"too_many_or_to_lack" = "Слишком мало либо слишком много источников.";
"error_adding_source_regex" = "Ошибка добавления источника: некорректная ссылка.";
"error_adding_source_long" = "Ошибка добавления источника: слишком длинная ссылка.";
"error_adding_source_sus" = "Ошибка добавления источника: подозрительная ссылка.";
/* Admin actions */
"login_as" = "Войти как $1";
@ -1883,6 +1894,7 @@
/* Search */
"s_params" = "Параметры поиска";
"s_people" = "Пользователи";
"s_groups" = "Группы";
"s_apps" = "Приложения";

View file

@ -1,7 +1,7 @@
.page_header {
background-image: url('/themepack/midnight/0.0.2.9/resource/xheader.png') !important;
background-image: url('/themepack/midnight/0.0.3.0/resource/xheader.png') !important;
}
.page_custom_header {
background-image: url('/themepack/midnight/0.0.2.9/resource/xheader_custom.png') !important;
background-image: url('/themepack/midnight/0.0.3.0/resource/xheader_custom.png') !important;
}

View file

@ -9,7 +9,8 @@ html {
body,
#backdropDripper,
#standaloneCommentBox,
.ovk-photo-view {
.ovk-photo-view,
.articleView {
background-color: #0e0b1a;
color: #c6d2e8;
}
@ -23,7 +24,8 @@ span,
.crp-entry--message---text,
.messenger-app--messages---message .time,
.navigation-lang .link_new,
.tippy-box text {
.tippy-box text,
.articleView_author > div > span > a {
color: #8b9ab5 !important;
}
@ -130,10 +132,19 @@ th,
.borderup,
#tour,
#auth,
.ovk-photo-view {
.ovk-photo-view,
.page_wrap_content_main .def_row_content,
.topGrayBlock,
.bigPlayer {
border-color: #2c2640 !important;
}
.post-upload,
.post-has-poll,
.post-has-note {
color: #777;
}
.tippy-box[data-theme~="vk"][data-placement^='top']>.tippy-arrow::before,
.tippy-box[data-theme~="vk"][data-placement^='bottom']>.tippy-arrow::before {
border-top-color: #1e1a2b;
@ -154,22 +165,28 @@ hr {
.messagebox-content-header,
.accent-box,
.button_search,
.search_box_button {
.header_navigation #search_box .search_box_button {
background-color: #383052;
}
.header_navigation #search_box .search_box_button {
box-shadow: 0px 2px 0px 0px rgb(70, 63, 96) inset;
}
.search_option_name {
background-color: #383052 !important;
color: lightgrey !important;
}
.tab:hover {
.tab:hover,
.ntSelect:hover {
background-color: #40375e;
}
.menu_divider,
.ovk-diag-action,
.minilink .counter {
.minilink .counter,
.topGrayBlock {
background-color: #2c2640;
}
@ -266,7 +283,8 @@ center[style="background: white;border: #DEDEDE solid 1px;"],
td.e,
tr.e,
.playlistListView:hover,
.playlistListView .playlistCover {
.playlistListView .playlistCover,
.photosInsert > div {
background-color: #231e33 !important;
}
@ -295,11 +313,11 @@ tr.v,
}
.content_title_expanded {
background-image: url("/themepack/midnight/0.0.2.9/resource/flex_arrow_open.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/flex_arrow_open.png") !important;
}
.content_title_unexpanded {
background-image: url("/themepack/midnight/0.0.2.9/resource/flex_arrow_shut.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/flex_arrow_shut.gif") !important;
}
.ovk-video>.preview,
@ -326,17 +344,17 @@ tr.h {
.page_yellowheader {
color: #c6d2e8;
background-image: url("/themepack/midnight/0.0.2.9/resource/header_purple.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/header_purple.png") !important;
background-color: #231f34;
border-color: #231f34;
}
.page_header {
background-image: url("/themepack/midnight/0.0.2.9/resource/header.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/header.png") !important;
}
.page_custom_header {
background-image: url("/themepack/midnight/0.0.2.9/resource/header_custom.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/header_custom.png") !important;
}
.page_yellowheader span,
@ -374,11 +392,11 @@ select,
}
input[type="checkbox"] {
background-image: url("/themepack/midnight/0.0.2.9/resource/checkbox.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/checkbox.png") !important;
}
input[type="radio"] {
background-image: url("/themepack/midnight/0.0.2.9/resource/radio.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/radio.png") !important;
}
.header_navigation .link, .header_navigation .header_divider_stick {
@ -386,20 +404,20 @@ input[type="radio"] {
}
.heart {
background-image: url("/themepack/midnight/0.0.2.9/resource/like.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/like.gif") !important;
}
.pinned-mark,
.post-author .pin {
background-image: url("/themepack/midnight/0.0.2.9/resource/pin.png") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/pin.png") !important;
}
.repost-icon {
background-image: url("/themepack/midnight/0.0.2.9/resource/published.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/published.gif") !important;
}
.post-author .delete {
background-image: url("/themepack/midnight/0.0.2.9/resource/input_clear.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/input_clear.gif") !important;
}
.user-alert {
@ -432,7 +450,7 @@ input[type="radio"] {
}
#backdropEditor {
background-image: url("/themepack/midnight/0.0.2.9/resource/backdrop-editor.gif") !important;
background-image: url("/themepack/midnight/0.0.3.0/resource/backdrop-editor.gif") !important;
border-color: #473e66 !important;
}
@ -485,7 +503,8 @@ input[type="radio"] {
background: #19142D !important;
}
.audioEntry .performer a {
.audioEntry .performer a,
.bigPlayer .paddingLayer .trackInfo a {
color: #a2a1a1 !important;
}
@ -591,3 +610,7 @@ ul {
background: #28223a;
border: #2c2640 solid 1px;
}
#backdropFilePicker {
margin: 15px !important;
}

View file

@ -1,5 +1,5 @@
id: midnight
version: "0.0.2.9"
version: "0.0.3.0"
openvk_version: 0
enabled: 1
metadata: