Skip to content

Commit

Permalink
Merge branch 'develop' into add/filter-for-profile
Browse files Browse the repository at this point in the history
  • Loading branch information
Badmajor committed Oct 25, 2024
2 parents 6c3073f + d92fc66 commit 0d6d376
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 54 deletions.
34 changes: 28 additions & 6 deletions src/backend/api/v1/projects/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,6 @@ class Meta(BaseParticipationRequestSerializer.Meta):
fields: ClassVar[Tuple[str, ...]] = (
*BaseParticipationRequestSerializer.Meta.fields,
"cover_letter",
"answer",
)

def _get_existing_participation_request(
Expand Down Expand Up @@ -386,14 +385,39 @@ def validate_project(self, value):
if (
user == project.creator
or user == project.owner
or user in project.participants.all()
):
raise serializers.ValidationError(
"Вы не можете создать заявку на участие в проекте, в котором "
"уже участвуете."
)
return value

def validate_position(self, value):
"""
Метод, проверяет, является ли позиция валидной для данного проекта.
"""

project_id = self.initial_data.get("project")
if project_id is None:
raise serializers.ValidationError("Проект не найден.")
try:
project = Project.objects.get(pk=project_id)
except Project.DoesNotExist:
raise serializers.ValidationError("Проект не найден.")
request = self.context.get("request")
if request.method in ("PATCH", "PUT"):
project_specialists = project.project_specialists.all()
if not any(
specialist.profession.id != value.id and specialist.is_required
for specialist in project_specialists
):
raise serializers.ValidationError(
f"Специальность '{value.profession.specialization}' "
f"не требуется в проекте '{project.name}'."
)
return value
return value

def validate(self, attrs) -> Dict[str, Any]:
"""Метод валидации атрибутов запроса на участие в проекте."""
errors: Dict = {}
Expand All @@ -417,7 +441,6 @@ def validate(self, attrs) -> Dict[str, Any]:
f"Вас уже существует и находится в статусе "
f"'{participation_request.get_status_display()}'."
)

