Skip to content

Commit 0900d34

Browse files
authored
Merge pull request #641 from PROCOLLAB-github/refactor/modules
Refactor/modules
2 parents b9dde5d + be1cbab commit 0900d34

26 files changed

Lines changed: 2584 additions & 911 deletions

docs/modules/feed.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ handlers для служебных записей.
2626

2727
## Архитектура
2828

29-
- `feed/views.py` - endpoint `/feed/`, фильтрация по типам и финальная сборка
30-
response payload.
31-
- `feed/serializers.py` - `FeedNewsResponseSerializer`, который превращает
32-
`news.News` в элемент ленты.
29+
- `feed/views.py` - endpoint `/feed/` и фильтрация по типам.
30+
- `feed/serializers.py` - `FeedItemResponseSerializer`, который превращает
31+
`news.News` в элемент ленты формата `{type_model, content}`.
3332
- `feed/services.py` - helpers для лайков и служебных feed-записей.
3433
- `feed/mapping.py` - соответствие content object типам и serializers.
3534
- `feed/constants.py` - типы моделей, для которых signals создают feed-записи.
@@ -45,14 +44,28 @@ Frontend вызывает `/feed/?type=...`.
4544
View выбирает подходящие `news.News`, сериализует их и возвращает элементы
4645
ленты с полями `type_model` и `content`.
4746

47+
Ответ использует стандартную пагинацию DRF: `count`, `next`, `previous`,
48+
`results`. Каждый элемент `results` содержит только:
49+
50+
- `type_model` - тип элемента ленты;
51+
- `content` - сериализованный объект, соответствующий этому типу.
52+
4853
### 2. В ленту попадает обычная новость
4954

50-
Если `news.News` содержит текст и относится к пользователю или проекту, лента
51-
возвращает ее как новость.
55+
Если `news.News` содержит текст и относится к пользователю, проекту или
56+
партнерской программе, лента возвращает ее как новость.
5257

5358
Проектная новость с текстом возвращается как `type_model = "news"`, даже если
5459
ее `content_object` - проект.
5560

61+
Новость партнерской программы с текстом тоже возвращается как
62+
`type_model = "news"`. Отдельный `type_model = "partner_program"` пока не
63+
вводится.
64+
65+
Служебные feed-записи партнерских программ сейчас не создаются. Если такой
66+
сценарий понадобится, для него нужно отдельно согласовать `type_model` и
67+
frontend-контракт.
68+
5669
### 3. В ленту попадает служебная запись
5770

5871
Служебные feed-записи создаются через `feed.services.create_news_for_model()`.
@@ -78,14 +91,17 @@ View выбирает подходящие `news.News`, сериализует
7891
- `GET /feed/?type=news` - новости пользователей.
7992
- `GET /feed/?type=project` - проектные новости и проектные feed-записи.
8093
- `GET /feed/?type=vacancy` - служебные feed-записи вакансий.
81-
- `GET /feed/?type=project|news|vacancy` - комбинированная выдача по нескольким
82-
типам.
94+
- `GET /feed/?type=partnerprogram` - новости партнерских программ.
95+
- `GET /feed/?type=project|vacancy|news|partnerprogram` - комбинированная
96+
выдача по нескольким типам.
8397

8498
## Ограничения и правила
8599

86100
- Feed читает данные из `news.News`, но не отвечает за создание обычных
87101
project/user/program news.
88102
- Служебная feed-запись определяется через пустой `text`.
103+
- Новости партнерских программ с текстом отображаются как обычные новости;
104+
отдельные служебные карточки программ в ленте пока не поддерживаются.
89105
- Signals `feed` создают или удаляют служебные feed-записи для проектов и
90106
вакансий. Более широкие сценарии публикации проекта остаются в модуле
91107
`projects`.
@@ -96,6 +112,8 @@ View выбирает подходящие `news.News`, сериализует
96112

97113
- `/feed/?type=news` возвращает пользовательские новости;
98114
- `/feed/?type=project` возвращает проектные новости в frontend-формате;
115+
- `/feed/?type=partnerprogram` возвращает новости программ как
116+
`type_model = "news"`;
99117
- `/feed/?type=project` возвращает служебную feed-запись проекта как
100118
`type_model = "project"`;
101119
- `/feed/?type=vacancy` возвращает служебную feed-запись вакансии как

docs/modules/partner-programs.md

Lines changed: 210 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,212 @@
11
# Partner Programs
22

