Skip to content

Commit

Permalink
Группы как сущность (#30)
Browse files Browse the repository at this point in the history
## Изменения
- Группы выделены в отдельную сущность и созданы подтипы для групп тг/вк
- Добавлен create_ts для вебхук стоража
- Группы тг теперь создаются автоматически
  • Loading branch information
dyakovri authored Apr 15, 2024
1 parent d5e4f84 commit 3359b85
Show file tree
Hide file tree
Showing 21 changed files with 377 additions and 73 deletions.
78 changes: 78 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Python tests

on:
pull_request:

jobs:
test:
name: Unit tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_HOST_AUTH_METHOD: trust
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
-p 5432:5432
steps:
- name: Checkout
uses: actions/checkout@v4
- uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install dependencies
run: |
python -m ensurepip
python -m pip install --upgrade pip
pip install --upgrade -r requirements.txt -r requirements.dev.txt
- name: Migrate DB
run: |
DB_DSN=postgresql://postgres@localhost:5432/postgres alembic upgrade head
- name: Build coverage file
id: pytest
run: |
DB_DSN=postgresql://postgres@localhost:5432/postgres pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=services_backend tests/ | tee pytest-coverage.txt
exit ${PIPESTATUS[0]}
- name: Print report
if: always()
run: |
cat pytest-coverage.txt
- name: Pytest coverage comment
uses: MishaKav/pytest-coverage-comment@main
with:
pytest-coverage-path: ./pytest-coverage.txt
title: Coverage Report
badge-title: Code Coverage
hide-badge: false
hide-report: false
create-new-comment: false
hide-comment: false
report-only-changed-files: false
remove-link-from-badge: false
junitxml-path: ./pytest.xml
junitxml-title: Summary
- name: Fail on pytest errors
if: steps.pytest.outcome == 'failure'
run: exit 1

linting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v2
with:
python-version: 3.11
- uses: isort/isort-action@master
with:
requirementsFiles: "requirements.txt requirements.dev.txt"
- uses: psf/black@stable
- name: Comment if linting failed
if: failure()
uses: thollander/actions-comment-pull-request@v2
with:
message: |
:poop: Code linting failed, use `black` and `isort` to fix it.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ format: configure
source ./venv/bin/activate && autoflake -r --in-place --remove-all-unused-imports ./social
source ./venv/bin/activate && isort ./social
source ./venv/bin/activate && black ./social
source ./venv/bin/activate && autoflake -r --in-place --remove-all-unused-imports ./tests
source ./venv/bin/activate && isort ./tests
source ./venv/bin/activate && black ./tests
source ./venv/bin/activate && autoflake -r --in-place --remove-all-unused-imports ./migrations
source ./venv/bin/activate && isort ./migrations
source ./venv/bin/activate && black ./migrations

configure: venv
source ./venv/bin/activate && pip install -r requirements.dev.txt -r requirements.txt
Expand Down
101 changes: 101 additions & 0 deletions migrations/versions/1cacaf803a1d_user_defined_groups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""User defined groups
Revision ID: 1cacaf803a1d
Revises: 9d98c1e9c864
Create Date: 2024-04-14 23:38:18.956845
"""

import sqlalchemy as sa
from alembic import op
from sqlalchemy.schema import CreateSequence, Sequence


# revision identifiers, used by Alembic.
revision = '1cacaf803a1d'
down_revision = '9d98c1e9c864'
branch_labels = None
depends_on = None


def upgrade():
op.create_table(
'group',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('type', sa.String(), nullable=False),
sa.Column('owner_id', sa.Integer(), nullable=True),
sa.Column('is_deleted', sa.Boolean(), nullable=False),
sa.Column('last_active_ts', sa.DateTime(), nullable=False),
sa.Column('create_ts', sa.DateTime(), nullable=False),
sa.Column('update_ts', sa.DateTime(), nullable=False),
)
op.execute(
'''
INSERT INTO "group"
(id, type, is_deleted, last_active_ts, create_ts, update_ts)
SELECT id, 'vk_group', False, now(), create_ts, update_ts
FROM vk_groups;
'''
)

max_id = op.get_bind().execute(sa.text('SELECT MAX(id) FROM "group";')).scalar() or 0
op.create_primary_key('group_pk', 'group', ['id'])
op.execute(CreateSequence(Sequence('group_id_seq', max_id + 1)))
op.alter_column('group', 'id', server_default=sa.text('nextval(\'group_id_seq\')'))

op.create_table(
'telegram_channel',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('channel_id', sa.BigInteger(), nullable=False),
sa.ForeignKeyConstraint(
['id'],
['group.id'],
),
sa.PrimaryKeyConstraint('id'),
)
op.create_table(
'telegram_chat',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('chat_id', sa.BigInteger(), nullable=False),
sa.ForeignKeyConstraint(
['id'],
['group.id'],
),
sa.PrimaryKeyConstraint('id'),
)
op.create_table(
'vk_chat',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('peer_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(
['id'],
['group.id'],
),
sa.PrimaryKeyConstraint('id'),
)
op.create_foreign_key('group_vkgroup_fk', 'vk_groups', 'group', ['id'], ['id'])
op.drop_column('vk_groups', 'update_ts')
op.drop_column('vk_groups', 'create_ts')
op.execute('DROP SEQUENCE IF EXISTS vk_groups_id_seq CASCADE;')
op.rename_table('vk_groups', 'vk_group')


def downgrade():
op.rename_table('vk_group', 'vk_groups')

max_id = op.get_bind().execute(sa.text('SELECT MAX(id) FROM "vk_groups";')).scalar() or 0
op.execute(CreateSequence(Sequence('vk_groups_id_seq', max_id + 1)))
op.alter_column('vk_groups', 'id', server_default=sa.text('nextval(\'vk_groups_id_seq\')'))

op.add_column('vk_groups', sa.Column('create_ts', sa.DateTime()))
op.add_column('vk_groups', sa.Column('update_ts', sa.DateTime()))
op.execute('UPDATE vk_groups SET create_ts = (SELECT create_ts FROM "group" WHERE "group".id = vk_groups.id);')
op.execute('UPDATE vk_groups SET update_ts = (SELECT update_ts FROM "group" WHERE "group".id = vk_groups.id);')
op.alter_column('vk_groups', 'create_ts', nullable=False)
op.alter_column('vk_groups', 'update_ts', nullable=False)
op.drop_constraint('group_vkgroup_fk', 'vk_groups', type_='foreignkey')
op.drop_table('vk_chat')
op.drop_table('telegram_chat')
op.drop_table('telegram_channel')
op.drop_table('group')
op.execute('DROP SEQUENCE IF EXISTS group_id_seq CASCADE;')
1 change: 1 addition & 0 deletions migrations/versions/57c72962d2b4_webhook_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Create Date: 2023-03-12 14:22:34.958257
"""

import sqlalchemy as sa
from alembic import op

Expand Down
25 changes: 25 additions & 0 deletions migrations/versions/62addefd9655_webhookstorage_event_ts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""WebhookStorage event_ts
Revision ID: 62addefd9655
Revises: 1cacaf803a1d
Create Date: 2024-04-15 00:21:54.075449
"""

import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = '62addefd9655'
down_revision = '1cacaf803a1d'
branch_labels = None
depends_on = None


def upgrade():
op.add_column('webhook_storage', sa.Column('event_ts', sa.DateTime(), nullable=True))


def downgrade():
op.drop_column('webhook_storage', 'event_ts')
8 changes: 5 additions & 3 deletions migrations/versions/9d98c1e9c864_vk.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
Create Date: 2023-08-19 15:53:19.787309
"""
from alembic import op

import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
Expand All @@ -17,14 +18,15 @@


def upgrade():
op.create_table('vk_groups',
op.create_table(
'vk_groups',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('group_id', sa.Integer(), nullable=False),
sa.Column('confirmation_token', sa.String(), nullable=False),
sa.Column('secret_key', sa.String(), nullable=False),
sa.Column('create_ts', sa.DateTime(), nullable=False),
sa.Column('update_ts', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
sa.PrimaryKeyConstraint('id'),
)


Expand Down
1 change: 1 addition & 0 deletions social/handlers_discord/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from collections.abc import Callable

from social.utils.events import EventProcessor


Expand Down
1 change: 1 addition & 0 deletions social/handlers_github/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from collections.abc import Callable

from social.utils.events import EventProcessor


Expand Down
2 changes: 2 additions & 0 deletions social/handlers_telegram/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

@lru_cache()
def get_application():
if not settings.TELEGRAM_BOT_TOKEN:
return None
context_types = ContextTypes(context=CustomContext)
app = Application.builder().token(settings.TELEGRAM_BOT_TOKEN).updater(None).context_types(context_types).build()
logger.info("Telegram API initialized successfully")
Expand Down
1 change: 1 addition & 0 deletions social/handlers_telegram/handlers_viribus.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Для создания нового обработчика создай асинхронную функцию в конце файла с параметрами
Update и Context, а потом зарегистрируй ее внутри функции `register_handlers`.
"""

import logging
from random import choice
from string import ascii_letters, digits, punctuation
Expand Down
4 changes: 2 additions & 2 deletions social/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .vk import VkGroups
from .group import TelegramChannel, TelegramChat, VkChat, VkGroup
from .webhook_storage import WebhookStorage


__all__ = ['WebhookStorage', 'VkGroups']
__all__ = ['WebhookStorage', 'TelegramChannel', 'TelegramChat', 'VkGroup', 'VkChat']
60 changes: 60 additions & 0 deletions social/models/group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from datetime import UTC, datetime

import sqlalchemy as sa
from sqlalchemy.orm import Mapped, mapped_column

from .base import Base


class Group(Base):
id: Mapped[int] = mapped_column(primary_key=True)
type: Mapped[str]
owner_id: Mapped[int | None]

is_deleted: Mapped[bool] = mapped_column(default=False)
last_active_ts: Mapped[datetime | None]

create_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC))
update_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC), onupdate=lambda: datetime.now(UTC))

__mapper_args__ = {
"polymorphic_on": "type",
}


class VkGroup(Group):
id: Mapped[int] = mapped_column(sa.ForeignKey("group.id"), primary_key=True)
group_id: Mapped[int]
confirmation_token: Mapped[str]
secret_key: Mapped[str]

__mapper_args__ = {
"polymorphic_identity": "vk_group",
}


class VkChat(Group):
id: Mapped[int] = mapped_column(sa.ForeignKey("group.id"), primary_key=True)
peer_id: Mapped[int]

__mapper_args__ = {
"polymorphic_identity": "vk_chat",
}


class TelegramChannel(Group):
id: Mapped[int] = mapped_column(sa.ForeignKey("group.id"), primary_key=True)
channel_id: Mapped[int]

__mapper_args__ = {
"polymorphic_identity": "tg_channel",
}


class TelegramChat(Group):
id: Mapped[int] = mapped_column(sa.ForeignKey("group.id"), primary_key=True)
chat_id: Mapped[int]

__mapper_args__ = {
"polymorphic_identity": "tg_chat",
}
15 changes: 0 additions & 15 deletions social/models/vk.py

This file was deleted.

2 changes: 2 additions & 0 deletions social/models/webhook_storage.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from datetime import UTC, datetime
from enum import Enum

import sqlalchemy as sa
Expand All @@ -17,3 +18,4 @@ class WebhookStorage(Base):
id: Mapped[int] = mapped_column(sa.Integer, primary_key=True)
system: Mapped[WebhookSystems] = mapped_column(sa.Enum(WebhookSystems, native_enum=False))
message: Mapped[sa.JSON] = mapped_column(sa.JSON(True))
event_ts: Mapped[datetime] = mapped_column(default=lambda: datetime.now(UTC), nullable=True)
Loading

0 comments on commit 3359b85

Please sign in to comment.