if errors:
raise serializers.ValidationError(errors)
return attrs
Expand Down Expand Up @@ -477,9 +500,8 @@ class ReadRetrieveParticipationRequestSerializer(
class Meta(ReadListParticipationRequestSerializer.Meta):
fields: ClassVar[Tuple[str, ...]] = (
*ReadListParticipationRequestSerializer.Meta.fields,
"answer", # какая-то дичь происходит, зачем нам тут видеть и ответ
"cover_letter", # и сопроводительное письмо не понимаю,
"created", # не хочу разбираться сейчас.
"cover_letter",
"created",
)

def to_representation(self, instance):
Expand Down
57 changes: 17 additions & 40 deletions src/backend/api/v1/projects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ def favorite(self, request, *args, **kwargs):
user = request.user
project = self.get_object()
if method == "POST":
project.is_favorite.add(user)
project.favorited_by.add(user)
return Response(status=status.HTTP_201_CREATED)
project.is_favorite.remove(user)
project.favorited_by.remove(user)
return Response(status=status.HTTP_204_NO_CONTENT)

@action(
Expand Down Expand Up @@ -288,12 +288,23 @@ def get_queryset(self) -> QuerySet["ParticipationRequest"]:
queryset = queryset.prefetch_related(
"position__skills",
)
user = self.request.user
if (
queryset.filter(project__owner=user).exists()
or queryset.filter(project__creator=user).exists()
):
queryset = queryset.exclude(
status__in=[
RequestStatuses.ACCEPTED,
RequestStatuses.REJECTED,
]
)
else:
status_filter = self.request.query_params.get("status")
if status_filter:
queryset = queryset.filter(status=status_filter)
return queryset.filter(
Q(user=self.request.user)
| (
Q(project__owner=self.request.user)
| Q(project__creator=self.request.user)
)
).only(*PROJECT_PARTICIPATION_REQUEST_ONLY_FIELDS.get(self.action, ()))

def get_object(self) -> ParticipationRequest:
Expand Down Expand Up @@ -355,40 +366,6 @@ def answer(self, request, pk) -> Response:
return Response(serializer.data, status=status.HTTP_200_OK)


# class ParticipantsViewSet(
# mixins.ListModelMixin,
# mixins.DestroyModelMixin,
# GenericViewSet,
# ):
# """Представление для участников проекта."""
#
# queryset = ProjectParticipant.objects.all()
# serializer_class = ReadParticipantSerializer
# pagination_class = None
# http_method_names = ("get", "delete", "options")
#
# def get_queryset(self) -> QuerySet["ProjectParticipant"]:
# """Метод получения queryset-а для участников проекта."""
#
# queryset = (
# super()
# .get_queryset()
# .filter(
# project=self.kwargs.get("project_pk"),
# )
# )
#
# if self.request.method == "GET":
# queryset = queryset.select_related(
# "user__profile", "profession"
# ).only(
# "user__profile__user_id",
# "user__profile__avatar",
# "profession",
# )
# return queryset


class InvitationToProjectViewSet(ModelViewSet):
"""Представление для создания и управления приглашениями в проект"""

Expand Down
6 changes: 3 additions & 3 deletions src/backend/apps/profile/constants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MAX_LENGTH_NAME = 30
MAX_LENGTH_COUNTRY = 255
MAX_LENGTH_CITY = 255
MAX_LENGTH_ABOUT = 750
MAX_LENGTH_ABOUT = 1500

MAX_LENGTH_PORTFOLIO_URL = 256
MIN_LENGTH_PORTFOLIO_URL = 5
Expand All @@ -12,10 +12,10 @@

MIN_LENGTH_NAME = 2
MIN_LENGTH_NAME_MESSAGE = "Должно быть минимум символов"
MIN_LENGTH_ABOUT = 50
MIN_LENGTH_ABOUT = 20
REGEX_PROFILE_NAME = r"^[a-zA-Zа-яА-Я -]+$"
REGEX_PROFILE_NAME_MESSAGE = "Введите кириллицу или латиницу"
REGEX_PROFILE_ABOUT = r"^[a-zA-Zа-яА-Я0-9\s!@#$%^&*()-_+=<>?]+$"
REGEX_PROFILE_ABOUT = r"(^[\Wa-zа-яё0-9\s]+)\Z"
REGEX_PROFILE_ABOUT_MESSAGE = "Введите кириллицу или латиницу"
MAX_SPECIALISTS = 2
MAX_BIRTHDAY_MESSAGE = "Дата не может быть в будущем."
Expand Down
29 changes: 29 additions & 0 deletions src/backend/apps/profile/migrations/0009_alter_profile_about.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 5.0.1 on 2024-10-04 21:05

import django.core.validators
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("profile", "0008_alter_profile_portfolio_link"),
]

operations = [
migrations.AlterField(
model_name="profile",
name="about",
field=models.TextField(
blank=True,
max_length=1500,
validators=[
django.core.validators.RegexValidator(
message="Введите кириллицу или латиницу",
regex="(^[\\Wa-zа-яё0-9\\s]+)\\Z",
),
django.core.validators.MinLengthValidator(limit_value=20),
],
verbose_name="О себе",
),
),
]
8 changes: 4 additions & 4 deletions src/backend/apps/projects/constants.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.db import models

MAX_LENGTH_DESCRIPTION = 750
MIN_LENGTH_DESCRIPTION = 50
MAX_LENGTH_DESCRIPTION = 1500
MIN_LENGTH_DESCRIPTION = 20
LENGTH_DESCRIPTION_ERROR_TEXT = (
f"Длина поля от {MIN_LENGTH_DESCRIPTION} до {MAX_LENGTH_DESCRIPTION} "
"символов."
Expand All @@ -18,10 +18,10 @@
f"Длина поля от {MIN_LENGTH_PROJECT_NAME} до {MAX_LENGTH_PROJECT_NAME} "
"символов."
)
REGEX_PROJECT_NAME = r"(^[+/:,.0-9A-Za-zА-Яа-яЁё\s\-–—]+)\Z"
REGEX_PROJECT_NAME = r"(^[+/_:,.0-9A-Za-zА-Яа-яЁё\s\-–—]+)\Z"
REGEX_PROJECT_NAME_ERROR_TEXT = (
"Название проекта может содержать: кириллические и латинские символы, "
"цифры и символы .,-—+/:"
"цифры и символы .,-—+_/:"
)

MAX_LENGTH_DIRECTION_NAME = 20
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Generated by Django 5.0.1 on 2024-10-04 21:05

import apps.general.fields
import django.core.validators
import re
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("projects", "0017_alter_project_participants"),
]

