mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Add Arcadia Notifications to Front end
This commit is contained in:
parent
834f6f3c3b
commit
6c1e1b4737
@ -45,6 +45,7 @@ class Users(BaseModel):
|
||||
manager = IntegerField(default=None, null=True)
|
||||
pfp = CharField(default="/static/assets/images/faces-clipart/pic-3.png")
|
||||
theme = CharField(default="default")
|
||||
cleared_notifs = CharField(default="default")
|
||||
|
||||
class Meta:
|
||||
table_name = "users"
|
||||
@ -171,6 +172,7 @@ class HelperUsers:
|
||||
"roles": [],
|
||||
"servers": [],
|
||||
"support_logs": "",
|
||||
"cleared_notifs": "",
|
||||
}
|
||||
user = model_to_dict(Users.get(Users.user_id == user_id))
|
||||
|
||||
|
@ -581,12 +581,16 @@ class Helpers:
|
||||
|
||||
@staticmethod
|
||||
def get_announcements():
|
||||
data = (
|
||||
'[{"id":"1","date":"Unknown",'
|
||||
'"title":"Error getting Announcements",'
|
||||
'"desc":"Error getting Announcements","link":""}]'
|
||||
)
|
||||
|
||||
data = []
|
||||
data = [
|
||||
{
|
||||
"id": "4db1a43b-d451-4abc-bb10-5a45676d95f7",
|
||||
"date": "Unknown",
|
||||
"title": "Error getting Announcements",
|
||||
"desc": "Error getting Announcements",
|
||||
"link": "",
|
||||
}
|
||||
]
|
||||
try:
|
||||
response = requests.get("https://craftycontrol.com/notify.json", timeout=2)
|
||||
data = json.loads(response.content)
|
||||
|
@ -40,6 +40,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.public import ApiUsersUserPublicHandler
|
||||
from app.classes.web.routes.api.crafty.announcements.index import ApiAnnounceIndexHandler
|
||||
|
||||
|
||||
def api_handlers(handler_args):
|
||||
@ -55,6 +56,11 @@ def api_handlers(handler_args):
|
||||
ApiAuthInvalidateTokensHandler,
|
||||
handler_args,
|
||||
),
|
||||
(
|
||||
r"/api/v2/crafty/announcements/?",
|
||||
ApiAnnounceIndexHandler,
|
||||
handler_args,
|
||||
),
|
||||
# User routes
|
||||
(
|
||||
r"/api/v2/users/?",
|
||||
|
106
app/classes/web/routes/api/crafty/announcements/index.py
Normal file
106
app/classes/web/routes/api/crafty/announcements/index.py
Normal file
@ -0,0 +1,106 @@
|
||||
import logging
|
||||
import json
|
||||
from jsonschema import ValidationError, validate
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
notif_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {"type": "string"},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
}
|
||||
|
||||
|
||||
class ApiAnnounceIndexHandler(BaseApiHandler):
|
||||
def get(self):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
(
|
||||
_,
|
||||
_exec_user_crafty_permissions,
|
||||
_,
|
||||
_,
|
||||
_user,
|
||||
) = auth_data
|
||||
|
||||
data = self.helper.get_announcements()
|
||||
cleared = str(
|
||||
self.controller.users.get_user_by_id(auth_data[4]["user_id"])[
|
||||
"cleared_notifs"
|
||||
]
|
||||
).split(",")
|
||||
res = [d.get("id", None) for d in data]
|
||||
# remove notifs that are no longer in Crafty.
|
||||
for item in cleared[:]:
|
||||
if item not in res:
|
||||
cleared.remove(item)
|
||||
if len(cleared) > 0:
|
||||
for item in data[:]:
|
||||
if item["id"] in cleared:
|
||||
data.remove(item)
|
||||
|
||||
self.finish_json(
|
||||
200,
|
||||
{
|
||||
"status": "ok",
|
||||
"data": data,
|
||||
},
|
||||
)
|
||||
|
||||
def post(self):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
(
|
||||
_,
|
||||
_exec_user_crafty_permissions,
|
||||
_,
|
||||
_,
|
||||
_user,
|
||||
) = auth_data
|
||||
print(self.request)
|
||||
try:
|
||||
data = json.loads(self.request.body)
|
||||
print(data)
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
|
||||
)
|
||||
|
||||
try:
|
||||
validate(data, notif_schema)
|
||||
except ValidationError as e:
|
||||
return self.finish_json(
|
||||
400,
|
||||
{
|
||||
"status": "error",
|
||||
"error": "INVALID_JSON_SCHEMA",
|
||||
"error_data": str(e),
|
||||
},
|
||||
)
|
||||
announcements = self.helper.get_announcements()
|
||||
res = [d.get("id", None) for d in announcements]
|
||||
cleared_notifs = str(
|
||||
self.controller.users.get_user_by_id(auth_data[4]["user_id"])[
|
||||
"cleared_notifs"
|
||||
]
|
||||
).split(",")
|
||||
# remove notifs that are no longer in Crafty.
|
||||
for item in cleared_notifs[:]:
|
||||
if item not in res:
|
||||
cleared_notifs.remove(item)
|
||||
cleared_notifs.append(data["id"])
|
||||
updata = {"cleared_notifs": ",".join(cleared_notifs)}
|
||||
self.controller.users.update_user(auth_data[4]["user_id"], updata)
|
||||
self.finish_json(
|
||||
200,
|
||||
{
|
||||
"status": "ok",
|
||||
"data": {},
|
||||
},
|
||||
)
|
@ -1,27 +1,32 @@
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link count-indicator">
|
||||
<a class="nav-link count-indicator dropdown-toggle" id="notifDropdown" href="#" data-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<i class="fas fa-broadcast-tower
|
||||
{% if data.get('update_available') %}
|
||||
text-danger
|
||||
{% end %}
|
||||
"></i>
|
||||
<!-- <span class="count bg-success">3</span>-->
|
||||
</a>
|
||||
"></i><span id="notif-count" class="badge badge-notify"></span> </a>
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown" style="width: 40vw;" aria-labelledby="notifDropdown">
|
||||
<ul id="announcements">
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link count-indicator" href="/panel/panel_config">
|
||||
<a class="nav-link" href="/panel/panel_config">
|
||||
<i class="fas fa-cogs"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown user-dropdown">
|
||||
<a class="nav-link dropdown-toggle" id="UserDropdown" href="#" data-toggle="dropdown" aria-expanded="false">
|
||||
<img class="img-xs rounded-circle profile-picture" onerror="pfpError(this)" src="{{ data['user_data']['pfp'] }}" alt="Profile image"> </a>
|
||||
<img class="img-xs rounded-circle profile-picture" onerror="pfpError(this)" src="{{ data['user_data']['pfp'] }}"
|
||||
alt="Profile image"> </a>
|
||||
<div class="dropdown-menu dropdown-menu-right navbar-dropdown" aria-labelledby="UserDropdown">
|
||||
<div class="dropdown-header text-center">
|
||||
<img class="img-md rounded-circle profile-picture" onerror="pfpError(this)" src="{{ data['user_data']['pfp'] }}" alt="Profile image">
|
||||
<img class="img-md rounded-circle profile-picture" onerror="pfpError(this)" src="{{ data['user_data']['pfp'] }}"
|
||||
alt="Profile image">
|
||||
<p class="mb-1 mt-3 font-weight-semibold">{{ data['user_data']['username'] }}</p>
|
||||
<p class="font-weight-light text-muted mb-0">Roles: </p>
|
||||
{% for r in data['user_role'] %}
|
||||
@ -33,27 +38,118 @@
|
||||
<p class="font-weight-light text-muted mb-0">Email: {{ data['user_data']['email'] }}</p>
|
||||
</div>
|
||||
{% if data['user_data']['preparing'] %}
|
||||
<span class="dropdown-item" id="support_progress"><i class="dropdown-item-icon mdi mdi-download-outline text-primary"></i>{{ translate('notify', 'supportLogs', data['lang']) }}<br><br></span>
|
||||
<span class="dropdown-item" id="support_progress"><i
|
||||
class="dropdown-item-icon mdi mdi-download-outline text-primary"></i>{{ translate('notify', 'supportLogs',
|
||||
data['lang']) }}<br><br></span>
|
||||
<span class="dropdown-item" id="support_progress">
|
||||
<div class="support_progress" style="height: 15px; width: 100%;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" id="logs_progress_bar" role="progressbar" style="width:0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" id="logs_progress_bar" role="progressbar"
|
||||
style="width:0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>
|
||||
</div>
|
||||
</span>
|
||||
{% else %}
|
||||
<a class="dropdown-item" id="support_logs"><i class="dropdown-item-icon mdi mdi-download-outline text-primary"></i>{{ translate('notify', 'supportLogs', data['lang']) }}</i></a>
|
||||
<a class="dropdown-item" id="support_logs"><i
|
||||
class="dropdown-item-icon mdi mdi-download-outline text-primary"></i>{{ translate('notify', 'supportLogs',
|
||||
data['lang']) }}</i></a>
|
||||
{% end %}
|
||||
{% if data['superuser'] %}
|
||||
<a class="dropdown-item" href="/panel/activity_logs"><i class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i>{{ translate('notify', 'activityLog', data['lang']) }}</a>
|
||||
<a class="dropdown-item" href="/panel/activity_logs"><i
|
||||
class="dropdown-item-icon mdi mdi-calendar-check-outline text-primary"></i>{{ translate('notify',
|
||||
'activityLog', data['lang']) }}</a>
|
||||
{% end %}
|
||||
<a class="dropdown-item" href="/logout"><i class="dropdown-item-icon mdi mdi-power text-primary"></i>{{ translate('notify', 'logout', data['lang']) }}</a>
|
||||
<a class="dropdown-item" href="/logout"><i class="dropdown-item-icon mdi mdi-power text-primary"></i>{{
|
||||
translate('notify', 'logout', data['lang']) }}</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<style>
|
||||
.badge-notify {
|
||||
background: var(--purple);
|
||||
position: absolute;
|
||||
-moz-transform: translate(-70%, -70%);
|
||||
/* For Firefox */
|
||||
-ms-transform: translate(-70%, -70%);
|
||||
/* for IE */
|
||||
-webkit-transform: translate(-70%, -70%);
|
||||
/* For Safari, Chrome, iOS */
|
||||
-o-transform: translate(-70%, -70%);
|
||||
}
|
||||
|
||||
.clear-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function pfpError(image) {
|
||||
image.onerror = "";
|
||||
image.src = "/static/assets/images/faces-clipart/pic-3.png";
|
||||
return true;
|
||||
}
|
||||
function updateAnnouncements(data) {
|
||||
console.log(data)
|
||||
let text = "";
|
||||
for (i = 0; i < data.length; i++) {
|
||||
text += `<li id="${data[i].id}"><p style="float: right;"><i data-id="${data[i].id}"class="clear-button fa-regular fa-x"></i></p><a style="color: var(--purple);" href=${data[i].link} target="_blank"><h6>${data[i].title}</h6><small><p>${data[i].date}</p></small><p>${data[i].desc}</p></li></a>`
|
||||
}
|
||||
if (data.length > 0) {
|
||||
localStorage.setItem("notif-count", data.length);
|
||||
$("#notif-count").html(data.length);
|
||||
$("#announcements").html(text);
|
||||
} else {
|
||||
$("#announcements").html("<p style='margin-top: 15px;' class='text-center'>No notifications</p>");
|
||||
}
|
||||
$(".clear-button").on("click", function (event) {
|
||||
console.log("CLEAR BUTTON")
|
||||
let uuid = event.target.getAttribute("data-id");
|
||||
$(`#${uuid}`).remove();
|
||||
send_clear(uuid);
|
||||
notif_count = localStorage.getItem("notif-count") - 1;
|
||||
if (notif_count > 0) {
|
||||
localStorage.setItem("notif-count", notif_count);
|
||||
$("#notif-count").html(notif_count);
|
||||
} else {
|
||||
$("#announcements").html("<p style='margin-top: 15px;' class='text-center'>No notifications</p>")
|
||||
$("#notif-count").html("");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
async function getAnnouncements() {
|
||||
var token = getCookie("_xsrf");
|
||||
let res = await fetch(`/api/v2/crafty/announcements/`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
});
|
||||
let responseData = await res.json();
|
||||
console.log(responseData);
|
||||
if (responseData.status === "ok") {
|
||||
updateAnnouncements(responseData.data)
|
||||
} else {
|
||||
updateAnnouncements("<li><p>Trouble Getting Annoucements</p></li>")
|
||||
}
|
||||
}
|
||||
async function send_clear(uuid) {
|
||||
var token = getCookie("_xsrf");
|
||||
let body = JSON.stringify({ "id": uuid });
|
||||
console.log(body)
|
||||
let res = await fetch(`/api/v2/crafty/announcements/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-XSRFToken': token,
|
||||
},
|
||||
body: body,
|
||||
});
|
||||
let responseData = await res.json();
|
||||
console.log(responseData);
|
||||
if (responseData.status === "ok") {
|
||||
return
|
||||
} else {
|
||||
bootbox.alert(responseData.error)
|
||||
}
|
||||
}
|
||||
$(document).ready(function () {
|
||||
getAnnouncements();
|
||||
})
|
||||
</script>
|
16
app/migrations/20230901_user_notif.py
Normal file
16
app/migrations/20230901_user_notif.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns("users", cleared_notifs=peewee.CharField(default=""))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns("users", ["cleared_notifs"])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
Loading…
Reference in New Issue
Block a user