Explicit account modification #42
2 changed files with 91 additions and 32 deletions
|
@ -37,22 +37,45 @@ def get_random_character() -> Character | None:
|
|||
'image_url': chosen['file_id']
|
||||
}
|
||||
|
||||
|
||||
def get_or_create_user(username: str) -> int:
|
||||
'''Retrieves an ID for a given user, if the user does not exist, it will be
|
||||
created.'''
|
||||
def get_player(username: str) -> int:
|
||||
'''Retrieve a player ID by username, or return None if not found.'''
|
||||
CURSOR.execute('SELECT id FROM users WHERE username = ?', (username,))
|
||||
user = CURSOR.fetchone()
|
||||
if user:
|
||||
return int(user[0])
|
||||
|
||||
# New user starts with has_rolled = False
|
||||
def insert_player(username: str) -> int:
|
||||
'''Insert a new player with default has_rolled = False and return their user ID.'''
|
||||
CURSOR.execute(
|
||||
'INSERT INTO users (username, has_rolled) VALUES (?, ?)',
|
||||
(username, False)
|
||||
)
|
||||
user_id = CURSOR.lastrowid
|
||||
return user_id if user_id else 0
|
||||
return CURSOR.lastrowid
|
||||
|
||||
def delete_player(username: str) -> bool:
|
||||
'''Permanently deletes a user and all their pulls.'''
|
||||
CURSOR.execute(
|
||||
'SELECT id FROM users WHERE username = ?',
|
||||
(username,)
|
||||
)
|
||||
user = CURSOR.fetchone()
|
||||
|
||||
user_id = user[0]
|
||||
|
||||
|
||||
# Delete pulls
|
||||
CURSOR.execute(
|
||||
'DELETE FROM pulls WHERE user_id = ?',
|
||||
(user_id,)
|
||||
)
|
||||
|
||||
# Delete user
|
||||
CURSOR.execute(
|
||||
'DELETE FROM users WHERE id = ?',
|
||||
(user_id,)
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def insert_character(
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
from datetime import datetime, timedelta, timezone
|
||||
from typing import TypedDict, Any, List, Dict
|
||||
from db_utils import get_or_create_user, insert_pull, get_last_rolled_at, \
|
||||
from db_utils import get_player, insert_player, delete_player, insert_pull, get_last_rolled_at, \
|
||||
get_random_character
|
||||
from add_character import add_character
|
||||
from config import GACHA_ROLL_INTERVAL
|
||||
from custom_types import BotResponse, ParsedNotification
|
||||
|
||||
|
||||
def do_roll(full_user: str) -> BotResponse:
|
||||
def do_roll(author: str) -> BotResponse:
|
||||
nai
commented
The function seems to grow too big too huge. Instead of piling every action in one file The function seems to grow too big too huge. Instead of piling every action in one file `response.py`, splitting every do_* into separate files could help. The file will be very heavy on a lot of unrelated to each other changes, hence every function belongs to a separate "domain", that could be expressed by splitting
|
||||
'''Determines whether the user can roll, then pulls a random character'''
|
||||
user_id = get_or_create_user(full_user)
|
||||
|
||||
user_id = get_player(author)
|
||||
if not user_id:
|
||||
return {
|
||||
'message':f'{author} 🛑 You haven’t signed up yet! Use the `signup` command to start playing.',
|
||||
'attachment_urls': None
|
||||
}
|
||||
# Get date of user's last roll
|
||||
date = get_last_rolled_at(user_id)
|
||||
|
||||
|
@ -36,7 +40,7 @@ def do_roll(full_user: str) -> BotResponse:
|
|||
remaining_duration = f'{duration.seconds} seconds'
|
||||
|
||||
return {
|
||||
'message': f'{full_user} ⏱️ Please wait another \
|
||||
'message': f'{author} ⏱️ Please wait another \
|
||||
{remaining_duration} before rolling again.',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
@ -45,7 +49,7 @@ def do_roll(full_user: str) -> BotResponse:
|
|||
|
||||
if not character:
|
||||
return {
|
||||
'message': f'{full_user} Uwaaa... something went wrong! No \
|
||||
'message': f'{author} Uwaaa... something went wrong! No \
|
||||
characters found. 😿',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
@ -53,11 +57,26 @@ characters found. 😿',
|
|||
insert_pull(user_id, character['id'])
|
||||
stars = '⭐️' * character['rarity']
|
||||
return {
|
||||
'message': f'@{full_user} 🎲 Congrats! You rolled {stars} \
|
||||
'message': f'{author} 🎲 Congrats! You rolled {stars} \
|
||||
**{character['name']}**\nShe\'s all yours now~ 💖✨',
|
||||
'attachment_urls': [character['image_url']]
|
||||
}
|
||||
|
||||
def do_signup(author: str) -> BotResponse:
|
||||
'''Registers a new user if they haven’t signed up yet.'''
|
||||
user_id = get_player(author)
|
||||
|
||||
if user_id:
|
||||
return {
|
||||
'message':f'{author} 👀 You’re already signed up! Let the rolling begin~ 🎲',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
||||
new_user_id = insert_player(author)
|
||||
return {
|
||||
'message': f'{author} ✅ Signed up successfully! Your gacha destiny begins now... ✨ Use the roll command to start!',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
||||
def is_float(val: Any) -> bool:
|
||||
'''Returns true if `val` can be converted to a float'''
|
||||
|
@ -69,7 +88,7 @@ def is_float(val: Any) -> bool:
|
|||
|
||||
|
||||
def do_create(
|
||||
full_user: str,
|
||||
author: str,
|
||||
arguments: List[str],
|
||||
note_obj: Dict[str, Any]) -> BotResponse:
|
||||
'''Creates a character'''
|
||||
|
@ -79,27 +98,27 @@ def do_create(
|
|||
|
||||
if not image_url:
|
||||
return {
|
||||
'message': f'{full_user} You need an image to create a character, \
|
||||
'message': f'{author} You need an image to create a character, \
|
||||
dumbass.',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
||||
if len(arguments) != 3:
|
||||
return {
|
||||
'message': f'{full_user} Please specify the following attributes \
|
||||
'message': f'{author} Please specify the following attributes \
|
||||
in order: name, rarity, drop weighting',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
||||
if not (arguments[1].isnumeric() and 1 <= int(arguments[1]) <= 5):
|
||||
return {
|
||||
'message': f'{full_user} Invalid rarity: \'{arguments[1]}\' must \
|
||||
'message': f'{author} Invalid rarity: \'{arguments[1]}\' must \
|
||||
be a number between 1 and 5',
|
||||
'attachment_urls': None
|
||||
}
|
||||
if not (is_float(arguments[2]) and 0.0 < float(arguments[2]) <= 1.0):
|
||||
nai
commented
it'd be more readable if you unpacked the array into variables that have names. it'd be more readable if you unpacked the array into variables that have names. `is_float(arguments[2]))` is too low-level if you are not someone who wrote this function.
For example, `is_float(rarity)` seems better and less bug prone, since you can't fuck up accessing by a wrong index
|
||||
return {
|
||||
'message': f'{full_user} Invalid drop weight: \'{arguments[2]}\' \
|
||||
'message': f'{author} Invalid drop weight: \'{arguments[2]}\' \
|
||||
must be a decimal value between 0.0 and 1.0',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
@ -111,7 +130,7 @@ must be a decimal value between 0.0 and 1.0',
|
|||
image_url=image_url
|
||||
)
|
||||
return {
|
||||
'message': f'{full_user} Added {arguments[0]}, ID {character_id}.',
|
||||
'message': f'{author} Added {arguments[0]}, ID {character_id}.',
|
||||
'attachment_urls': [file_id]
|
||||
}
|
||||
|
||||
|
@ -119,17 +138,30 @@ must be a decimal value between 0.0 and 1.0',
|
|||
def do_help(author: str) -> BotResponse:
|
||||
'''Provides a list of commands that the bot can do.'''
|
||||
return {
|
||||
'message': f'{author} Here\'s what I can do:\n\
|
||||
- `roll` Pulls a random character.\n\
|
||||
- `create <name> <rarity> <weight>` Creates a character using a given image.\n\
|
||||
- `help` Shows this message.',
|
||||
'message':f'{author} Here\'s what I can do:\n \
|
||||
- `roll` Pulls a random character.\
|
||||
- `create <name> <rarity> <weight>` Creates a character using a given image.\
|
||||
- `signup` Registers your account.\
|
||||
- `delete_account` Deletes your account.\
|
||||
- `help` Shows this message',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
||||
def delete_account(author: str) -> BotResponse:
|
||||
return {
|
||||
'message':f'{author} ⚠️ This will permanently delete your account and all your cards.\n'
|
||||
'If you’re sure, reply with `confirm_delete` to proceed.\n\n'
|
||||
'**There is no undo.** Your gacha luck will be lost to the void... 💀✨',
|
||||
'attachment_urls': None
|
||||
|
||||
}
|
||||
|
||||
def confirm_delete(author: str) -> BotResponse:
|
||||
|
||||
delete_player(author)
|
||||
|
||||
def do_signup() -> BotResponse:
|
||||
return {
|
||||
'message': '',
|
||||
'message':f'{author} 🧼 Your account and all your cards have been deleted. RIP your gacha history 🕊️✨',
|
||||
'attachment_urls': None
|
||||
}
|
||||
|
||||
|
@ -142,7 +174,7 @@ def generate_response(notification: ParsedNotification) -> BotResponse | None:
|
|||
res: BotResponse | None = None
|
||||
# TODO: Check if the user has an account
|
||||
author = notification['author']
|
||||
user_id = get_or_create_user(author)
|
||||
user_id = get_player(author)
|
||||
command = notification['command']
|
||||
# Check if the user is an administrator
|
||||
# user_is_administrator = user_is_administrator()
|
||||
|
@ -150,9 +182,11 @@ def generate_response(notification: ParsedNotification) -> BotResponse | None:
|
|||
# Unrestricted commands
|
||||
match command:
|
||||
case 'signup':
|
||||
res = do_signup()
|
||||
res = do_signup(author)
|
||||
case 'help':
|
||||
res = do_help(author)
|
||||
case 'roll':
|
||||
res = do_roll(author)
|
||||
case _:
|
||||
pass
|
||||
|
||||
|
@ -161,16 +195,18 @@ def generate_response(notification: ParsedNotification) -> BotResponse | None:
|
|||
|
||||
# User commands
|
||||
match command:
|
||||
case 'delete_account':
|
||||
pass
|
||||
case 'roll':
|
||||
res = do_roll(author)
|
||||
case 'create':
|
||||
res = do_create(
|
||||
author,
|
||||
notification['arguments'],
|
||||
notification['note_obj']
|
||||
)
|
||||
case 'signup':
|
||||
res = do_signup(author)
|
||||
case 'delete_account':
|
||||
res = delete_account(author)
|
||||
case 'confirm_delete':
|
||||
res = confirm_delete(author)
|
||||
case _:
|
||||
pass
|
||||
# if not user_is_administrator:
|
||||
|
|
Loading…
Add table
Reference in a new issue
I mean, you do expect this username to be deleted anyway, right. False if the user does exist and the operation failed for some reason. Though depends on the use-case