make /notifications/messages LIVE

master
Aevann 2023-09-26 23:05:39 +03:00
parent 22121ab051
commit e7ab0be33b
9 changed files with 183 additions and 149 deletions

View File

@ -13,43 +13,11 @@ const socket = io()
const chatline = document.getElementsByClassName('chat-line')[0]
const box = document.getElementById('chat-window')
const ta = document.getElementById('input-text')
const icon = document.querySelector("link[rel~='icon']")
const vid = document.getElementById('vid').value
const site_name = document.getElementById('site_name').value
const slurreplacer = document.getElementById('slurreplacer').value
let notifs = 0;
let focused = true;
let is_typing = false;
let alert=true;
function flash(){
let title = document.getElementsByTagName('title')[0]
if (notifs >= 1 && !focused){
title.innerHTML = `[+${notifs}] Chat`;
if (alert) {
icon.href = `/i/${site_name}/alert.ico?v=3009`
alert=false;
}
else {
icon.href = `/i/${site_name}/icon.webp?x=6`
alert=true;
}
setTimeout(flash, 500)
}
else {
icon.href = `/i/${site_name}/icon.webp?x=6`
notifs = 0
title.innerHTML = 'Chat';
}
if (is_typing) {
is_typing = false
socket.emit('typing', false);
}
}
const blocked_user_ids = document.getElementById('blocked_user_ids').value.split(', ')
@ -77,7 +45,7 @@ socket.on('speak', function(json) {
notifs = notifs + 1;
if (notifs == 1) {
setTimeout(flash, 500);
flash();
}
const users = document.getElementsByClassName('user_id');
@ -247,12 +215,6 @@ socket.on('online', function(data){
bs_trigger(document.getElementById('online3'))
})
addEventListener('blur', function(){
focused = false
})
addEventListener('focus', function(){
focused = true
})
let timer_id;
function remove_typing() {

View File

@ -0,0 +1,35 @@
const SITE_NAME = document.querySelector("[property='og:site_name']").content
const icon = document.querySelector("link[rel~='icon']")
const page_title = document.getElementsByTagName('title')[0].innerHTML
let notifs = 0
let focused = true
let alert = true;
addEventListener('blur', function(){
focused = false
})
addEventListener('focus', function(){
focused = true
})
function flash(){
let title = document.getElementsByTagName('title')[0]
if (notifs >= 1 && !focused){
title.innerHTML = `[+${notifs}] ${page_title}`
if (alert) {
icon.href = `/i/${SITE_NAME}/alert.ico?v=3009`
alert = false
}
else {
icon.href = `/i/${SITE_NAME}/icon.webp?x=6`
alert = true
}
setTimeout(flash, 500)
}
else {
icon.href = `/i/${SITE_NAME}/icon.webp?x=6`
notifs = 0
title.innerHTML = page_title
}
}

View File

@ -0,0 +1,11 @@
const socket = io()
socket.on('insert_reply', function(data) {
const replies = document.getElementById(`replies-of-c_${data[0]}`)
replies.insertAdjacentHTML('beforeend', data[1]);
notifs = notifs + 1;
if (notifs == 1) {
flash();
}
})

View File

@ -27,7 +27,10 @@ socketio = SocketIO(
muted = cache.get(f'muted') or {}
ALLOWED_REFERRERS = {f'{SITE_FULL}/chat'}
ALLOWED_REFERRERS = {
f'{SITE_FULL}/chat',
f'{SITE_FULL}/notifications/messages',
}
messages = cache.get(f'messages') or {
f'{SITE_FULL}/chat': {},
@ -192,6 +195,10 @@ def connect(v):
if request.referrer not in ALLOWED_REFERRERS:
return '', 400
if request.referrer == f'{SITE_FULL}/notifications/messages':
join_room(v.id)
return ''
join_room(request.referrer)
if [v.username, v.id, v.name_color, v.patron] not in online[request.referrer]:
@ -213,6 +220,10 @@ def disconnect(v):
if request.referrer not in ALLOWED_REFERRERS:
return '', 400
if request.referrer == f'{SITE_FULL}/notifications/messages':
leave_room(v.id)
return ''
leave_room(request.referrer)
for val in online.values():
@ -262,3 +273,115 @@ def close_running_threads():
cache.set('messages', messages)
cache.set('muted', muted)
atexit.register(close_running_threads)
@app.post("/reply")
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
@limiter.limit("6/minute;50/hour;200/day", deduct_when=lambda response: response.status_code < 400)
@limiter.limit("6/minute;50/hour;200/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def messagereply(v):
body = request.values.get("body", "")
body = body[:COMMENT_BODY_LENGTH_LIMIT].strip()
id = request.values.get("parent_id")
parent = get_comment(id, v=v)
if parent.parent_post or parent.wall_user_id:
abort(403, "You can only reply to messages!")
user_id = parent.author.id
if v.is_permabanned and parent.sentto != MODMAIL_ID:
abort(403, "You are permabanned and may not reply to messages!")
elif v.is_muted and parent.sentto == MODMAIL_ID:
abort(403, "You are forbidden from replying to modmail!")
if parent.sentto == MODMAIL_ID: user_id = None
elif v.id == user_id: user_id = parent.sentto
user = None
if user_id:
user = get_account(user_id, v=v, include_blocks=True)
if hasattr(user, 'is_blocking') and user.is_blocking:
abort(403, f"You're blocking @{user.username}")
elif (v.admin_level <= PERMS['MESSAGE_BLOCKED_USERS']
and hasattr(user, 'is_blocked') and user.is_blocked):
abort(403, f"You're blocked by @{user.username}")
if user.has_muted(v):
abort(403, f"@{user.username} is muting notifications from you, so messaging them is pointless!")
if not g.is_tor and get_setting("dm_media"):
body = process_files(request.files, v, body, is_dm=True, dm_user=user)
body = body[:COMMENT_BODY_LENGTH_LIMIT].strip() #process_files potentially adds characters to the post
if not body: abort(400, "Message is empty!")
body_html = sanitize(body)
if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT:
abort(400, "Message too long!")
if parent.sentto == MODMAIL_ID:
sentto = MODMAIL_ID
else:
sentto = user_id
c = Comment(author_id=v.id,
parent_post=None,
parent_comment_id=id,
top_comment_id=parent.top_comment_id,
level=parent.level + 1,
sentto=sentto,
body=body,
body_html=body_html,
)
g.db.add(c)
g.db.flush()
execute_blackjack(v, c, c.body_html, 'message')
execute_under_siege(v, c, c.body_html, 'message')
if user_id and user_id not in {v.id, MODMAIL_ID} | BOT_IDs:
notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=user_id).one_or_none()
if not notif:
notif = Notification(comment_id=c.id, user_id=user_id)
g.db.add(notif)
title = f'New message from @{c.author_name}'
url = f'{SITE_FULL}/notifications/messages'
push_notif({user_id}, title, body, url)
top_comment = c.top_comment
if top_comment.sentto == MODMAIL_ID:
admin_ids = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id)]
if SITE == 'watchpeopledie.tv':
if AEVANN_ID in admin_ids:
admin_ids.remove(AEVANN_ID)
if 'delete' in top_comment.body.lower() and 'account' in top_comment.body.lower():
admin_ids.remove(15447)
if parent.author.id not in admin_ids + [v.id]:
admin_ids.append(parent.author.id)
#Don't delete unread notifications, so the replies don't get collapsed and they get highlighted
ids = [top_comment.id] + [x.id for x in top_comment.replies(sort="old")]
notifications = g.db.query(Notification).filter(Notification.read == True, Notification.comment_id.in_(ids), Notification.user_id.in_(admin_ids))
for n in notifications:
g.db.delete(n)
for admin in admin_ids:
notif = Notification(comment_id=c.id, user_id=admin)
g.db.add(notif)
else:
c.unread = True
rendered = render_template("comments.html", v=get_account(top_comment.sentto), comments=[c])
emit('insert_reply', [parent.id, rendered], namespace='/', to=top_comment.sentto)
return {"comment": render_template("comments.html", v=v, comments=[c])}

View File

@ -684,113 +684,6 @@ def message2(v, username=None, id=None):
return {"message": "Message sent!"}
@app.post("/reply")
@limiter.limit('1/second', scope=rpath)
@limiter.limit('1/second', scope=rpath, key_func=get_ID)
@limiter.limit("6/minute;50/hour;200/day", deduct_when=lambda response: response.status_code < 400)
@limiter.limit("6/minute;50/hour;200/day", deduct_when=lambda response: response.status_code < 400, key_func=get_ID)
@auth_required
def messagereply(v):
body = request.values.get("body", "")
body = body[:COMMENT_BODY_LENGTH_LIMIT].strip()
id = request.values.get("parent_id")
parent = get_comment(id, v=v)
if parent.parent_post or parent.wall_user_id:
abort(403, "You can only reply to messages!")
user_id = parent.author.id
if v.is_permabanned and parent.sentto != MODMAIL_ID:
abort(403, "You are permabanned and may not reply to messages!")
elif v.is_muted and parent.sentto == MODMAIL_ID:
abort(403, "You are forbidden from replying to modmail!")
if parent.sentto == MODMAIL_ID: user_id = None
elif v.id == user_id: user_id = parent.sentto
user = None
if user_id:
user = get_account(user_id, v=v, include_blocks=True)
if hasattr(user, 'is_blocking') and user.is_blocking:
abort(403, f"You're blocking @{user.username}")
elif (v.admin_level <= PERMS['MESSAGE_BLOCKED_USERS']
and hasattr(user, 'is_blocked') and user.is_blocked):
abort(403, f"You're blocked by @{user.username}")
if user.has_muted(v):
abort(403, f"@{user.username} is muting notifications from you, so messaging them is pointless!")
if not g.is_tor and get_setting("dm_media"):
body = process_files(request.files, v, body, is_dm=True, dm_user=user)
body = body[:COMMENT_BODY_LENGTH_LIMIT].strip() #process_files potentially adds characters to the post
if not body: abort(400, "Message is empty!")
body_html = sanitize(body)
if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT:
abort(400, "Message too long!")
if parent.sentto == MODMAIL_ID:
sentto = MODMAIL_ID
else:
sentto = user_id
c = Comment(author_id=v.id,
parent_post=None,
parent_comment_id=id,
top_comment_id=parent.top_comment_id,
level=parent.level + 1,
sentto=sentto,
body=body,
body_html=body_html,
)
g.db.add(c)
g.db.flush()
execute_blackjack(v, c, c.body_html, 'message')
execute_under_siege(v, c, c.body_html, 'message')
if user_id and user_id not in {v.id, MODMAIL_ID} | BOT_IDs:
notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=user_id).one_or_none()
if not notif:
notif = Notification(comment_id=c.id, user_id=user_id)
g.db.add(notif)
title = f'New message from @{c.author_name}'
url = f'{SITE_FULL}/notifications/messages'
push_notif({user_id}, title, body, url)
top_comment = c.top_comment
if top_comment.sentto == MODMAIL_ID:
admin_ids = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id)]
if SITE == 'watchpeopledie.tv':
if AEVANN_ID in admin_ids:
admin_ids.remove(AEVANN_ID)
if 'delete' in top_comment.body.lower() and 'account' in top_comment.body.lower():
admin_ids.remove(15447)
if parent.author.id not in admin_ids + [v.id]:
admin_ids.append(parent.author.id)
#Don't delete unread notifications, so the replies don't get collapsed and they get highlighted
ids = [top_comment.id] + [x.id for x in top_comment.replies(sort="old")]
notifications = g.db.query(Notification).filter(Notification.read == True, Notification.comment_id.in_(ids), Notification.user_id.in_(admin_ids))
for n in notifications:
g.db.delete(n)
for admin in admin_ids:
notif = Notification(comment_id=c.id, user_id=admin)
g.db.add(notif)
return {"comment": render_template("comments.html", v=v, comments=[c])}
@app.get("/2faqr/<secret>")
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400)
@limiter.limit(DEFAULT_RATELIMIT, deduct_when=lambda response: response.status_code < 400, key_func=get_ID)

