2022-03-24 19:44:12 +00:00
|
|
|
import time
|
2022-09-24 22:05:50 +00:00
|
|
|
import uuid
|
2023-10-02 06:12:31 +00:00
|
|
|
from hashlib import md5
|
2022-11-15 09:19:08 +00:00
|
|
|
|
2024-04-08 05:37:42 +00:00
|
|
|
from sqlalchemy.orm import load_only
|
2023-09-05 15:32:57 +00:00
|
|
|
from flask_socketio import SocketIO, emit, join_room, leave_room
|
2023-02-16 13:41:58 +00:00
|
|
|
from flask import request
|
2022-11-15 09:19:08 +00:00
|
|
|
|
|
|
|
from files.helpers.actions import *
|
2022-07-11 09:52:59 +00:00
|
|
|
from files.helpers.alerts import *
|
2022-12-11 23:44:34 +00:00
|
|
|
from files.helpers.config.const import *
|
2023-09-22 17:01:30 +00:00
|
|
|
from files.helpers.slurs_and_profanities import censor_slurs_profanities
|
2022-06-24 14:30:59 +00:00
|
|
|
from files.helpers.regex import *
|
2023-03-06 19:52:31 +00:00
|
|
|
from files.helpers.media import *
|
2023-02-07 03:31:49 +00:00
|
|
|
from files.helpers.sanitize import *
|
2022-12-26 03:14:02 +00:00
|
|
|
from files.helpers.alerts import push_notif
|
2023-10-05 10:09:58 +00:00
|
|
|
from files.helpers.can_see import *
|
2022-11-15 09:19:08 +00:00
|
|
|
from files.routes.wrappers import *
|
Bring back orgies (watchparties), now controllable by admins, and generally better in all ways (#165)
This PR adds orgies back into rdrama. Long ago, snakes made the original orgy code, and it was super fun. But he had to rush it out, and ended up making it a bit unsustainable, and had a couple questionable coding decisions, which meant that it had to be removed. Hey, the man literally did it in a few hours before the DB trial continued, lmao.
Anyways, I took my own approach to it. I do not use iframes, i just just repurpose code from /chat window. Because I had that freedom, I also moved things around to make the user experience a bit better. I also added a title to give users some context about what's happening. Check it out
![image](/attachments/6719146c-4922-4d75-967d-8d424a09b198)
Most importantly, this is all configurable from the site. Admins with the permission "ORGIES" will see this in their control panel
![image](/attachments/423d6046-a11d-4e84-bd2c-a2a641afd552)
Nigga, idk where to put it, so I made my own category.
If there is no orgy in progress, admins will see this:
![image](/attachments/7c64b9fa-cdf4-4986-a0c4-f2324878062e)
Click the button, and, viola, the orgy begins.
If there is an orgy in progress, the page will look like this:
![image](/attachments/b65be4b3-5db1-43cb-8857-7d3a8ea24ca7)
Click the button, and the orgy stops.
If an orgy is in progress, navigating to /chat will take the user to the orgy seemlessly. But what if they don't want to participate, liek some kind of spoilsport? Just navigate to /old_chat.
That's just about it, it's really that simple. I have lots of ideas for the future, but I'll let that wait til later :).
A few notes about implementation:
- I moved some functionality out of /templates/chat.html and into /templates/util/macros.html. This is just so I could reference the code directly from my new template, /templates/orgy.html.
- The orgy is stored as a single row in the new table "orgies". Okay, I know this is a little silly, but you know what they say: "if it's stupid and it works, it's not stupid". (tbf the oceangate ceo also said that)
Co-authored-by: Chuck Sneed <sneed@formerlychucks.net>
Reviewed-on: https://fsdfsd.net/rDrama/rDrama/pulls/165
Co-authored-by: HeyMoon <heymoon@noreply.fsdfsd.net>
Co-committed-by: HeyMoon <heymoon@noreply.fsdfsd.net>
2023-07-02 23:55:37 +00:00
|
|
|
from files.classes.orgy import *
|
2024-04-06 06:27:43 +00:00
|
|
|
from files.classes.chats import *
|
2022-11-15 09:19:08 +00:00
|
|
|
|
2024-04-19 21:11:48 +00:00
|
|
|
from files.__main__ import app, cache, limiter, db_session
|
2022-03-20 20:41:54 +00:00
|
|
|
|
2023-10-26 16:20:05 +00:00
|
|
|
from engineio.payload import Payload
|
|
|
|
Payload.max_decode_packets = 50
|
|
|
|
|
2023-01-21 10:36:21 +00:00
|
|
|
socketio = SocketIO(
|
|
|
|
app,
|
|
|
|
async_mode='gevent',
|
2023-10-26 16:17:50 +00:00
|
|
|
max_http_buffer_size=8388608, #for images
|
2023-01-21 10:36:21 +00:00
|
|
|
)
|
2022-03-24 19:44:12 +00:00
|
|
|
|
2023-01-23 06:04:02 +00:00
|
|
|
muted = cache.get(f'muted') or {}
|
2024-04-06 04:31:51 +00:00
|
|
|
online = {"messages": set()}
|
|
|
|
typing = {}
|
2023-09-05 15:32:57 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
cache.set('loggedin_chat', 0, timeout=86400)
|
2023-10-07 18:25:22 +00:00
|
|
|
|
2023-09-14 17:20:44 +00:00
|
|
|
def auth_required_socketio(f):
|
2023-07-24 10:33:04 +00:00
|
|
|
def wrapper(*args, **kwargs):
|
2024-04-19 21:11:48 +00:00
|
|
|
if not hasattr(g, 'db'): g.db = db_session()
|
2023-07-24 10:33:04 +00:00
|
|
|
v = get_logged_in_user()
|
2024-03-10 14:27:21 +00:00
|
|
|
if not v or v.is_permabanned: return ''
|
2024-04-19 21:11:48 +00:00
|
|
|
x = make_response(f(*args, v=v, **kwargs))
|
|
|
|
try: g.db.commit()
|
|
|
|
except: g.db.rollback()
|
|
|
|
g.db.close()
|
|
|
|
stdout.flush()
|
|
|
|
return x
|
2023-07-24 10:33:04 +00:00
|
|
|
wrapper.__name__ = f.__name__
|
|
|
|
return wrapper
|
|
|
|
|
2024-04-08 06:33:47 +00:00
|
|
|
@app.post('/chat/<int:chat_id>/refresh_chat')
|
|
|
|
def refresh_chat(chat_id):
|
|
|
|
emit('refresh_chat', namespace='/', to=f'{SITE_FULL}/chat/{chat_id}')
|
2023-09-26 12:29:36 +00:00
|
|
|
return ''
|
|
|
|
|
2022-03-24 19:44:12 +00:00
|
|
|
@socketio.on('speak')
|
2024-04-19 21:11:48 +00:00
|
|
|
@auth_required_socketio
|
2022-03-24 19:44:12 +00:00
|
|
|
def speak(data, v):
|
2024-05-31 08:26:29 +00:00
|
|
|
if SITE_NAME == 'WPD' and v.is_suspended:
|
|
|
|
return ''
|
2024-04-19 21:11:48 +00:00
|
|
|
|
2024-04-20 14:55:22 +00:00
|
|
|
try: chat_id = int(data['chat_id'])
|
|
|
|
except: return ''
|
2024-03-10 14:27:21 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
chat = g.db.get(Chat, chat_id)
|
2024-04-09 15:09:37 +00:00
|
|
|
if not chat: return ''
|
2024-03-10 14:27:21 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
if chat.id == 1:
|
|
|
|
if not v.allowed_in_chat: return ''
|
|
|
|
else:
|
2024-03-10 14:27:21 +00:00
|
|
|
is_member = g.db.query(ChatMembership.user_id).filter_by(user_id=v.id, chat_id=chat_id).one_or_none()
|
|
|
|
if not is_member: return ''
|
|
|
|
|
2023-01-21 10:36:21 +00:00
|
|
|
image = None
|
|
|
|
if data['file']:
|
|
|
|
name = f'/chat_images/{time.time()}'.replace('.','') + '.webp'
|
|
|
|
with open(name, 'wb') as f:
|
|
|
|
f.write(data['file'])
|
|
|
|
image = process_image(name, v)
|
|
|
|
|
2024-04-19 17:47:42 +00:00
|
|
|
text = data['message'].strip()[:1000]
|
2023-03-12 13:02:31 +00:00
|
|
|
if image: text += f'\n\n{image}'
|
2024-03-10 14:27:21 +00:00
|
|
|
if not text: return ''
|
2022-08-14 02:38:07 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
if chat.id == 1:
|
|
|
|
vname = v.username.lower()
|
|
|
|
if vname in muted:
|
|
|
|
if time.time() < muted[vname]:
|
|
|
|
return ''
|
|
|
|
else:
|
|
|
|
del muted[vname]
|
|
|
|
refresh_online(f'{SITE_FULL}/chat/1')
|
|
|
|
if v.admin_level >= PERMS['USER_BAN']:
|
2024-04-06 05:20:06 +00:00
|
|
|
for i in mute_regex.finditer(text.lower()):
|
2024-04-06 04:31:51 +00:00
|
|
|
username = i.group(1).lower()
|
|
|
|
muted_until = int(int(i.group(2)) * 60 + time.time())
|
|
|
|
muted[username] = muted_until
|
|
|
|
refresh_online(f'{SITE_FULL}/chat/1')
|
2024-04-06 05:20:06 +00:00
|
|
|
for i in unmute_regex.finditer(text.lower()):
|
2024-04-06 04:31:51 +00:00
|
|
|
username = i.group(1).lower()
|
|
|
|
muted.pop(username, None)
|
|
|
|
refresh_online(f'{SITE_FULL}/chat/1')
|
|
|
|
|
2023-03-19 12:01:54 +00:00
|
|
|
text_html = sanitize(text, count_emojis=True, chat=True)
|
2024-03-10 14:27:21 +00:00
|
|
|
if isinstance(text_html , tuple): return ''
|
2024-04-09 15:17:34 +00:00
|
|
|
if len(text_html) > 5000: return ''
|
2023-01-27 07:07:58 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
quotes = data['quotes']
|
|
|
|
if quotes: quotes = int(quotes)
|
|
|
|
else: quotes = None
|
|
|
|
|
|
|
|
chat_message = ChatMessage(
|
|
|
|
user_id=v.id,
|
|
|
|
chat_id=chat_id,
|
|
|
|
quotes=quotes,
|
|
|
|
text=text,
|
|
|
|
text_censored=censor_slurs_profanities(text, 'chat', True),
|
|
|
|
text_html=text_html,
|
|
|
|
text_html_censored=censor_slurs_profanities(text_html, 'chat'),
|
|
|
|
)
|
|
|
|
g.db.add(chat_message)
|
|
|
|
g.db.flush()
|
|
|
|
|
2024-05-17 14:30:01 +00:00
|
|
|
execute_blackjack(v, chat_message, text, "chat")
|
|
|
|
execute_under_siege(v, chat_message, text, "chat")
|
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
if v.id == chat.owner_id:
|
|
|
|
for i in chat_adding_regex.finditer(text):
|
|
|
|
user = get_user(i.group(1), graceful=True, attributes=[User.id])
|
|
|
|
if user and not user.has_muted(v) and not user.has_blocked(v):
|
|
|
|
existing = g.db.query(ChatMembership.user_id).filter_by(user_id=user.id, chat_id=chat_id).one_or_none()
|
2024-05-02 02:58:54 +00:00
|
|
|
if not existing:
|
2024-04-06 04:31:51 +00:00
|
|
|
chat_membership = ChatMembership(
|
|
|
|
user_id=user.id,
|
|
|
|
chat_id=chat_id,
|
|
|
|
)
|
|
|
|
g.db.add(chat_membership)
|
|
|
|
g.db.flush()
|
|
|
|
|
|
|
|
for i in chat_kicking_regex.finditer(text):
|
|
|
|
user = get_user(i.group(1), graceful=True, attributes=[User.id])
|
|
|
|
if user:
|
|
|
|
existing = g.db.query(ChatMembership).filter_by(user_id=user.id, chat_id=chat_id).one_or_none()
|
|
|
|
if existing:
|
|
|
|
g.db.delete(existing)
|
|
|
|
g.db.flush()
|
|
|
|
|
2024-06-04 17:35:49 +00:00
|
|
|
if chat.id != 1: #disabled on wpd for now cuz it takes too long, need to put it in gevent
|
2024-05-26 01:27:12 +00:00
|
|
|
alrdy_here = set(online[request.referrer].keys())
|
|
|
|
memberships = g.db.query(ChatMembership).options(load_only(ChatMembership.user_id)).filter(
|
|
|
|
ChatMembership.chat_id == chat_id,
|
|
|
|
ChatMembership.user_id.notin_(alrdy_here),
|
|
|
|
ChatMembership.notification == False,
|
|
|
|
)
|
|
|
|
for membership in memberships:
|
|
|
|
membership.notification = True
|
|
|
|
g.db.add(membership)
|
|
|
|
|
|
|
|
uids = set(x.user_id for x in memberships)
|
|
|
|
title = f'New messages in "{chat.name}"'
|
|
|
|
body = ''
|
|
|
|
url = f'{SITE_FULL}/chat/{chat.id}'
|
2024-06-03 12:13:01 +00:00
|
|
|
push_notif(uids, title, body, url, chat_id=chat.id)
|
2024-05-23 23:47:40 +00:00
|
|
|
|
2024-06-04 17:35:49 +00:00
|
|
|
if SITE_NAME == 'rDrama':
|
|
|
|
notify_users = NOTIFY_USERS(chat_message.text, v)
|
|
|
|
if chat_message.quotes:
|
|
|
|
notify_users.add(chat_message.quoted_message.user_id)
|
|
|
|
notify_users -= alrdy_here
|
|
|
|
|
|
|
|
if notify_users:
|
|
|
|
memberships = g.db.query(ChatMembership).options(load_only(ChatMembership.user_id)).filter(
|
|
|
|
ChatMembership.chat_id == chat_id,
|
|
|
|
ChatMembership.user_id.in_(notify_users),
|
|
|
|
)
|
|
|
|
for membership in memberships:
|
|
|
|
membership.mentions += 1
|
|
|
|
g.db.add(membership)
|
|
|
|
|
|
|
|
uids = set(x.user_id for x in memberships)
|
|
|
|
title = f'New mention of you in "{chat.name}"'
|
|
|
|
body = chat_message.text
|
|
|
|
url = f'{SITE_FULL}/chat/{chat.id}#{chat_message.id}'
|
|
|
|
push_notif(uids, title, body, url, chat_id=chat.id)
|
2024-05-24 02:16:13 +00:00
|
|
|
|
2024-05-23 23:47:40 +00:00
|
|
|
|
2022-11-16 14:00:04 +00:00
|
|
|
data = {
|
2024-04-06 04:31:51 +00:00
|
|
|
"id": chat_message.id,
|
|
|
|
"quotes": chat_message.quotes,
|
|
|
|
"hat": chat_message.hat,
|
|
|
|
"user_id": chat_message.user_id,
|
|
|
|
"username": chat_message.username,
|
|
|
|
"namecolor": chat_message.namecolor,
|
|
|
|
"patron": chat_message.patron,
|
|
|
|
"pride_username": chat_message.pride_username,
|
|
|
|
"text": chat_message.text,
|
|
|
|
"text_censored": chat_message.text_censored,
|
|
|
|
"text_html": chat_message.text_html,
|
|
|
|
"text_html_censored": chat_message.text_html_censored,
|
|
|
|
"created_utc": chat_message.created_utc,
|
2022-03-24 19:44:12 +00:00
|
|
|
}
|
2023-01-01 11:36:20 +00:00
|
|
|
|
2024-04-08 05:12:08 +00:00
|
|
|
if v.shadowbanned:
|
|
|
|
emit('speak', data)
|
|
|
|
else:
|
|
|
|
emit('speak', data, room=request.referrer)
|
2022-03-24 21:01:04 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
typing[request.referrer] = []
|
2023-01-23 06:04:02 +00:00
|
|
|
|
2023-10-10 19:30:52 +00:00
|
|
|
return ''
|
2022-03-24 19:44:12 +00:00
|
|
|
|
2024-03-10 14:27:21 +00:00
|
|
|
def refresh_online(room):
|
|
|
|
for k, val in list(online[room].items()):
|
2023-10-10 19:30:52 +00:00
|
|
|
if time.time() > val[0]:
|
2024-03-10 14:27:21 +00:00
|
|
|
del online[room][k]
|
|
|
|
if val[1] in typing[room]:
|
|
|
|
typing[room].remove(val[1])
|
2023-10-07 10:54:21 +00:00
|
|
|
|
2024-03-10 14:27:21 +00:00
|
|
|
data = [list(online[room].values()), muted]
|
2024-04-08 04:51:00 +00:00
|
|
|
emit("online", data, room=room)
|
2024-04-06 04:31:51 +00:00
|
|
|
if room == f'{SITE_FULL}/chat/1':
|
2024-04-04 02:15:02 +00:00
|
|
|
cache.set('loggedin_chat', len(online[room]), timeout=86400)
|
2023-01-20 04:25:35 +00:00
|
|
|
|
2022-03-24 19:44:12 +00:00
|
|
|
@socketio.on('connect')
|
2023-09-14 16:49:46 +00:00
|
|
|
@auth_required_socketio
|
2022-03-24 19:44:12 +00:00
|
|
|
def connect(v):
|
2024-04-07 08:50:58 +00:00
|
|
|
if not request.referrer: return ''
|
2024-04-06 04:31:51 +00:00
|
|
|
room = request.referrer
|
|
|
|
|
2024-04-10 03:01:51 +00:00
|
|
|
if room.startswith(f'{SITE_FULL}/notifications/messages'):
|
2023-09-26 20:05:39 +00:00
|
|
|
join_room(v.id)
|
2024-03-10 14:27:21 +00:00
|
|
|
online["messages"].add(v.id)
|
2024-03-09 17:07:10 +00:00
|
|
|
return ''
|
2023-09-26 20:05:39 +00:00
|
|
|
|
2024-03-10 14:27:21 +00:00
|
|
|
join_room(room)
|
2023-10-04 19:53:54 +00:00
|
|
|
|
2024-04-10 12:23:31 +00:00
|
|
|
if not online.get(room):
|
|
|
|
online[room] = {}
|
|
|
|
|
2024-03-10 14:27:21 +00:00
|
|
|
if not typing.get(room):
|
|
|
|
typing[room] = []
|
|
|
|
|
|
|
|
if v.username in typing.get(room):
|
|
|
|
typing[room].remove(v.username)
|
|
|
|
|
|
|
|
emit('typing', typing[room], room=room)
|
2024-04-06 04:31:51 +00:00
|
|
|
|
2023-10-10 19:30:52 +00:00
|
|
|
return ''
|
2023-10-04 19:02:53 +00:00
|
|
|
|
2022-03-24 19:44:12 +00:00
|
|
|
@socketio.on('disconnect')
|
2023-09-14 16:49:46 +00:00
|
|
|
@auth_required_socketio
|
2022-03-24 19:44:12 +00:00
|
|
|
def disconnect(v):
|
2024-04-07 08:50:58 +00:00
|
|
|
if not request.referrer: return ''
|
2024-04-06 04:31:51 +00:00
|
|
|
room = request.referrer
|
|
|
|
|
2024-04-10 03:01:51 +00:00
|
|
|
if room.startswith(f'{SITE_FULL}/notifications/messages'):
|
2023-10-10 19:30:52 +00:00
|
|
|
leave_room(v.id)
|
2024-04-09 15:14:32 +00:00
|
|
|
online["messages"].discard(v.id)
|
2024-03-09 17:07:10 +00:00
|
|
|
return ''
|
2023-10-07 10:54:21 +00:00
|
|
|
|
2024-04-09 14:58:05 +00:00
|
|
|
if online.get(room):
|
|
|
|
online[room].pop(v.id, None)
|
2023-09-06 14:29:31 +00:00
|
|
|
|
2024-03-10 14:27:21 +00:00
|
|
|
if v.username in typing[room]:
|
|
|
|
typing[room].remove(v.username)
|
2023-09-07 15:26:31 +00:00
|
|
|
|
2024-03-10 14:27:21 +00:00
|
|
|
leave_room(room)
|
2024-04-10 03:05:56 +00:00
|
|
|
|
|
|
|
if online.get(room):
|
|
|
|
refresh_online(room)
|
2023-10-10 19:30:52 +00:00
|
|
|
|
|
|
|
return ''
|
2022-03-24 19:44:12 +00:00
|
|
|
|
2023-10-07 10:54:21 +00:00
|
|
|
@socketio.on('heartbeat')
|
|
|
|
@auth_required_socketio
|
|
|
|
def heartbeat(v):
|
2024-04-07 08:50:58 +00:00
|
|
|
if not request.referrer: return ''
|
2024-04-06 04:31:51 +00:00
|
|
|
room = request.referrer
|
2024-03-10 14:27:21 +00:00
|
|
|
|
|
|
|
if not online.get(room):
|
|
|
|
online[room] = {}
|
|
|
|
|
2023-10-07 10:54:21 +00:00
|
|
|
expire_utc = int(time.time()) + 3610
|
2024-03-10 14:27:21 +00:00
|
|
|
already_there = online[room].get(v.id)
|
|
|
|
online[room][v.id] = (expire_utc, v.username, v.name_color, v.patron, v.id, bool(v.has_badge(303)))
|
2023-10-07 20:32:09 +00:00
|
|
|
if not already_there:
|
2024-03-10 14:27:21 +00:00
|
|
|
refresh_online(room)
|
|
|
|
|
2023-10-10 19:30:52 +00:00
|
|
|
return ''
|
2023-10-07 10:54:21 +00:00
|
|
|
|
2022-03-24 19:44:12 +00:00
|
|
|
@socketio.on('typing')
|
2024-04-19 21:11:48 +00:00
|
|
|
@auth_required_socketio
|
2022-03-24 19:44:12 +00:00
|
|
|
def typing_indicator(data, v):
|
2024-05-10 17:04:31 +00:00
|
|
|
if v.is_suspended or v.shadowbanned: return ''
|
2024-04-19 21:11:48 +00:00
|
|
|
|
2024-04-07 08:50:58 +00:00
|
|
|
if not request.referrer: return ''
|
2024-04-06 04:31:51 +00:00
|
|
|
room = request.referrer
|
2024-03-10 14:27:21 +00:00
|
|
|
|
|
|
|
if not typing.get(room):
|
|
|
|
typing[room] = []
|
|
|
|
|
2024-05-10 17:04:31 +00:00
|
|
|
if data and v.username not in typing[room]:
|
|
|
|
typing[room].append(v.username)
|
|
|
|
elif not data and v.username in typing[room]:
|
|
|
|
typing[room].remove(v.username)
|
|
|
|
|
|
|
|
emit('typing', typing[room], room=room)
|
2024-04-06 04:31:51 +00:00
|
|
|
|
2023-10-10 19:30:52 +00:00
|
|
|
return ''
|
2022-03-24 19:44:12 +00:00
|
|
|
|
|
|
|
|
2022-09-10 09:31:51 +00:00
|
|
|
@socketio.on('delete')
|
2024-04-19 21:11:48 +00:00
|
|
|
@auth_required_socketio
|
2023-01-21 10:36:21 +00:00
|
|
|
def delete(id, v):
|
2024-04-19 21:11:48 +00:00
|
|
|
if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
|
|
|
|
return ''
|
|
|
|
|
2024-05-16 23:13:20 +00:00
|
|
|
for msg in g.db.query(ChatMessage).filter_by(quotes=id):
|
|
|
|
msg.quotes = None
|
|
|
|
g.db.add(msg)
|
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
message = g.db.get(ChatMessage, id)
|
|
|
|
g.db.delete(message)
|
2024-04-08 04:51:00 +00:00
|
|
|
emit('delete', id, room=f'{SITE_FULL}/chat/1')
|
2022-09-10 09:31:51 +00:00
|
|
|
|
2024-04-06 04:31:51 +00:00
|
|
|
return ''
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
@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):
|
2024-02-14 09:27:00 +00:00
|
|
|
body = request.values.get("body", "").strip()
|
|
|
|
if len(body) > COMMENT_BODY_LENGTH_LIMIT:
|
2024-02-14 09:34:49 +00:00
|
|
|
abort(400, f'Message is too long (max {COMMENT_BODY_LENGTH_LIMIT} characters)')
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
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:
|
2024-02-01 00:30:12 +00:00
|
|
|
abort(403, "You are muted!")
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
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)
|
2024-02-14 09:27:00 +00:00
|
|
|
if len(body) > COMMENT_BODY_LENGTH_LIMIT:
|
2024-02-14 09:34:49 +00:00
|
|
|
abort(400, f'Message is too long (max {COMMENT_BODY_LENGTH_LIMIT} characters)')
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
if not body: abort(400, "Message is empty!")
|
|
|
|
|
|
|
|
body_html = sanitize(body)
|
|
|
|
|
|
|
|
if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT:
|
2024-02-14 09:34:49 +00:00
|
|
|
abort(400, "Rendered message is too long!")
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
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()
|
2024-03-09 17:06:13 +00:00
|
|
|
execute_blackjack(v, c, c.body_html, 'message')
|
|
|
|
execute_under_siege(v, c, c.body_html, 'message')
|
2023-09-26 20:05:39 +00:00
|
|
|
|
2024-04-09 15:02:56 +00:00
|
|
|
if user_id and user_id not in {v.id, MODMAIL_ID} | BOT_IDs and user_id not in online["messages"] and can_see(user, v):
|
|
|
|
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)
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
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:
|
2024-02-01 00:30:12 +00:00
|
|
|
if parent.author.id != v.id and parent.author.admin_level < PERMS['VIEW_MODMAIL']:
|
|
|
|
notif = Notification(comment_id=c.id, user_id=parent.author.id)
|
2023-09-26 20:05:39 +00:00
|
|
|
g.db.add(notif)
|
2023-09-26 20:35:41 +00:00
|
|
|
elif user_id and user_id not in {v.id, MODMAIL_ID} | BOT_IDs:
|
2023-09-26 20:05:39 +00:00
|
|
|
c.unread = True
|
2024-03-08 08:10:23 +00:00
|
|
|
rendered = render_template("comments.html", v=get_account(user_id), comments=[c])
|
|
|
|
emit('insert_reply', [parent.id, rendered], namespace='/', to=user_id)
|
2023-09-26 20:05:39 +00:00
|
|
|
|
|
|
|
return {"comment": render_template("comments.html", v=v, comments=[c])}
|