Add login photo to API v2

This commit is contained in:
amcmanu3 2023-09-04 13:30:48 -04:00
parent 61699d6a27
commit e79f33fcc4
2 changed files with 237 additions and 21 deletions

View File

@ -1,6 +1,9 @@
import os
import json
from jsonschema import ValidationError, validate
import orjson
from playhouse.shortcuts import model_to_dict
from app.classes.shared.file_helpers import FileHelpers
from app.classes.web.base_api_handler import BaseApiHandler
config_json_schema = {
@ -33,6 +36,24 @@ config_json_schema = {
"additionalProperties": False,
"minProperties": 1,
}
customize_json_schema = {
"type": "object",
"properties": {
"photo": {"type": "string"},
"opacity": {"type": "string"},
},
"additionalProperties": False,
"minProperties": 1,
}
photo_delete_schema = {
"type": "object",
"properties": {
"photo": {"type": "string"},
},
"additionalProperties": False,
"minProperties": 1,
}
class ApiCraftyConfigIndexHandler(BaseApiHandler):
@ -111,3 +132,181 @@ class ApiCraftyConfigIndexHandler(BaseApiHandler):
200,
{"status": "ok"},
)
class ApiCraftyCustomizeIndexHandler(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, customize_json_schema)
except ValidationError as e:
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
if not self.helper.validate_traversal(
os.path.join(
self.controller.project_root,
"app/frontend/static/assets/images/auth/",
),
os.path.join(
self.controller.project_root,
f"app/frontend/static/assets/images/auth/{data['photo']}",
),
):
return self.finish_json(
400,
{
"status": "error",
"error": "TRAVERSAL DETECTED",
"error_data": "TRIED TO REACH FILES THAT ARE"
" NOT SUPPOSED TO BE ACCESSIBLE",
},
)
self.controller.management.add_to_audit_log(
user["user_id"],
f"customized login photo: {data['photo']}/{data['opacity']}",
server_id=0,
source_ip=self.get_remote_ip(),
)
self.controller.management.set_login_opacity(int(data["opacity"]))
if data["photo"] == "login_1.jpg":
self.controller.management.set_login_image("login_1.jpg")
self.controller.cached_login = f"{data['photo']}"
else:
self.controller.management.set_login_image(f"custom/{data['photo']}")
self.controller.cached_login = f"custom/{data['photo']}"
self.finish_json(
200,
{
"status": "ok",
"data": {"photo": data["photo"], "opacity": data["opacity"]},
},
)
def delete(self):
auth_data = self.authenticate_user()
if not auth_data:
return
if not auth_data[4]["superuser"]:
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
try:
data = json.loads(self.request.body)
except json.decoder.JSONDecodeError as e:
return self.finish_json(
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
validate(data, photo_delete_schema)
except ValidationError as e:
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
if not self.helper.validate_traversal(
os.path.join(
self.controller.project_root,
"app",
"frontend",
"/static/assets/images/auth/",
),
os.path.join(
self.controller.project_root,
"app",
"frontend",
"/static/assets/images/auth/",
data["photo"],
),
):
return self.finish_json(
400,
{
"status": "error",
"error": "TRAVERSAL DETECTED",
"error_data": "TRIED TO REACH FILES THAT ARE"
" NOT SUPPOSED TO BE ACCESSIBLE",
},
)
if data["photo"] == "login_1.jpg":
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID FILE",
"error_data": "CANNOT DELETE DEFAULT",
},
)
FileHelpers.del_file(
os.path.join(
self.controller.project_root,
f"app/frontend/static/assets/images/auth/custom/{data['photo']}",
)
)
current = self.controller.cached_login
split = current.split("/")
if len(split) == 1:
current_photo = current
else:
current_photo = split[1]
if current_photo == data["photo"]:
self.controller.management.set_login_image("login_1.jpg")
self.controller.cached_login = "login_1.jpg"
return self.finish_json(200, {"status": "ok"})

View File

@ -297,33 +297,50 @@
});
});
$('.delete-photo').click(function () {
var token = getCookie("_xsrf")
$('.delete-photo').click(async function () {
let photo = $('#photo').find(":selected").val();
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/ajax/delete_photo?photo=' + encodeURIComponent(photo),
success: function (data) {
location.reload();
},
});
var token = getCookie("_xsrf")
let res = await fetch(`/api/v2/crafty/config/customize`, {
method: 'DELETE',
headers: {
'X-XSRFToken': token
},
body: JSON.stringify({"photo": photo}),
});
let responseData = await res.json();
if (responseData.status === "ok") {
window.location.reload();
} else {
bootbox.alert({
title: responseData.status,
message: responseData.error
});
}
})
$('.select-photo').click(function () {
var token = getCookie("_xsrf")
$('.select-photo').click(async function () {
let photo = $('#photo').find(":selected").val();
let opacity = $('#modal_opacity').val();
let enc_photo = encodeURIComponent(photo);
$.ajax({
type: "POST",
headers: { 'X-XSRFToken': token },
url: '/ajax/select_photo?photo=' + enc_photo + '&opacity=' + opacity,
success: function (data) {
console.log(JSON.stringify({"photo": photo, "opacity": opacity}))
var token = getCookie("_xsrf")
let res = await fetch(`/api/v2/crafty/config/customize`, {
method: 'PATCH',
headers: {
'X-XSRFToken': token
},
body: JSON.stringify({"photo": photo, "opacity": opacity}),
});
let responseData = await res.json();
if (responseData.status === "ok") {
window.location.reload();
},
});
} else {
bootbox.alert({
title: responseData.status,
message: responseData.error
});
}
})
$(document).ready(function () {