Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Группы как сущность #30

Merged
merged 12 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading