Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
b2f65ba21f | |||
45effe5a33 | |||
83b723f5b9 | |||
8b62b8b7a6 | |||
ff265ce1d4 | |||
|
c9c5837b38 | ||
|
d7bef1ad26 | ||
7b9ce61733 | |||
|
b95b7caefd | ||
49be3c376c |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,8 @@
|
||||
venv/
|
||||
node_modules/
|
||||
|
||||
init.lock
|
||||
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
|
9
Makefile
9
Makefile
@ -37,5 +37,14 @@ revision:
|
||||
cd $(API_APPLICATION_NAME)/db && \
|
||||
PYTHONPATH='../..' ALEMBIC_MIGRATIONS=True alembic revision --autogenerate
|
||||
|
||||
venv-api:
|
||||
cd api && \
|
||||
poetry install
|
||||
|
||||
install:
|
||||
make migrate head && \
|
||||
cd api && \
|
||||
poetry run python3 api/utils/init.py
|
||||
|
||||
%::
|
||||
echo $(MESSAGE)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import uuid
|
||||
|
||||
from os import environ
|
||||
from functools import cached_property
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic_settings import BaseSettings
|
||||
@ -43,6 +44,26 @@ class DefaultSettings(BaseSettings):
|
||||
REDIS_DB: int = int(environ.get("REDIS_DB", "0"))
|
||||
REDIS_PASSWORD: str = environ.get("REDIS_PASSWORD", "hackme")
|
||||
|
||||
@cached_property
|
||||
def database_settings(self) -> dict:
|
||||
"""Get all settings for connection with database."""
|
||||
return {
|
||||
"database": self.MYSQL_DB,
|
||||
"user": self.MYSQL_USER,
|
||||
"password": self.MYSQL_PASSWORD,
|
||||
"host": self.MYSQL_HOST,
|
||||
"port": self.MYSQL_PORT,
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def database_uri(self) -> str:
|
||||
"""Get uri for connection with database."""
|
||||
uri = "mysql+aiomysql://{user}:{password}@{host}:{port}/{database}".format(
|
||||
**self.database_settings,
|
||||
)
|
||||
print("database_uri", uri)
|
||||
return uri
|
||||
|
||||
class Config:
|
||||
# env_file = "../.env"
|
||||
env_file_encoding = "utf-8"
|
||||
|
@ -7,7 +7,7 @@ from sqlalchemy import pool
|
||||
|
||||
from alembic import context
|
||||
|
||||
from api.db import metadata
|
||||
from api.db import metadata, tables
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
|
63
api/api/db/connection/session.py
Normal file
63
api/api/db/connection/session.py
Normal file
@ -0,0 +1,63 @@
|
||||
import contextlib
|
||||
import json
|
||||
import os
|
||||
from typing import Any, AsyncGenerator
|
||||
|
||||
import asyncio
|
||||
|
||||
import sqlalchemy
|
||||
from loguru import logger
|
||||
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine, create_async_engine
|
||||
from sqlalchemy import URL,create_engine, text
|
||||
|
||||
|
||||
from api.config import get_settings
|
||||
from api.config.default import DbCredentialsSchema
|
||||
|
||||
|
||||
|
||||
class SessionManager:
|
||||
engines: Any
|
||||
|
||||
|
||||
def __init__(self, database_uri=get_settings().database_uri) -> None:
|
||||
self.database_uri = database_uri
|
||||
self.refresh(database_uri)
|
||||
# self.reflect()
|
||||
|
||||
def __new__(cls, database_uri=get_settings().database_uri):
|
||||
if not hasattr(cls, "instance"):
|
||||
cls.instance = super(SessionManager, cls).__new__(cls)
|
||||
cls.instance.engines = {}
|
||||
return cls.instance
|
||||
|
||||
def refresh(self, database_uri) -> None:
|
||||
# if not self.engines:
|
||||
# self.engines = {}
|
||||
if database_uri not in self.engines:
|
||||
self.engines[database_uri] = create_async_engine(
|
||||
database_uri,
|
||||
echo=True,
|
||||
future=True,
|
||||
# json_serializer=serializer,
|
||||
pool_recycle=1800,
|
||||
pool_size=get_settings().CONNECTION_POOL_SIZE,
|
||||
max_overflow=get_settings().CONNECTION_OVERFLOW,
|
||||
)
|
||||
def get_engine_by_db_uri(self, database_uri) -> AsyncEngine:
|
||||
return self.engines[database_uri]
|
||||
|
||||
@contextlib.asynccontextmanager
|
||||
async def get_connection(
|
||||
database_uri=None,
|
||||
) -> AsyncGenerator[AsyncConnection, None]:
|
||||
if not database_uri:
|
||||
database_uri = get_settings().database_uri
|
||||
engine = SessionManager(database_uri).get_engine_by_db_uri(database_uri)
|
||||
logger.debug(f"engine {engine} {SessionManager(database_uri).engines}")
|
||||
async with engine.connect() as conn:
|
||||
yield conn
|
||||
|
||||
async def get_connection_dep() -> AsyncConnection:
|
||||
async with get_connection() as conn:
|
||||
yield conn
|
18
api/api/db/sql_types.py
Normal file
18
api/api/db/sql_types.py
Normal file
@ -0,0 +1,18 @@
|
||||
__all__ = ["BigIntegerPK", "SAEnum", "UnsignedInt"]
|
||||
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import BigInteger, Enum, Integer
|
||||
from sqlalchemy.dialects import mysql
|
||||
|
||||
|
||||
# class SAEnum(Enum):
|
||||
# def __init__(self, *enums: object, **kw: Any):
|
||||
# validate_strings = kw.pop("validate_strings", True)
|
||||
# super().__init__(*enums, **kw, validate_strings=validate_strings)
|
||||
|
||||
|
||||
# # https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer
|
||||
|
||||
# BigIntegerPK = BigInteger().with_variant(Integer, "sqlite")
|
||||
UnsignedInt = Integer().with_variant(mysql.INTEGER(unsigned=True), "mysql")
|
@ -0,0 +1 @@
|
||||
from . import account,events,process
|
73
api/api/db/tables/account.py
Normal file
73
api/api/db/tables/account.py
Normal file
@ -0,0 +1,73 @@
|
||||
from sqlalchemy import Table, Column, Integer, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from enum import Enum, auto
|
||||
|
||||
from api.db.sql_types import UnsignedInt
|
||||
|
||||
from api.db import metadata
|
||||
|
||||
|
||||
class AccountRole(str,Enum):
|
||||
OWNER = auto()
|
||||
ADMIN = auto()
|
||||
EDITOR = auto()
|
||||
VIEWER = auto()
|
||||
|
||||
class AccountStatus(str,Enum):
|
||||
ACTIVE = auto()
|
||||
DISABLED = auto()
|
||||
BLOCKED = auto()
|
||||
DELETED = auto()
|
||||
|
||||
|
||||
|
||||
account_table = Table(
|
||||
'account', metadata,
|
||||
Column('id', UnsignedInt, primary_key=True, autoincrement=True),
|
||||
Column('name', String(100), nullable=False),
|
||||
Column('login', String(100), nullable=False),
|
||||
Column('email', String(100), nullable=True),
|
||||
Column('bind_tenant_id', String(40), nullable=True),
|
||||
Column('role', SQLAEnum(AccountRole), nullable=False),
|
||||
Column('meta', JSON, default={}),
|
||||
Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=True),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('status', SQLAEnum(AccountStatus), nullable=False),
|
||||
|
||||
Index('idx_login', 'login'),
|
||||
Index('idx_name', 'name'),
|
||||
)
|
||||
|
||||
class KeyType(str,Enum):
|
||||
PASSWORD = auto()
|
||||
ACCESS_TOKEN = auto()
|
||||
REFRESH_TOKEN = auto()
|
||||
API_KEY = auto()
|
||||
|
||||
class KeyStatus(str,Enum):
|
||||
ACTIVE = auto()
|
||||
EXPIRED = auto()
|
||||
DELETED = auto()
|
||||
|
||||
account_keyring_table = Table(
|
||||
'account_keyring', metadata,
|
||||
Column('owner_id', UnsignedInt, ForeignKey('account.id'), primary_key=True, nullable=False),
|
||||
Column('key_type', SQLAEnum(KeyType), primary_key=True, nullable=False),
|
||||
Column('key_id', String(40), default=None),
|
||||
Column('key_value', String(64), nullable=False),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('expiry', DateTime(timezone=True), nullable=True),
|
||||
Column('status', SQLAEnum(KeyStatus), nullable=False), )
|
||||
|
||||
|
||||
def set_expiry_for_key_type(key_type: KeyType) -> datetime:
|
||||
match key_type:
|
||||
case KeyType.ACCESS_TOKEN:
|
||||
return datetime.now() + timedelta(hours=1) # 1 hour
|
||||
case KeyType.REFRESH_TOKEN:
|
||||
return datetime.now() + timedelta(days=365) # 1 year
|
||||
case KeyType.API_KEY:
|
||||
return datetime.max # max datetime
|
29
api/api/db/tables/events.py
Normal file
29
api/api/db/tables/events.py
Normal file
@ -0,0 +1,29 @@
|
||||
from sqlalchemy import Table, Column, Integer, String, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index
|
||||
from sqlalchemy.sql import func
|
||||
from enum import Enum, auto
|
||||
|
||||
from api.db.sql_types import UnsignedInt
|
||||
|
||||
from api.db import metadata
|
||||
|
||||
class EventState(str, Enum):
|
||||
AUTO = auto()
|
||||
DESCRIPTED = auto()
|
||||
|
||||
class EventStatus(str, Enum):
|
||||
ACTIVE = auto()
|
||||
DISABLED = auto()
|
||||
DELETED = auto()
|
||||
|
||||
|
||||
list_events_table = Table(
|
||||
'list_events', metadata,
|
||||
Column('id', UnsignedInt, primary_key=True, autoincrement=True),
|
||||
Column('name', String(40, collation='latin1_bin'), nullable=False,unique=True),
|
||||
Column('title', String(64), nullable=False),
|
||||
Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('schema', JSON, default={}),
|
||||
Column('state', SQLAEnum(EventState), nullable=False),
|
||||
Column('status', SQLAEnum(EventStatus), nullable=False),
|
||||
)
|
84
api/api/db/tables/process.py
Normal file
84
api/api/db/tables/process.py
Normal file
@ -0,0 +1,84 @@
|
||||
from sqlalchemy import Table, Column, Integer, String, Text, Enum as SQLAEnum, JSON, ForeignKey, DateTime, Index, PrimaryKeyConstraint
|
||||
from sqlalchemy.sql import func
|
||||
from enum import Enum, auto
|
||||
|
||||
from api.db.sql_types import UnsignedInt
|
||||
|
||||
from api.db import metadata
|
||||
|
||||
|
||||
# Определение перечислений для статуса процесса
|
||||
class ProcessStatus(str, Enum):
|
||||
ACTIVE = auto()
|
||||
STOPPING = auto()
|
||||
STOPPED = auto()
|
||||
DELETED = auto()
|
||||
|
||||
# Определение таблицы process_schema
|
||||
process_schema_table = Table(
|
||||
'process_schema', metadata,
|
||||
Column('id', UnsignedInt, primary_key=True, autoincrement=True),
|
||||
Column('title', String(100), nullable=False),
|
||||
Column('description', Text, nullable=False),
|
||||
Column('owner_id', UnsignedInt, ForeignKey('account.id'), nullable=False),
|
||||
Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('settings', JSON, default={}),
|
||||
Column('status', SQLAEnum(ProcessStatus), nullable=False),
|
||||
|
||||
Index('idx_owner_id', 'owner_id',)
|
||||
)
|
||||
|
||||
process_version_archive_table = Table(
|
||||
'process_version_archive', metadata,
|
||||
Column('id', UnsignedInt, autoincrement=True, nullable=False),
|
||||
Column('ps_id', UnsignedInt, ForeignKey('process_schema.id'), nullable=False),
|
||||
Column('version', UnsignedInt, default=1, nullable=False),
|
||||
Column('snapshot', JSON, default={}),
|
||||
Column('owner_id', UnsignedInt, ForeignKey('account.id'), nullable=False),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('is_last', UnsignedInt, default=0),
|
||||
PrimaryKeyConstraint('id', 'version') )
|
||||
|
||||
class NodeStatus(str, Enum):
|
||||
ACTIVE = auto()
|
||||
DISABLED = auto()
|
||||
DELETED = auto()
|
||||
|
||||
class NodeType(Enum):
|
||||
TYPE1 = 'Type1'
|
||||
TYPE2 = 'Type2'
|
||||
TYPE3 = 'Type3'
|
||||
|
||||
ps_node_table = Table(
|
||||
'ps_node', metadata,
|
||||
Column('id', UnsignedInt, autoincrement=True, primary_key=True, nullable=False),
|
||||
Column('ps_id', UnsignedInt, ForeignKey('process_schema.id'), nullable=False),
|
||||
Column('node_type', SQLAEnum(NodeType), nullable=False),
|
||||
Column('settings', JSON, default={}),
|
||||
Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('status', SQLAEnum(NodeStatus), nullable=False),
|
||||
|
||||
Index('idx_ps_id', 'ps_id')
|
||||
)
|
||||
|
||||
class NodeLinkStatus(str, Enum):
|
||||
ACTIVE = auto()
|
||||
STOPPING = auto()
|
||||
STOPPED = auto()
|
||||
DELETED = auto()
|
||||
|
||||
node_link_table = Table(
|
||||
'node_link', metadata,
|
||||
Column('id', UnsignedInt, autoincrement=True, primary_key=True, nullable=False),
|
||||
Column('link_name', String(20), nullable=False),
|
||||
Column('node_id', UnsignedInt, ForeignKey('ps_node.id'), nullable=False),
|
||||
Column('next_node_id', UnsignedInt, ForeignKey('ps_node.id'), nullable=False),
|
||||
Column('settings', JSON, default={}),
|
||||
Column('creator_id', UnsignedInt, ForeignKey('account.id'), nullable=False),
|
||||
Column('created_at', DateTime(timezone=True), server_default=func.now()),
|
||||
Column('status', SQLAEnum(NodeLinkStatus),nullable=False),
|
||||
|
||||
Index('idx_node_id', 'node_id'),
|
||||
Index('idx_next_node_id', 'next_node_id'))
|
0
api/api/schemas/account/__init__.py
Normal file
0
api/api/schemas/account/__init__.py
Normal file
30
api/api/schemas/account/account.py
Normal file
30
api/api/schemas/account/account.py
Normal file
@ -0,0 +1,30 @@
|
||||
import datetime
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
|
||||
class Role(Enum):
|
||||
OWNER = "Owner"
|
||||
ADMIN = "Admin"
|
||||
EDITOR = "Editor"
|
||||
VIEWER = "Viewer"
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
DISABLED = "Disabled"
|
||||
BLOCKED = "Blocked"
|
||||
DELETED = "Deleted"
|
||||
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name: str = Field(..., max_length=100)
|
||||
login: str = Field(..., max_length=100)
|
||||
email: EmailStr = Field(..., max_length=100)
|
||||
bind_tenant_id: str = Field(..., max_length=40)
|
||||
role: Role
|
||||
meta: dict
|
||||
creator_id: int
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
status: Status
|
27
api/api/schemas/account/account_keyring.py
Normal file
27
api/api/schemas/account/account_keyring.py
Normal file
@ -0,0 +1,27 @@
|
||||
import datetime
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Type(Enum):
|
||||
PASSWORD = "password"
|
||||
ACCESS_TOKEN = "access_token"
|
||||
REFRESH_TOKEN = "refresh_token"
|
||||
API_KEY = "api_key"
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
EXPIRED = "Expired"
|
||||
DELETED = "Deleted"
|
||||
|
||||
class AccountKeyring(BaseModel):
|
||||
owner_id: int
|
||||
key_type: Type
|
||||
key_id: str = Field(..., max_length=40)
|
||||
key_value: str = Field(..., max_length=64)
|
||||
created_at: datetime
|
||||
expiry: datetime
|
||||
status: Status
|
0
api/api/schemas/events/__init__.py
Normal file
0
api/api/schemas/events/__init__.py
Normal file
25
api/api/schemas/events/list_events.py
Normal file
25
api/api/schemas/events/list_events.py
Normal file
@ -0,0 +1,25 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class State(Enum):
|
||||
AUTO = "Auto"
|
||||
DESCRIPTED = "Descripted"
|
||||
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
DISABLED = "Disabled"
|
||||
DELETED = "Deleted"
|
||||
|
||||
class ListEvent(BaseModel):
|
||||
id: int
|
||||
name: str = Field(..., max_length=40)
|
||||
title: str = Field(..., max_length=64)
|
||||
creator_id: int
|
||||
created_at: datetime
|
||||
schema: Dict[str, Any]
|
||||
state: State
|
||||
status: Status
|
0
api/api/schemas/process/__init__.py
Normal file
0
api/api/schemas/process/__init__.py
Normal file
20
api/api/schemas/process/node_link.py
Normal file
20
api/api/schemas/process/node_link.py
Normal file
@ -0,0 +1,20 @@
|
||||
from pydantic import BaseModel, Field, conint
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
STOPPING = "Stopping"
|
||||
STOPPED = "Stopped"
|
||||
DELETED = "Deleted"
|
||||
|
||||
class MyModel(BaseModel):
|
||||
id: int
|
||||
link_name: str = Field(..., max_length=20)
|
||||
node_id: int
|
||||
next_node_id: int
|
||||
settings: Dict[str, Any]
|
||||
creator_id: int
|
||||
created_at: datetime
|
||||
status: Status
|
20
api/api/schemas/process/process_schema.py
Normal file
20
api/api/schemas/process/process_schema.py
Normal file
@ -0,0 +1,20 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
STOPPING = "Stopping"
|
||||
STOPPED = "Stopped"
|
||||
DELETED = "Deleted"
|
||||
|
||||
class ProcessSchema(BaseModel):
|
||||
id: int
|
||||
title: str = Field(..., max_length=100)
|
||||
description: str
|
||||
owner_id: int
|
||||
creator_id: int
|
||||
created_at: datetime
|
||||
settings: Dict[str, Any]
|
||||
status: Status
|
11
api/api/schemas/process/process_version_archive.py
Normal file
11
api/api/schemas/process/process_version_archive.py
Normal file
@ -0,0 +1,11 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Dict, Any
|
||||
from datetime import datetime
|
||||
|
||||
class ProcessStatusSchema(BaseModel):
|
||||
id: int
|
||||
version: int
|
||||
snapshot: Dict[str, Any]
|
||||
owner_id: int
|
||||
created_at: datetime
|
||||
is_last: int
|
23
api/api/schemas/process/ps_node.py
Normal file
23
api/api/schemas/process/ps_node.py
Normal file
@ -0,0 +1,23 @@
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class NodeType(Enum):
|
||||
|
||||
pass
|
||||
|
||||
class Status(Enum):
|
||||
ACTIVE = "Active"
|
||||
DISABLED = "Disabled"
|
||||
DELETED = "Deleted"
|
||||
|
||||
class Ps_Node(BaseModel):
|
||||
id: int
|
||||
ps_id: int
|
||||
node_type: NodeType
|
||||
settings: dict
|
||||
creator_id: Dict[str, Any]
|
||||
created_at: datetime
|
||||
status: Status
|
60
api/api/utils/init.py
Normal file
60
api/api/utils/init.py
Normal file
@ -0,0 +1,60 @@
|
||||
import os
|
||||
import asyncio
|
||||
import hashlib
|
||||
import secrets
|
||||
|
||||
from api.db.connection.session import get_connection
|
||||
from api.db.tables.account import account_table, account_keyring_table, AccountRole, KeyType, KeyStatus
|
||||
|
||||
INIT_LOCK_FILE = "../init.lock"
|
||||
DEFAULT_LOGIN = "vorkout"
|
||||
|
||||
|
||||
def hash_password(password: str) -> str:
|
||||
return hashlib.sha256(password.encode()).hexdigest()
|
||||
|
||||
|
||||
def generate_password() -> str:
|
||||
return secrets.token_urlsafe(20)
|
||||
|
||||
|
||||
async def init():
|
||||
if os.path.exists(INIT_LOCK_FILE):
|
||||
print("Sorry, service is already initialized")
|
||||
return
|
||||
|
||||
async with get_connection() as conn:
|
||||
password = generate_password()
|
||||
hashed_password = hash_password(password)
|
||||
|
||||
create_user_query = account_table.insert().values(
|
||||
name=DEFAULT_LOGIN,
|
||||
login=DEFAULT_LOGIN,
|
||||
role=AccountRole.OWNER,
|
||||
)
|
||||
|
||||
res = await conn.execute(create_user_query)
|
||||
user_id = res.lastrowid
|
||||
|
||||
create_key_query = account_keyring_table.insert().values(
|
||||
owner_id=user_id,
|
||||
key_type=KeyType.PASSWORD,
|
||||
key_value=hashed_password,
|
||||
status=KeyStatus.ACTIVE,
|
||||
)
|
||||
|
||||
await conn.execute(create_key_query)
|
||||
|
||||
await conn.commit()
|
||||
|
||||
await conn.close()
|
||||
|
||||
with open(INIT_LOCK_FILE, "w") as lock_file:
|
||||
lock_file.write("initialized\n")
|
||||
|
||||
print(f"Login: {DEFAULT_LOGIN}")
|
||||
print(f"Password: {password}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.get_event_loop().run_until_complete(init())
|
@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "api"
|
||||
version = "0.0.1"
|
||||
version = "0.0.2"
|
||||
description = ""
|
||||
authors = [
|
||||
{name = "Vladislav",email = "vlad.dev@heado.ru"}
|
||||
|
@ -3,13 +3,13 @@ version: "3.1"
|
||||
services:
|
||||
rabbitmq:
|
||||
image: rabbitmq:4-management-alpine
|
||||
container_name: rabbitmq
|
||||
container_name: rabbitmq-connect
|
||||
ports:
|
||||
- 5672:5672
|
||||
- 15672:15672
|
||||
db:
|
||||
image: mysql:8.0
|
||||
container_name: mysql
|
||||
container_name: mysql-connect
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: hackme
|
||||
MYSQL_DATABASE: connect_test
|
||||
@ -21,7 +21,7 @@ services:
|
||||
- "3306:3306"
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: redis
|
||||
container_name: redis-connect
|
||||
command: redis-server --requirepass password
|
||||
environment:
|
||||
REDIS_PASSWORD: hackme
|
||||
|
Loading…
Reference in New Issue
Block a user