Skip to content

Commit e19e434

Browse files
authored
Merge pull request #121 from profcomff/pivo.advancedSort
Pivo.advanced sort
2 parents 391d0f7 + 6f44efb commit e19e434

File tree

5 files changed

+100
-32
lines changed

5 files changed

+100
-32
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""advanced_sort
2+
3+
Revision ID: 1c001709fc55
4+
Revises: dd44854aa12a
5+
Create Date: 2025-04-26 17:01:57.140143
6+
7+
"""
8+
9+
import sqlalchemy as sa
10+
from alembic import op
11+
12+
13+
revision = '1c001709fc55'
14+
down_revision = 'dd44854aa12a'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
op.alter_column('comment', 'approved_by', existing_type=sa.INTEGER(), nullable=True)
21+
22+
23+
def downgrade():
24+
op.alter_column('comment', 'approved_by', existing_type=sa.INTEGER(), nullable=False)

rating_api/models/db.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from fastapi_sqlalchemy import db
99
from sqlalchemy import UUID, Boolean, DateTime
1010
from sqlalchemy import Enum as DbEnum
11-
from sqlalchemy import ForeignKey, Integer, String, UnaryExpression, and_, func, nulls_last, or_, true
11+
from sqlalchemy import ForeignKey, Integer, String, UnaryExpression, and_, desc, func, nulls_last, or_, true
1212
from sqlalchemy.ext.hybrid import hybrid_method, hybrid_property
1313
from sqlalchemy.orm import Mapped, mapped_column, relationship
1414
from sqlalchemy.orm.attributes import InstrumentedAttribute
@@ -123,6 +123,28 @@ class Comment(BaseDbModel):
123123
def mark_general(self):
124124
return (self.mark_kindness + self.mark_freebie + self.mark_clarity) / 3
125125

126+
@hybrid_method
127+
def order_by_create_ts(
128+
self, query: str, asc_order: bool
129+
) -> UnaryExpression[datetime.datetime] | InstrumentedAttribute:
130+
return getattr(Comment, query) if asc_order else desc(getattr(Comment, query))
131+
132+
@hybrid_method
133+
def order_by_mark(self, query: str, asc_order: bool) -> UnaryExpression[float] | InstrumentedAttribute:
134+
return getattr(Comment, query) if asc_order else desc(getattr(Comment, query))
135+
136+
@hybrid_method
137+
def search_by_lectorer_id(self, query: int) -> bool:
138+
if not query:
139+
return true()
140+
return and_(Comment.review_status == ReviewStatus.APPROVED, Comment.lecturer_id == query)
141+
142+
@hybrid_method
143+
def search_by_user_id(self, query: int) -> bool:
144+
if not query:
145+
return true()
146+
return Comment.user_id == query
147+
126148

127149
class LecturerUserComment(BaseDbModel):
128150
id: Mapped[int] = mapped_column(Integer, primary_key=True)

rating_api/routes/comment.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -173,28 +173,47 @@ async def get_comments(
173173
offset: int = 0,
174174
lecturer_id: int | None = None,
175175
user_id: int | None = None,
176-
order_by: list[Literal["create_ts"]] = Query(default=[]),
176+
order_by: str = Query(
177+
enum=["create_ts", "mark_kindness", "mark_freebie", "mark_clarity", "mark_general"],
178+
default="create_ts",
179+
),
177180
unreviewed: bool = False,
178-
user=Depends(UnionAuth(scopes=["rating.comment.review"], auto_error=False, allow_none=True)),
181+
asc_order: bool = False,
182+
user=Depends(UnionAuth(scopes=["rating.comment.review"], auto_error=False, allow_none=False)),
179183
) -> CommentGetAll:
180184
"""
181-
Scopes: `["rating.comment.review"]`
185+
Scopes: `["rating.comment.review"]`
186+
187+
`limit` - максимальное количество возвращаемых комментариев
182188
183-
`limit` - максимальное количество возвращаемых комментариев
189+
`offset` - смещение, определяющее, с какого по порядку комментария начинать выборку.
190+
Если без смещения возвращается комментарий с условным номером N,
191+
то при значении offset = X будет возвращаться комментарий с номером N + X
184192
185-
`offset` - смещение, определяющее, с какого по порядку комментария начинать выборку.
186-
Если без смещения возвращается комментарий с условным номером N,
187-
то при значении offset = X будет возвращаться комментарий с номером N + X
193+
`order_by` - возможные значения `"create_ts", "mark_kindness", "mark_freebie", "mark_clarity", "mark_general"`.
194+
Если передано `'create_ts'` - возвращается список комментариев отсортированных по времени
195+
Если передано `'mark_...'` - возвращается список комментариев отсортированных по конкретной оценке
188196
189-
`order_by` - возможное значение `'create_ts'` - возвращается список комментариев отсортированных по времени создания
197+
`lecturer_id` - вернет все комментарии для преподавателя с конкретным id, по дефолту возвращает вообще все аппрувнутые комментарии.
190198
191-
`lecturer_id` - вернет все комментарии для преподавателя с конкретным id, по дефолту возвращает вообще все аппрувнутые комментарии.
199+
`user_id` - вернет все комментарии пользователя с конкретным id
192200
193-
`user_id` - вернет все комментарии пользователя с конкретным id
201+
`unreviewed` - вернет все непроверенные комментарии, если True. По дефолту False.
194202
195-
`unreviewed` - вернет все непроверенные комментарии, если True. По дефолту False.
203+
`asc_order` -Если передано true, сортировать в порядке возрастания. Иначе - в порядке убывания
196204
"""
197-
comments = Comment.query(session=db.session).all()
205+
comments_query = (
206+
Comment.query(session=db.session)
207+
.filter(Comment.search_by_lectorer_id(lecturer_id))
208+
.filter(Comment.search_by_user_id(user_id))
209+
.order_by(
210+
Comment.order_by_mark(order_by, asc_order)
211+
if "mark" in order_by
212+
else Comment.order_by_create_ts(order_by, asc_order)
213+
)
214+
)
215+
216+
comments = comments_query.limit(limit).offset(offset).all()
198217
if not comments:
199218
raise ObjectNotFound(Comment, 'all')
200219
if user and "rating.comment.review" in [scope['name'] for scope in user.get('session_scopes')]:
@@ -206,12 +225,8 @@ async def get_comments(
206225
else:
207226
result = CommentGetAll(limit=limit, offset=offset, total=len(comments))
208227
comment_validator = CommentGet
209-
result.comments = comments
210-
if user_id is not None:
211-
result.comments = [comment for comment in result.comments if comment.user_id == user_id]
212228

213-
if lecturer_id is not None:
214-
result.comments = [comment for comment in result.comments if comment.lecturer_id == lecturer_id]
229+
result.comments = comments
215230

216231
if unreviewed:
217232
if not user:
@@ -223,13 +238,9 @@ async def get_comments(
223238
else:
224239
result.comments = [comment for comment in result.comments if comment.review_status is ReviewStatus.APPROVED]
225240

226-
result.comments = result.comments[offset : limit + offset]
227-
228-
if "create_ts" in order_by:
229-
result.comments.sort(key=lambda comment: comment.create_ts, reverse=True)
230241
result.total = len(result.comments)
231242
result.comments = [comment_validator.model_validate(comment) for comment in result.comments]
232-
result.comments.sort(key=lambda comment: comment.create_ts, reverse=True)
243+
233244
return result
234245

235246

tests/conftest.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ def lecturer(dbsession):
4646
@pytest.fixture
4747
def comment(dbsession, lecturer):
4848
_comment = Comment(
49+
user_id=0,
50+
create_ts="2025-04-25T19:38:56.408Z",
4951
subject="test_subject",
5052
text="test_comment",
5153
mark_kindness=1,
@@ -166,8 +168,9 @@ def lecturers_with_comments(dbsession, lecturers):
166168
(lecturers[2].id, 9992, 'test_subject12', ReviewStatus.APPROVED, 0, 0, 0),
167169
]
168170

169-
comments = [
170-
Comment(
171+
comments = []
172+
for lecturer_id, user_id, subject, review_status, mark_kindness, mark_clarity, mark_freebie in comments_data:
173+
comment = Comment(
171174
subject=subject,
172175
text="test_comment",
173176
mark_kindness=mark_kindness,
@@ -177,8 +180,12 @@ def lecturers_with_comments(dbsession, lecturers):
177180
user_id=user_id,
178181
review_status=review_status,
179182
)
180-
for lecturer_id, user_id, subject, review_status, mark_kindness, mark_clarity, mark_freebie in comments_data
181-
]
183+
184+
# Set approved_by to -1 for approved or dismissed comments
185+
if review_status in [ReviewStatus.APPROVED, ReviewStatus.DISMISSED]:
186+
comment.approved_by = -1
187+
188+
comments.append(comment)
182189

183190
dbsession.add_all(comments)
184191
dbsession.commit()

tests/test_routes/test_comment.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,16 @@ def test_create_comment(client, dbsession, lecturers, body, lecturer_n, response
198198

199199
def test_get_comment(client, comment):
200200
response_comment = client.get(f'{url}/{comment.uuid}')
201+
print("1")
201202
assert response_comment.status_code == status.HTTP_200_OK
202203
random_uuid = uuid.uuid4()
203204
response = client.get(f'{url}/{random_uuid}')
204205
assert response.status_code == status.HTTP_404_NOT_FOUND
205206

206207

207208
@pytest.mark.parametrize(
208-
'lecturer_n,response_status', [(0, status.HTTP_200_OK), (1, status.HTTP_200_OK), (3, status.HTTP_200_OK)]
209+
'lecturer_n,response_status',
210+
[(0, status.HTTP_200_OK), (1, status.HTTP_200_OK), (2, status.HTTP_200_OK), (3, status.HTTP_404_NOT_FOUND)],
209211
)
210212
def test_comments_by_lecturer_id(client, lecturers_with_comments, lecturer_n, response_status):
211213
lecturers, comments = lecturers_with_comments
@@ -216,8 +218,10 @@ def test_comments_by_lecturer_id(client, lecturers_with_comments, lecturer_n, re
216218
assert len(json_response["comments"]) == len(
217219
[
218220
comment
219-
for comment in lecturers[lecturer_n].comments
220-
if comment.review_status == ReviewStatus.APPROVED and not comment.is_deleted
221+
for comment in comments
222+
if comment.lecturer_id == lecturers[lecturer_n].id
223+
and comment.review_status == ReviewStatus.APPROVED
224+
and not comment.is_deleted
221225
]
222226
)
223227

@@ -227,15 +231,15 @@ def test_comments_by_lecturer_id(client, lecturers_with_comments, lecturer_n, re
227231
)
228232
def test_comments_by_user_id(client, lecturers_with_comments, user_id, response_status):
229233
_, comments = lecturers_with_comments
230-
response = response = client.get(f'{url}', params={"user_id": user_id})
234+
response = client.get(f'{url}', params={"user_id": 9990 + user_id})
231235
assert response.status_code == response_status
232236
if response.status_code == status.HTTP_200_OK:
233237
json_response = response.json()
234238
assert len(json_response["comments"]) == len(
235239
[
236240
comment
237241
for comment in comments
238-
if comment.user_id == user_id
242+
if comment.user_id == 9990 + user_id
239243
and comment.review_status == ReviewStatus.APPROVED
240244
and not comment.is_deleted
241245
]

0 commit comments

Comments
 (0)