feat(admin): added legal pages

darta 2022-01-25 22:54:54 +01:00
parent 5e4cb0fc6c
commit fe949b9f33
6 changed files with 386 additions and 1 deletions

View File

@ -0,0 +1,82 @@
import logging as log
import os
from pprint import pprint
from minio import Minio
from minio.commonconfig import REPLACE, CopySource
from minio.deleteobjects import DeleteObject
from requests import get, post
from admin import app
class Avatars:
def __init__(self):
self.mclient = Minio(
"isard-sso-avatars:9000",
access_key="AKIAIOSFODNN7EXAMPLE",
secret_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
secure=False,
)
self.bucket = "master-avatars"
self._minio_set_realm()
# self.update_missing_avatars()
def add_user_default_avatar(self, userid, role="unknown"):
self.mclient.fput_object(
self.bucket,
userid,
os.path.join(app.root_path, "../custom/avatars/" + role + ".jpg"),
content_type="image/jpeg ",
)
log.warning(
" AVATARS: Updated avatar for user " + userid + " with role " + role
)
def delete_user_avatar(self, userid):
self.minio_delete_object(userid)
def update_missing_avatars(self, users):
sys_roles = ["admin", "manager", "teacher", "student"]
for u in self.get_users_without_image(users):
try:
img = [r + ".jpg" for r in sys_roles if r in u["roles"]][0]
except:
img = "unknown.jpg"
self.mclient.fput_object(
self.bucket,
u["id"],
os.path.join(app.root_path, "../custom/avatars/" + img),
content_type="image/jpeg ",
)
log.warning(
" AVATARS: Updated avatar for user "
+ u["username"]
+ " with role "
+ img.split(".")[0]
)
def _minio_set_realm(self):
if not self.mclient.bucket_exists(self.bucket):
self.mclient.make_bucket(self.bucket)
def minio_get_objects(self):
return [o.object_name for o in self.mclient.list_objects(self.bucket)]
def minio_delete_all_objects(self):
delete_object_list = map(
lambda x: DeleteObject(x.object_name),
self.mclient.list_objects(self.bucket),
)
errors = self.mclient.remove_objects(self.bucket, delete_object_list)
for error in errors:
log.error(" AVATARS: Error occured when deleting avatar object: " + error)
def minio_delete_object(self, oid):
errors = self.mclient.remove_objects(self.bucket, [DeleteObject(oid)])
for error in errors:
log.error(" AVATARS: Error occured when deleting avatar object: " + error)
def get_users_without_image(self, users):
return [u for u in users if u["id"] and u["id"] not in self.minio_get_objects()]

View File

@ -0,0 +1,89 @@
$(document).ready(function () {
init_wysiwyg();
var lang = getCookie('KEYCLOAK_LOCALE') ? getCookie('KEYCLOAK_LOCALE') : 'ca'
$('#legal-lang').val(lang)
getLangLegal(lang)
// $('#privacy-lang').val(lang)
// $.ajax({
// type: "GET",
// url: "/api/legal/privacy",
// data: {
// lang: lang
// },
// success: function (data) {
// $('#editor-privacy').html(data.html)
// }
// })
$("#save-legal").click(function () {
$.ajax({
type: "POST",
url: "/api/legal/legal",
data: {
'html': $('#editor-legal').cleanHtml(),
'lang': $('#legal-lang').val()
},
success: function () {
},
});
});
$('#legal-lang').on('change', function() {
getLangLegal(this.value)
});
// $("#save-privacy").click(function () {
// $.ajax({
// type: "POST",
// url: "/api/legal/privacy",
// data: {
// 'html': $('#editor-privacy').cleanHtml(),
// 'lang': $('#legal-lang').val()
// },
// success: function () {
// },
// });
// });
});
function getLangLegal(lang) {
$.ajax({
type: "GET",
url: "/api/legal/legal",
data: {
lang: lang
},
success: function (data) {
$('#editor-legal').html(data.html)
}
})
}
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
function init_wysiwyg() {
$("#editor-legal").wysiwyg({
toolbarSelector: '[data-target="#editor-legal"]'
});
// $("#editor-privacy").wysiwyg({
// toolbarSelector: '[data-target="#editor-privacy"]'
// });
window.prettyPrint;
prettyPrint();
}

View File

