Skip to content

Commit c5e4afe

Browse files
committed
initial commit: barebones bot model plus bot_mode implementation details
1 parent 2c8e4f1 commit c5e4afe

File tree

3 files changed

+110
-22
lines changed

3 files changed

+110
-22
lines changed

sogs/model/bot.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from __future__ import annotations
2+
3+
from .. import crypto, db, config
4+
from ..db import query
5+
from ..web import app
6+
from .exc import NoSuchUser, BadPermission
7+
from sogs.model.user import User
8+
from .exc import (InvalidData)
9+
10+
from typing import Optional, List
11+
import time
12+
import contextlib
13+
14+
15+
class Bot:
16+
"""
17+
Class representing a simple bot to manage open group server
18+
19+
Object Properties:
20+
id - database primary key for user row
21+
session_id - jex encoded session_id of the bot
22+
banned - default to false
23+
global_admin - default to true for bot
24+
global_moderator - default to true for bot
25+
visible_mod - default to true for bot
26+
"""
27+
28+
def __init__(
29+
self,
30+
row = None,
31+
*,
32+
id: Optional[int] = None,
33+
session_id: Optional[int] = None) -> None:
34+
35+
# immutable attributes
36+
self._banned = False
37+
self._global_admin = False
38+
self._global_moderator = False
39+
self._visible_mod = False
40+
41+
# operational attributes
42+
self.current_message = None
43+
self.nlp_model = None
44+
self.language = "English"
45+
self.word_blacklist = ['placeholderlist', 'until', 'we', 'decide', 'naughty', 'words']
46+
47+
48+
def __setattr__(self, __name: str, __value) -> None:
49+
if __name in ['_banned', '_global_admin', '_global_moderator', '_visible_mod']:
50+
raise AttributeError("Cannot modify bots")
51+
else:
52+
setattr(self, __name, __value)
53+
54+
def __delattr__(self, __name: str) -> None:
55+
if __name in ['_banned', '_global_admin', '_global_moderator', '_visible_mod']:
56+
raise AttributeError("Cannot modify bots")
57+
else:
58+
delattr(self, __name)
59+
60+
def receive_message(self,
61+
user: User,
62+
data: bytes,
63+
sig: bytes,
64+
*,
65+
files: List[int] = []):
66+
67+
if data is None or sig is None or len(sig) != 64:
68+
raise InvalidData()
69+
70+

sogs/model/room.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
PostRateLimited,
1818
InvalidData,
1919
)
20+
from model.bot import Bot
2021

2122
import os
2223
import random
@@ -71,6 +72,9 @@ class Room:
7172
default_accessible - True if default user permissions include accessible permission
7273
default_write - True if default user permissions includes write permission
7374
default_upload - True if default user permissions includes file upload permission
75+
76+
NEW:
77+
bot_mode - true if bot moderator is actively on patrol
7478
"""
7579

7680
def __init__(self, row=None, *, id=None, token=None):
@@ -79,6 +83,12 @@ def __init__(self, row=None, *, id=None, token=None):
7983
looking up this raises a NoSuchRoom if no room with that token/id exists.
8084
"""
8185
self._refresh(id=id, token=token, row=row)
86+
self.bot_mode = False
87+
self.bot = None
88+
89+
def add_bot(self, _bot: Bot):
90+
self.bot = _bot
91+
self.bot_mode = True
8292

8393
def _refresh(self, *, id=None, token=None, row=None, perms=False):
8494
"""

sogs/routes/messages.py

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from .. import http, utils
22
from . import auth
3+
from model.room import Room
34

45
from flask import abort, jsonify, g, Blueprint, request
56

@@ -15,7 +16,7 @@ def qs_reactors():
1516

1617
@messages.get("/room/<Room:room>/messages/since/<int:seqno>")
1718
@auth.read_required
18-
def messages_since(room, seqno):
19+
def messages_since(room: Room, seqno):
1920
"""
2021
Retrieves message *updates* from a room. This is the main message polling endpoint in SOGS.
2122
@@ -99,7 +100,7 @@ def messages_since(room, seqno):
99100

100101
@messages.get("/room/<Room:room>/messages/before/<int:msg_id>")
101102
@auth.read_required
102-
def messages_before(room, msg_id):
103+
def messages_before(room: Room, msg_id):
103104
"""
104105
Retrieves messages from the room preceding a given id.
105106
@@ -142,7 +143,7 @@ def messages_before(room, msg_id):
142143

143144
@messages.get("/room/<Room:room>/messages/recent")
144145
@auth.read_required
145-
def messages_recent(room):
146+
def messages_recent(room: Room):
146147
"""
147148
Retrieves recent messages posted to this room.
148149
@@ -181,7 +182,7 @@ def messages_recent(room):
181182

