feat(admin): added legal pages
parent
5e4cb0fc6c
commit
fe949b9f33
|
@ -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()]
|
|
@ -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();
|
||||||
|
}
|
|
@ -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> <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>
|
|
@ -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>
|
|
@ -509,3 +509,32 @@ def dashboard_put(item):
|
||||||
500,
|
500,
|
||||||
{"Content-Type": "application/json"},
|
{"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'}
|
||||||
|
|
|
@ -86,13 +86,19 @@ def avatar(userid):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/dashboard")
|
@app.route("/dashboard")
|
||||||
# @login_required
|
@login_required
|
||||||
def dashboard(provider=False):
|
def dashboard(provider=False):
|
||||||
data = json.loads(requests.get("http://isard-sso-api/json").text)
|
data = json.loads(requests.get("http://isard-sso-api/json").text)
|
||||||
return render_template(
|
return render_template(
|
||||||
"pages/dashboard.html", title="Customization", nav="Customization", data=data
|
"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
|
### SYS ADMIN
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue