Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions Web/Presenters/AdminPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -872,4 +872,44 @@ public function renderLogs(): void
$this->template->logs = $logs;
$this->template->object_types = (new Logs())->getTypes();
}

public function renderConfig(): void
{
if (!OPENVK_ROOT_CONF["openvk"]["allowEditConfig"]) {
$this->notFound();
}

$cfg_filepath = __DIR__ . "../../../openvk.yml";

if ($_SERVER["REQUEST_METHOD"] !== "POST") {
$this->template->cfg = chandler_parse_yaml($cfg_filepath);
} else {
$this->assertNoCSRF();

$yaml = $this->postParam("yaml");
if (!$yaml) {
$this->notFound();
}

$tmp = $cfg_filepath . ".tmp";

if (file_put_contents($tmp, $yaml) === false) {
$this->returnJson(["success" => false, "error" => tr("admin_tuning_cfg_file_write_err")]);
}

$parsed_yaml = chandler_parse_yaml($tmp);

if (!$parsed_yaml || $parsed_yaml["openvk"]["allowEditConfig"] != OPENVK_ROOT_CONF["openvk"]["allowEditConfig"]) {
unlink($tmp);
$this->returnJson(["success" => false, "error" => tr("admin_tuning_cfg_tmp_read_fail_yaml")]);
}

if (!rename($tmp, $cfg_filepath)) {
unlink($tmp);
$this->returnJson(["success" => false, "error" => tr("admin_tuning_cfg_write_fail")]);
}

$this->returnJson(["success" => true]);
}
}
}
6 changes: 6 additions & 0 deletions Web/Presenters/templates/Admin/@layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@
<strong>{_admin_settings}</strong>
</div>
<ul class="aui-nav">
<li n:if='OPENVK_ROOT_CONF["openvk"]["allowEditConfig"]'>
<a class="aui-nav-item" href="/admin/config">
<span class="aui-icon aui-icon-small aui-iconfont-settings"></span>
<span class="aui-nav-item-label">{_admin_settings_config}</span>
</a>
</li>
<li>
<a class="aui-nav-item" href="/admin/logs">
<span class="aui-icon aui-icon-small aui-iconfont-list"></span>
Expand Down
25 changes: 25 additions & 0 deletions Web/Presenters/templates/Admin/Config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{extends "@layout.xml"}

{block title}
{_admin_settings_config}
{/block}

{block heading}
{include title}
<button id="save-button" class="aui-button aui-button-primary" onClick='convertFormToYAML("/admin/config", {$csrfToken});'>Сохранить все</button>
{/block}

{block content}
<style>
h1,h2,h5 {
margin: 5px;
}
#save-button {
float: right;
}
</style>
<form class="aui">
{include 'displayYamlData.xml', cfg => $cfg}
</form>
{script "js/yaml.js"}
{/block}
33 changes: 33 additions & 0 deletions Web/Presenters/templates/Admin/displayYamlData.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{block displayYamlData}
{foreach $cfg as $key => $value}
{var $level = 'h' . ($baseLevel + 1)}
{var $intLevel = $baseLevel + 1}
{var $indent = $intLevel * 10}
<div style="margin-left: {$indent}px;">
{if is_array($value)}
<input type="hidden" name="{$key}" level="{$baseLevel ?? 0}" noValue="1"/>

<{$level}>
{preg_match('/\d$/', $key) ? ($key + 1 . '. ') : (tr('admin_settings_tuning_' . $key) ?? $key)}
</{$level}>

{include 'displayYamlData.xml', cfg => $value, baseLevel => ($baseLevel + 1), prevLevel => $baseLevel}
{else}
<div class="field-group" style="padding: 0;">
<input disabled class="text long-field" type="text"
value="{preg_match('/\d$/', $key) ? ($key + 1 . '. ') : (tr('admin_settings_tuning_' . $key) ?? $key)}"
name="{$key}"/>

{if $value === true || $value === false}
<select class="select" name="{$key}" level="{$baseLevel}" {if $key === "allowEditConfig"}disabled{/if}>
<option value="true" {if $value === true}selected{/if}>{_yes}</option>
<option value="false" {if $value === false}selected{/if}>{_no}</option>
</select>
{else}
<input class="text long-field" type="text" name="{$key}" value="{$value}" level="{$baseLevel}"/>
{/if}
</div>
{/if}
</div>
{/foreach}
{/block}
2 changes: 2 additions & 0 deletions Web/routes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ routes:
handler: "Admin->chandlerGroup"
- url: "/admin/chandler/users/{slug}"
handler: "Admin->chandlerUser"
- url: "/admin/config"
handler: "Admin->config"
- url: "/noSpam"
handler: "NoSpam->index"
- url: "/al_abuse/search"
Expand Down
102 changes: 102 additions & 0 deletions Web/static/js/yaml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
function convertFormToYAML(handler, csrfToken) {
const form = $(".aui");
let formData = [];

form.find('input, select').each(function () {
let key = $(this).attr("name");
let value = $(this).val();
let level = $(this).attr("level") ?? 0;

if ($(this).is('select')) {
value = (value === 'true');
}

if ($(this).attr("disabled") && !(key == "allowEditConfig" && level == 1)) {
return;
}

if ($(this).attr("noValue")) {
formData.push({indentation: level, key: key, value: value, noValue: true});
} else {
formData.push({indentation: level, key: key, value: value});
}
});

const yaml = restoreYAMLFromJS(formData);
$.ajax({
type: "POST",
url: handler,
data: {
yaml: yaml,
hash: csrfToken
},
success: (data) => {
if (data.success) {
window.location.reload();
} else {
alert(data.error ?? "Неизвестная ошибка");
}
}
})
}

