Skip to content

Commit eec9df5

Browse files
authored
Merge pull request #140 from PROCOLLAB-github/dev
Links for users and projects
2 parents 077173e + 1ab3896 commit eec9df5

13 files changed

Lines changed: 270 additions & 29 deletions

File tree

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

projects/admin.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22

3-
from projects.models import Project, Achievement, Collaborator
3+
from projects.models import Project, Achievement, Collaborator, ProjectLink
44

55

66
@admin.register(Project)
@@ -21,6 +21,12 @@ class AchievementAdmin(admin.ModelAdmin):
2121
list_display = ("id", "title", "status", "project")
2222

2323

24+
@admin.register(ProjectLink)
25+
class ProjectLinkAdmin(admin.ModelAdmin):
26+
list_display = ("id", "link", "project")
27+
list_display_links = ("id", "link", "project")
28+
29+
2430
@admin.register(Collaborator)
2531
class CollaboratorAdmin(admin.ModelAdmin):
2632
list_display = (

projects/helpers.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.contrib.auth import get_user_model
44

55
from projects.constants import RECOMMENDATIONS_COUNT
6-
from projects.models import Project
6+
from projects.models import Project, ProjectLink, Achievement
77

88
User = get_user_model()
99

@@ -33,3 +33,54 @@ def get_recommended_users(project: Project) -> list[User]:
3333
)
3434

3535
return sampled_recommended_users
36+
37+
38+
def check_related_fields_update(data, pk):
39+
"""
40+
Check if achievements or links were updated and update them.
41+
"""
42+
43+
if data.get("achievements") is not None:
44+
update_achievements(data.get("achievements"), pk)
45+
46+
if data.get("links") is not None:
47+
update_links(data.get("links"), pk)
48+
49+
50+
def update_achievements(achievements, pk):
51+
"""
52+
Bootleg version of updating achievements via project
53+
"""
54+
55+
# delete all old achievements
56+
Achievement.objects.filter(project_id=pk).delete()
57+
# create new achievements
58+
Achievement.objects.bulk_create(
59+
[
60+
Achievement(
61+
project_id=pk,
62+
title=achievement.get("title"),
63+
status=achievement.get("status"),
64+
)
65+
for achievement in achievements
66+
]
67+
)
68+
69+
70+
def update_links(links, pk):
71+
"""
72+
Bootleg version of updating links via project
73+
"""
74+
75+
# delete all old links
76+
ProjectLink.objects.filter(project_id=pk).delete()
77+
# create new links
78+
ProjectLink.objects.bulk_create(
79+
[
80+
ProjectLink(
81+
project_id=pk,
82+
link=link,
83+
)
84+
for link in links
85+
]
86+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Generated by Django 4.2 on 2023-05-16 21:02
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("projects", "0011_project_views_count"),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name="ProjectLink",
16+
fields=[
17+
(
18+
"id",
19+
models.BigAutoField(
20+
auto_created=True,
21+
primary_key=True,
22+
serialize=False,
23+
verbose_name="ID",
24+
),
25+
),
26+
("link", models.URLField()),
27+
(
28+
"project",
29+
models.ForeignKey(
30+
on_delete=django.db.models.deletion.CASCADE,
31+
related_name="links",
32+
to="projects.project",
33+
),
34+
),
35+
],
36+
options={
37+
"verbose_name": "Ссылка проекта",
38+
"verbose_name_plural": "Ссылки проектов",
39+
"unique_together": {("project", "link")},
40+
},
41+
),
42+
]

projects/models.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,31 @@ class Meta:
9595
verbose_name_plural = "Проекты"
9696

9797

