Skip to content
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
79 changes: 64 additions & 15 deletions rating_api/routes/comment.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,19 @@
@comment.post("", response_model=CommentGet)
async def create_comment(lecturer_id: int, comment_info: CommentPost, user=Depends(UnionAuth())) -> CommentGet:
"""
Scopes: `["rating.comment.create"]`

Создает комментарий к преподавателю в базе данных RatingAPI
Для создания комментария нужно быть авторизованным

Комментарий создается со статусом PENDING (на модерации)

Исключение **TooManyCommentRequests**, если число комментариев превысило общий лимит

Исключение **TooManyCommentsToLecturer**, если число комментариев превысило лимит для лектора

Исключение **CommentTooLong**, если комментарий слишком длинный

Исключение **ForbiddenSymbol**, если в комментарии использованы запрещенные символы
"""
# Проверяем, что лектор с заданным id существует
Lecturer.get(session=db.session, id=lecturer_id)
Expand Down Expand Up @@ -148,7 +159,8 @@ async def import_comments(
) -> CommentGetAll:
"""
Scopes: `["rating.comment.import"]`
Создает комментарии в базе данных RatingAPI

Создает комментарии в базе данных
"""
number_of_comments = len(comments_info.comments)
result = CommentGetAll(limit=number_of_comments, offset=number_of_comments, total=number_of_comments)
Expand All @@ -165,7 +177,13 @@ async def import_comments(
@comment.get("/{uuid}", response_model=CommentGet)
async def get_comment(uuid: UUID, user=Depends(UnionAuth(auto_error=False, allow_none=False))) -> CommentGet:
"""
Scopes: `["rating.comment.read"]`

Возвращает комментарий по его UUID в базе данных RatingAPI

Если пользователь авторизован, добавляются флаги is_liked/is_disliked (реакция пользователя на комментарий)

Исключение **ObjectNotFound**, если `uuid` не найден
"""
comment: Comment = Comment.query(session=db.session).filter(Comment.uuid == uuid).one_or_none()
if comment is None:
Expand Down Expand Up @@ -213,6 +231,15 @@ async def get_comments(
`unreviewed` - вернет все непроверенные комментарии, если True. По дефолту False.

`asc_order` -Если передано true, сортировать в порядке возрастания. Иначе - в порядке убывания

Разные модели ответа в зависимости от прав пользователя:
CommentGetAllWithAllInfo: для модераторов (со статусом комментария);
CommentGetAllWithStatus: для авторов комментариев (со статусом);
CommentGetAll: для всех остальных (только одобренные комментарии)

Исключение **ObjectNotFound**, если комментарий с введенными параметрами не найден

Исключение **ForbiddenAction**, если пользователь пытается получить непроверенный комментарий
"""
comments_query = (
Comment.query(session=db.session)
Expand Down Expand Up @@ -288,6 +315,12 @@ async def review_comment(
`review_status` - возможные значения
`approved` - комментарий одобрен и возвращается при запросе лектора
`dismissed` - комментарий отклонен, не отображается в запросе лектора

Комментарий может быть либо одобрен, либо отклонен

Отклоненные комментарии не отображаются в обычных GET-запросах(можно посмотреть только через `uuid`)

Исключение **ObjectNotFound**, если `uuid` не найден
"""
check_comment: Comment = Comment.query(session=db.session).filter(Comment.uuid == uuid).one_or_none()

Expand All @@ -301,7 +334,17 @@ async def review_comment(

@comment.patch("/{uuid}", response_model=CommentGet)
async def update_comment(uuid: UUID, comment_update: CommentUpdate, user=Depends(UnionAuth())) -> CommentGet:
"""Позволяет изменить свой неанонимный комментарий"""
"""
Scopes: `["rating.comment.update"]`

Позволяет изменить свой неанонимный комментарий

После редактирования комментарий снова отправляется на модерацию

Исключение **ForbiddenAction** при попытке отредактировать чужой комментарий

Исключение **ForbiddenAction** при попытке отредактировать анонимный комментарий
"""
comment: Comment = Comment.get(session=db.session, id=uuid) # Ошибка, если не найден

if comment.user_id != user.get("id") or comment.user_id is None:
Expand Down Expand Up @@ -334,6 +377,16 @@ async def delete_comment(
Scopes: `["rating.comment.delete"]`

Удаляет комментарий по его UUID в базе данных RatingAPI

Модератор может удалить любой комментарий

Обычный пользователь может удалить только свой неанонимный комментарий

Анонимные комментарии может удалить только модератор

Исключение **ObjectNotFound**, если `uuid` не найден

Исключение **ForbiddenAction** при попытке удалить комментарий пользователем без прав
"""
comment = Comment.get(uuid, session=db.session)
if comment is None:
Expand All @@ -358,22 +411,18 @@ async def like_comment(
user=Depends(UnionAuth()),
) -> CommentGet:
"""
Handles like/dislike reactions for a comment.
Scopes: `["rating.comment.write"]`

This endpoint allows authenticated users to react to a comment (like/dislike) or change their existing reaction.
If the user has no existing reaction, a new one is created. If the user changes their reaction, it gets updated.
If the user clicks the same reaction again, the reaction is removed.
Ставит лайк или дизлайк на комментарий по его uuid
Comment thread
petrCher marked this conversation as resolved.

Args:
uuid (UUID): The UUID of the comment to react to.
reaction (Reaction): The reaction type (like/dislike).
user (dict): Authenticated user data from UnionAuth dependency.
Дизлайка и лайка не может быть одновременно

Returns:
CommentGet: The updated comment with reactions in CommentGet format.
Если реакции от пользователя на этот комментарий не было — создается новая;
Если была противоположная реакция — она заменяется на новую;
Если была такая же реакция — она удаляется;
После операции поля is_liked/is_disliked в ответе отражают итоговое состояние

Raises:
ObjectNotFound: If the comment with given UUID doesn't exist.
Исключение **ObjectNotFound**, если `uuid` не найден
"""
comment = Comment.get(session=db.session, id=uuid)
if not comment:
Expand Down
24 changes: 20 additions & 4 deletions rating_api/routes/lecturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ async def create_lecturer(
"""
Scopes: `["rating.lecturer.create"]`

Создает преподавателя в базе данных RatingAPI
Создает преподавателя в базе данных

Исключение **AlreadyExists**, если преподаватель с введеным `timetable_id` уже существует
"""
get_lecturer: Lecturer = (
Lecturer.query(session=db.session).filter(Lecturer.timetable_id == lecturer_info.timetable_id).one_or_none()
Expand All @@ -54,7 +56,7 @@ async def update_lecturer_rating(
"""
Scopes: `["rating.lecturer.update_rating"]`

Обновляет рейтинг преподавателя в базе данных RatingAPI
Обновляет рейтинг преподавателя в базе данных
"""
updated_lecturers = []
response = {
Expand Down Expand Up @@ -95,6 +97,8 @@ async def update_lecturer_rating(
async def get_lecturer_by_timetable_id(timetable_id: int) -> LecturerGet:
"""
Возвращает преподавателя по его timetable_id

Исключение **ObjectNotFound**, если `timetable_id` не найден
"""
lecturer: Lecturer = Lecturer.query(session=db.session).filter(Lecturer.timetable_id == timetable_id).one_or_none()
if lecturer is None:
Expand All @@ -107,11 +111,13 @@ async def get_lecturer(id: int, info: list[Literal["comments"]] = Query(default=
"""
Scopes: `["rating.lecturer.read"]`

Возвращает преподавателя по его ID в базе данных RatingAPI
Возвращает преподавателя по его ID в базе данных

*QUERY* `info: string` - возможные значения `'comments'`.
Если передано `'comments'`, то возвращаются одобренные комментарии к преподавателю.
Subject лектора возвращшается либо из базы данных, либо из любого аппрувнутого комментария
Subject лектора возвращается либо из базы данных, либо из любого аппрувнутого комментария

Исключение **ObjectNotFound**, если `id` не найден
"""
lecturer: Lecturer = Lecturer.query(session=db.session).filter(Lecturer.id == id).one_or_none()
if lecturer is None:
Expand Down Expand Up @@ -168,6 +174,8 @@ async def get_lecturers(
`mark`
Поле для оценки. Если передано, то возвращает только тех преподавателей, для которых средняя общая оценка ('general_mark')
больше, чем переданный 'mark'.

Исключение **ObjectNotFound**, если преподаватель с введенными параметрами не найден
"""
lecturers_query = lecturer_filter.filter(
Lecturer.query(session=db.session).outerjoin(Lecturer.comments).group_by(Lecturer.id)
Expand Down Expand Up @@ -212,6 +220,10 @@ async def update_lecturer(
) -> LecturerGet:
"""
Scopes: `["rating.lecturer.update"]`

Обновляет данные о преподавателе по его id

Исключение **ObjectNotFound**, если `id` не найден
"""
lecturer = Lecturer.get(id, session=db.session)
if lecturer is None:
Expand All @@ -238,6 +250,10 @@ async def delete_lecturer(
):
"""
Scopes: `["rating.lecturer.delete"]`

Удаляет из базы данных преподавателя по его id

Исключение **ObjectNotFound**, если `id` не найден
"""
check_lecturer = Lecturer.get(session=db.session, id=id)
if check_lecturer is None:
Expand Down
Loading