operations = [
migrations.AlterField(
model_name="invitationtoproject",
name="answer",
field=apps.general.fields.BaseTextField(
max_length=750,
null=True,
validators=[
django.core.validators.RegexValidator(
flags=re.RegexFlag["IGNORECASE"],
message="Поле может содержать: кириллические и латинские символы, цифры и спецсимовлы -!#$%%&'*+/=?^_;():@,.<>`{}~«»",
regex="(^[-%!#$&*'+/=?^_;():@,.<>`{|}~\\\"\\\\\\-«»0-9A-ZА-ЯЁ\\s]+)\\Z",
),
django.core.validators.MinLengthValidator(
limit_value=5,
message="Длина поля от 5 до 750 символов.",
),
],
verbose_name="Ответ",
),
),
migrations.AlterField(
model_name="invitationtoproject",
name="cover_letter",
field=apps.general.fields.BaseTextField(
max_length=750,
null=True,
validators=[
django.core.validators.RegexValidator(
flags=re.RegexFlag["IGNORECASE"],
message="Поле может содержать: кириллические и латинские символы, цифры и спецсимовлы -!#$%%&'*+/=?^_;():@,.<>`{}~«»",
regex="(^[-%!#$&*'+/=?^_;():@,.<>`{|}~\\\"\\\\\\-«»0-9A-ZА-ЯЁ\\s]+)\\Z",
),
django.core.validators.MinLengthValidator(
limit_value=5,
message="Длина поля от 5 до 750 символов.",
),
],
verbose_name="Сопроводительное письмо",
),
),
migrations.AlterField(
model_name="participationrequest",
name="answer",
field=apps.general.fields.BaseTextField(
max_length=750,
null=True,
validators=[
django.core.validators.RegexValidator(
flags=re.RegexFlag["IGNORECASE"],
message="Поле может содержать: кириллические и латинские символы, цифры и спецсимовлы -!#$%%&'*+/=?^_;():@,.<>`{}~«»",
regex="(^[-%!#$&*'+/=?^_;():@,.<>`{|}~\\\"\\\\\\-«»0-9A-ZА-ЯЁ\\s]+)\\Z",
),
django.core.validators.MinLengthValidator(
limit_value=5,
message="Длина поля от 5 до 750 символов.",
),
],
verbose_name="Ответ",
),
),
migrations.AlterField(
model_name="participationrequest",
name="cover_letter",
field=apps.general.fields.BaseTextField(
max_length=750,
null=True,
validators=[
django.core.validators.RegexValidator(
flags=re.RegexFlag["IGNORECASE"],
message="Поле может содержать: кириллические и латинские символы, цифры и спецсимовлы -!#$%%&'*+/=?^_;():@,.<>`{}~«»",
regex="(^[-%!#$&*'+/=?^_;():@,.<>`{|}~\\\"\\\\\\-«»0-9A-ZА-ЯЁ\\s]+)\\Z",
),
django.core.validators.MinLengthValidator(
limit_value=5,
message="Длина поля от 5 до 750 символов.",
),
],
verbose_name="Сопроводительное письмо",
),
),
migrations.AlterField(
model_name="project",
name="description",
field=models.TextField(
max_length=1500,
null=True,
validators=[
django.core.validators.MinLengthValidator(
limit_value=20,
message="Длина поля от 20 до 1500 символов.",
),
django.core.validators.RegexValidator(
flags=re.RegexFlag["IGNORECASE"],
message="Описание может содержать: кириллические и латинские буквы, цифры и специальные символы.",
regex="(^[\\Wa-zа-яё0-9\\s]+)\\Z",
),
],
verbose_name="Описание",
),
),
migrations.AlterField(
model_name="project",
name="name",
field=models.CharField(
max_length=100,
validators=[
django.core.validators.MinLengthValidator(
limit_value=5,
message="Длина поля от 5 до 100 символов.",
),
django.core.validators.RegexValidator(
message="Название проекта может содержать: кириллические и латинские символы, цифры и символы .,-—+_/:",
regex="(^[+/_:,.0-9A-Za-zА-Яа-яЁё\\s\\-–—]+)\\Z",
),
],
verbose_name="Название",
),
),
]
2 changes: 1 addition & 1 deletion src/backend/apps/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class Meta:


class ParticipationRequestAndInvitationBasemodel(CreatedModifiedFields):
"""Абстрактна модель для запросов на участие и приглашений в проект"""
"""Абстрактная модель для запросов на участие и приглашений в проект."""

project = models.ForeignKey(
Project,
Expand Down

0 comments on commit 0d6d376

Please sign in to comment.