GloryBot/classes/pycord_check.py
2024-06-02 21:51:07 +02:00

126 lines
3.2 KiB
Python

import logging
from dataclasses import dataclass
from datetime import UTC, datetime
from random import choice
from typing import Optional
from bson import ObjectId
from classes.errors import (
CheckAlreadyAssignedError,
CheckChallengeNotFoundError,
CheckNotFoundError,
GuildChallengesEmptyError,
)
from classes.pycord_challenge import PycordChallenge
from modules.database import col_challenges, col_checks
logger = logging.getLogger(__name__)
@dataclass
class PycordCheck:
"""Dataclass of DB entry of a security check"""
__slots__ = (
"_id",
"guild",
"active",
"thread_id",
"member",
"date_created",
"date_modified",
"challenge",
)
_id: ObjectId
guild: ObjectId
active: bool
thread_id: int
member: ObjectId
date_created: datetime
date_modified: datetime
challenge: ObjectId
@classmethod
async def find(
cls,
guild: ObjectId,
member: ObjectId,
):
db_entry = await col_checks.find_one(
{"active": True, "guild": guild, "member": member}
)
if not db_entry:
raise CheckNotFoundError(guild, member)
return cls(**db_entry)
@classmethod
async def create(
cls,
guild: ObjectId,
thread_id: int,
member: ObjectId,
challenge: Optional[ObjectId] = None,
):
# Check whether active check already exists
if await col_checks.find_one(
{"active": True, "guild": guild, "member": member}
):
raise CheckAlreadyAssignedError(guild, member)
# Get all enabled guild challenges
guild_challenges = [
challenge
async for challenge in col_challenges.find(
{"guild": guild, "enabled": True, "archived": False}
)
]
# Check whether guild has challenges at all
if not challenge and not guild_challenges:
raise GuildChallengesEmptyError(guild)
# Create a check dict
check = {
"guild": guild,
"active": True,
"thread_id": thread_id,
"member": member,
"date_created": datetime.now(UTC),
"date_modified": datetime.now(UTC),
"challenge": challenge or choice(guild_challenges)["_id"],
}
# Insert the check into the database
inserted = await col_checks.insert_one(check)
check["_id"] = inserted.inserted_id
return cls(**check)
async def deactivate(self) -> None:
"""Deactivate the check"""
await col_checks.update_one(
{"_id": self._id},
{"$set": {"active": False, "date_modified": datetime.now(UTC)}},
)
async def get_challenge(self) -> PycordChallenge:
"""Get check's bound challenge
### Raises:
* `CheckChallengeNotFoundError`: Challenge could not be found
### Returns:
* `PycordChallenge`: Captcha challenge
"""
challenge = await col_challenges.find_one({"_id": self.challenge})
if not challenge:
raise CheckChallengeNotFoundError(self._id, self.challenge)
return PycordChallenge(**challenge)