View File

@ -31,11 +31,11 @@
</div>
<input id="vid" hidden value="{{v.id}}">
<input id="site_name" hidden value="{{SITE_NAME}}">
<input id="slurreplacer" hidden value="{{v.slurreplacer}}">
<input id="admin_level" hidden value="{{v.admin_level}}">
<input id="blocked_user_ids" hidden value="{{(v.userblocks|string)[1:-1]}}">
<script defer src="{{'js/vendor/socketio.js' | asset}}"></script>
<script defer src="{{'js/flash.js' | asset}}"></script>
<script defer src="{{'js/vendor/lozad.js' | asset}}"></script>
<script defer src="{{'js/vendor/lite-youtube.js' | asset}}"></script>
<script defer src="{{'js/chat.js' | asset}}"></script>

View File

@ -140,6 +140,12 @@
<link rel="stylesheet" href="{{('css/notifications.css') | asset}}">
{% if request.path == '/notifications/messages' %}
<script defer src="{{'js/vendor/socketio.js' | asset}}"></script>
<script defer src="{{'js/flash.js' | asset}}"></script>
<script defer src="{{'js/messages.js' | asset}}"></script>
{% endif %}
{% endblock %}
{% block GIFpicker %}{% endblock %}

View File

@ -47,11 +47,11 @@
</div>
<input id="vid" hidden value="{{v.id}}">
<input id="site_name" hidden value="{{SITE_NAME}}">
<input id="slurreplacer" hidden value="{{v.slurreplacer}}">
<input id="admin_level" hidden value="{{v.admin_level}}">
<input id="blocked_user_ids" hidden value="{{(v.userblocks|string)[1:-1]}}">
<script defer src="{{'js/vendor/socketio.js' | asset}}"></script>
<script defer src="{{'js/flash.js' | asset}}"></script>
<script defer src="{{'js/vendor/lozad.js' | asset}}"></script>
<script defer src="{{'js/vendor/lite-youtube.js' | asset}}"></script>
<script defer src="{{'js/chat.js' | asset}}"></script>

View File

@ -30,6 +30,10 @@ server {
proxy_pass http://localhost:5001/refresh_chat;
include includes/headers;
}
location /reply {
proxy_pass http://localhost:5001/reply;
include includes/headers;
}
location =/offline.html {
alias /d/files/templates/errors/offline.html;