-
Notifications
You must be signed in to change notification settings - Fork 3
Рейтинг преподавателей #6
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
Merged
The head ref may contain hidden characters: "1-\u0431\u044D\u043A-\u0440\u0435\u0439\u0442\u0438\u043D\u0433\u0430-\u043F\u0440\u0435\u043F\u043E\u0434\u043E\u0432"
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
3f736c6
DB. Lecturer routes
Temmmmmo aa14c58
Comment. Linting
Temmmmmo e7178ba
Linting
Temmmmmo 92ba076
makefile fix
Temmmmmo 2a127bf
lecturer scopes fix
Temmmmmo c2de3de
refactor fixes
Temmmmmo c24983e
Add uuid to comment. Fixes
Temmmmmo c80b4c7
Linting
Temmmmmo 7c24d94
Linting
Temmmmmo e472916
Adding UUID
Temmmmmo f4a98af
Adding Tests
Temmmmmo fa93539
Linting
Temmmmmo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
migrations/versions/656228b2d6e0_delete_id_from_comment.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| """delete-id-from-comment | ||
|
|
||
| Revision ID: 656228b2d6e0 | ||
| Revises: 7354951f8e4c | ||
| Create Date: 2024-10-17 15:30:15.168365 | ||
|
|
||
| """ | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
|
|
||
| revision = '656228b2d6e0' | ||
| down_revision = '7354951f8e4c' | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| op.drop_column('comment', 'id') | ||
|
|
||
|
|
||
| def downgrade(): | ||
| op.add_column('comment', sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| """add-uuid-to-comment | ||
|
|
||
| Revision ID: 7354951f8e4c | ||
| Revises: dbe6ca79a40d | ||
| Create Date: 2024-10-17 15:25:02.529966 | ||
|
|
||
| """ | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
|
|
||
| revision = '7354951f8e4c' | ||
| down_revision = 'dbe6ca79a40d' | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| op.add_column('comment', sa.Column('uuid', sa.UUID(), nullable=True)) | ||
| op.execute(f'UPDATE "comment" SET uuid = gen_random_uuid()') | ||
| op.alter_column('comment', 'uuid', nullable=False) | ||
|
|
||
|
|
||
| def downgrade(): | ||
| op.drop_column('comment', 'uuid') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| """init | ||
|
|
||
| Revision ID: dbe6ca79a40d | ||
| Revises: | ||
| Create Date: 2024-10-16 23:21:37.960911 | ||
|
|
||
| """ | ||
|
|
||
| import sqlalchemy as sa | ||
| from alembic import op | ||
|
|
||
|
|
||
| revision = 'dbe6ca79a40d' | ||
| down_revision = None | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade(): | ||
| op.create_table( | ||
| 'lecturer', | ||
| sa.Column('id', sa.Integer(), nullable=False), | ||
| sa.Column('first_name', sa.String(), nullable=False), | ||
| sa.Column('last_name', sa.String(), nullable=False), | ||
| sa.Column('middle_name', sa.String(), nullable=False), | ||
| sa.Column('subject', sa.String(), nullable=True), | ||
| sa.Column('avatar_link', sa.String(), nullable=True), | ||
| sa.Column('timetable_id', sa.Integer(), nullable=False), | ||
| sa.PrimaryKeyConstraint('id'), | ||
| sa.UniqueConstraint('timetable_id'), | ||
| ) | ||
| op.create_table( | ||
| 'comment', | ||
| sa.Column('id', sa.Integer(), nullable=False), | ||
| sa.Column('create_ts', sa.DateTime(), nullable=False), | ||
| sa.Column('update_ts', sa.DateTime(), nullable=False), | ||
| sa.Column('subject', sa.String(), nullable=False), | ||
| sa.Column('text', sa.String(), nullable=True), | ||
| sa.Column('mark_kindness', sa.Integer(), nullable=False), | ||
| sa.Column('mark_freebie', sa.Integer(), nullable=False), | ||
| sa.Column('mark_clarity', sa.Integer(), nullable=False), | ||
| sa.Column('lecturer_id', sa.Integer(), nullable=False), | ||
| sa.Column( | ||
| 'review_status', | ||
| sa.Enum('APPROVED', 'PENDING', 'DISMISSED', name='reviewstatus', native_enum=False), | ||
| nullable=False, | ||
| ), | ||
| sa.ForeignKeyConstraint( | ||
| ['lecturer_id'], | ||
| ['lecturer.id'], | ||
| ), | ||
| sa.PrimaryKeyConstraint('id'), | ||
| ) | ||
| op.create_table( | ||
| 'lecturer_user_comment', | ||
| sa.Column('id', sa.Integer(), nullable=False), | ||
| sa.Column('lecturer_id', sa.Integer(), nullable=False), | ||
| sa.Column('user_id', sa.Integer(), nullable=False), | ||
| sa.Column('create_ts', sa.DateTime(), nullable=False), | ||
| sa.Column('update_ts', sa.DateTime(), nullable=False), | ||
| sa.ForeignKeyConstraint( | ||
| ['lecturer_id'], | ||
| ['lecturer.id'], | ||
| ), | ||
| sa.PrimaryKeyConstraint('id'), | ||
| ) | ||
|
|
||
|
|
||
| def downgrade(): | ||
| op.drop_table('lecturer_user_comment') | ||
| op.drop_table('comment') | ||
| op.drop_table('lecturer') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| from .base import Base, BaseDbModel | ||
| from .db import * | ||
|
|
||
|
|
||
| __all__ = ["Base", "BaseDbModel", "Lecturer", "LecturerUserComment", "Comment"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import re | ||
|
|
||
| from sqlalchemy import Integer, not_ | ||
| from sqlalchemy.exc import NoResultFound | ||
| from sqlalchemy.orm import Mapped, Query, Session, as_declarative, declared_attr, mapped_column | ||
|
|
||
| from rating_api.exceptions import ObjectNotFound | ||
|
|
||
|
|
||
| @as_declarative() | ||
| class Base: | ||
| """Base class for all database entities""" | ||
|
|
||
| @declared_attr | ||
| def __tablename__(cls) -> str: # pylint: disable=no-self-argument | ||
| """Generate database table name automatically. | ||
| Convert CamelCase class name to snake_case db table name. | ||
| """ | ||
| return re.sub(r"(?<!^)(?=[A-Z])", "_", cls.__name__).lower() | ||
|
|
||
| def __repr__(self): | ||
| attrs = [] | ||
| for c in self.__table__.columns: | ||
| attrs.append(f"{c.name}={getattr(self, c.name)}") | ||
| return "{}({})".format(c.__class__.__name__, ', '.join(attrs)) | ||
|
|
||
|
|
||
| class BaseDbModel(Base): | ||
| __abstract__ = True | ||
|
|
||
| @classmethod | ||
| def create(cls, *, session: Session, **kwargs) -> BaseDbModel: | ||
| obj = cls(**kwargs) | ||
| session.add(obj) | ||
| session.flush() | ||
| return obj | ||
|
|
||
| @classmethod | ||
| def query(cls, *, with_deleted: bool = False, session: Session) -> Query: | ||
| """Get all objects with soft deletes""" | ||
| objs = session.query(cls) | ||
| if not with_deleted and hasattr(cls, "is_deleted"): | ||
| objs = objs.filter(not_(cls.is_deleted)) | ||
| return objs | ||
|
|
||
| @classmethod | ||
| def get(cls, id: int | str, *, with_deleted=False, session: Session) -> BaseDbModel: | ||
| """Get object with soft deletes""" | ||
| objs = session.query(cls) | ||
| if not with_deleted and hasattr(cls, "is_deleted"): | ||
| objs = objs.filter(not_(cls.is_deleted)) | ||
| try: | ||
| if hasattr(cls, "uuid"): | ||
| return objs.filter(cls.uuid == id).one() | ||
| return objs.filter(cls.id == id).one() | ||
| except NoResultFound: | ||
| raise ObjectNotFound(cls, id) | ||
|
|
||
| @classmethod | ||
| def update(cls, id: int | str, *, session: Session, **kwargs) -> BaseDbModel: | ||
| obj = cls.get(id, session=session) | ||
| for k, v in kwargs.items(): | ||
| setattr(obj, k, v) | ||
| session.flush() | ||
| return obj | ||
|
|
||
| @classmethod | ||
| def delete(cls, id: int | str, *, session: Session) -> None: | ||
| """Soft delete object if possible, else hard delete""" | ||
| obj = cls.get(id, session=session) | ||
| if hasattr(obj, "is_deleted"): | ||
| obj.is_deleted = True | ||
| else: | ||
| session.delete(obj) | ||
| session.flush() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import datetime | ||
| import logging | ||
| import uuid | ||
| from enum import Enum | ||
|
|
||
| from sqlalchemy import UUID, Boolean, DateTime | ||
| from sqlalchemy import Enum as DbEnum | ||
| from sqlalchemy import ForeignKey, Integer, String | ||
| from sqlalchemy.orm import Mapped, mapped_column, relationship | ||
|
|
||
| from rating_api.settings import get_settings | ||
|
|
||
| from .base import BaseDbModel | ||
|
|
||
|
|
||
| settings = get_settings() | ||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class ReviewStatus(str, Enum): | ||
| APPROVED: str = "approved" | ||
| PENDING: str = "pending" | ||
| DISMISSED: str = "dismissed" | ||
|
|
||
|
|
||
| class Lecturer(BaseDbModel): | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| first_name: Mapped[str] = mapped_column(String, nullable=False) | ||
| last_name: Mapped[str] = mapped_column(String, nullable=False) | ||
| middle_name: Mapped[str] = mapped_column(String, nullable=False) | ||
| subject: Mapped[str] = mapped_column(String, nullable=True) | ||
| avatar_link: Mapped[str] = mapped_column(String, nullable=True) | ||
| timetable_id: Mapped[int] = mapped_column(Integer, unique=True, nullable=False) | ||
| comments: Mapped[list[Comment]] = relationship("Comment", back_populates="lecturer") | ||
|
|
||
|
|
||
| class Comment(BaseDbModel): | ||
| uuid: Mapped[uuid.UUID] = mapped_column(UUID, primary_key=True, default=uuid.uuid4) | ||
| create_ts: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.datetime.utcnow, nullable=False) | ||
| update_ts: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.datetime.utcnow, nullable=False) | ||
| subject: Mapped[str] = mapped_column(String, nullable=False) | ||
| text: Mapped[str] = mapped_column(String, nullable=True) | ||
| mark_kindness: Mapped[int] = mapped_column(Integer, nullable=False) | ||
| mark_freebie: Mapped[int] = mapped_column(Integer, nullable=False) | ||
| mark_clarity: Mapped[int] = mapped_column(Integer, nullable=False) | ||
| lecturer_id: Mapped[int] = mapped_column(Integer, ForeignKey("lecturer.id")) | ||
| lecturer: Mapped[Lecturer] = relationship("Lecturer", back_populates="comments") | ||
| review_status: Mapped[ReviewStatus] = mapped_column(DbEnum(ReviewStatus, native_enum=False), nullable=False) | ||
|
|
||
|
|
||
| class LecturerUserComment(BaseDbModel): | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| lecturer_id: Mapped[int] = mapped_column(Integer, ForeignKey("lecturer.id")) | ||
| user_id: Mapped[int] = mapped_column(Integer, nullable=False) | ||
|
Temmmmmo marked this conversation as resolved.
|
||
| create_ts: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.datetime.utcnow, nullable=False) | ||
| update_ts: Mapped[datetime.datetime] = mapped_column(DateTime, default=datetime.datetime.utcnow, nullable=False) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import datetime | ||
| from typing import Type | ||
|
|
||
|
|
||
| class RatingAPIError(Exception): | ||
| eng: str | ||
| ru: str | ||
|
|
||
| def __init__(self, eng: str, ru: str) -> None: | ||
| self.eng = eng | ||
| self.ru = ru | ||
| super().__init__(eng) | ||
|
|
||
|
|
||
| class ObjectNotFound(RatingAPIError): | ||
| def __init__(self, obj: type, obj_id_or_name: int | str): | ||
| super().__init__( | ||
| f"Object {obj.__name__} {obj_id_or_name=} not found", | ||
| f"Объект {obj.__name__} с идентификатором {obj_id_or_name} не найден", | ||
| ) | ||
|
|
||
|
|
||
| class AlreadyExists(RatingAPIError): | ||
| def __init__(self, obj: type, obj_id_or_name: int | str): | ||
| super().__init__( | ||
| f"Object {obj.__name__}, {obj_id_or_name=} already exists", | ||
| f"Объект {obj.__name__} с идентификатором {obj_id_or_name=} уже существует", | ||
| ) | ||
|
|
||
|
|
||
| class TooManyCommentRequests(RatingAPIError): | ||
| delay_time: datetime.timedelta | ||
|
|
||
| def __init__(self, dtime: datetime.timedelta): | ||
| self.delay_time = dtime | ||
| super().__init__( | ||
| f'Too many comment requests. Delay: {dtime}', | ||
| f'Слишком много попыток оставить комментарий. Задержка: {dtime}', | ||
| ) | ||
|
|
||
|
|
||
| class ForbiddenAction(RatingAPIError): | ||
| def __init__(self, type: Type): | ||
| super().__init__(f"Forbidden action with {type.__name__}", f"Запрещенное действие с объектом {type.__name__}") |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| from . import exc_handlers | ||
| from .base import app | ||
|
|
||
|
|
||
| __all__ = ["app", "exc_handlers"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.