v0.4.7
This commit is contained in:
parent
a9d181db8f
commit
79f7c914d7
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -1,3 +1,20 @@
|
||||||
|
#### [0.4.7]
|
||||||
|
- `get_my_rates_shouts` resolver added with:
|
||||||
|
- `shout_id` and `my_rate` fields in response
|
||||||
|
- filters by `Reaction.deleted_at.is_(None)`
|
||||||
|
- filters by `Reaction.kind.in_([ReactionKind.LIKE.value, ReactionKind.DISLIKE.value])`
|
||||||
|
- filters by `Reaction.reply_to.is_(None)`
|
||||||
|
- uses `local_session()` context manager
|
||||||
|
- returns empty list on errors
|
||||||
|
- SQLAlchemy syntax updated:
|
||||||
|
- `select()` statement fixed for newer versions
|
||||||
|
- `Reaction` model direct selection instead of labeled columns
|
||||||
|
- proper row access with `row[0].shout` and `row[0].kind`
|
||||||
|
- GraphQL resolver fixes:
|
||||||
|
- added root parameter `_` to match schema
|
||||||
|
- proper async/await handling with `@login_required`
|
||||||
|
- error logging added via `logger.error()`
|
||||||
|
|
||||||
#### [0.4.6]
|
#### [0.4.6]
|
||||||
- login_accepted decorator added
|
- login_accepted decorator added
|
||||||
- `docs` added
|
- `docs` added
|
||||||
|
|
87
README.md
87
README.md
|
@ -1,16 +1,46 @@
|
||||||
# discoursio-api
|
# GraphQL API Backend
|
||||||
|
|
||||||
## Техстек
|
Backend service providing GraphQL API for content management system with reactions, ratings and comments.
|
||||||
|
|
||||||
- sqlalchemy
|
## Core Features
|
||||||
- redis
|
|
||||||
- ariadne
|
|
||||||
- starlette
|
|
||||||
- granian
|
|
||||||
|
|
||||||
## Локальная разработка
|
### Shouts (Posts)
|
||||||
|
- CRUD operations via GraphQL mutations
|
||||||
|
- Rich filtering and sorting options
|
||||||
|
- Support for multiple authors and topics
|
||||||
|
- Rating system with likes/dislikes
|
||||||
|
- Comments and nested replies
|
||||||
|
- Bookmarks and following
|
||||||
|
|
||||||
Запустите API-сервер с ключом `dev`:
|
### Reactions System
|
||||||
|
- `ReactionKind` types: LIKE, DISLIKE, COMMENT
|
||||||
|
- Rating calculation for shouts and comments
|
||||||
|
- User-specific reaction tracking
|
||||||
|
- Reaction stats and aggregations
|
||||||
|
- Nested comments support
|
||||||
|
|
||||||
|
### Authors & Topics
|
||||||
|
- Author profiles with stats
|
||||||
|
- Topic categorization and hierarchy
|
||||||
|
- Following system for authors/topics
|
||||||
|
- Activity tracking and stats
|
||||||
|
- Community features
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
- **(Python)[https://www.python.org/]** 3.12+
|
||||||
|
- **GraphQL** with [Ariadne](https://ariadnegraphql.org/)
|
||||||
|
- **(SQLAlchemy)[https://docs.sqlalchemy.org/en/20/orm/]**
|
||||||
|
- **(PostgreSQL)[https://www.postgresql.org/]/(SQLite)[https://www.sqlite.org/]** support
|
||||||
|
- **(Starlette)[https://www.starlette.io/]** for ASGI server
|
||||||
|
- **(Redis)[https://redis.io/]** for caching
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
|
||||||
|
Start API server with `dev` key:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
mkdir .venv
|
mkdir .venv
|
||||||
|
@ -20,10 +50,43 @@ poetry update
|
||||||
poetry run server.py dev
|
poetry run server.py dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### Полезные команды
|
### Useful Commands
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
poetry run ruff check . --fix --select I # линтер и сортировка импортов
|
# Linting and import sorting
|
||||||
poetry run ruff format . --line-length=120 # форматирование кода
|
poetry run ruff check . --fix --select I
|
||||||
|
|
||||||
|
# Code formatting
|
||||||
|
poetry run ruff format . --line-length=120
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
poetry run pytest
|
||||||
|
|
||||||
|
# Type checking
|
||||||
|
poetry run mypy .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Code Style
|
||||||
|
|
||||||
|
We use:
|
||||||
|
- Ruff for linting and import sorting
|
||||||
|
- Line length: 120 characters
|
||||||
|
- Python type hints
|
||||||
|
- Docstrings for public methods
|
||||||
|
|
||||||
|
### GraphQL Development
|
||||||
|
|
||||||
|
Test queries in GraphQL Playground at `http://localhost:8000`:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
# Example query
|
||||||
|
query GetShout($slug: String) {
|
||||||
|
get_shout(slug: $slug) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
main_author {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
94
docs/follower.md
Normal file
94
docs/follower.md
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
# Following System
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
System supports following different entity types:
|
||||||
|
- Authors
|
||||||
|
- Topics
|
||||||
|
- Communities
|
||||||
|
- Shouts (Posts)
|
||||||
|
|
||||||
|
## GraphQL API
|
||||||
|
|
||||||
|
### Mutations
|
||||||
|
|
||||||
|
#### follow
|
||||||
|
Follow an entity (author/topic/community/shout).
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `what: String!` - Entity type (`AUTHOR`, `TOPIC`, `COMMUNITY`, `SHOUT`)
|
||||||
|
- `slug: String` - Entity slug
|
||||||
|
- `entity_id: Int` - Optional entity ID
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
```typescript
|
||||||
|
{
|
||||||
|
authors?: Author[] // For AUTHOR type
|
||||||
|
topics?: Topic[] // For TOPIC type
|
||||||
|
communities?: Community[] // For COMMUNITY type
|
||||||
|
shouts?: Shout[] // For SHOUT type
|
||||||
|
error?: String // Error message if any
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### unfollow
|
||||||
|
Unfollow an entity.
|
||||||
|
|
||||||
|
**Parameters:** Same as `follow`
|
||||||
|
|
||||||
|
**Returns:** Same as `follow`
|
||||||
|
|
||||||
|
### Queries
|
||||||
|
|
||||||
|
#### get_shout_followers
|
||||||
|
Get list of users who reacted to a shout.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `slug: String` - Shout slug
|
||||||
|
- `shout_id: Int` - Optional shout ID
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
```typescript
|
||||||
|
Author[] // List of authors who reacted
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caching System
|
||||||
|
|
||||||
|
### Supported Entity Types
|
||||||
|
- Authors: `cache_author`, `get_cached_follower_authors`
|
||||||
|
- Topics: `cache_topic`, `get_cached_follower_topics`
|
||||||
|
- Communities: No cache
|
||||||
|
- Shouts: No cache
|
||||||
|
|
||||||
|
### Cache Flow
|
||||||
|
1. On follow/unfollow:
|
||||||
|
- Update entity in cache
|
||||||
|
- Update follower's following list
|
||||||
|
2. Cache is updated before notifications
|
||||||
|
|
||||||
|
## Notifications
|
||||||
|
|
||||||
|
- Sent when author is followed/unfollowed
|
||||||
|
- Contains:
|
||||||
|
- Follower info
|
||||||
|
- Author ID
|
||||||
|
- Action type ("follow"/"unfollow")
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- Unauthorized access check
|
||||||
|
- Entity existence validation
|
||||||
|
- Duplicate follow prevention
|
||||||
|
- Full error logging
|
||||||
|
- Transaction safety with `local_session()`
|
||||||
|
|
||||||
|
## Database Schema
|
||||||
|
|
||||||
|
### Follower Tables
|
||||||
|
- `AuthorFollower`
|
||||||
|
- `TopicFollower`
|
||||||
|
- `CommunityFollower`
|
||||||
|
- `ShoutReactionsFollower`
|
||||||
|
|
||||||
|
Each table contains:
|
||||||
|
- `follower` - ID of following user
|
||||||
|
- `{entity_type}` - ID of followed entity
|
|
@ -1,23 +1,80 @@
|
||||||
## Reader resolvers
|
# Система загрузки публикаций
|
||||||
|
|
||||||
### load_shouts_by
|
## Особенности реализации
|
||||||
|
|
||||||
Если graphql запрос содержит ожидаемые поля `stat`, `authors` или `topics`, то будут выполнены дополнительные подзапросы.
|
### Базовый запрос
|
||||||
|
- Автоматически подгружает основного автора
|
||||||
|
- Добавляет основную тему публикации
|
||||||
|
- Поддерживает гибкую систему фильтрации
|
||||||
|
- Оптимизирует запросы на основе запрошенных полей
|
||||||
|
|
||||||
#### Параметры
|
### Статистика
|
||||||
|
- Подсчёт лайков/дислайков
|
||||||
|
- Количество комментариев
|
||||||
|
- Дата последней реакции
|
||||||
|
- Статистика подгружается только при запросе поля `stat`
|
||||||
|
|
||||||
- `filters` - словарь с фильтрами
|
### Оптимизация производительности
|
||||||
- `featured` - фильтрует публикации, одобренные для показа на главной, по умолчанию не применяется
|
- Ленивая загрузка связанных данных
|
||||||
- `topics` - список идентификаторов тем, по умолчанию не применяется
|
- Кэширование результатов на 5 минут
|
||||||
- `authors` - список идентификаторов авторов, по умолчанию не применяется
|
- Пакетная загрузка авторов и тем
|
||||||
- `after` - unixtime после которого будут выбраны публикации, по умолчанию не применяется
|
- Использование подзапросов для сложных выборок
|
||||||
- `layouts` - список идентификаторов форматов, по умолчанию не применяется
|
|
||||||
- `order_by` может быть `rating`, `comments_count`, `last_reacted_at`. По умолчанию применяется сортировка по `published_at`
|
|
||||||
- `order_by_desc` определяет порядок сортировки, по умолчанию применяется `desc`
|
|
||||||
- `offset` и `limit` определяют смещение и ограничение, по умолчанию `0` и `10`
|
|
||||||
|
|
||||||
### load_shouts_feed, load_shouts_followed, load_shouts_followed_by, load_shouts_discussed, load_shouts_reacted
|
## Типы лент
|
||||||
|
|
||||||
Параметры аналогичны `load_shouts_by`, но применяются дополнительные фильтры:
|
### Случайные топовые посты (load_shouts_random_top)
|
||||||
|
**Преимущества:**
|
||||||
|
- Разнообразный контент
|
||||||
|
- Быстрая выборка из кэша топовых постов
|
||||||
|
- Настраиваемый размер пула для выборки
|
||||||
|
|
||||||
- `reacted` - фильтр наличия реакции пользователя
|
**Ограничения:**
|
||||||
|
- Обновление раз в 5 минут
|
||||||
|
- Максимальный размер пула: 100 постов
|
||||||
|
- Учитываются только лайки/дислайки (без комментариев)
|
||||||
|
|
||||||
|
### Неоцененные посты (load_shouts_unrated)
|
||||||
|
**Преимущества:**
|
||||||
|
- Помогает найти новый контент
|
||||||
|
- Равномерное распределение оценок
|
||||||
|
- Случайный порядок выдачи
|
||||||
|
|
||||||
|
**Ограничения:**
|
||||||
|
- Только посты с менее чем 3 реакциями
|
||||||
|
- Не учитываются комментарии
|
||||||
|
- Без сортировки по рейтингу
|
||||||
|
|
||||||
|
### Закладки (load_shouts_bookmarked)
|
||||||
|
**Преимущества:**
|
||||||
|
- Персонализированная выборка
|
||||||
|
- Быстрый доступ к сохраненному
|
||||||
|
- Поддержка всех фильтров
|
||||||
|
|
||||||
|
**Ограничения:**
|
||||||
|
- Требует авторизации
|
||||||
|
- Ограничение на количество закладок
|
||||||
|
- Кэширование отключено
|
||||||
|
|
||||||
|
## Важные моменты
|
||||||
|
|
||||||
|
### Пагинация
|
||||||
|
- Стандартный размер страницы: 10
|
||||||
|
- Максимальный размер: 100
|
||||||
|
- Поддержка курсор-пагинации
|
||||||
|
|
||||||
|
### Кэширование
|
||||||
|
- TTL: 5 минут
|
||||||
|
- Инвалидация при изменении поста
|
||||||
|
- Отдельный кэш для каждого типа сортировки
|
||||||
|
|
||||||
|
### Сортировка
|
||||||
|
- По рейтингу (лайки минус дислайки)
|
||||||
|
- По количеству комментариев
|
||||||
|
- По дате последней реакции
|
||||||
|
- По дате публикации (по умолчанию)
|
||||||
|
|
||||||
|
### Безопасность
|
||||||
|
- Проверка прав доступа
|
||||||
|
- Фильтрация удаленного контента
|
||||||
|
- Защита от SQL-инъекций
|
||||||
|
- Валидация входных данных
|
82
docs/rating.md
Normal file
82
docs/rating.md
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
# Rating System
|
||||||
|
|
||||||
|
## GraphQL Resolvers
|
||||||
|
|
||||||
|
### Queries
|
||||||
|
|
||||||
|
#### get_my_rates_shouts
|
||||||
|
Get user's reactions (LIKE/DISLIKE) for specified posts.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `shouts: [Int!]!` - array of shout IDs
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
```typescript
|
||||||
|
[{
|
||||||
|
shout_id: Int
|
||||||
|
my_rate: ReactionKind // LIKE or DISLIKE
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### get_my_rates_comments
|
||||||
|
Get user's reactions (LIKE/DISLIKE) for specified comments.
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `comments: [Int!]!` - array of comment IDs
|
||||||
|
|
||||||
|
**Returns:**
|
||||||
|
```typescript
|
||||||
|
[{
|
||||||
|
comment_id: Int
|
||||||
|
my_rate: ReactionKind // LIKE or DISLIKE
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mutations
|
||||||
|
|
||||||
|
#### rate_author
|
||||||
|
Rate another author (karma system).
|
||||||
|
|
||||||
|
**Parameters:**
|
||||||
|
- `rated_slug: String!` - author's slug
|
||||||
|
- `value: Int!` - rating value (positive/negative)
|
||||||
|
|
||||||
|
## Rating Calculation
|
||||||
|
|
||||||
|
### Author Rating Components
|
||||||
|
|
||||||
|
#### Shouts Rating
|
||||||
|
- Calculated from LIKE/DISLIKE reactions on author's posts
|
||||||
|
- Each LIKE: +1
|
||||||
|
- Each DISLIKE: -1
|
||||||
|
- Excludes deleted reactions
|
||||||
|
- Excludes comment reactions
|
||||||
|
|
||||||
|
#### Comments Rating
|
||||||
|
- Calculated from LIKE/DISLIKE reactions on author's comments
|
||||||
|
- Each LIKE: +1
|
||||||
|
- Each DISLIKE: -1
|
||||||
|
- Only counts reactions to COMMENT type reactions
|
||||||
|
- Excludes deleted reactions
|
||||||
|
|
||||||
|
#### Legacy Karma
|
||||||
|
- Based on direct author ratings via `rate_author` mutation
|
||||||
|
- Stored in `AuthorRating` table
|
||||||
|
- Each positive rating: +1
|
||||||
|
- Each negative rating: -1
|
||||||
|
|
||||||
|
### Helper Functions
|
||||||
|
|
||||||
|
- `count_author_comments_rating()` - Calculate comment rating
|
||||||
|
- `count_author_shouts_rating()` - Calculate posts rating
|
||||||
|
- `get_author_rating_old()` - Get legacy karma rating
|
||||||
|
- `get_author_rating_shouts()` - Get posts rating (optimized)
|
||||||
|
- `get_author_rating_comments()` - Get comments rating (optimized)
|
||||||
|
- `add_author_rating_columns()` - Add rating columns to author query
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- All ratings exclude deleted content
|
||||||
|
- Reactions are unique per user/content
|
||||||
|
- Rating calculations are optimized with SQLAlchemy
|
||||||
|
- System supports both direct author rating and content-based rating
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "core"
|
name = "core"
|
||||||
version = "0.4.6"
|
version = "0.4.7"
|
||||||
description = "core module for discours.io"
|
description = "core module for discours.io"
|
||||||
authors = ["discoursio devteam"]
|
authors = ["discoursio devteam"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user