WIP: Part 1
This commit is contained in:
parent
fa901d9f94
commit
83ef964122
159
.gitignore
vendored
159
.gitignore
vendored
@ -1,20 +1,157 @@
|
||||
# ---> JupyterNotebooks
|
||||
# gitignore template for Jupyter Notebooks
|
||||
# website: http://jupyter.org/
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
*/.ipynb_checkpoints/*
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# Remove previous ipynb_checkpoints
|
||||
# git rm -r .ipynb_checkpoints/
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
.vscode
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Custom
|
||||
.old/
|
||||
config.json
|
||||
data.json
|
||||
|
||||
loop.sh
|
||||
start.sh
|
14
.renovaterc
14
.renovaterc
@ -2,5 +2,19 @@
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"baseBranches": [
|
||||
"dev"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": [
|
||||
"minor",
|
||||
"patch",
|
||||
"pin",
|
||||
"digest"
|
||||
],
|
||||
"automerge": true
|
||||
}
|
||||
]
|
||||
}
|
1
classes/enums/__init__.py
Normal file
1
classes/enums/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .member_status import MemberStatus
|
8
classes/enums/member_status.py
Normal file
8
classes/enums/member_status.py
Normal file
@ -0,0 +1,8 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class MemberStatus(Enum):
|
||||
UNVERIFIED = 0
|
||||
VERIFIED = 1
|
||||
ADDITIONAL = 2
|
||||
FAILED = 3
|
1
classes/errors/__init__.py
Normal file
1
classes/errors/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .member import MemberNotFoundError
|
21
classes/errors/member.py
Normal file
21
classes/errors/member.py
Normal file
@ -0,0 +1,21 @@
|
||||
from typing import Union
|
||||
from bson import ObjectId
|
||||
|
||||
|
||||
class MemberNotFoundError(Exception):
|
||||
"""Exception raised when member does not exist in a database.
|
||||
|
||||
### Attributes:
|
||||
* id: Member ID.
|
||||
* guild: Member's guild.
|
||||
"""
|
||||
|
||||
def __init__(self, id: Union[int, ObjectId], guild: ObjectId):
|
||||
self.id = id
|
||||
self.guild = guild
|
||||
super().__init__(
|
||||
f"Could not find member entry for {str(id)} in the guild with id {str(guild)}."
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"Could not find member entry for {str(self.id)} in the guild with id {str(self.guild)}."
|
43
classes/pycordbot.py
Normal file
43
classes/pycordbot.py
Normal file
@ -0,0 +1,43 @@
|
||||
from typing import Any, Union
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from bson import ObjectId
|
||||
from libbot.pycord.classes import PycordBot as LibPycordBot
|
||||
|
||||
from classes.pycordmember import PycordMember
|
||||
|
||||
|
||||
class PycordBot(LibPycordBot):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.client_session = ClientSession()
|
||||
|
||||
if self.scheduler is None:
|
||||
return
|
||||
|
||||
async def find_user(
|
||||
self, id: Union[int, ObjectId], guild: ObjectId
|
||||
) -> PycordMember:
|
||||
"""Find member by their ID and guild.
|
||||
|
||||
### Args:
|
||||
* id (`Union[int, ObjectId]`): Member's Discord ID
|
||||
* guild (`ObjectId`): Discord guild's database ID
|
||||
|
||||
### Raises:
|
||||
* `MemberNotFoundError`: Raised when member entry after insertion could not be found.
|
||||
|
||||
### Returns:
|
||||
* `PycordMember`: Member in database representation.
|
||||
"""
|
||||
|
||||
return await PycordMember.find(id, guild)
|
||||
|
||||
async def close(self, *args: Any, **kwargs: Any) -> None:
|
||||
await self.client_session.close()
|
||||
|
||||
if self.scheduler is not None:
|
||||
self.scheduler.shutdown()
|
||||
|
||||
await super().close(*args, **kwargs)
|
36
classes/pycordcheck.py
Normal file
36
classes/pycordcheck.py
Normal file
@ -0,0 +1,36 @@
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from bson import ObjectId
|
||||
from bson.regex import Regex
|
||||
|
||||
from modules.database import col_checks
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PycordCheck:
|
||||
"""Dataclass of DB entry of a security check"""
|
||||
|
||||
__slots__ = (
|
||||
"_id",
|
||||
"guild",
|
||||
"thread_id",
|
||||
"member",
|
||||
"date_created",
|
||||
"date_modified",
|
||||
"challenge",
|
||||
"answers",
|
||||
)
|
||||
|
||||
_id: ObjectId
|
||||
guild: ObjectId
|
||||
thread_id: int
|
||||
member: ObjectId
|
||||
date_created: datetime
|
||||
date_modified: datetime
|
||||
challenge: str
|
||||
answers: List[Regex]
|
9
classes/pycordguild_colors.py
Normal file
9
classes/pycordguild_colors.py
Normal file
@ -0,0 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class PycordGuildColors:
|
||||
default: str
|
||||
success: str
|
||||
warning: str
|
||||
error: str
|
85
classes/pycordmember.py
Normal file
85
classes/pycordmember.py
Normal file
@ -0,0 +1,85 @@
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal, Union
|
||||
|
||||
from bson import ObjectId
|
||||
from discord import Thread
|
||||
|
||||
from classes.enums import MemberStatus
|
||||
from classes.errors import MemberNotFoundError
|
||||
from classes.pycordcheck import PycordCheck
|
||||
from modules.database import col_members
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PycordMember:
|
||||
"""Dataclass of DB entry of a member"""
|
||||
|
||||
__slots__ = ("_id", "id", "guild", "status")
|
||||
|
||||
_id: ObjectId
|
||||
id: int
|
||||
guild: ObjectId
|
||||
status: Literal[
|
||||
MemberStatus.VERIFIED,
|
||||
MemberStatus.UNVERIFIED,
|
||||
MemberStatus.FAILED,
|
||||
MemberStatus.ADDITIONAL,
|
||||
]
|
||||
|
||||
@classmethod
|
||||
async def find(cls, id: Union[int, ObjectId], guild: ObjectId):
|
||||
"""Find a member in a database.
|
||||
|
||||
### Args:
|
||||
* id (`Union[int, ObjectId]`): Member's Discord ID
|
||||
* guild (`ObjectId`): Discord guild's database ID
|
||||
|
||||
### Raises:
|
||||
* `MemberNotFoundError`: Raised when member entry after insertion could not be found.
|
||||
|
||||
### Returns:
|
||||
* `PycordMember`: Member with its database data.
|
||||
"""
|
||||
db_entry = await col_members.find_one(
|
||||
(
|
||||
{"id": id, "guild": guild}
|
||||
if isinstance(id, int)
|
||||
else {"_id": id, "guild": guild}
|
||||
)
|
||||
)
|
||||
|
||||
if db_entry is None:
|
||||
raise MemberNotFoundError(id, guild)
|
||||
|
||||
return cls(**db_entry)
|
||||
|
||||
@classmethod
|
||||
async def create(
|
||||
cls,
|
||||
id: int,
|
||||
guild: ObjectId,
|
||||
status: Literal[
|
||||
MemberStatus.VERIFIED,
|
||||
MemberStatus.UNVERIFIED,
|
||||
MemberStatus.FAILED,
|
||||
MemberStatus.ADDITIONAL,
|
||||
],
|
||||
):
|
||||
pass
|
||||
|
||||
async def get_check(self, guild: ObjectId) -> PycordCheck:
|
||||
pass
|
||||
|
||||
async def set_status(
|
||||
self,
|
||||
status: Literal[
|
||||
MemberStatus.VERIFIED,
|
||||
MemberStatus.UNVERIFIED,
|
||||
MemberStatus.FAILED,
|
||||
MemberStatus.ADDITIONAL,
|
||||
],
|
||||
) -> Union[Thread, None]:
|
||||
pass
|
@ -1,260 +1,38 @@
|
||||
{
|
||||
"token": "",
|
||||
"locale": "en",
|
||||
"debug": false,
|
||||
"guild": 0,
|
||||
"admins": [],
|
||||
"channels": {
|
||||
"nsfw": {
|
||||
"access": 0,
|
||||
"ass": 0,
|
||||
"ass_2d": 0,
|
||||
"tits": 0,
|
||||
"tits_2d": 0
|
||||
},
|
||||
"verification": {
|
||||
"captcha": 0,
|
||||
"captcha_log": 0,
|
||||
"verification": 0,
|
||||
"additional_verification": 0
|
||||
},
|
||||
"general": {
|
||||
"chat": 0,
|
||||
"art": 0
|
||||
"bot": {
|
||||
"owners": [
|
||||
0
|
||||
],
|
||||
"debug_guilds": [
|
||||
0
|
||||
],
|
||||
"bot_token": "",
|
||||
"status": {
|
||||
"enabled": true,
|
||||
"activity_type": 0,
|
||||
"activity_text": "The Game Of Life"
|
||||
}
|
||||
},
|
||||
"roles": {
|
||||
"nsfw": 0,
|
||||
"admin": 0,
|
||||
"verified": 0,
|
||||
"failed_captcha": 0,
|
||||
"additional_verification": 0
|
||||
"database": {
|
||||
"user": null,
|
||||
"password": null,
|
||||
"host": "127.0.0.1",
|
||||
"port": 27017,
|
||||
"name": "javelina"
|
||||
},
|
||||
"msg": {
|
||||
"denied": "Команду можуть виконувати лише адміністратори",
|
||||
"denied_guild": "Команда працює лише на сервері Crue-11 Raise"
|
||||
},
|
||||
"auto_nsfw": [
|
||||
{
|
||||
"channel": 0,
|
||||
"booru": "3d",
|
||||
"tags": "ass",
|
||||
"limit": 60
|
||||
},
|
||||
{
|
||||
"channel": 0,
|
||||
"booru": "3d",
|
||||
"tags": "boobs",
|
||||
"limit": 60
|
||||
},
|
||||
{
|
||||
"channel": 0,
|
||||
"booru": "2d",
|
||||
"tags": "ass",
|
||||
"limit": 60
|
||||
},
|
||||
{
|
||||
"channel": 0,
|
||||
"booru": "2d",
|
||||
"tags": "boobs",
|
||||
"limit": 60
|
||||
"modules": {
|
||||
"captcha": {
|
||||
"challenges": [
|
||||
{
|
||||
"question": "Sample Question",
|
||||
"answers": [
|
||||
"sample answer"
|
||||
]
|
||||
}
|
||||
],
|
||||
"blacklist": []
|
||||
}
|
||||
],
|
||||
"forbidden_replies": [
|
||||
"русский военный корабль, иди нахуй"
|
||||
],
|
||||
"forbidden_answers": [
|
||||
"славароссии",
|
||||
"славаросии",
|
||||
"славаросси",
|
||||
"славаросії",
|
||||
"славарф",
|
||||
"славаросеи",
|
||||
"пошёлтынахуй",
|
||||
"пошёлнахуй",
|
||||
"пошелнахуй",
|
||||
"идинах",
|
||||
"пошелтынахуй",
|
||||
"славапутину",
|
||||
"славасоветскомусоюзу",
|
||||
"славассср",
|
||||
"путинбог",
|
||||
"путінбог",
|
||||
"говно",
|
||||
"хуйня",
|
||||
"хуй",
|
||||
"славапутіну"
|
||||
],
|
||||
"captchas": [
|
||||
{
|
||||
"question": "Як умру",
|
||||
"answer": [
|
||||
"то поховайте"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Хіба ревуть воли",
|
||||
"answer": [
|
||||
"як ясла повні"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Слуга",
|
||||
"answer": [
|
||||
"народу"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Олені, Олені",
|
||||
"answer": [
|
||||
"небриті і неголені"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "У всякого своя доля",
|
||||
"answer": [
|
||||
"І свій шлях широкий"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Хто ти, човне? Що шукаєш?",
|
||||
"answer": [
|
||||
"Відки і куди пливеш",
|
||||
"Звідки і куди пливеш",
|
||||
"Відки й куди пливеш",
|
||||
"Звідки й куди пливеш"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Доброго вечора",
|
||||
"answer": [
|
||||
"Ми з України",
|
||||
"Ми з Украіни"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Душу й тіло ми положим",
|
||||
"answer": [
|
||||
"за нашу свободу"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Згинуть наші вороженьки",
|
||||
"answer": [
|
||||
"як роса на сонці"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Садок вишневий",
|
||||
"answer": [
|
||||
"коло хати"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Ой, хто п'є",
|
||||
"answer": [
|
||||
"Тому наливайте"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Хто не п'є",
|
||||
"answer": [
|
||||
"Тому не давайте"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Ой Житомир",
|
||||
"answer": [
|
||||
"це не місто не село",
|
||||
"то не місто не село"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Файне місто",
|
||||
"answer": [
|
||||
"Тернопіль"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Хто покаже в чарці дно",
|
||||
"answer": [
|
||||
"Тому щастя і добро",
|
||||
"Тому щастя й добро"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Батько наш Бандера",
|
||||
"answer": [
|
||||
"Україна мати",
|
||||
"Україна - мати",
|
||||
"Украіна мати",
|
||||
"Украіна - мати",
|
||||
"Україна – мати",
|
||||
"Украіна – мати",
|
||||
"Україна — мати",
|
||||
"Украіна — мати"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Ми за Україну",
|
||||
"answer": [
|
||||
"підем воювати",
|
||||
"будем воювати"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Зродились ми",
|
||||
"answer": [
|
||||
"великої години",
|
||||
"великої годинки"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Ах, Бандеро",
|
||||
"answer": [
|
||||
"Український апостол",
|
||||
"Украінський апостол",
|
||||
"Тобі жилось непросто",
|
||||
"Народний наш герой"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Той мурує",
|
||||
"answer": [
|
||||
"той руйнує"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Як умру то поховайте",
|
||||
"answer": [
|
||||
"мене на могилі"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Серед степу широкого",
|
||||
"answer": [
|
||||
"На Вкраїні милій",
|
||||
"На Вкраіні милій"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Щоб лани широкополі",
|
||||
"answer": [
|
||||
"І Дніпро, і кручі",
|
||||
"І Дніпро і кручі"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Ой у лузі",
|
||||
"answer": [
|
||||
"Червона калина"
|
||||
]
|
||||
},
|
||||
{
|
||||
"question": "Чогось наша славна Україна",
|
||||
"answer": [
|
||||
"зажурилася",
|
||||
"зажурилась"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
6
dsbot.py
6
dsbot.py
@ -1,6 +0,0 @@
|
||||
@client.slash_command(name="link", description="Connect to your AutoZoom")
|
||||
async def nazi(ctx: discord.ApplicationContext, code: discord.Option(str, "Code you got in AutoZoom app")):
|
||||
|
||||
|
||||
|
||||
client.run(getConfig("token"))
|
593
glorybot.py
593
glorybot.py
@ -1,593 +0,0 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from random import choice
|
||||
import traceback
|
||||
from typing import List
|
||||
import discord, ujson
|
||||
import os
|
||||
|
||||
from modules.booruGet import booruGet
|
||||
|
||||
from discord import Embed, ButtonStyle, ApplicationContext, Option # type: ignore
|
||||
|
||||
#from discord_slash import SlashCommand, SlashContext
|
||||
|
||||
intents = discord.Intents().all()
|
||||
client = discord.Bot(intents=intents)
|
||||
|
||||
# Technical ==============================================================================================================
|
||||
def nowtime():
|
||||
return datetime.now().strftime("%d.%m.%Y | %H:%M:%S")
|
||||
|
||||
def logWrite(message):
|
||||
print(f"[{nowtime()}] {message}")
|
||||
|
||||
def jsonSave(filename, value):
|
||||
with open(filename, 'w', encoding="utf-8") as f:
|
||||
f.write(ujson.dumps(value, indent=4, ensure_ascii=False))
|
||||
|
||||
def jsonLoad(filename):
|
||||
with open(filename, 'r', encoding="utf-8") as f:
|
||||
value = ujson.loads(f.read())
|
||||
return value
|
||||
#=========================================================================================================================
|
||||
|
||||
|
||||
# Configuration ==========================================================================================================
|
||||
def configGet(key: str, *args: str):
|
||||
this_dict = jsonLoad("config.json")
|
||||
this_key = this_dict
|
||||
for dict_key in args:
|
||||
this_key = this_key[dict_key]
|
||||
return this_key[key]
|
||||
|
||||
def configSet(key, value):
|
||||
config = jsonLoad("config.json")
|
||||
config[key] = value
|
||||
jsonSave("config.json", config)
|
||||
#=========================================================================================================================
|
||||
|
||||
|
||||
# Discord Utils ==========================================================================================================
|
||||
def getChan(channels, id):
|
||||
return discord.utils.get(channels, id=id)
|
||||
|
||||
async def rmMsg(channel_id, message_id):
|
||||
try:
|
||||
channel = client.get_channel(channel_id)
|
||||
message = await channel.fetch_message(message_id)
|
||||
await message.delete()
|
||||
except:
|
||||
pass
|
||||
|
||||
def makeEmbed(title="", description="", footer="", image=None, color=0xffffff):
|
||||
embed=Embed(title=title, description=description, color=color)
|
||||
if footer is not None:
|
||||
embed.set_footer(text=footer)
|
||||
if image is not None:
|
||||
embed.set_image(url=image)
|
||||
return embed
|
||||
|
||||
async def is_correct_answer(answer: str, correct: List[str]) -> bool:
|
||||
for entry in correct:
|
||||
if (answer.lower().replace(" ", "").replace(",", "").replace(".", "").replace("–", "-").replace("—", "-")).startswith(entry.lower().replace(" ", "")):
|
||||
return True
|
||||
return False
|
||||
#=========================================================================================================================
|
||||
|
||||
|
||||
# Booru Function =========================================================================================================
|
||||
async def booruAuto(channel, booru, tags, limit):
|
||||
try:
|
||||
output = await booruGet(booru, tags, limit=limit)
|
||||
if output["kind"] == "image" and output["error"] == "":
|
||||
await channel.send(
|
||||
embed=makeEmbed(image=output["image"], footer=f'Теги: {output["tags"]}', color=0x2400e8),
|
||||
view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Джерело Фото", url=output["source"]))
|
||||
)
|
||||
elif output["kind"] == "video" and output["thumbnail"] != "":
|
||||
await channel.send(
|
||||
embed=makeEmbed(image=output["thumbnail"], footer=f'Теги: {output["tags"]}', color=0x2400e8),
|
||||
view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Дивитись Відео", url=output["source"]))
|
||||
)
|
||||
except:
|
||||
# traceback.print_exc()
|
||||
pass
|
||||
|
||||
async def booruCommand(ctx, booru, tags, limit, page, times):
|
||||
for _ in range(times):
|
||||
try:
|
||||
output = await booruGet(booru, tags, limit=limit, page=page)
|
||||
if output["kind"] == "image" and output["error"] == "":
|
||||
await ctx.respond(
|
||||
embed=makeEmbed(image=output["image"], footer=f'Теги: {output["tags"]}', color=0x2400e8),
|
||||
view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Джерело Фото", url=output["source"]))
|
||||
)
|
||||
elif output["kind"] == "video" and output["thumbnail"] != "":
|
||||
await ctx.respond(
|
||||
embed=makeEmbed(image=output["thumbnail"], footer=f'Теги: {output["tags"]}', color=0x2400e8),
|
||||
view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Дивитись Відео", url=output["source"]))
|
||||
)
|
||||
else:
|
||||
traceback.print_exc()
|
||||
if configGet("debug"):
|
||||
await ctx.respond(embed=makeEmbed(image=output["image"], footer="Exception: "+output["error"], color=0xf74b3a))
|
||||
else:
|
||||
await ctx.respond(embed=makeEmbed(image=output["image"], color=0xf74b3a))
|
||||
except:
|
||||
# traceback.print_exc()
|
||||
pass
|
||||
await asyncio.sleep(.25)
|
||||
#=========================================================================================================================
|
||||
|
||||
# Auto Nudes Sender ======================================================================================================
|
||||
async def sendNudes():
|
||||
|
||||
await client.wait_until_ready()
|
||||
guild = client.get_guild(configGet("guild"))
|
||||
|
||||
while True:
|
||||
for entry in configGet("auto_nsfw"):
|
||||
await booruAuto(getChan(guild.channels, entry["channel"]), entry["booru"], entry["tags"], entry["limit"])
|
||||
await asyncio.sleep(.25)
|
||||
await asyncio.sleep(60)
|
||||
#=========================================================================================================================
|
||||
|
||||
# @client.slash_command(name="autonsfw", description="2д пікча з бордів за тегом")
|
||||
# async def autonsfw(
|
||||
# ctx: ApplicationContext,
|
||||
# booru: Option(str, "Назва booru сервісу", choices=["realbooru", "yandere", "danbooru", "konachan", "rule34"]), # type: ignore
|
||||
# tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
# limit: Option(int, "Сторінки (Кількість зображень/сторінку) (20 якщо не задано)", required=False, default=20), # type: ignore
|
||||
# page: Option(int, "Номер сторінки результатів (Рандомна якщо не задано)", required=False, default=None), # type: ignore
|
||||
# cooldown: Option(int, "Затримка між запитами", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
# ):
|
||||
# await booruCommand(ctx, "2d", tags, limit, page, times)
|
||||
|
||||
# NSFW Commands ==========================================================================================================
|
||||
nsfw = client.create_group("nsfw", "Команди з відвертим вмістом")
|
||||
|
||||
@nsfw.command(name="2d", description="2д пікча з бордів за тегом")
|
||||
async def nsfw_2d(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "2d", tags, limit, page, times)
|
||||
|
||||
@nsfw.command(name="3d", description="3д пікча з бордів за тегом")
|
||||
async def nsfw_3d(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "3d", tags, limit, page, times)
|
||||
|
||||
@nsfw.command(name="yandere", description="Пікча з yande.re за тегом")
|
||||
async def nsfw_yandere(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "yandere", tags, limit, page, times)
|
||||
|
||||
@nsfw.command(name="konachan", description="Пікча з konachan.com за тегом")
|
||||
async def nsfw_konachan(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "konachan", tags, limit, page, times)
|
||||
|
||||
@nsfw.command(name="danbooru", description="Пікча з danbooru.donmai.us за тегом")
|
||||
async def nsfw_danbooru(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "danbooru", tags, limit, page, times)
|
||||
|
||||
@nsfw.command(name="rule34", description="Пікча rule34.xxx за тегом")
|
||||
async def nsfw_rule34(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "rule34", tags, limit, page, times)
|
||||
|
||||
@nsfw.command(name="realbooru", description="Пікча з realbooru.com за тегом")
|
||||
async def nsfw_realbooru(
|
||||
ctx: ApplicationContext,
|
||||
tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore
|
||||
limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore
|
||||
page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore
|
||||
times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore
|
||||
):
|
||||
await booruCommand(ctx, "realbooru", tags, limit, page, times)
|
||||
#=========================================================================================================================
|
||||
|
||||
|
||||
async def pidozra(ctx, user, reason="Не вказана"):
|
||||
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
if str(user.id) not in userdata["dms"]:
|
||||
captcha = choice(configGet("captchas"))
|
||||
userdata["dms"][str(user.id)] = {}
|
||||
userdata["dms"][str(user.id)]["captcha"] = captcha
|
||||
else:
|
||||
captcha = userdata["dms"][str(user.id)]["captcha"]
|
||||
|
||||
logWrite(f"User {user.name}#{user.discriminator} manually sent to verification due to '{reason}' (q: '{captcha['question']}' a: {str(captcha['answer'])})")
|
||||
|
||||
try:
|
||||
sent_msg = await user.send(content=f"{user.mention} Вибачте, але вам потрібно пройти невеличкий тест для продовження користування сервером Crue-11 Raise\n\n**{captcha['question']} ...**\n\n```\nПродовжіть речення або надішліть правильну відповідь щоб пройти перевірку\n```")
|
||||
if not isinstance(ctx, discord.Message):
|
||||
await ctx.respond(content=f"Юзеру `{user.name}#{user.discriminator}` оголешно про підозру")
|
||||
except Exception as exp:
|
||||
if not isinstance(ctx, discord.Message):
|
||||
await ctx.respond(content=f"Не вдалось оголосити `{user.name}#{user.discriminator}` про підозру:\n`{exp}`")
|
||||
return
|
||||
|
||||
|
||||
await getChan(user.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="❓ Відправлено на перевірку", description=f"**Ім'я:** `{user.name}#{user.discriminator}`\n**Причина:** `{reason}`\n**Питання:** `{captcha['question']}`\n**Відповіді:** `{str(captcha['answer'])}`", color=0x6996e4))
|
||||
|
||||
await user.remove_roles(getChan(user.guild.roles, configGet("verified", "roles")))
|
||||
await user.add_roles(getChan(user.guild.roles, configGet("additional_verification", "roles")))
|
||||
|
||||
userdata["dms"][str(user.id)]["question_id"] = sent_msg.id
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
|
||||
|
||||
@client.event
|
||||
async def on_ready():
|
||||
|
||||
print(f"Logged in as {client.user}")
|
||||
await client.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name="Гімн України"))
|
||||
await sendNudes()
|
||||
|
||||
# Guild Commands =========================================================================================================
|
||||
@client.slash_command(name="verify", description="Підтвердити що юзер не московит")
|
||||
async def verify(ctx: ApplicationContext, user: Option(discord.User, "Юзер сервера")): # type: ignore
|
||||
|
||||
if ctx.author.id in configGet("admins"):
|
||||
|
||||
if ctx.guild is not None:
|
||||
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
logWrite(f"User {user.name}#{user.discriminator} verified by admin {ctx.author.name}#{ctx.author.discriminator}")
|
||||
|
||||
await ctx.respond(content=f"{user.mention} Ласкаво просимо!\nУ вас тепер є повний доступ до всього сервера. Приємного спілкування!", delete_after=3)
|
||||
|
||||
await user.add_roles(getChan(user.guild.roles, configGet("verified", "roles")))
|
||||
|
||||
await getChan(user.guild.channels, configGet("chat", "channels", "general")).send(content=f"У нас поповнення у вигляді {user.mention}. Познайомтесь :)")
|
||||
|
||||
await user.remove_roles(getChan(user.guild.roles, configGet("failed_captcha", "roles")))
|
||||
|
||||
await getChan(user.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="✅ Юзера верифіковано вручну", description=f"**Ім'я:** `{user.name}#{user.discriminator}`\n**Адмін**: `{ctx.author.name}#{ctx.author.discriminator}`", color=0xffc300))
|
||||
|
||||
try:
|
||||
del userdata[str(user.id)]
|
||||
jsonSave("data.json", userdata)
|
||||
except:
|
||||
pass
|
||||
|
||||
return
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied_guild", "msg"))
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied", "msg"))
|
||||
|
||||
@client.slash_command(name="pidozra", description="Оголосити юзеру про підозру")
|
||||
async def pidozra_cmd(ctx: ApplicationContext, user: Option(discord.User, "Юзер сервера"), reason: Option(str, "Причина", required=False, default="Не вказана")): # type: ignore
|
||||
|
||||
if ctx.author.id in configGet("admins"):
|
||||
if ctx.guild is not None:
|
||||
await pidozra(ctx, user, reason=reason)
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied_guild", "msg"))
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied", "msg"))
|
||||
|
||||
@client.slash_command(name="nazi", description="Денацифікувати обраного московита")
|
||||
async def nazi(ctx: ApplicationContext, user: Option(discord.User, "Обраний московит")): # type: ignore
|
||||
|
||||
if ctx.author.id in configGet("admins"):
|
||||
|
||||
if ctx.guild is not None:
|
||||
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
logWrite(f"User {user.name}#{user.discriminator} was sent to russian warship by {ctx.author.name}#{ctx.author.discriminator}")
|
||||
|
||||
await ctx.respond(content=f"{user.mention} {choice(configGet('forbidden_replies'))}", delete_after=4)
|
||||
|
||||
await asyncio.sleep(3)
|
||||
|
||||
await user.ban(reason="Московит йобаний", delete_message_days=3)
|
||||
|
||||
await getChan(user.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзера послано нахуй", description=f"**Ім'я:** `{user.name}#{user.discriminator}`\n**Адмін:** `{ctx.author.name}#{ctx.author.discriminator}`", color=0xea3319))
|
||||
|
||||
try:
|
||||
del userdata[str(user.id)]
|
||||
jsonSave("data.json", userdata)
|
||||
except:
|
||||
pass
|
||||
|
||||
return
|
||||
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied_guild", "msg"))
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied", "msg"))
|
||||
#=========================================================================================================================
|
||||
|
||||
|
||||
# Utility Commands =======================================================================================================
|
||||
@client.slash_command(name="debug", description="Переключити режим відлагодження")
|
||||
async def debug(ctx: ApplicationContext, value: Option(bool, "Стан режиму")): # type: ignore
|
||||
|
||||
if ctx.author.id in configGet("admins"):
|
||||
configSet("debug", value)
|
||||
logWrite(f"User {ctx.author.name}#{ctx.author.discriminator} set debug mode to {str(value)}")
|
||||
await ctx.respond(content=f"Режим відлагодження змінено на `{str(value)}`")
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied", "msg"))
|
||||
|
||||
@client.slash_command(name="reboot", description="Перезапустити бота")
|
||||
async def reboot(ctx: ApplicationContext):
|
||||
|
||||
if ctx.author.id in configGet("admins"):
|
||||
logWrite(f"User {ctx.author.name}#{ctx.author.discriminator} called reboot")
|
||||
await ctx.respond(content=f"Вимикаюсь з номером процесу `{os.getpid()}`")
|
||||
os.system(f"kill -9 {os.getpid()}")
|
||||
else:
|
||||
await ctx.respond(content=configGet("denied", "msg"))
|
||||
#=========================================================================================================================
|
||||
|
||||
|
||||
# Discord Events =========================================================================================================
|
||||
@client.event
|
||||
async def on_member_join(member):
|
||||
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
if str(member.id) not in userdata:
|
||||
captcha = choice(configGet("captchas"))
|
||||
userdata[str(member.id)] = {}
|
||||
userdata[str(member.id)]["captcha"] = captcha
|
||||
else:
|
||||
captcha = userdata[str(member.id)]["captcha"]
|
||||
|
||||
logWrite(f"User {member.name}#{member.discriminator} joined with (q: '{captcha['question']}' a: {str(captcha['answer'])})")
|
||||
|
||||
await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🆕 Юзер зайшов", description=f"**Ім'я:** `{member.name}#{member.discriminator}`\n**Питання:** `{captcha['question']}`\n**Відповіді:** `{str(captcha['answer'])}`", color=0x6996e4))
|
||||
await asyncio.sleep(3)
|
||||
|
||||
sent_msg = await getChan(member.guild.channels, configGet("captcha", "channels", "verification")).send(content=f"{member.mention} Ласкаво просимо!\n\n**{captcha['question']} ...**\n\n```\nПродовжіть речення або надішліть правильну відповідь щоб пройти перевірку\n```", delete_after=1800)
|
||||
|
||||
userdata[str(member.id)]["question_id"] = sent_msg.id
|
||||
jsonSave("data.json", userdata)
|
||||
|
||||
await asyncio.sleep(300)
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
if str(member.id) in userdata:
|
||||
try:
|
||||
logWrite(f"User {member.name}#{member.discriminator} ignored verification (q: '{userdata[str(member.id)]['captcha']['question']}' a: {str(userdata[str(member.id)]['captcha']['answer'])})")
|
||||
await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🔇 Юзер проігнорував тест", description=f"**Ім'я:** `{member.name}#{member.discriminator}`\n**Питання:** `{userdata[str(member.id)]['captcha']['question']}`\n**Відповіді:** `{str(userdata[str(member.id)]['captcha']['answer'])}`", color=0xffc300))
|
||||
await getChan(member.guild.channels, configGet("captcha", "channels", "verification")).send(content=f"{member.mention} Тест проігноровано, до побачення", delete_after=4)
|
||||
await asyncio.sleep(3)
|
||||
await member.kick(reason="Ігнорування вступного тесту")
|
||||
del userdata[str(member.id)]
|
||||
jsonSave("data.json", userdata)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
@client.event
|
||||
async def on_member_remove(member):
|
||||
|
||||
logWrite(f"User {member.name}#{member.discriminator} left")
|
||||
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
if str(member.id) in userdata:
|
||||
|
||||
try:
|
||||
await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🚪 Юзер вийшов", description=f"**Ім'я:** `{member.name}#{member.discriminator}`\n**Питання:** `{userdata[str(member.id)]['question']}`\n**Відповіді:** `{str(userdata[str(member.id)]['answer'])}`", color=0x6996e4))
|
||||
except:
|
||||
await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🚪 Юзер вийшов", description=f"**Ім'я:** `{member.name}#{member.discriminator}`", color=0x6996e4))
|
||||
|
||||
if "question_id" in userdata[str(member.id)]:
|
||||
await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(member.id)]["question_id"])
|
||||
del userdata[str(member.id)]["question_id"]
|
||||
|
||||
if userdata[str(member.id)] == {}:
|
||||
del userdata[str(member.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
|
||||
@client.event
|
||||
async def on_raw_reaction_add(payload):
|
||||
if payload.channel_id == configGet("access", "channels", "nsfw"):
|
||||
if str(payload.emoji) == "✅":
|
||||
logWrite(f"User {payload.member.name}#{payload.member.discriminator} gets NSFW role")
|
||||
await payload.member.add_roles(getChan(payload.member.guild.roles, configGet("nsfw", "roles")))
|
||||
|
||||
@client.event
|
||||
async def on_raw_reaction_remove(payload):
|
||||
user = discord.utils.get(client.get_all_members(), id=payload.user_id)
|
||||
if payload.channel_id == configGet("access", "channels", "nsfw"):
|
||||
if str(payload.emoji) == "✅":
|
||||
logWrite(f"User {user.name}#{user.discriminator} lost NSFW role")
|
||||
await user.remove_roles(getChan(user.guild.roles, configGet("nsfw", "roles")))
|
||||
|
||||
@client.event
|
||||
async def on_message(message):
|
||||
|
||||
userdata = jsonLoad("data.json")
|
||||
|
||||
if message.channel.id == configGet("art", "channels", "general"):
|
||||
|
||||
await message.add_reaction('🔺')
|
||||
await message.add_reaction('🔻')
|
||||
|
||||
thread = await message.create_thread(name=f"{message.author.name} ({datetime.now().strftime('%d.%m.%Y')})", auto_archive_duration=10080)
|
||||
await thread.send(content="**Гілку для коментарів створено!**\nНадсилайте коментарі до цієї роботи/фотографії користуючись гілкою.")
|
||||
|
||||
elif message.channel.id == configGet("captcha", "channels", "verification"):
|
||||
|
||||
if message.author != client.user:
|
||||
|
||||
if await is_correct_answer(message.content, userdata[str(message.author.id)]["captcha"]["answer"]):
|
||||
|
||||
logWrite(f"User {message.author.name}#{message.author.discriminator} verified")
|
||||
|
||||
await message.reply(content=f"{message.author.mention} Ласкаво просимо!\nУ вас тепер є повний доступ до всього сервера. Приємного спілкування!", delete_after=3)
|
||||
|
||||
await message.delete()
|
||||
await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(message.author.id)]["question_id"])
|
||||
|
||||
await message.author.add_roles(getChan(message.guild.roles, configGet("verified", "roles")))
|
||||
|
||||
await getChan(message.author.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="✅ Юзера верифіковано", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata[str(message.author.id)]['captcha']['question']}`\n**Відповіді:** `{str(userdata[str(message.author.id)]['captcha']['answer'])}`", color=0xffc300))
|
||||
|
||||
await getChan(message.author.guild.channels, configGet("chat", "channels", "general")).send(content=f"У нас поповнення у вигляді {message.author.mention}. Познайомтесь :)")
|
||||
|
||||
del userdata[str(message.author.id)]["captcha"]
|
||||
del userdata[str(message.author.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
return
|
||||
|
||||
if message.content.lower().replace(" ", "") in configGet("forbidden_answers"):
|
||||
|
||||
logWrite(f"User {message.author.name}#{message.author.discriminator} was piece of shit and replied '{message.content}'")
|
||||
|
||||
await message.reply(content=f"{message.author.mention} {choice(configGet('forbidden_replies'))}", delete_after=4)
|
||||
|
||||
await message.delete()
|
||||
await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(message.author.id)]["question_id"])
|
||||
|
||||
await asyncio.sleep(3)
|
||||
|
||||
await message.author.ban(reason="Московит йобаний", delete_message_days=1)
|
||||
|
||||
await getChan(message.author.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер руснявий виблядок", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata[str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata[str(message.author.id)]['captcha']['answer'])}`", color=0xea3319))
|
||||
|
||||
del userdata[str(message.author.id)]["captcha"]
|
||||
del userdata[str(message.author.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
return
|
||||
|
||||
else:
|
||||
|
||||
logWrite(f"User {message.author.name}#{message.author.discriminator} failed verification (q: '{userdata[str(message.author.id)]['captcha']['question']}' a: {str(userdata[str(message.author.id)]['captcha']['answer'])} replied: '{message.content}')")
|
||||
|
||||
await message.reply(content=f"{message.author.mention} відповідь неправильна!\nВідправляйтесь у канал {getChan(message.guild.channels, configGet('verification', 'channels', 'verification')).mention}", delete_after=3)
|
||||
await getChan(message.guild.channels, configGet("verification", "channels", "verification")).send(content=f"Користувач {message.author.mention} потребує перевірки {getChan(message.guild.roles, configGet('admin', 'roles')).mention}\n\nПитання: `{userdata[str(message.author.id)]['captcha']['question']}`\nВідповідь: `{str(userdata[str(message.author.id)]['captcha']['answer'])}`\n\nВідповів: `{message.content}`", delete_after=300)
|
||||
|
||||
await message.delete()
|
||||
await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(message.author.id)]["question_id"])
|
||||
await asyncio.sleep(1)
|
||||
|
||||
await message.author.add_roles(getChan(message.guild.roles, configGet("failed_captcha", "roles")))
|
||||
|
||||
await getChan(message.author.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер не пройшов", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata[str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata[str(message.author.id)]['captcha']['answer'])}`", color=0xea3319))
|
||||
|
||||
del userdata[str(message.author.id)]["captcha"]
|
||||
del userdata[str(message.author.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
return
|
||||
|
||||
elif isinstance(message.channel, discord.DMChannel) and str(message.author.id) in userdata["dms"]:
|
||||
|
||||
guild = client.get_guild(configGet("guild"))
|
||||
member = guild.get_member(message.author.id)
|
||||
|
||||
for answer in userdata["dms"][str(message.author.id)]["captcha"]["answer"]:
|
||||
|
||||
if answer.lower().replace(" ", "") in message.content.lower().replace(" ", "").replace(",", "").replace(".", ""):
|
||||
|
||||
logWrite(f"User {message.author.name}#{message.author.discriminator} additionally verified")
|
||||
|
||||
await message.reply(content=f"{message.author.mention} Ласкаво просимо!\nУ вас тепер є повний доступ до всього сервера. Приємного спілкування!")
|
||||
|
||||
#await rmMsg(message.channel.id, userdata["dms"][str(message.author.id)]["question_id"])
|
||||
|
||||
await member.add_roles(guild.get_role(configGet("verified", "roles")))
|
||||
await member.remove_roles(guild.get_role(configGet("additional_verification", "roles")))
|
||||
|
||||
await getChan(guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="✅ Юзера додатково верифіковано", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata['dms'][str(message.author.id)]['captcha']['question']}`\n**Відповіді:** `{str(userdata['dms'][str(message.author.id)]['captcha']['answer'])}`", color=0xffc300))
|
||||
|
||||
del userdata["dms"][str(message.author.id)]["captcha"]
|
||||
del userdata["dms"][str(message.author.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
return
|
||||
|
||||
if message.content.lower().replace(" ", "") in configGet("forbidden_answers"):
|
||||
|
||||
logWrite(f"User {message.author.name}#{message.author.discriminator} was piece of shit and replied '{message.content}'")
|
||||
|
||||
await message.reply(content=f"{choice(configGet('forbidden_replies'))}")
|
||||
|
||||
await rmMsg(message.channel.id, userdata["dms"][str(message.author.id)]["question_id"])
|
||||
|
||||
await member.ban(reason="Московит йобаний", delete_message_days=7)
|
||||
|
||||
await getChan(guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер руснявий виблядок", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata['dms'][str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata['dms'][str(message.author.id)]['captcha']['answer'])}`", color=0xea3319))
|
||||
|
||||
del userdata["dms"][str(message.author.id)]["captcha"]
|
||||
del userdata["dms"][str(message.author.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
return
|
||||
|
||||
else:
|
||||
|
||||
logWrite(f"User {message.author.name}#{message.author.discriminator} failed verification (q: '{userdata['dms'][str(message.author.id)]['captcha']['question']}' a: {str(userdata['dms'][str(message.author.id)]['captcha']['answer'])} replied: '{message.content}')")
|
||||
|
||||
await message.reply(content=f"{message.author.mention} відповідь неправильна!\nВідправляйтесь у канал {getChan(guild.channels, configGet('verification', 'channels', 'verification')).mention}")
|
||||
await getChan(guild.channels, configGet("verification", "channels", "verification")).send(content=f"Користувач {message.author.mention} потребує перевірки {getChan(guild.roles, configGet('admin_id')).mention}", delete_after=300)
|
||||
|
||||
await rmMsg(message.channel.id, userdata["dms"][str(message.author.id)]["question_id"])
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
await member.add_roles(guild.get_role(configGet("failed_captcha", "roles")))
|
||||
await member.remove_roles(guild.get_role(configGet("additional_verification", "roles")))
|
||||
|
||||
await getChan(guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер не пройшов", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata['dms'][str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata['dms'][str(message.author.id)]['captcha']['answer'])}`", color=0xea3319))
|
||||
|
||||
del userdata["dms"][str(message.author.id)]["captcha"]
|
||||
del userdata["dms"][str(message.author.id)]
|
||||
|
||||
jsonSave("data.json", userdata)
|
||||
return
|
||||
|
||||
if "🇷🇺" in message.content:
|
||||
|
||||
await pidozra(message, message.author, "Прапор московитів")
|
||||
await message.delete()
|
||||
return
|
||||
#=========================================================================================================================
|
||||
|
||||
client.run(configGet("token"))
|
35
locale/en.json
Normal file
35
locale/en.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"messages": {
|
||||
"welcome": {
|
||||
"morning": [
|
||||
"{0} Good morning and welcome! {1}",
|
||||
"{0} Доброго ранку та ласкаво просимо! {1}",
|
||||
"{0} Вітаннячко! Ласкаво просимо! {1}",
|
||||
"{0} Доброго ранку! Ласкаво просимо! {1}"
|
||||
],
|
||||
"midday": [
|
||||
"{0} Good day and welcome! {1}",
|
||||
"{0} Добридень! Ласкаво просимо! {1}",
|
||||
"{0} День добрий! Ласкаво просимо! {1}",
|
||||
"{0} Мої вітання! Ласкаво просимо! {1}",
|
||||
"{0} Здоровенькі були! Ласкаво просимо! {1}",
|
||||
"{0} Раді вітати вас! Ласкаво просимо! {1}",
|
||||
"{0} Доброго здоров’ячка! Ласкаво просимо! {1}"
|
||||
],
|
||||
"evening": [
|
||||
"{0} Good evening and welcome! {1}",
|
||||
"{0} Доброго вечора! Ласкаво просимо! {1}",
|
||||
"{0} Добривечір! Ласкаво просимо! {1}",
|
||||
"{0} Доброго вечора та ласкаво просимо! {1}",
|
||||
"{0} Добрий вечір та ласкаво просимо! {1}"
|
||||
],
|
||||
"night": [
|
||||
"{0} Good night and welcome! {1}",
|
||||
"{0} Здоровенькі були! Ласкаво просимо! {1}"
|
||||
],
|
||||
"unknown": [
|
||||
"{0} Hello and welcome! {1}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
35
locale/uk.json
Normal file
35
locale/uk.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"messages": {
|
||||
"welcome": {
|
||||
"morning": [
|
||||
"{0} Добрий ранок та ласкаво просимо! {1}",
|
||||
"{0} Доброго ранку та ласкаво просимо! {1}",
|
||||
"{0} Вітаннячко! Ласкаво просимо! {1}",
|
||||
"{0} Доброго ранку! Ласкаво просимо! {1}"
|
||||
],
|
||||
"midday": [
|
||||
"{0} Добрий день! Ласкаво просимо! {1}",
|
||||
"{0} Добридень! Ласкаво просимо! {1}",
|
||||
"{0} День добрий! Ласкаво просимо! {1}",
|
||||
"{0} Мої вітання! Ласкаво просимо! {1}",
|
||||
"{0} Здоровенькі були! Ласкаво просимо! {1}",
|
||||
"{0} Раді вітати вас! Ласкаво просимо! {1}",
|
||||
"{0} Доброго здоров’ячка! Ласкаво просимо! {1}"
|
||||
],
|
||||
"evening": [
|
||||
"{0} Добрий вечір! Ласкаво просимо! {1}",
|
||||
"{0} Доброго вечора! Ласкаво просимо! {1}",
|
||||
"{0} Добривечір! Ласкаво просимо! {1}",
|
||||
"{0} Доброго вечора та ласкаво просимо! {1}",
|
||||
"{0} Добрий вечір та ласкаво просимо! {1}"
|
||||
],
|
||||
"night": [
|
||||
"{0} Доброї ночі! Ласкаво просимо! {1}",
|
||||
"{0} Здоровенькі були! Ласкаво просимо! {1}"
|
||||
],
|
||||
"unknown": [
|
||||
"{0} Вітаннячко! Ласкаво просимо! {1}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
34
main.py
Normal file
34
main.py
Normal file
@ -0,0 +1,34 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from os import getpid
|
||||
|
||||
from discord import Intents
|
||||
from libbot import sync
|
||||
|
||||
from classes.pycordbot import PycordBot
|
||||
from modules.scheduler import scheduler
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG if sync.config_get("debug") else logging.INFO,
|
||||
format="%(name)s.%(funcName)s | %(levelname)s | %(message)s",
|
||||
datefmt="[%X]",
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def main():
|
||||
bot = PycordBot(scheduler=scheduler, intents=Intents.all())
|
||||
|
||||
bot.load_extension("cogs")
|
||||
|
||||
try:
|
||||
await bot.start(sync.config_get("bot_token", "bot"))
|
||||
except KeyboardInterrupt:
|
||||
logger.warning("Forcefully shutting down with PID %s...", getpid())
|
||||
await bot.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main())
|
4
migrate.py
Normal file
4
migrate.py
Normal file
@ -0,0 +1,4 @@
|
||||
from modules.migrator import migrate_database
|
||||
|
||||
|
||||
migrate_database()
|
0
migrations/.gitkeep
Normal file
0
migrations/.gitkeep
Normal file
@ -1,111 +0,0 @@
|
||||
import json
|
||||
import traceback
|
||||
import requests
|
||||
import webbrowser
|
||||
import random
|
||||
import asyncio
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
async def booruGet(booru, tags, page=None, limit=30):
|
||||
|
||||
try:
|
||||
|
||||
booru_list = ["realbooru", "yandere", "danbooru", "konachan", "rule34"]
|
||||
real_list = ["realbooru"]
|
||||
anime_list = ["yandere", "danbooru", "konachan"]
|
||||
|
||||
thumbnail = ""
|
||||
|
||||
if page is None:
|
||||
page = random.randint(0, 30)
|
||||
|
||||
if booru == "2d":
|
||||
booru = random.choice(anime_list)
|
||||
elif booru == "3d":
|
||||
booru = random.choice(real_list)
|
||||
elif booru == "random" or booru not in booru_list:
|
||||
booru = random.choice(booru_list)
|
||||
|
||||
if booru == "realbooru":
|
||||
|
||||
url = f"https://realbooru.com/index.php?page=dapi&s=post&q=index&limit={limit}&pid={page}&tags={tags}"
|
||||
base_url = "https://realbooru.com/images/"
|
||||
thumbnail_url = "https://realbooru.com/thumbnails/"
|
||||
|
||||
post = random.choice(ET.fromstring(requests.get(url).text))
|
||||
file_format = post.get("file_url").split(".")[-1]
|
||||
thumb_format = post.get("preview_url").split(".")[-1]
|
||||
md5 = post.get("md5")
|
||||
output = f"{md5[:2]}/{md5[2:4]}/{md5}.{file_format}"
|
||||
output_thumb = f"{md5[:2]}/{md5[2:4]}/thumbnail_{md5}.{thumb_format}"
|
||||
|
||||
image = source = base_url+output
|
||||
thumbnail = thumbnail_url+output_thumb
|
||||
|
||||
tags = post.get("tags")
|
||||
|
||||
elif booru == "yandere":
|
||||
|
||||
url = f"https://yande.re/post.json?limit={limit}&tags={tags}&page={page}"
|
||||
output = random.choice(json.loads(requests.get(url).text))
|
||||
|
||||
image = output["sample_url"]
|
||||
source = output["file_url"]
|
||||
|
||||
tags = output["tags"]
|
||||
|
||||
elif booru == "danbooru":
|
||||
|
||||
url = f"https://danbooru.donmai.us/posts.json?&page={page}&tags={tags}&limit={limit}"
|
||||
output = random.choice(json.loads(requests.get(url).text))
|
||||
|
||||
image = output["large_file_url"]
|
||||
source = output["file_url"]
|
||||
|
||||
tags = output["tag_string"]
|
||||
|
||||
elif booru == "konachan":
|
||||
|
||||
url = f"https://konachan.com/post.json?&page={page}&tags={tags}&limit={limit}"
|
||||
output = random.choice(json.loads(requests.get(url).text))
|
||||
|
||||
image = output["sample_url"]
|
||||
source = output["file_url"]
|
||||
|
||||
tags = output["tags"]
|
||||
|
||||
elif booru == "rule34":
|
||||
|
||||
url = f"https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&limit={limit}&pid={page}&tags={tags}&json=1"
|
||||
print(url)
|
||||
print(requests.get(url).json)
|
||||
output = random.choice(json.loads(requests.get(url).json))
|
||||
|
||||
image = output["sample_url"]
|
||||
source = output["file_url"]
|
||||
|
||||
tags = output["tags"]
|
||||
|
||||
if (".jpg" in image) or (".png" in image) or (".webp" in image) or (".jpeg" in image) or (".gif" in image):
|
||||
kind = "image"
|
||||
else:
|
||||
kind = "video"
|
||||
|
||||
return {"image": image, "thumbnail": thumbnail, "source": source, "kind": kind, "tags": tags.strip(), "error": ""}
|
||||
|
||||
except IndexError:
|
||||
|
||||
return {"image": "http://res.end-play.xyz/discord/invalid.jpg", "thumbnail": "", "source": "N/A", "kind": "image", "tags": "", "error": "Found page with such tags is empty.\nDecrease images limit or page number and try again."}
|
||||
|
||||
except Exception as exp:
|
||||
|
||||
return {"image": "http://res.end-play.xyz/discord/invalid.jpg", "thumbnail": "", "source": "N/A", "kind": "image", "tags": "", "error": str(traceback.format_exc())}
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
booru = input("Input booru: ")
|
||||
tags = input("Input tags: ")
|
||||
|
||||
url = asyncio.run(booruGet(booru, tags))
|
||||
print(url)
|
||||
webbrowser.open(url["image"])
|
28
modules/database.py
Normal file
28
modules/database.py
Normal file
@ -0,0 +1,28 @@
|
||||
"""Module that provides all database collections"""
|
||||
|
||||
from typing import Any, Mapping
|
||||
|
||||
from async_pymongo import AsyncClient, AsyncCollection, AsyncDatabase
|
||||
from libbot.sync import config_get
|
||||
|
||||
db_config: Mapping[str, Any] = config_get("database")
|
||||
|
||||
if db_config["user"] is not None and db_config["password"] is not None:
|
||||
con_string = "mongodb://{0}:{1}@{2}:{3}/{4}".format(
|
||||
db_config["user"],
|
||||
db_config["password"],
|
||||
db_config["host"],
|
||||
db_config["port"],
|
||||
db_config["name"],
|
||||
)
|
||||
else:
|
||||
con_string = "mongodb://{0}:{1}/{2}".format(
|
||||
db_config["host"], db_config["port"], db_config["name"]
|
||||
)
|
||||
|
||||
db_client = AsyncClient(con_string)
|
||||
db: AsyncDatabase = db_client.get_database(name=db_config["name"])
|
||||
|
||||
col_guilds: AsyncCollection = db.get_collection("guilds")
|
||||
col_checks: AsyncCollection = db.get_collection("checks")
|
||||
col_members: AsyncCollection = db.get_collection("members")
|
22
modules/migrator.py
Normal file
22
modules/migrator.py
Normal file
@ -0,0 +1,22 @@
|
||||
from typing import Any, Mapping
|
||||
|
||||
from libbot.sync import config_get
|
||||
from mongodb_migrations.cli import MigrationManager
|
||||
from mongodb_migrations.config import Configuration
|
||||
|
||||
|
||||
def migrate_database() -> None:
|
||||
"""Apply migrations from folder `migrations/` to the database"""
|
||||
db_config: Mapping[str, Any] = config_get("database")
|
||||
|
||||
manager_config = Configuration(
|
||||
{
|
||||
"mongo_host": db_config["host"],
|
||||
"mongo_port": db_config["port"],
|
||||
"mongo_database": db_config["name"],
|
||||
"mongo_username": db_config["user"],
|
||||
"mongo_password": db_config["password"],
|
||||
}
|
||||
)
|
||||
manager = MigrationManager(manager_config)
|
||||
manager.run()
|
3
modules/scheduler.py
Normal file
3
modules/scheduler.py
Normal file
@ -0,0 +1,3 @@
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
|
||||
scheduler = AsyncIOScheduler()
|
@ -1,3 +1,6 @@
|
||||
py-cord[speed]==2.5.0
|
||||
requests==2.31.0
|
||||
ujson==5.9.0
|
||||
apscheduler~=3.10.4
|
||||
mongodb-migrations==1.3.0
|
||||
pytz~=2024.1
|
||||
--extra-index-url https://git.end-play.xyz/api/packages/profitroll/pypi/simple
|
||||
async_pymongo==0.1.4
|
||||
libbot[speed,pycord]==3.0.0
|
@ -1 +0,0 @@
|
||||
[]
|
855
validation/GloryBot.dmm
Normal file
855
validation/GloryBot.dmm
Normal file
@ -0,0 +1,855 @@
|
||||
{
|
||||
"tables": {
|
||||
"8218c159-d6ac-4582-ada6-42234c3b4bb9": {
|
||||
"id": "8218c159-d6ac-4582-ada6-42234c3b4bb9",
|
||||
"visible": true,
|
||||
"name": "members",
|
||||
"desc": "",
|
||||
"estimatedSize": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "cd82ad71-4ec4-4422-bf25-143b09789a88",
|
||||
"name": "_id",
|
||||
"datatype": "objectId",
|
||||
"param": "",
|
||||
"pk": true,
|
||||
"nn": true,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": "",
|
||||
"fk": false
|
||||
},
|
||||
{
|
||||
"id": "ef5b6eaa-ff48-4cf5-a5dd-017ae5abcbdd",
|
||||
"name": "id",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "90568cc9-2179-42e2-8126-5dda98a4ff75",
|
||||
"name": "guild",
|
||||
"datatype": "objectId",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": "",
|
||||
"fk": true
|
||||
},
|
||||
{
|
||||
"id": "6f7b3891-5599-434e-a99c-240c72103ebc",
|
||||
"name": "status",
|
||||
"datatype": "enum",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
}
|
||||
],
|
||||
"relations": [
|
||||
"4fe09974-9056-4780-a40b-0b98427c9806",
|
||||
"66940f28-fcde-4d2a-9012-ba7e6bd626e8"
|
||||
],
|
||||
"lines": [],
|
||||
"keys": [
|
||||
{
|
||||
"id": "15192abf-c4da-4d33-a7c7-af68f1e7e607",
|
||||
"name": "Primary",
|
||||
"isPk": true,
|
||||
"cols": []
|
||||
},
|
||||
{
|
||||
"id": "1c494fbe-59ab-47bf-a18b-f5767cde72d1",
|
||||
"isPk": false,
|
||||
"name": "members_ai_1",
|
||||
"cols": [
|
||||
{
|
||||
"id": "0e9654cf-049e-40f0-a081-245792ed3173",
|
||||
"colid": "cd82ad71-4ec4-4422-bf25-143b09789a88"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"embeddable": false,
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"beforeScript": "",
|
||||
"afterScript": "",
|
||||
"validationLevel": "na",
|
||||
"validationAction": "na",
|
||||
"collation": "",
|
||||
"others": "",
|
||||
"size": "",
|
||||
"max": "",
|
||||
"validation": "",
|
||||
"capped": false
|
||||
},
|
||||
"50052cf6-a0b4-4480-b01f-d9067db1442d": {
|
||||
"id": "50052cf6-a0b4-4480-b01f-d9067db1442d",
|
||||
"visible": true,
|
||||
"name": "guilds",
|
||||
"desc": "",
|
||||
"estimatedSize": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "90dab62e-469d-4eaa-b69c-cbee4dcc46ca",
|
||||
"name": "_id",
|
||||
"datatype": "objectId",
|
||||
"param": "",
|
||||
"pk": true,
|
||||
"nn": true,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": "",
|
||||
"fk": false
|
||||
},
|
||||
{
|
||||
"id": "5f241e7a-231f-471d-a402-433ca73937bc",
|
||||
"name": "id",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "6b66ce5e-a042-4d41-952a-c125cce3737d",
|
||||
"name": "channels",
|
||||
"datatype": "9e99a5bf-54d6-4743-9a19-0c122cdaf236",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "4a3e6d9c-7c0a-4bff-b65f-d6be5431623d",
|
||||
"name": "roles",
|
||||
"datatype": "ecee86d4-9d49-446d-93bb-d41274023485",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
}
|
||||
],
|
||||
"relations": [
|
||||
"0c5b44eb-1d1a-4c61-aa95-a5e4e71095f1",
|
||||
"66940f28-fcde-4d2a-9012-ba7e6bd626e8"
|
||||
],
|
||||
"lines": [],
|
||||
"keys": [
|
||||
{
|
||||
"id": "d834da3e-7541-487f-9ed7-f07156a4c6cc",
|
||||
"name": "Primary",
|
||||
"isPk": true,
|
||||
"cols": []
|
||||
},
|
||||
{
|
||||
"id": "37b7443d-a933-4e05-856a-236e8a786531",
|
||||
"isPk": false,
|
||||
"name": "guilds_ai_1",
|
||||
"cols": [
|
||||
{
|
||||
"id": "4ce6dde7-8001-4653-acd7-2bc301702b45",
|
||||
"colid": "90dab62e-469d-4eaa-b69c-cbee4dcc46ca"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "d5cf1cce-1151-48cb-88da-bdaebc19b8e7",
|
||||
"isPk": false,
|
||||
"name": "guilds_ai_2",
|
||||
"cols": [
|
||||
{
|
||||
"id": "10b76400-aef6-4ea1-a621-e153cefc6b9d",
|
||||
"colid": "90dab62e-469d-4eaa-b69c-cbee4dcc46ca"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"embeddable": false,
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"beforeScript": "",
|
||||
"afterScript": "",
|
||||
"validationLevel": "na",
|
||||
"validationAction": "na",
|
||||
"collation": "",
|
||||
"others": "",
|
||||
"size": "",
|
||||
"max": "",
|
||||
"validation": "",
|
||||
"capped": false
|
||||
},
|
||||
"6e055f35-bf3f-4561-8a6c-e0420c36e4ef": {
|
||||
"id": "6e055f35-bf3f-4561-8a6c-e0420c36e4ef",
|
||||
"visible": true,
|
||||
"name": "checks",
|
||||
"desc": "",
|
||||
"estimatedSize": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "8dd045aa-3176-4528-868b-8711e194d788",
|
||||
"name": "_id",
|
||||
"datatype": "objectId",
|
||||
"param": "",
|
||||
"pk": true,
|
||||
"nn": true,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "72bcf507-6b2f-4916-b8ae-eff282cd510d",
|
||||
"name": "guild",
|
||||
"datatype": "objectId",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": "",
|
||||
"fk": true
|
||||
},
|
||||
{
|
||||
"id": "89ff6268-aaf0-4d94-8b23-af84af81d233",
|
||||
"name": "thread_id",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "8d58b94a-dc20-4659-a403-298cdfd109d0",
|
||||
"name": "member",
|
||||
"datatype": "objectId",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": "",
|
||||
"fk": true
|
||||
},
|
||||
{
|
||||
"id": "9a6be1e7-c31e-4536-a09a-61c8ef8dc0d5",
|
||||
"name": "date_created",
|
||||
"datatype": "date",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "c8af1e88-3146-40bc-8c3b-0acc666f4847",
|
||||
"name": "date_modified",
|
||||
"datatype": "date",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "d3b8a5d5-aecf-4c63-af11-2d3c6f1cdef3",
|
||||
"name": "challenge",
|
||||
"datatype": "string",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "0f31f5de-1fb1-4635-ac20-b1dc5a75cff6",
|
||||
"name": "answers",
|
||||
"datatype": "regex",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": true,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
}
|
||||
],
|
||||
"relations": [
|
||||
"4fe09974-9056-4780-a40b-0b98427c9806",
|
||||
"0c5b44eb-1d1a-4c61-aa95-a5e4e71095f1"
|
||||
],
|
||||
"lines": [],
|
||||
"keys": [
|
||||
{
|
||||
"id": "47a67dd7-391a-4d12-8583-7376a6173f31",
|
||||
"name": "Primary",
|
||||
"isPk": true,
|
||||
"cols": [
|
||||
{
|
||||
"id": "2d16233d-51c4-469b-9ead-1c4e93527f67",
|
||||
"colid": "8dd045aa-3176-4528-868b-8711e194d788"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "6d879c59-8368-4a64-bbc6-57f8875f125d",
|
||||
"isPk": false,
|
||||
"name": "checks_ai_1",
|
||||
"cols": [
|
||||
{
|
||||
"id": "66211936-42bf-4794-ba1b-ef4ed5ac5f3f",
|
||||
"colid": "8d58b94a-dc20-4659-a403-298cdfd109d0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "4b7c01a8-4353-4735-a34f-ee9a5fa0a841",
|
||||
"isPk": false,
|
||||
"name": "checks_ai_2",
|
||||
"cols": [
|
||||
{
|
||||
"id": "96e53783-2729-42e0-9b7d-b2fab3024271",
|
||||
"colid": "72bcf507-6b2f-4916-b8ae-eff282cd510d"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"embeddable": false,
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"beforeScript": "",
|
||||
"afterScript": "",
|
||||
"validationLevel": "na",
|
||||
"validationAction": "na",
|
||||
"collation": "",
|
||||
"others": "",
|
||||
"size": "",
|
||||
"max": "",
|
||||
"validation": "",
|
||||
"capped": false
|
||||
},
|
||||
"9e99a5bf-54d6-4743-9a19-0c122cdaf236": {
|
||||
"id": "9e99a5bf-54d6-4743-9a19-0c122cdaf236",
|
||||
"visible": false,
|
||||
"name": "object",
|
||||
"desc": "",
|
||||
"estimatedSize": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "e347d86c-20af-4947-aa5e-5711d398c03a",
|
||||
"name": "captcha",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "d6ab1041-ee1b-4b93-b0f6-aabf506aefae",
|
||||
"name": "logging",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "84e03c39-4ddc-4958-8075-e03c2407f588",
|
||||
"name": "welcome",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
}
|
||||
],
|
||||
"relations": [],
|
||||
"lines": [],
|
||||
"keys": [
|
||||
{
|
||||
"id": "504c1660-ec59-48f2-a536-f7a0132a0e62",
|
||||
"name": "Primary key",
|
||||
"isPk": true,
|
||||
"cols": []
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"embeddable": true,
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"beforeScript": "",
|
||||
"afterScript": "",
|
||||
"validationLevel": "na",
|
||||
"validationAction": "na",
|
||||
"collation": "",
|
||||
"others": "",
|
||||
"size": "",
|
||||
"max": "",
|
||||
"validation": "",
|
||||
"capped": false
|
||||
},
|
||||
"ecee86d4-9d49-446d-93bb-d41274023485": {
|
||||
"id": "ecee86d4-9d49-446d-93bb-d41274023485",
|
||||
"visible": false,
|
||||
"name": "object",
|
||||
"desc": "",
|
||||
"estimatedSize": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "ebdfc6a6-4ecb-43d9-b680-bec113642463",
|
||||
"name": "moderator",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "6e67129f-49ff-4851-b53d-bcad6694a5d3",
|
||||
"name": "captcha_verified",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "263e0911-d6ab-455f-829a-13402122f573",
|
||||
"name": "captcha_failed",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
},
|
||||
{
|
||||
"id": "2789fc3e-d195-4a61-9ccd-5c3bbd1e10b9",
|
||||
"name": "captcha_additional",
|
||||
"datatype": "long",
|
||||
"param": "",
|
||||
"pk": false,
|
||||
"nn": false,
|
||||
"list": false,
|
||||
"comment": "",
|
||||
"data": "",
|
||||
"enum": "",
|
||||
"validation": "",
|
||||
"pattern": false,
|
||||
"estimatedSize": "",
|
||||
"any": ""
|
||||
}
|
||||
],
|
||||
"relations": [],
|
||||
"lines": [],
|
||||
"keys": [
|
||||
{
|
||||
"id": "50995e39-016c-401a-a1a4-6f95eecd2a29",
|
||||
"name": "Primary key",
|
||||
"isPk": true,
|
||||
"cols": []
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"embeddable": true,
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"beforeScript": "",
|
||||
"afterScript": "",
|
||||
"validationLevel": "na",
|
||||
"validationAction": "na",
|
||||
"collation": "",
|
||||
"others": "",
|
||||
"size": "",
|
||||
"max": "",
|
||||
"validation": "",
|
||||
"capped": false
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"4fe09974-9056-4780-a40b-0b98427c9806": {
|
||||
"id": "4fe09974-9056-4780-a40b-0b98427c9806",
|
||||
"visible": true,
|
||||
"name": "_id_member",
|
||||
"desc": "",
|
||||
"type": "identifying",
|
||||
"parent_key": "1c494fbe-59ab-47bf-a18b-f5767cde72d1",
|
||||
"parent": "8218c159-d6ac-4582-ada6-42234c3b4bb9",
|
||||
"child": "6e055f35-bf3f-4561-8a6c-e0420c36e4ef",
|
||||
"c_mp": "true",
|
||||
"c_mch": "true",
|
||||
"c_p": "one",
|
||||
"c_ch": "many",
|
||||
"c_cp": "",
|
||||
"c_cch": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "b7398f91-c5b9-480b-af51-4bc9485904f1",
|
||||
"parentcol": "cd82ad71-4ec4-4422-bf25-143b09789a88",
|
||||
"childcol": "8d58b94a-dc20-4659-a403-298cdfd109d0"
|
||||
}
|
||||
],
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"relationColor": "transparent"
|
||||
},
|
||||
"0c5b44eb-1d1a-4c61-aa95-a5e4e71095f1": {
|
||||
"id": "0c5b44eb-1d1a-4c61-aa95-a5e4e71095f1",
|
||||
"visible": true,
|
||||
"name": "_id_guild",
|
||||
"desc": "",
|
||||
"type": "identifying",
|
||||
"parent_key": "37b7443d-a933-4e05-856a-236e8a786531",
|
||||
"parent": "50052cf6-a0b4-4480-b01f-d9067db1442d",
|
||||
"child": "6e055f35-bf3f-4561-8a6c-e0420c36e4ef",
|
||||
"c_mp": "true",
|
||||
"c_mch": "true",
|
||||
"c_p": "one",
|
||||
"c_ch": "many",
|
||||
"c_cp": "",
|
||||
"c_cch": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "dd222990-42cd-42d8-b7bb-cbddf53a8c50",
|
||||
"parentcol": "90dab62e-469d-4eaa-b69c-cbee4dcc46ca",
|
||||
"childcol": "72bcf507-6b2f-4916-b8ae-eff282cd510d"
|
||||
}
|
||||
],
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"relationColor": "transparent"
|
||||
},
|
||||
"66940f28-fcde-4d2a-9012-ba7e6bd626e8": {
|
||||
"id": "66940f28-fcde-4d2a-9012-ba7e6bd626e8",
|
||||
"visible": true,
|
||||
"name": "_id_guild",
|
||||
"desc": "",
|
||||
"type": "identifying",
|
||||
"parent_key": "d5cf1cce-1151-48cb-88da-bdaebc19b8e7",
|
||||
"parent": "50052cf6-a0b4-4480-b01f-d9067db1442d",
|
||||
"child": "8218c159-d6ac-4582-ada6-42234c3b4bb9",
|
||||
"c_mp": "true",
|
||||
"c_mch": "true",
|
||||
"c_p": "one",
|
||||
"c_ch": "many",
|
||||
"c_cp": "",
|
||||
"c_cch": "",
|
||||
"cols": [
|
||||
{
|
||||
"id": "bad556f3-bee0-4e02-9be1-74fa88ac1c28",
|
||||
"parentcol": "90dab62e-469d-4eaa-b69c-cbee4dcc46ca",
|
||||
"childcol": "90568cc9-2179-42e2-8126-5dda98a4ff75"
|
||||
}
|
||||
],
|
||||
"generate": true,
|
||||
"generateCustomCode": true,
|
||||
"customCode": "",
|
||||
"relationColor": "transparent"
|
||||
}
|
||||
},
|
||||
"notes": {},
|
||||
"lines": {},
|
||||
"model": {
|
||||
"name": "GloryBot",
|
||||
"id": "2eda0a98-3835-4c9d-a356-43df11098784",
|
||||
"activeDiagram": "8b5fdfd4-c1f4-4646-be16-a36f71f9357b",
|
||||
"desc": "",
|
||||
"path": "",
|
||||
"type": "MONGODB",
|
||||
"version": 1,
|
||||
"parentTableInFkCols": true,
|
||||
"caseConvention": "under",
|
||||
"replaceSpace": "_",
|
||||
"color": "transparent",
|
||||
"sideSelections": true,
|
||||
"isDirty": true,
|
||||
"storedin": {
|
||||
"major": 8,
|
||||
"minor": 5,
|
||||
"extra": 1
|
||||
},
|
||||
"laststoredin": {
|
||||
"major": 8,
|
||||
"minor": 5,
|
||||
"extra": 1
|
||||
},
|
||||
"writeFileParam": false,
|
||||
"authorName": "",
|
||||
"companyDetails": "",
|
||||
"companyUrl": "",
|
||||
"def_coltopk": true,
|
||||
"def_validationLevel": "na",
|
||||
"def_validationAction": "na",
|
||||
"def_collation": "",
|
||||
"def_others": "",
|
||||
"connectionVersion": "",
|
||||
"lastSaved": 1714494820523
|
||||
},
|
||||
"otherObjects": {},
|
||||
"diagrams": {
|
||||
"8b5fdfd4-c1f4-4646-be16-a36f71f9357b": {
|
||||
"name": "Main Diagram",
|
||||
"description": "",
|
||||
"id": "8b5fdfd4-c1f4-4646-be16-a36f71f9357b",
|
||||
"keysgraphics": true,
|
||||
"linegraphics": "detailed",
|
||||
"zoom": 1,
|
||||
"background": "transparent",
|
||||
"lineColor": "transparent",
|
||||
"isOpen": true,
|
||||
"main": true,
|
||||
"diagramItems": {
|
||||
"8218c159-d6ac-4582-ada6-42234c3b4bb9": {
|
||||
"referencedItemId": "8218c159-d6ac-4582-ada6-42234c3b4bb9",
|
||||
"x": 623,
|
||||
"y": 165,
|
||||
"gHeight": 99,
|
||||
"gWidth": 186,
|
||||
"color": "#ffffff",
|
||||
"background": "#03a9f4",
|
||||
"resized": false,
|
||||
"autoExpand": true,
|
||||
"backgroundOpacity": "10",
|
||||
"collapsed": false
|
||||
},
|
||||
"50052cf6-a0b4-4480-b01f-d9067db1442d": {
|
||||
"referencedItemId": "50052cf6-a0b4-4480-b01f-d9067db1442d",
|
||||
"x": 45,
|
||||
"y": 187,
|
||||
"gHeight": 225,
|
||||
"gWidth": 210,
|
||||
"color": "#ffffff",
|
||||
"background": "#03a9f4",
|
||||
"resized": false,
|
||||
"autoExpand": true,
|
||||
"backgroundOpacity": "10",
|
||||
"collapsed": false
|
||||
},
|
||||
"6e055f35-bf3f-4561-8a6c-e0420c36e4ef": {
|
||||
"referencedItemId": "6e055f35-bf3f-4561-8a6c-e0420c36e4ef",
|
||||
"x": 917,
|
||||
"y": 39,
|
||||
"gHeight": 171,
|
||||
"gWidth": 221,
|
||||
"color": "#ffffff",
|
||||
"background": "#03a9f4",
|
||||
"resized": false,
|
||||
"autoExpand": true,
|
||||
"backgroundOpacity": "10",
|
||||
"collapsed": false
|
||||
},
|
||||
"9e99a5bf-54d6-4743-9a19-0c122cdaf236": {
|
||||
"referencedItemId": "9e99a5bf-54d6-4743-9a19-0c122cdaf236",
|
||||
"x": -1,
|
||||
"y": -1,
|
||||
"gHeight": -1,
|
||||
"gWidth": -1,
|
||||
"color": "#ffffff",
|
||||
"background": "transparent",
|
||||
"resized": false,
|
||||
"autoExpand": true,
|
||||
"backgroundOpacity": "10",
|
||||
"collapsed": false
|
||||
},
|
||||
"ecee86d4-9d49-446d-93bb-d41274023485": {
|
||||
"referencedItemId": "ecee86d4-9d49-446d-93bb-d41274023485",
|
||||
"x": -1,
|
||||
"y": -1,
|
||||
"gHeight": -1,
|
||||
"gWidth": -1,
|
||||
"color": "#ffffff",
|
||||
"background": "transparent",
|
||||
"resized": false,
|
||||
"autoExpand": true,
|
||||
"backgroundOpacity": "10",
|
||||
"collapsed": false
|
||||
}
|
||||
},
|
||||
"scroll": {
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"type": "erd",
|
||||
"showHorizontal": true,
|
||||
"showDescriptions": true,
|
||||
"showIndicators": true,
|
||||
"showProgress": true,
|
||||
"lineWidth": "2",
|
||||
"boxSize": "0",
|
||||
"boxSpacing": "2",
|
||||
"boxAlign": "center",
|
||||
"showIndicatorCaptions": true,
|
||||
"showEstimatedSize": false,
|
||||
"showSchemaContainer": true,
|
||||
"showEmbeddedInParents": true,
|
||||
"showCardinalityCaptions": true,
|
||||
"showRelationshipNames": false,
|
||||
"showLineCaptions": false,
|
||||
"showColumns": true,
|
||||
"showColumnDataTypes": true,
|
||||
"showSampleData": false,
|
||||
"showTableIndexes": true,
|
||||
"showTableDescriptions": false,
|
||||
"showRelations": true,
|
||||
"backgroundImage": "na",
|
||||
"descriptionsColor": "transparent",
|
||||
"embeddedSpacing": "2",
|
||||
"showMainIcon": true,
|
||||
"showLabels": true,
|
||||
"showCustomizations": false
|
||||
}
|
||||
},
|
||||
"diagramsOrder": [],
|
||||
"order": [],
|
||||
"collapsedTreeItems": [],
|
||||
"reverseStats": {}
|
||||
}
|
0
validation/members.json
Normal file
0
validation/members.json
Normal file
Loading…
Reference in New Issue
Block a user