function restoreYAMLFromJS(formData) {
let yamlData = '';
let stack = [];
let currentIndent = 0;
let addDashForNextKey = false;
let nextSpacesOverride = null;

formData.forEach((_key, i) => {
let {indentation, key} = _key;
let value = _key.value;
const level = parseInt(indentation);

console.log(_key);

let spaces = ' '.repeat(nextSpacesOverride ?? (level * 4));
nextSpacesOverride = null;

while (level < currentIndent) {
stack.pop();
currentIndent -= 1;
}

if (_key?.noValue) {
yamlData += `${spaces}${key}:\n`;
} else {
if (/\d$/.test(key) && value.length === 0) {
addDashForNextKey = true;
} else {
if (addDashForNextKey) {
let _s = `${spaces}- ${key}: \"${value}\"\n`;
nextSpacesOverride = _s.split(key)[0].length;
yamlData += _s;
addDashForNextKey = false;
} else if (/\d: ".*"/.test(`${key}: \"${value}\"`)) {
yamlData += `${spaces}- ${value}\n`;
addDashForNextKey = false;
} else {
if (value.length === 0) {
yamlData += `${spaces}${key}: \"\"\n`;
} else if (typeof value === 'boolean') {
yamlData += `${spaces}${key}: ${value}\n`;
} else if (value === 'null' || value == " ") {
yamlData += `${spaces}${key}: null\n`;
} else if (value.startsWith('"') && value.endsWith('"')) {
yamlData += `${spaces}${key}: ${value}\n`;
} else {
yamlData += `${spaces}${key}: \"${value}\"\n`;
currentIndent = level + 1;

stack.push(yamlData);
stack.push(level + 1);
stack.push(key);
}
}
}
}
});

return yamlData;
}
114 changes: 114 additions & 0 deletions locales/en.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,120 @@
"admin_overview_chandler_groups_missing" = "Permissions groups are necessary for full access to instance management (Helpdesk, moderation, noSpam)";
"admin_overview_chandler_groups_create_missing" = "Create missing permissions groups";

"save_all" = "Save all";
"admin_tuning_cfg_file_write_err" = "Configuration file could not be written, editing is blocked";
"admin_tuning_cfg_tmp_read_fail_yaml" = "Error when reading temporary file: possibly incorrect YAML was passed";
"admin_tuning_cfg_write_fail" = "Error writing a configuration file";
"admin_settings_config" = "Config";

