Merge branch 'dev'
このコミットが含まれているのは:
コミット
f3de542e3b
|
@ -31,9 +31,9 @@ def get_all_messages_for_websocket():
|
||||||
))
|
))
|
||||||
|
|
||||||
def add_chat_message(user, nonce, comment, ignore_empty=False):
|
def add_chat_message(user, nonce, comment, ignore_empty=False):
|
||||||
# Special case: if the comment is empty, do nothing and return
|
# Special case: if the comment is empty, do nothing and return None
|
||||||
if ignore_empty and len(comment) == 0:
|
if ignore_empty and len(comment) == 0:
|
||||||
return False
|
return None
|
||||||
|
|
||||||
timestamp_ms = time.time_ns() // 1_000_000
|
timestamp_ms = time.time_ns() // 1_000_000
|
||||||
timestamp = timestamp_ms // 1000
|
timestamp = timestamp_ms // 1000
|
||||||
|
@ -137,7 +137,7 @@ def add_chat_message(user, nonce, comment, ignore_empty=False):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return True
|
return seq
|
||||||
|
|
||||||
def delete_chat_messages(seqs):
|
def delete_chat_messages(seqs):
|
||||||
seq_set = set(seqs)
|
seq_set = set(seqs)
|
||||||
|
|
|
@ -3,9 +3,14 @@
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from anonstream.control.spec import Spec, NoParse, Ambiguous, Parsed
|
from quart import current_app
|
||||||
|
|
||||||
|
from anonstream.control.spec import Spec, NoParse, Ambiguous, BadArgument, Parsed
|
||||||
from anonstream.control.spec.utils import get_item, startswith
|
from anonstream.control.spec.utils import get_item, startswith
|
||||||
|
|
||||||
|
USERS_BY_TOKEN = current_app.users_by_token
|
||||||
|
USERS = current_app.users
|
||||||
|
|
||||||
class Str(Spec):
|
class Str(Spec):
|
||||||
AS_ARG = False
|
AS_ARG = False
|
||||||
|
|
||||||
|
@ -146,3 +151,26 @@ class ArgsJsonStringArray(ArgsJson):
|
||||||
f'bad argument at position {index} {obj_json!r}: '
|
f'bad argument at position {index} {obj_json!r}: '
|
||||||
f'could not decode json array of strings'
|
f'could not decode json array of strings'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class ArgsJsonTokenUser(ArgsJsonString):
|
||||||
|
def transform_obj(self, token):
|
||||||
|
try:
|
||||||
|
user = USERS_BY_TOKEN[token]
|
||||||
|
except KeyError:
|
||||||
|
raise BadArgument(f'no user with token {token!r}')
|
||||||
|
return user
|
||||||
|
|
||||||
|
class ArgsJsonHashUser(ArgsString):
|
||||||
|
def transform_string(self, token_hash):
|
||||||
|
for user in USERS:
|
||||||
|
if user['token_hash'] == token_hash:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise BadArgument(f'no user with token_hash {token_hash!r}')
|
||||||
|
return user
|
||||||
|
|
||||||
|
def ArgsUser(spec):
|
||||||
|
return Str({
|
||||||
|
'token': ArgsJsonTokenUser(spec),
|
||||||
|
'hash': ArgsJsonHashUser(spec),
|
||||||
|
})
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
from anonstream.chat import delete_chat_messages
|
from anonstream.chat import delete_chat_messages
|
||||||
|
from anonstream.control.exceptions import CommandFailed
|
||||||
from anonstream.control.spec import NoParse
|
from anonstream.control.spec import NoParse
|
||||||
from anonstream.control.spec.common import Str, End, Args
|
from anonstream.control.spec.common import Str, End, Args, ArgsJsonString, ArgsUser
|
||||||
from anonstream.control.spec.utils import get_item, json_dumps_contiguous
|
from anonstream.control.spec.utils import get_item, json_dumps_contiguous
|
||||||
|
from anonstream.chat import add_chat_message, Rejected
|
||||||
|
|
||||||
class ArgsSeqs(Args):
|
class ArgsSeqs(Args):
|
||||||
def consume(self, words, index):
|
def consume(self, words, index):
|
||||||
|
@ -33,12 +35,18 @@ async def cmd_chat_help():
|
||||||
response = (
|
response = (
|
||||||
'Usage: chat delete SEQS\n'
|
'Usage: chat delete SEQS\n'
|
||||||
'Commands:\n'
|
'Commands:\n'
|
||||||
#' chat show [MESSAGES]......show chat messages\n'
|
#' chat show [MESSAGES]...........show chat messages\n'
|
||||||
' chat delete SEQS..........delete chat messages\n'
|
' chat delete SEQS...............delete chat messages\n'
|
||||||
|
' chat add USER NONCE COMMENT....add chat message\n'
|
||||||
'Definitions:\n'
|
'Definitions:\n'
|
||||||
#' MESSAGES..................undefined\n'
|
#' MESSAGES...................undefined\n'
|
||||||
' SEQS......................=SEQ [SEQ...]\n'
|
' SEQS.......................=SEQ [SEQ...]\n'
|
||||||
' SEQ.......................a chat message\'s seq, base-10 integer\n'
|
' SEQ........................a chat message\'s seq, base-10 integer\n'
|
||||||
|
' USER.......................={token TOKEN | hash HASH}\n'
|
||||||
|
' TOKEN......................a user\'s token, json string\n'
|
||||||
|
' HASH.......................a user\'s token hash\n'
|
||||||
|
' NONCE......................a chat message\'s nonce, json string\n'
|
||||||
|
' COMMENT....................json string\n'
|
||||||
)
|
)
|
||||||
return normal, response
|
return normal, response
|
||||||
|
|
||||||
|
@ -48,8 +56,24 @@ async def cmd_chat_delete(*seqs):
|
||||||
response = ''
|
response = ''
|
||||||
return normal, response
|
return normal, response
|
||||||
|
|
||||||
|
async def cmd_chat_add(user, nonce, comment):
|
||||||
|
try:
|
||||||
|
seq = add_chat_message(user, nonce, comment)
|
||||||
|
except Rejected as e:
|
||||||
|
raise CommandFailed(f'rejected: {e}') from e
|
||||||
|
else:
|
||||||
|
assert seq is not None
|
||||||
|
normal = [
|
||||||
|
'chat', 'add',
|
||||||
|
'token', json_dumps_contiguous(user['token']),
|
||||||
|
json_dumps_contiguous(nonce), json_dumps_contiguous(comment),
|
||||||
|
]
|
||||||
|
response = str(seq) + '\n'
|
||||||
|
return normal, response
|
||||||
|
|
||||||
SPEC = Str({
|
SPEC = Str({
|
||||||
None: End(cmd_chat_help),
|
None: End(cmd_chat_help),
|
||||||
'help': End(cmd_chat_help),
|
'help': End(cmd_chat_help),
|
||||||
'delete': ArgsSeqs(End(cmd_chat_delete)),
|
'delete': ArgsSeqs(End(cmd_chat_delete)),
|
||||||
|
'add': ArgsUser(ArgsJsonString(ArgsJsonString(End(cmd_chat_add)))),
|
||||||
})
|
})
|
||||||
|
|
|
@ -18,8 +18,10 @@ async def cmd_help():
|
||||||
' user set USER ATTR VALUE.......set an attribute of a user\n'
|
' user set USER ATTR VALUE.......set an attribute of a user\n'
|
||||||
' user eyes USER [show]..........show a list of active video responses\n'
|
' user eyes USER [show]..........show a list of active video responses\n'
|
||||||
' user eyes USER delete EYES_ID..end a video response\n'
|
' user eyes USER delete EYES_ID..end a video response\n'
|
||||||
|
' user add VERIFIED TOKEN........add new user\n'
|
||||||
#' chat show MESSAGES.............show a list of messages\n'
|
#' chat show MESSAGES.............show a list of messages\n'
|
||||||
' chat delete SEQS...............delete a set of messages\n'
|
' chat delete SEQS...............delete a set of messages\n'
|
||||||
|
' chat add USER NONCE COMMENT....add chat message\n'
|
||||||
' allowedness [show].............show the current allowedness\n'
|
' allowedness [show].............show the current allowedness\n'
|
||||||
' allowedness setdefault BOOLEAN.set the default allowedness\n'
|
' allowedness setdefault BOOLEAN.set the default allowedness\n'
|
||||||
' allowedness add SET STRING.....add to the blacklist/whitelist\n'
|
' allowedness add SET STRING.....add to the blacklist/whitelist\n'
|
||||||
|
|
|
@ -6,38 +6,15 @@ import json
|
||||||
from quart import current_app
|
from quart import current_app
|
||||||
|
|
||||||
from anonstream.control.exceptions import CommandFailed
|
from anonstream.control.exceptions import CommandFailed
|
||||||
from anonstream.control.spec import BadArgument
|
from anonstream.control.spec.common import Str, End, ArgsInt, ArgsString, ArgsJson, ArgsJsonBoolean, ArgsJsonString, ArgsUser
|
||||||
from anonstream.control.spec.common import Str, End, ArgsInt, ArgsString, ArgsJson, ArgsJsonString
|
from anonstream.control.spec.utils import json_dumps_contiguous
|
||||||
from anonstream.control.spec.utils import get_item, json_dumps_contiguous
|
|
||||||
from anonstream.utils.user import USER_WEBSOCKET_ATTRS
|
from anonstream.utils.user import USER_WEBSOCKET_ATTRS
|
||||||
|
from anonstream.routes.wrappers import generate_and_add_user
|
||||||
|
from anonstream.wrappers import get_timestamp
|
||||||
|
|
||||||
USERS_BY_TOKEN = current_app.users_by_token
|
USERS_BY_TOKEN = current_app.users_by_token
|
||||||
USERS = current_app.users
|
|
||||||
USERS_UPDATE_BUFFER = current_app.users_update_buffer
|
USERS_UPDATE_BUFFER = current_app.users_update_buffer
|
||||||
|
|
||||||
class ArgsJsonTokenUser(ArgsJsonString):
|
|
||||||
def transform_obj(self, token):
|
|
||||||
try:
|
|
||||||
user = USERS_BY_TOKEN[token]
|
|
||||||
except KeyError:
|
|
||||||
raise BadArgument(f'no user with token {token!r}')
|
|
||||||
return user
|
|
||||||
|
|
||||||
class ArgsJsonHashUser(ArgsString):
|
|
||||||
def transform_string(self, token_hash):
|
|
||||||
for user in USERS:
|
|
||||||
if user['token_hash'] == token_hash:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise BadArgument(f'no user with token_hash {token_hash!r}')
|
|
||||||
return user
|
|
||||||
|
|
||||||
def ArgsUser(spec):
|
|
||||||
return Str({
|
|
||||||
'token': ArgsJsonTokenUser(spec),
|
|
||||||
'hash': ArgsJsonHashUser(spec),
|
|
||||||
})
|
|
||||||
|
|
||||||
async def cmd_user_help():
|
async def cmd_user_help():
|
||||||
normal = ['user', 'help']
|
normal = ['user', 'help']
|
||||||
response = (
|
response = (
|
||||||
|
@ -49,6 +26,7 @@ async def cmd_user_help():
|
||||||
' user set USER ATTR VALUE......set an attribute of a user\n'
|
' user set USER ATTR VALUE......set an attribute of a user\n'
|
||||||
' user eyes USER [show].........show a user\'s active video responses\n'
|
' user eyes USER [show].........show a user\'s active video responses\n'
|
||||||
' user eyes USER delete EYES_ID.end a video response to a user\n'
|
' user eyes USER delete EYES_ID.end a video response to a user\n'
|
||||||
|
' user add VERIFIED TOKEN.......add new user\n'
|
||||||
'Definitions:\n'
|
'Definitions:\n'
|
||||||
' USER..........................={token TOKEN | hash HASH}\n'
|
' USER..........................={token TOKEN | hash HASH}\n'
|
||||||
' TOKEN.........................a token, json string\n'
|
' TOKEN.........................a token, json string\n'
|
||||||
|
@ -56,6 +34,7 @@ async def cmd_user_help():
|
||||||
' ATTR..........................a user attribute, re:[a-z0-9_]+\n'
|
' ATTR..........................a user attribute, re:[a-z0-9_]+\n'
|
||||||
' VALUE.........................json value\n'
|
' VALUE.........................json value\n'
|
||||||
' EYES_ID.......................a user\'s eyes_id, base 10 integer\n'
|
' EYES_ID.......................a user\'s eyes_id, base 10 integer\n'
|
||||||
|
' VERIFIED......................user\'s verified state: true = normal, false = can\'t chat, null = will be kicked to access captcha\n'
|
||||||
)
|
)
|
||||||
return normal, response
|
return normal, response
|
||||||
|
|
||||||
|
@ -132,6 +111,21 @@ async def cmd_user_eyes_delete(user, eyes_id):
|
||||||
response = ''
|
response = ''
|
||||||
return normal, response
|
return normal, response
|
||||||
|
|
||||||
|
async def cmd_user_add(verified, token):
|
||||||
|
if token in USERS_BY_TOKEN:
|
||||||
|
raise CommandFailed(f'user with token {token!r} already exists')
|
||||||
|
_user = generate_and_add_user(
|
||||||
|
timestamp=get_timestamp(),
|
||||||
|
token=token,
|
||||||
|
verified=verified,
|
||||||
|
)
|
||||||
|
normal = [
|
||||||
|
'user', 'add',
|
||||||
|
json_dumps_contiguous(verified), json_dumps_contiguous(token),
|
||||||
|
]
|
||||||
|
response = ''
|
||||||
|
return normal, response
|
||||||
|
|
||||||
SPEC = Str({
|
SPEC = Str({
|
||||||
None: End(cmd_user_show),
|
None: End(cmd_user_show),
|
||||||
'help': End(cmd_user_help),
|
'help': End(cmd_user_help),
|
||||||
|
@ -144,4 +138,5 @@ SPEC = Str({
|
||||||
'show': End(cmd_user_eyes_show),
|
'show': End(cmd_user_eyes_show),
|
||||||
'delete': ArgsInt(End(cmd_user_eyes_delete)),
|
'delete': ArgsInt(End(cmd_user_eyes_delete)),
|
||||||
})),
|
})),
|
||||||
|
'add': ArgsJsonBoolean(ArgsJsonString(End(cmd_user_add))),
|
||||||
})
|
})
|
||||||
|
|
|
@ -135,12 +135,13 @@ async def nojs_submit_message(timestamp, user):
|
||||||
try:
|
try:
|
||||||
# If the comment is empty but the captcha was just solved,
|
# If the comment is empty but the captcha was just solved,
|
||||||
# be lenient: don't raise an exception and don't create a notice
|
# be lenient: don't raise an exception and don't create a notice
|
||||||
message_was_added = add_chat_message(
|
seq = add_chat_message(
|
||||||
user,
|
user,
|
||||||
nonce,
|
nonce,
|
||||||
comment,
|
comment,
|
||||||
ignore_empty=verification_happened,
|
ignore_empty=verification_happened,
|
||||||
)
|
)
|
||||||
|
message_was_added = seq is not None
|
||||||
except Rejected as e:
|
except Rejected as e:
|
||||||
notice, *_ = e.args
|
notice, *_ = e.args
|
||||||
state_id = add_state(
|
state_id = add_state(
|
||||||
|
|
|
@ -140,12 +140,13 @@ def handle_inbound_message(timestamp, queue, user, nonce, comment, digest, answe
|
||||||
message_was_added = False
|
message_was_added = False
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
message_was_added = add_chat_message(
|
seq = add_chat_message(
|
||||||
user,
|
user,
|
||||||
nonce,
|
nonce,
|
||||||
comment,
|
comment,
|
||||||
ignore_empty=verification_happened,
|
ignore_empty=verification_happened,
|
||||||
)
|
)
|
||||||
|
message_was_added = seq is not None
|
||||||
except Rejected as e:
|
except Rejected as e:
|
||||||
notice, *_ = e.args
|
notice, *_ = e.args
|
||||||
message_was_added = False
|
message_was_added = False
|
||||||
|
|
読み込み中…
新しいイシューから参照