98+
class ProjectLink(models.Model):
99+
"""
100+
Project link model
101+
102+
Attributes:
103+
project: A ForeignKey referring to the Project model.
104+
link: A URLField link to the project.
105+
"""
106+
107+
project = models.ForeignKey(
108+
Project,
109+
on_delete=models.CASCADE,
110+
related_name="links",
111+
)
112+
link = models.URLField(null=False, blank=False)
113+
114+
def __str__(self):
115+
return f"ProjectLink<{self.id}> - {self.project.name}"
116+
117+
class Meta:
118+
verbose_name = "Ссылка проекта"
119+
verbose_name_plural = "Ссылки проектов"
120+
unique_together = ("project", "link")
121+
122+
98123
class Achievement(models.Model):
99124
"""
100125
Achievement model

projects/serializers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class ProjectDetailSerializer(serializers.ModelSerializer):
6767
short_description = serializers.SerializerMethodField()
6868
industry_id = serializers.IntegerField(required=False)
6969
likes_count = serializers.SerializerMethodField(method_name="count_likes")
70+
links = serializers.SerializerMethodField()
71+
72+
@classmethod
73+
def get_links(cls, project):
74+
return [link.link for link in project.links.all()]
7075

7176
def validate(self, data):
7277
super().validate(data)
@@ -92,6 +97,7 @@ class Meta:
9297
"description",
9398
"short_description",
9499
"achievements",
100+
"links",
95101
"region",
96102
"step",
97103
"industry",

projects/views.py

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from core.permissions import IsStaffOrReadOnly
1010
from projects.filters import ProjectFilter
1111
from projects.constants import VERBOSE_STEPS
12-
from projects.helpers import get_recommended_users
12+
from projects.helpers import get_recommended_users, check_related_fields_update
1313
from projects.models import Project, Achievement
1414
from projects.permissions import (
1515
IsProjectLeaderOrReadOnlyForNonDrafts,
@@ -91,23 +91,11 @@ def retrieve(self, request, *args, **kwargs):
9191
return Response(serializer.data)
9292

9393
def put(self, request, pk, **kwargs):
94-
# bootleg version of updating achievements via project
95-
if request.data.get("achievements") is not None:
96-
achievements = request.data.get("achievements")
97-
# delete all old achievements
98-
Achievement.objects.filter(project_id=pk).delete()
99-
# create new achievements
100-
Achievement.objects.bulk_create(
101-
[
102-
Achievement(
103-
project_id=pk,
104-
title=achievement.get("title"),
105-
status=achievement.get("status"),
106-
)
107-
for achievement in achievements
108-
]
109-
)
94+
check_related_fields_update(request.data, pk)
95+
return super(ProjectDetail, self).put(request, pk)
11096

97+
def patch(self, request, pk, **kwargs):
98+
check_related_fields_update(request.data, pk)
11199
return super(ProjectDetail, self).put(request, pk)
112100

113101

users/admin.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22
from django.contrib import admin
33

44
from .helpers import send_verification_completed_email
5-
from .models import CustomUser, UserAchievement, Member, Mentor, Expert, Investor
5+
from .models import (
6+
CustomUser,
7+
UserAchievement,
8+
Member,
9+
Mentor,
10+
Expert,
11+
Investor,
12+
UserLink,
13+
)
614

715

816
@admin.register(CustomUser)
@@ -136,3 +144,9 @@ def save_model(self, request, obj, form, change):
136144
@admin.register(UserAchievement)
137145
class UserAchievementAdmin(admin.ModelAdmin):
138146
list_display = ("id", "title", "status", "user")
147+
148+
149+
@admin.register(UserLink)
150+
class UserLinkAdmin(admin.ModelAdmin):
151+
list_display = ("id", "user", "link")
152+
list_display_links = ("id", "user", "link")

users/helpers.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from core.utils import Email
77
from users.constants import PROTOCOL
8-
from users.models import UserAchievement
8+
from users.models import UserAchievement, UserLink
99

1010
User = get_user_model()
1111

@@ -91,7 +91,23 @@ def send_verification_completed_email(user: User):
9191
Email.send_email(data)
9292

9393

94+
def check_related_fields_update(data, pk):
95+
"""
96+
Check if achievements or links were updated and update them.
97+
"""
98+
99+
if data.get("achievements") is not None:
100+
update_achievements(data.get("achievements"), pk)
101+
102+
if data.get("links") is not None:
103+
update_links(data.get("links"), pk)
104+
105+
94106
def update_achievements(achievements, pk):
107+
"""
108+
Bootleg version of updating achievements via user
109+
"""
110+
95111
# delete all old achievements
96112
UserAchievement.objects.filter(user_id=pk).delete()
97113
# create new achievements
@@ -105,3 +121,22 @@ def update_achievements(achievements, pk):
105121
for achievement in achievements
106122
]
107123
)
124+
125+
126+
def update_links(links, pk):
127+
"""
128+
Bootleg version of updating links via user
129+
"""
130+
131+
# delete all old links
132+
UserLink.objects.filter(user_id=pk).delete()
133+
# create new links
134+
UserLink.objects.bulk_create(
135+
[
136+
UserLink(
137+
user_id=pk,
138+
link=link,
139+
)
140+
for link in links
141+
]
142+
)

users/migrations/0036_userlink.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Generated by Django 4.2 on 2023-05-16 19:48
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
("users", "0035_alter_customuser_onboarding_stage"),
12+
]
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name="UserLink",
17+
fields=[
18+
(
19+
"id",
20+
models.BigAutoField(
21+
auto_created=True,
22+
primary_key=True,
23+
serialize=False,
24+
verbose_name="ID",
25+
),
26+
),
27+
("link", models.URLField()),
28+
(
29+
"user",
30+
models.ForeignKey(
31+
on_delete=django.db.models.deletion.CASCADE,
32+
related_name="links",
33+
to=settings.AUTH_USER_MODEL,
34+
),
35+
),
36+
],
37+
options={
38+
"verbose_name": "Ссылка пользователя",
39+
"verbose_name_plural": "Ссылки пользователей",
40+
"unique_together": {("user", "link")},
41+
},
42+
),
43+
]

0 commit comments

Comments
 (0)