"admin_settings_tuning_openvk" = "OpenVK";
"admin_settings_tuning_debug" = "Debug mode";
"admin_settings_tuning_appearance" = "Appearance";
"admin_settings_tuning_name" = "Name";
"admin_settings_tuning_motd" = "Instance description";
"admin_settings_tuning_preferences" = "Settings";
"admin_settings_tuning_femaleGenderPriority" = "Female gender priority";
"admin_settings_tuning_nginxCacheTime" = "nginx Cache time";
"admin_settings_tuning_uploads" = "Uploads";
"admin_settings_tuning_disableLargeUploads" = "Disable large uploads";
"admin_settings_tuning_mode" = "Mode";
"admin_settings_tuning_api" = "API";
"admin_settings_tuning_maxFilesPerDomain" = "Max files per domain";
"admin_settings_tuning_maxFileSize" = "Max file size";
"admin_settings_tuning_shortcodes" = "Shortcodes";
"admin_settings_tuning_minLength" = "Min length";
"admin_settings_tuning_forbiddenNames" = "Forbidden names";
"admin_settings_tuning_array_element" = "Array Item";
"admin_settings_tuning_photos" = "Photos";
"admin_settings_tuning_upgradeStructure" = "Upgrade structure";
"admin_settings_tuning_photoSaving" = "Photo saving";
"admin_settings_tuning_videos" = "Videos";
"admin_settings_tuning_disableUploading" = "Disable uploading";
"admin_settings_tuning_apps" = "Apps";
"admin_settings_tuning_withdrawTax" = "Withdraw tax";
"admin_settings_tuning_security" = "Security";
"admin_settings_tuning_requireEmail" = "Require Email";
"admin_settings_tuning_requirePhone" = "Require phone";
"admin_settings_tuning_forcePhoneVerification" = "Force phone verification";
"admin_settings_tuning_forceEmailVerification" = "Force Email verification";
"admin_settings_tuning_forceStrongPassword" = "Force strong password";
"admin_settings_tuning_disablePasswordRestoring" = "Disable password restoring";
"admin_settings_tuning_enableSu" = "Allow user substitution";
"admin_settings_tuning_rateLimits" = "Rate limits";
"admin_settings_tuning_actions" = "Actions";
"admin_settings_tuning_time" = "Time";
"admin_settings_tuning_maxViolations" = "Max violations";
"admin_settings_tuning_maxViolationsAge" = "Max violations age";
"admin_settings_tuning_autoban" = "Auto ban";
"admin_settings_tuning_registration" = "Registration";
"admin_settings_tuning_enable" = "Enable";
"admin_settings_tuning_disablingReason" = "Disabling reason";
"admin_settings_tuning_support" = "Support";
"admin_settings_tuning_supportName" = "Default responder name";
"admin_settings_tuning_adminAccount" = "Admin account";
"admin_settings_tuning_messages" = "Messages";
"admin_settings_tuning_wall" = "Wall";
"admin_settings_tuning_anonymousPosting" = "Anonymous posting";
"admin_settings_tuning_account" = "Account";
"admin_settings_tuning_postSizes" = "Post sizes";
"admin_settings_tuning_maxSize" = "Max size";
"admin_settings_tuning_processingLimit" = "Предел обработки";
"admin_settings_tuning_emojiProcessingLimit" = "Emoji processing limit";
"admin_settings_tuning_commerce" = "Commerce enabled";
"admin_settings_tuning_susLinks" = "Suspicious links";
"admin_settings_tuning_warnings" = "Warnings";
"admin_settings_tuning_showReason" = "Show the reason";
"admin_settings_tuning_maintenanceMode" = "Maintenance";
"admin_settings_tuning_all" = "All";
"admin_settings_tuning_messenger" = "Messenger";
"admin_settings_tuning_user" = "User";
"admin_settings_tuning_group" = "Groups";
"admin_settings_tuning_comment" = "Comments";
"admin_settings_tuning_gifts" = "Gifts";
"admin_settings_tuning_notes" = "Notes";
"admin_settings_tuning_notification" = "Notifications";
"admin_settings_tuning_topics" = "Topics";
"admin_settings_tuning_ton" = "TON";
"admin_settings_tuning_enabled" = "Enabled";
"admin_settings_tuning_menu" = "Menu";
"admin_settings_tuning_links" = "Links";
"admin_settings_tuning_about" = "About";
"admin_settings_tuning_url" = "URL";
"admin_settings_tuning_adPoster" = "Ad poster";
"admin_settings_tuning_src" = "Source";
"admin_settings_tuning_caption" = "Caption";
"admin_settings_tuning_link" = "Link";
"admin_settings_tuning_defaultMobileTheme" = "Default mobile theme";
"admin_settings_tuning_telemetry" = "Telemetry";
"admin_settings_tuning_piwik" = "Piwik";
"admin_settings_tuning_matomo" = "Matomo";
"admin_settings_tuning_container" = "Container";
"admin_settings_tuning_site" = "Site";
"admin_settings_tuning_credentials" = "Credentials";
"admin_settings_tuning_smsc" = "SMSC";
"admin_settings_tuning_client" = "Client";
"admin_settings_tuning_layer" = "Layer";
"admin_settings_tuning_secret" = "Secret key";
"admin_settings_tuning_token" = "Token";
"admin_settings_tuning_helpdeskChat" = "Helpdesk chat";
"admin_settings_tuning_telegram" = "Telegram";
"admin_settings_tuning_eventDB" = "eventDB";
"admin_settings_tuning_kafka" = "Kafka";
"admin_settings_tuning_database" = "Database";
"admin_settings_tuning_dsn" = "DSN";
"admin_settings_tuning_password" = "Password";
"admin_settings_tuning_notificationsBroker" = "Notifications broker";
"admin_settings_tuning_domain" = "Domain";
"admin_settings_tuning_server" = "Server";
"admin_settings_tuning_address" = "Address";
"admin_settings_tuning_testnet" = "Testnet";
"admin_settings_tuning_regex" = "Regex";
"admin_settings_tuning_hint" = "Hint";
"admin_settings_tuning_addr" = "Address";
"admin_settings_tuning_port" = "Port";
"admin_settings_tuning_topic" = "Topic";
"admin_settings_tuning_allowEditConfig" = "Config editor allowed";

/* Paginator (deprecated) */

"paginator_back" = "Back";
Expand Down
Loading