@ -0,0 +1,98 @@
<div class="form-group row">
<div id="alerts"></div>
<div
class="btn-toolbar editor"
data-role="editor-toolbar_{{ type }}"
data-target="#editor-{{ type }}"
>
<div class="col-md-1 col-sm-1 ">
<select id="{{type}}-lang" class="form-control">
{% for lang in [{'text': 'Español', 'code': 'es'}, {'text': 'English', 'code': 'en'}, {'text': 'Català', 'code': 'ca'}, {'text': 'Français', 'code': 'fr'}] %}
<option value="{{ lang['code'] }}">{{ lang['text'] }}</option>
{% endfor %}
</select>
</div>
<div class="btn-group">
<a class="btn dropdown-toggle" data-toggle="dropdown" title="Font Size"
><i class="fa fa-text-height"></i>&nbsp;<b class="caret"></b
></a>
<ul class="dropdown-menu">
<li>
<a data-edit="fontSize 5">
<p style="font-size: 17px">Huge</p>
</a>
</li>
<li>
<a data-edit="fontSize 3">
<p style="font-size: 14px">Normal</p>
</a>
</li>
<li>
<a data-edit="fontSize 1">
<p style="font-size: 11px">Small</p>
</a>
</li>
</ul>
</div>
<div class="btn-group">
<a class="btn" data-edit="bold" title="Bold (Ctrl/Cmd+B)"
><i class="fa fa-bold"></i
></a>
<a class="btn" data-edit="italic" title="Italic (Ctrl/Cmd+I)"
><i class="fa fa-italic"></i
></a>
<a class="btn" data-edit="strikethrough" title="Strikethrough"
><i class="fa fa-strikethrough"></i
></a>
<a class="btn" data-edit="underline" title="Underline (Ctrl/Cmd+U)"
><i class="fa fa-underline"></i
></a>
</div>
<div class="btn-group">
<a class="btn" data-edit="insertunorderedlist" title="Bullet list"
><i class="fa fa-list-ul"></i
></a>
<a class="btn" data-edit="insertorderedlist" title="Number list"
><i class="fa fa-list-ol"></i
></a>
<a class="btn" data-edit="outdent" title="Reduce indent (Shift+Tab)"
><i class="fa fa-dedent"></i
></a>
<a class="btn" data-edit="indent" title="Indent (Tab)"
><i class="fa fa-indent"></i
></a>
</div>
<div class="btn-group">
<a class="btn" data-edit="justifyleft" title="Align Left (Ctrl/Cmd+L)"
><i class="fa fa-align-left"></i
></a>
<a class="btn" data-edit="justifycenter" title="Center (Ctrl/Cmd+E)"
><i class="fa fa-align-center"></i
></a>
<a class="btn" data-edit="justifyright" title="Align Right (Ctrl/Cmd+R)"
><i class="fa fa-align-right"></i
></a>
<a class="btn" data-edit="justifyfull" title="Justify (Ctrl/Cmd+J)"
><i class="fa fa-align-justify"></i
></a>
</div>
<div class="btn-group">
<a class="btn" data-edit="undo" title="Undo (Ctrl/Cmd+Z)"
><i class="fa fa-undo"></i
></a>
<a class="btn" data-edit="redo" title="Redo (Ctrl/Cmd+Y)"
><i class="fa fa-repeat"></i
></a>
</div>
</div>
<div id="editor-{{ type }}" type="{{ type }}" class="editor-wrapper"></div>
<textarea name="descr" id="descr" style="display: none"></textarea>
</div>

View File

@ -0,0 +1,81 @@
<!-- extend base layout -->
{% extends "base.html" %} {% block css %}
<!-- Ion.RangeSlider -->
<link href="/vendors/normalize-css/normalize.css" rel="stylesheet" />
<!-- Switchery -->
<link href="/vendors/switchery/dist/switchery.min.css" rel="stylesheet" />
<!-- Bootstrap Colorpicker -->
<link
href="/vendors/mjolnic-bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css"
rel="stylesheet"
/>
{% endblock %} {% block content %}
<style>
#select_fa {
font-family: "FontAwesome", "Liberation Sans";
font-size: 14px;
}
#select_fa::before {
vertical-align: middle;
}
</style>
<div class="row">
<!-- form color picker -->
<div class="col-md-12 col-sm-12">
<div class="x_panel">
<div class="x_title">
<h2>Legal<small>Company/School</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
{% with type = 'legal' %}
{% include 'aux/text-editor.html' %}
{% endwith %}
<div class="form-group row docs-buttons">
<ul class="nav navbar-right panel_toolbox">
<li>
<button id="save-legal" type="button" class="btn btn-primary">
Save changes
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- <div class="row">
<div class="col-md-12 col-sm-12">
<div class="x_panel">
<div class="x_title">
<h2>Privacy policy<small></small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
{% with type = 'privacy' %}
{% include 'aux/text-editor.html' %}
{% endwith %}
<div class="form-group row docs-buttons">
<ul class="nav navbar-right panel_toolbox">
<li>
<button id="save-privacy" type="button" class="btn btn-primary">
Save changes
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</div> -->
{% endblock %} {% block pagescript %}
<script src="/static/js/legal.js"></script>
<!-- bootstrap-wysiwyg -->
<script src="/vendors/bootstrap-wysiwyg/js/bootstrap-wysiwyg.min.js"></script>
<script src="/vendors/jquery.hotkeys/jquery.hotkeys.js"></script>
<script src="/vendors/google-code-prettify/src/prettify.js"></script>
{% endblock %}
</div>

View File

@ -509,3 +509,32 @@ def dashboard_put(item):
500,
{"Content-Type": "application/json"},
)
@app.route("/api/legal/<item>", methods=["GET", "POST"])
# @login_required
def legal_put(item):
if request.method == "GET":
if item == "legal":
lang = request.args.get("lang")
return json.dumps({ "html": "<b>Legal</b><br>This works! in lang: "+lang}), 200, {'Content-Type': 'application/json'}
# if item == "privacy":
# return json.dumps({ "html": "<b>Privacy policy</b><br>This works!"}), 200, {'Content-Type': 'application/json'}
if request.method == "POST":
if item == "legal":
data = None
try:
data = request.json
html = data["html"]
lang = data["lang"]
except:
log.error(traceback.format_exc())
return json.dumps(data), 200, {'Content-Type': 'application/json'}
# if item == "privacy":
# data = None
# try:
# data = request.json
# html = data["html"]
# lang = data["lang"]
# except:
# log.error(traceback.format_exc())
# return json.dumps(data), 200, {'Content-Type': 'application/json'}

View File

@ -86,13 +86,19 @@ def avatar(userid):
@app.route("/dashboard")
# @login_required
@login_required
def dashboard(provider=False):
data = json.loads(requests.get("http://isard-sso-api/json").text)
return render_template(
"pages/dashboard.html", title="Customization", nav="Customization", data=data
)
@app.route("/legal")
@login_required
def legal():
# data = json.loads(requests.get("http://isard-sso-api/json").text)
return render_template("pages/legal.html", title="Legal", nav="Legal", data={})
### SYS ADMIN