Use API for config.json

This commit is contained in:
amcmanu3
2023-08-15 16:09:06 -04:00
parent 4e0743bc1f
commit 93428b2e05
4 changed files with 182 additions and 27 deletions

View File

@ -5,6 +5,7 @@ from datetime import datetime
import platform import platform
import shutil import shutil
import time import time
import json
import logging import logging
import threading import threading
from peewee import DoesNotExist from peewee import DoesNotExist
@ -84,6 +85,13 @@ class Controller:
def set_project_root(self, root_dir): def set_project_root(self, root_dir):
self.project_root = root_dir self.project_root = root_dir
def set_config_json(self, data):
keys = list(data.keys())
keys.sort()
sorted_data = {i: data[i] for i in keys}
with open(self.helper.settings_file, "w", encoding="utf-8") as f:
json.dump(sorted_data, f, indent=4)
def package_support_logs(self, exec_user): def package_support_logs(self, exec_user):
if exec_user["preparing"]: if exec_user["preparing"]:
return return

View File

@ -49,6 +49,7 @@ from app.classes.web.routes.api.users.user.permissions import (
) )
from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
from app.classes.web.routes.api.users.user.public import ApiUsersUserPublicHandler from app.classes.web.routes.api.users.user.public import ApiUsersUserPublicHandler
from app.classes.web.routes.api.crafty.config.index import ApiCraftyConfigIndexHandler
def api_handlers(handler_args): def api_handlers(handler_args):
@ -64,6 +65,11 @@ def api_handlers(handler_args):
ApiAuthInvalidateTokensHandler, ApiAuthInvalidateTokensHandler,
handler_args, handler_args,
), ),
(
r"/api/v2/crafty/config/?",
ApiCraftyConfigIndexHandler,
handler_args,
),
# User routes # User routes
( (
r"/api/v2/users/?", r"/api/v2/users/?",

View File

@ -0,0 +1,113 @@
from jsonschema import ValidationError, validate
import orjson
from playhouse.shortcuts import model_to_dict
from app.classes.web.base_api_handler import BaseApiHandler
config_json_schema = {
"type": "object",
"properties": {
"http_port": {"type": "integer"},
"https_port": {"type": "integer"},
"language": {
"type": "string",
},
"cookie_expire": {"type": "integer"},
"show_errors": {"type": "boolean"},
"history_max_age": {"type": "integer"},
"stats_update_frequency_seconds": {"type": "integer"},
"delete_default_json": {"type": "boolean"},
"show_contribute_link": {"type": "boolean"},
"virtual_terminal_lines": {"type": "integer"},
"max_log_lines": {"type": "integer"},
"max_audit_entries": {"type": "integer"},
"disabled_language_files": {"type": "array"},
"stream_size_GB": {"type": "integer"},
"keywords": {"type": "string"},
"allow_nsfw_profile_pictures": {"type": "boolean"},
"enable_user_self_delete": {"type": "boolean"},
"reset_secrets_on_next_boot": {"type": "boolean"},
"monitored_mounts": {"type": "array"},
"dir_size_poll_freq_minutes": {"type": "integer"},
"crafty_logs_delete_after_days": {"type": "integer"},
},
"additionalProperties": False,
"minProperties": 1,
}
class ApiCraftyConfigIndexHandler(BaseApiHandler):
def get(self):
auth_data = self.authenticate_user()
if not auth_data:
return
(
_,
_,
_,
superuser,
_,
) = auth_data
# GET /api/v2/roles?ids=true
get_only_ids = self.get_query_argument("ids", None) == "true"
if not superuser:
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
self.finish_json(
200,
{
"status": "ok",
"data": self.controller.roles.get_all_role_ids()
if get_only_ids
else [model_to_dict(r) for r in self.controller.roles.get_all_roles()],
},
)
def patch(self):
auth_data = self.authenticate_user()
if not auth_data:
return
(
_,
_,
_,
superuser,
user,
) = auth_data
if not superuser:
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
try:
data = orjson.loads(self.request.body)
except orjson.decoder.JSONDecodeError as e:
return self.finish_json(
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
validate(data, config_json_schema)
except ValidationError as e:
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
self.controller.set_config_json(data)
self.controller.management.add_to_audit_log(
user["user_id"],
"edited config.json",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.finish_json(
200,
{"status": "ok"},
)

View File

@ -50,7 +50,6 @@
<!-- Page Title Header Ends--> <!-- Page Title Header Ends-->
<form id="config-form" class="forms-sample" method="post" action="/panel/config_json"> <form id="config-form" class="forms-sample" method="post" action="/panel/config_json">
{% raw xsrf_form_html() %}
{% for item in data['config-json'].items() %} {% for item in data['config-json'].items() %}
{% if item[0] == "reset_secrets_on_next_boot" %} {% if item[0] == "reset_secrets_on_next_boot" %}
@ -156,36 +155,65 @@
{% block js %} {% block js %}
<script> <script>
$("#config-form").submit(function (e) { function replacer(key, value) {
let uuid = uuidv4(); if (key == "disabled_language_files") {
var token = getCookie("_xsrf") if (value == 0){
return []
} else {
return value
}
}
if (typeof value == "boolean") {
return value
} else {
return (isNaN(value) ? value : +value);
}
}
$("#config-form").on("submit", async function (e) {
e.preventDefault(); e.preventDefault();
$("#submit-status").html('<i class="fa fa-spinner fa-spin"></i>'); $("#submit-status").html('<i class="fa fa-spinner fa-spin"></i>');
/* Convert multiple select to text list */ var token = getCookie("_xsrf")
let selected_Lang = $('#lang_select').val(); let configForm = document.getElementById("config-form");
$('#disabled_lang').val(selected_Lang);
let mounts = $('#mount_select').val(); let formData = new FormData(configForm);
$('#monitored_mounts').val(mounts); formData.delete("disabled_lang");
formData.delete("lang_select");
let class_list = document.getElementsByClassName("list"); //Create an object from the form data entries
let form_json = convertFormToJSON($("#config-form")); let formDataObject = Object.fromEntries(formData.entries());
for (let i = 0; i < class_list.length; i++) { //We need to make sure these are sent regardless of whether or not they're checked
let str = String($(class_list.item(i)).val()) formDataObject.disabled_language_files = $('#lang_select').val();
form_json[$(class_list.item(i)).attr("name")] = uuid + "," + str.replace(/\s/g, ''); formDataObject.monitored_mounts = $('#mount_select').val();
}; $('#config-form input[type="radio"]:checked').each(function() {
form_json['uuid'] = uuid; if ($(this).val() == 'True'){
$.ajax({ formDataObject[this.name] = true;
type: "POST", }else{
headers: { 'X-XSRFToken': token }, formDataObject[this.name] = false;
dataType: "text", }
url: '/panel/config_json',
data: form_json,
success: function (data) {
$("#submit-status").html('<i class="fa fa-check"></i>');
},
}); });
console.log(formDataObject);
// Format the plain form data as JSON
let formDataJsonString = JSON.stringify(formDataObject, replacer);
console.log(formDataJsonString);
let res = await fetch(`/api/v2/crafty/config/`, {
method: 'PATCH',
headers: {
'X-XSRFToken': token
},
body: formDataJsonString,
});
let responseData = await res.json();
if (responseData.status === "ok") {
$("#submit-status").html('<i class="fa fa-check"></i>');
} else {
bootbox.alert({
title: responseData.error,
message: responseData.error_data
});
}
}); });
function uuidv4() { function uuidv4() {