182183
@messages.get("/room/<Room:room>/message/<int:msg_id>")
183184
@auth.read_required
184-
def message_single(room, msg_id):
185+
def message_single(room: Room, msg_id):
185186
"""
186187
Returns a single message by ID.
187188
@@ -310,7 +311,7 @@ def message_single(room, msg_id):
310311

311312
@messages.post("/room/<Room:room>/message")
312313
@auth.user_required
313-
def post_message(room):
314+
def post_message(room: Room):
314315
"""
315316
Posts a new message to a room.
316317
@@ -359,21 +360,28 @@ def post_message(room):
359360
"""
360361
req = request.json
361362

362-
msg = room.add_post(
363-
g.user,
364-
data=utils.decode_base64(req.get('data')),
365-
sig=utils.decode_base64(req.get('signature')),
366-
whisper_to=req.get('whisper_to'),
367-
whisper_mods=bool(req.get('whisper_mods')),
368-
files=[int(x) for x in req.get('files', [])],
369-
)
363+
if room.bot_mode:
364+
room.bot.receive_message(
365+
user = g.user,
366+
data = utils.decode_base64(req.get('data')),
367+
sig = utils.decode_base64(req.get('signature')),
368+
files = [int(x) for x in req.get('files', [])])
369+
else:
370+
msg = room.add_post(
371+
g.user,
372+
data=utils.decode_base64(req.get('data')),
373+
sig=utils.decode_base64(req.get('signature')),
374+
whisper_to=req.get('whisper_to'),
375+
whisper_mods=bool(req.get('whisper_mods')),
376+
files=[int(x) for x in req.get('files', [])],
377+
)
370378

371379
return utils.jsonify_with_base64(msg), http.CREATED
372380

373381

374382
@messages.put("/room/<Room:room>/message/<int:msg_id>")
375383
@auth.user_required
376-
def edit_message(room, msg_id):
384+
def edit_message(room: Room, msg_id):
377385
"""
378386
Edits a message, replacing its existing content with new content and a new signature.
379387
@@ -420,7 +428,7 @@ def edit_message(room, msg_id):
420428

421429
@messages.delete("/room/<Room:room>/message/<int:msg_id>")
422430
@auth.user_required
423-
def remove_message(room, msg_id):
431+
def remove_message(room: Room, msg_id):
424432
"""
425433
Remove a message by its message id
426434
@@ -447,7 +455,7 @@ def remove_message(room, msg_id):
447455

448456

449457
@messages.post("/room/<Room:room>/pin/<int:msg_id>")
450-
def message_pin(room, msg_id):
458+
def message_pin(room: Room, msg_id):
451459
"""
452460
Adds a pinned message to this room.
453461
@@ -490,7 +498,7 @@ def message_pin(room, msg_id):
490498

491499

492500
@messages.post("/room/<Room:room>/unpin/<int:msg_id>")
493-
def message_unpin(room, msg_id):
501+
def message_unpin(room: Room, msg_id):
494502
"""
495503
Remove a message from this room's pinned message list.
496504
@@ -524,7 +532,7 @@ def message_unpin(room, msg_id):
524532

525533

526534
@messages.post("/room/<Room:room>/unpin/all")
527-
def message_unpin_all(room):
535+
def message_unpin_all(room: Room):
528536
"""
529537
Removes *all* pinned messages from this room.
530538
@@ -553,7 +561,7 @@ def message_unpin_all(room):
553561
@messages.put("/room/<Room:room>/reaction/<int:msg_id>/<path:reaction>")
554562
@auth.user_required
555563
@auth.read_required
556-
def message_react(room, msg_id, reaction):
564+
def message_react(room: Room, msg_id, reaction):
557565
"""
558566
Adds a reaction to the given message in this room. The user must have read access in the room.
559567
@@ -606,7 +614,7 @@ def message_react(room, msg_id, reaction):
606614
@messages.delete("/room/<Room:room>/reaction/<int:msg_id>/<path:reaction>")
607615
@auth.user_required
608616
@auth.read_required
609-
def message_unreact(room, msg_id, reaction):
617+
def message_unreact(room: Room, msg_id, reaction):
610618
"""
611619
Removes a reaction from a post this room. The user must have read access in the room. This
612620
only removes the user's own reaction but does not affect the reactions of other users.
@@ -642,7 +650,7 @@ def message_unreact(room, msg_id, reaction):
642650
@messages.delete("/room/<Room:room>/reactions/<int:msg_id>/<path:reaction>")
643651
@messages.delete("/room/<Room:room>/reactions/<int:msg_id>")
644652
@auth.mod_required
645-
def message_delete_reactions(room, msg_id, reaction=None):
653+
def message_delete_reactions(room: Room, msg_id, reaction=None):
646654
"""
647655
Removes all reactions of all users from a post in this room. The calling must have moderator
648656
permissions in the room. This endpoint can either remove a single reaction (e.g. remove all 🍆
@@ -677,7 +685,7 @@ def message_delete_reactions(room, msg_id, reaction=None):
677685

678686
@messages.get("/room/<Room:room>/reactors/<int:msg_id>/<path:reaction>")
679687
@auth.read_required
680-
def message_get_reactors(room, msg_id, reaction):
688+
def message_get_reactors(room: Room, msg_id, reaction):
681689
"""
682690
Returns the list of all reactors who have added a particular reaction to a particular message.
683691

0 commit comments

Comments
 (0)