3-
TODO
3+
## Назначение
4+
5+
Модуль `partner_programs` отвечает за партнерские программы: регистрацию
6+
участников, привязку проектов к программе, дополнительные поля заявки,
7+
сдачу проектов на проверку, фильтрацию и выгрузки проектов программы.
8+
9+
Программа объединяет пользователей, проекты, новости, курсы и оценки проектов.
10+
11+
## Статус модуля
12+
13+
Модуль рабочий и используется продуктом, но пока остается архитектурно тяжелым:
14+
значительная часть бизнес-логики находится во `views.py`, а тесты только
15+
начинают приводиться к структуре, принятой для свежих модулей.
16+
17+
## Основные возможности
18+
19+
- список и детальная карточка партнерских программ;
20+
- регистрация пользователя в программе;
21+
- регистрация нового пользователя через внешнюю форму;
22+
- просмотр материалов и связанных курсов программы;
23+
- подача проекта в программу;
24+
- заполнение дополнительных полей проекта в программе;
25+
- сдача конкурсного проекта на проверку;
26+
- список и фильтрация проектов программы для менеджеров;
27+
- экспорт проектов и оценок;
28+
- публикация проектов после окончания программы;
29+
- новости программы через общий модуль `news`.
30+
31+
## Архитектура
32+
33+
- `partner_programs/models.py` - модели программ, участников, материалов,
34+
проектов программы и дополнительных полей.
35+
- `partner_programs/views.py` - API программы, регистрации, подачи проектов,
36+
фильтров и экспортов.
37+
- `partner_programs/serializers/` - request/response serializers и validation
38+
дополнительных полей.
39+
- `partner_programs/services/` - сервисы регистрации в программе, подачи
40+
проектов, фильтрации проектов, публикации проектов и подготовки
41+
Excel-выгрузок.
42+
- `partner_programs/selectors.py` - выборки участников для аналитики и
43+
напоминаний.
44+
- `partner_programs/permissions.py` - проверки менеджера программы, админа и
45+
лидера проекта.
46+
- `partner_programs/tasks.py` - celery-задача публикации проектов после
47+
завершения программы.
48+
- `partner_programs/tests/` - regression-тесты API, serializers и сервисов.
49+
50+
## Ключевые сущности
51+
52+
- `PartnerProgram` - сама программа, даты регистрации, подачи и завершения,
53+
настройки конкурсности и публикации проектов.
54+
- `PartnerProgramUserProfile` - участие пользователя в программе и данные
55+
регистрационной формы.
56+
- `PartnerProgramProject` - связь проекта с программой, статус сдачи проекта и
57+
дата сдачи.
58+
- `PartnerProgramField` - дополнительное поле программы.
59+
- `PartnerProgramFieldValue` - значение дополнительного поля для проекта в
60+
программе.
61+
- `PartnerProgramMaterial` - материал программы: ссылка или файл.
62+
63+
## API
64+
65+
- `GET /programs/` - список опубликованных программ.
66+
- `GET /programs/?participating=1` - активные программы текущего участника.
67+
- `GET /programs/<id>/` - детальная карточка программы.
68+
- `GET /programs/<id>/schema/` - схема регистрационных данных программы.
69+
- `POST /programs/<id>/register/` - регистрация текущего пользователя в
70+
программе.
71+
- `POST /programs/<id>/register_new/` - регистрация нового пользователя через
72+
внешнюю форму.
73+
- `POST /programs/<id>/set_liked/` - лайк программы.
74+
- `POST /programs/<id>/set_viewed/` - просмотр программы.
75+
- `GET /programs/<id>/news/` - новости программы.
76+
- `POST /programs/<id>/news/` - создание новости программы менеджером.
77+
- `GET /programs/<id>/projects/apply/` - данные формы подачи проекта.
78+
- `POST /programs/<id>/projects/apply/` - подача проекта в программу.
79+
- `POST /programs/partner-program-projects/<link_id>/submit/` - сдача проекта
80+
на проверку.
81+
- `PUT /projects/<project_id>/program-fields/` - обновление дополнительных
82+
полей проекта в программе.
83+
- `GET /programs/<id>/filters/` - доступные фильтры проектов программы.
84+
- `POST /programs/<id>/projects/filter/` - фильтрация проектов по
85+
дополнительным полям.
86+
- `GET /programs/<id>/projects/` - список проектов программы.
87+
- `GET /programs/<id>/export-projects/` - Excel-выгрузка проектов.
88+
- `GET /programs/<id>/export-rates/` - Excel-выгрузка оценок.
89+
90+
## Основные сценарии
91+
92+
### 1. Пользователь смотрит список программ
93+
94+
Список `/programs/` показывает только программы с `draft = False`.
95+
Для авторизованного пользователя response дополнительно показывает признак
96+
`is_user_member`.
97+
98+
Фильтр `participating=1` возвращает только активные программы, в которых
99+
текущий пользователь является участником.
100+
101+
### 2. Пользователь открывает программу
102+
103+
Детальная карточка возвращает разные поля для участника и не-участника.
104+
Если пользователь авторизован, просмотр программы фиксируется через общий
105+
механизм просмотров.
106+
107+
Связанные курсы программы возвращаются в поле `courses`; для каждого курса
108+
указывается `is_available`.
109+
110+
### 3. Пользователь регистрируется в программе
111+
112+
`POST /programs/<id>/register/` создает `PartnerProgramUserProfile` для текущего
113+
пользователя и сохраняет переданные данные формы в `partner_program_data`.
114+
115+
Если срок регистрации завершен или пользователь уже зарегистрирован, API
116+
возвращает ошибку.
117+
118+
### 4. Пользователь подает проект в программу
119+
120+
Участник программы открывает форму `/programs/<id>/projects/apply/`, получает
121+
список дополнительных полей и отправляет проект.
122+
123+
При успешной подаче создаются:
124+
125+
- черновой непубличный `Project`;
126+
- связь `PartnerProgramProject`;
127+
- значения `PartnerProgramFieldValue`;
128+
- связь `PartnerProgramUserProfile.project` с новым проектом.
129+
130+
Подача запрещена не-участнику, после дедлайна, при повторной подаче проекта и
131+
при некорректных дополнительных полях.
132+
133+
### 5. Лидер обновляет поля проекта в программе
134+
135+
`PUT /projects/<project_id>/program-fields/` обновляет значения дополнительных
136+
полей проекта.
137+
138+
Изменять значения может только лидер проекта. Для конкурсной программы после
139+
сдачи проекта на проверку редактирование блокируется.
140+
141+
### 6. Лидер сдает проект на проверку
142+
143+
`POST /programs/partner-program-projects/<link_id>/submit/` переводит связь
144+
проекта с программой в `submitted = True` и заполняет `datetime_submitted`.
145+
146+
Сдача доступна только лидеру проекта, только для конкурсных программ и только
147+
до дедлайна подачи проектов.
148+
149+
### 7. Менеджер работает с проектами программы
150+
151+
Менеджер или администратор программы может:
152+
153+
- смотреть список проектов программы;
154+
- получать список доступных фильтров;
155+
- фильтровать проекты по значениям дополнительных полей;
156+
- выгружать проекты и оценки в Excel.
157+
158+
## Связи с другими модулями
159+
160+
- `projects` - проекты подаются в программу и связываются через
161+
`PartnerProgramProject`.
162+
- `users` - участники и менеджеры программы.
163+
- `news` - новости программы создаются и читаются через общий news API.
164+
- `feed` - текстовые новости программы могут попадать в общую ленту как
165+
`type_model = "news"`.
166+
- `courses` - курс может быть связан с программой и доступен участникам
167+
программы.
168+
- `project_rates` - оценки проектов используются в выгрузке результатов.
169+
- `mailing` / `vacancy.tasks.send_email` - уведомления после регистрации в
170+
программе.
171+
- `files` - материалы программы могут ссылаться на `UserFile`.
172+
173+
## Ограничения и правила
174+
175+
- Дополнительные поля программы задаются через `PartnerProgramField`.
176+
- Значения дополнительных полей хранятся в `PartnerProgramFieldValue`.
177+
- После сдачи проекта в конкурсной программе значения полей редактировать
178+
нельзя.
179+
- Служебные feed-карточки программ пока не поддерживаются; новости программ в
180+
feed отображаются как обычные новости.
181+
- Основной API-код пока сосредоточен во `views.py`; перед крупным рефакторингом
182+
нужно зафиксировать больше regression-тестов.
183+
184+
## Тесты
185+
186+
Текущие regression-тесты проверяют:
187+
188+
- validation дополнительных полей: `text`, `textarea`, `checkbox`, `select`,
189+
`radio`, `file`;
190+
- список программ и фильтр `participating`;
191+
- регистрацию текущего пользователя в программе;
192+
- регистрацию нового пользователя через внешнюю форму;
193+
- запрет повторной регистрации и регистрации после дедлайна;
194+
- detail программы с курсами для участника и не-участника;
195+
- подачу проекта участником программы или менеджером программы;
196+
- запрет повторной подачи проекта тем же лидером;
197+
- запрет подачи проекта не-участником, после дедлайна, с дублями полей,
198+
незаполненными обязательными полями и полями другой программы;
199+
- обновление дополнительных полей проекта лидером;
200+
- запрет обновления полей не-лидером и после сдачи конкурсного проекта;
201+
- сдачу проекта на проверку;
202+
- запрет сдачи проекта не-лидером, после дедлайна и для неконкурсной программы;
203+
- список фильтров программы;
204+
- фильтрацию проектов программы по дополнительным полям;
205+
- список проектов программы для менеджера;
206+
- Excel-выгрузку проектов программы, включая режим `only_submitted`;
207+
- запрет выгрузки проектов пользователем без прав менеджера;
208+
- Excel-выгрузку оценок проектов программы;
209+
- подготовку данных выгрузки оценок, когда критерии есть, но оценок еще нет;
210+
- базовые permissions для менеджера программы, staff-пользователя,
211+
постороннего пользователя, anonymous и лидера проекта;
212+
- публикацию проектов после завершения программы.

feed/mapping.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
from vacancy.models import Vacancy
77
from vacancy.serializers import VacancyDetailSerializer
88

9-
CONTENT_OBJECT_MAPPING: dict[str, str | None] = {
9+
CONTENT_OBJECT_MAPPING: dict[str, str] = {
1010
Project.__name__.lower(): "project",
1111
CustomUser.__name__.lower(): "news",
12-
"partnerprogram": None,
1312
Vacancy.__name__.lower(): "vacancy",
1413
}
1514

0 commit comments

Comments
 (0)