Skip to content

Commit 42087cd

Browse files
authored
Merge pull request #146 from PROCOLLAB-github/dev
Projects news
2 parents 0371316 + 8164b21 commit 42087cd

16 files changed

Lines changed: 592 additions & 3 deletions

core/admin.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from django.contrib import admin
2+
from core.models import Like, View
3+
4+
5+
@admin.register(Like)
6+
class LikeAdmin(admin.ModelAdmin):
7+
list_display = ("id", "user", "content_type", "object_id", "content_object")
8+
list_display_links = ("id", "user", "content_type", "object_id", "content_object")
9+
10+
11+
@admin.register(View)
12+
class ViewAdmin(admin.ModelAdmin):
13+
list_display = ("id", "user", "content_type", "object_id", "content_object")
14+
list_display_links = ("id", "user", "content_type", "object_id", "content_object")

core/migrations/0001_initial.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Generated by Django 4.2 on 2023-06-08 20:05
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+
initial = True
11+
12+
dependencies = [
13+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
("contenttypes", "0002_remove_content_type_name"),
15+
]
16+
17+
operations = [
18+
migrations.CreateModel(
19+
name="Like",
20+
fields=[
21+
(
22+
"id",
23+
models.BigAutoField(
24+
auto_created=True,
25+
primary_key=True,
26+
serialize=False,
27+
verbose_name="ID",
28+
),
29+
),
30+
("object_id", models.PositiveIntegerField()),
31+
(
32+
"content_type",
33+
models.ForeignKey(
34+
on_delete=django.db.models.deletion.CASCADE,
35+
related_name="likes",
36+
to="contenttypes.contenttype",
37+
),
38+
),
39+
(
40+
"user",
41+
models.ForeignKey(
42+
on_delete=django.db.models.deletion.CASCADE,
43+
related_name="likes",
44+
to=settings.AUTH_USER_MODEL,
45+
),
46+
),
47+
],
48+
options={
49+
"verbose_name": "Лайк",
50+
"verbose_name_plural": "Лайки",
51+
"unique_together": {("user", "content_type", "object_id")},
52+
},
53+
),
54+
]

core/migrations/0002_view.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Generated by Django 4.2 on 2023-06-11 10:28
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+
("contenttypes", "0002_remove_content_type_name"),
12+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13+
("core", "0001_initial"),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name="View",
19+
fields=[
20+
(
21+
"id",
22+
models.BigAutoField(
23+
auto_created=True,
24+
primary_key=True,
25+
serialize=False,
26+
verbose_name="ID",
27+
),
28+
),
29+
("object_id", models.PositiveIntegerField()),
30+
(
31+
"content_type",
32+
models.ForeignKey(
33+
on_delete=django.db.models.deletion.CASCADE,
34+
related_name="views",
35+
to="contenttypes.contenttype",
36+
),
37+
),
38+
(
39+
"user",
40+
models.ForeignKey(
41+
on_delete=django.db.models.deletion.CASCADE,
42+
related_name="views",
43+
to=settings.AUTH_USER_MODEL,
44+
),
45+
),
46+
],
47+
options={
48+
"verbose_name": "Просмотр",
49+
"verbose_name_plural": "Просмотры",
50+
"unique_together": {("user", "content_type", "object_id")},
51+
},
52+
),
53+
]

core/migrations/__init__.py

Whitespace-only changes.

core/models.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
from django.contrib.auth import get_user_model
2+
from django.contrib.contenttypes.fields import GenericForeignKey
3+
from django.contrib.contenttypes.models import ContentType
4+
from django.db.models import Model
5+
from django.db import models
6+
7+
User = get_user_model()
8+
9+
10+
class Like(Model):
11+
"""
12+
Generic Like model based on contenttype
13+
"""
14+
15+
user = models.ForeignKey(
16+
User,
17+
on_delete=models.CASCADE,
18+
related_name="likes",
19+
)
20+
content_type = models.ForeignKey(
21+
ContentType,
22+
on_delete=models.CASCADE,
23+
related_name="likes",
24+
)
25+
object_id = models.PositiveIntegerField()
26+
content_object = GenericForeignKey("content_type", "object_id")
27+
# is liked?
28+
29+
class Meta:
30+
unique_together = ("user", "content_type", "object_id")
31+
verbose_name = "Лайк"
32+
verbose_name_plural = "Лайки"
33+
34+
def __str__(self):
35+
return f"Like<{self.user} - {self.content_object}>"
36+
37+
38+
class View(Model):
39+
"""
40+
Generic View model based on contenttype
41+
42+
Indicates if user has viewed the object
43+
44+
"""
45+
46+
user = models.ForeignKey(
47+
User,
48+
on_delete=models.CASCADE,
49+
related_name="views",
50+
)
51+
content_type = models.ForeignKey(
52+
ContentType,
53+
on_delete=models.CASCADE,
54+
related_name="views",
55+
)
56+
object_id = models.PositiveIntegerField()
57+
content_object = GenericForeignKey("content_type", "object_id")
58+
59+
class Meta:
60+
unique_together = ("user", "content_type", "object_id")
61+
verbose_name = "Просмотр"
62+
verbose_name_plural = "Просмотры"
63+
64+
def __str__(self):
65+
return f"View<{self.user} - {self.content_object}>"

core/serializers.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from rest_framework import serializers
2+
3+
4+
class SetLikedSerializer(serializers.Serializer):
5+
is_liked = serializers.BooleanField()
6+
7+
8+
class SetViewedSerializer(serializers.Serializer):
9+
is_viewed = serializers.BooleanField()

core/services.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from django.contrib.auth import get_user_model
2+
from django.contrib.contenttypes.models import ContentType
3+
4+
from core.models import Like, View
5+
6+
User = get_user_model()
7+
8+
9+
def add_like(obj, user):
10+
obj_type = ContentType.objects.get_for_model(obj)
11+
like, is_created = Like.objects.get_or_create(
12+
content_type=obj_type, object_id=obj.id, user=user
13+
)
14+
return like
15+
16+
17+
def remove_like(obj, user):
18+
obj_type = ContentType.objects.get_for_model(obj)
19+
Like.objects.filter(content_type=obj_type, object_id=obj.id, user=user).delete()
20+
21+
22+
def is_fan(obj, user) -> bool:
23+
if not user.is_authenticated:
24+
return False
25+
obj_type = ContentType.objects.get_for_model(obj)
26+
likes = Like.objects.filter(content_type=obj_type, object_id=obj.id, user=user)
27+
return likes.exists()
28+
29+
30+
def get_fans(obj):
31+
obj_type = ContentType.objects.get_for_model(obj)
32+
return User.objects.filter(likes__content_type=obj_type, likes__object_id=obj.id)
33+
34+
35+
def get_likes_count(obj):
36+
obj_type = ContentType.objects.get_for_model(obj)
37+
return User.objects.filter(
38+
likes__content_type=obj_type, likes__object_id=obj.id
39+
).count()
40+
41+
42+
def set_like(obj, user, is_liked):
43+
if is_liked:
44+
add_like(obj, user)
45+
else:
46+
remove_like(obj, user)
47+
48+
49+
def add_view(obj, user):
50+
obj_type = ContentType.objects.get_for_model(obj)
51+
view, is_created = View.objects.get_or_create(
52+
content_type=obj_type, object_id=obj.id, user=user
53+
)
54+
return view
55+
56+
57+
def remove_view(obj, user):
58+
obj_type = ContentType.objects.get_for_model(obj)
59+
View.objects.filter(content_type=obj_type, object_id=obj.id, user=user).delete()
60+
61+
62+
def is_viewer(obj, user) -> bool:
63+
if not user.is_authenticated:
64+
return False
65+
obj_type = ContentType.objects.get_for_model(obj)
66+
views = View.objects.filter(content_type=obj_type, object_id=obj.id, user=user)
67+
return views.exists()
68+
69+
70+
def get_viewers(obj):
71+
obj_type = ContentType.objects.get_for_model(obj)
72+
return User.objects.filter(views__content_type=obj_type, views__object_id=obj.id)
73+
74+
75+
def get_views_count(obj):
76+
obj_type = ContentType.objects.get_for_model(obj)
77+
return User.objects.filter(
78+
views__content_type=obj_type, views__object_id=obj.id
79+
).count()
80+
81+
82+
def set_viewed(obj, user, is_viewed):
83+
if is_viewed:
84+
add_view(obj, user)
85+
else:
86+
remove_view(obj, user)

procollab/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
"debug_toolbar",
7676
"django_rest_passwordreset",
7777
# My apps
78+
"core.apps.CoreConfig",
7879
"industries.apps.IndustriesConfig",
7980
"users.apps.UsersConfig",
8081
"projects.apps.ProjectsConfig",

projects/admin.py

Lines changed: 15 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, ProjectLink
3+
from projects.models import Project, Achievement, Collaborator, ProjectLink, ProjectNews
44

55

66
@admin.register(Project)
@@ -16,6 +16,20 @@ class ProjectAdmin(admin.ModelAdmin):
1616
)
1717

1818

19+
@admin.register(ProjectNews)
20+
class ProjectNewsAdmin(admin.ModelAdmin):
21+
list_display = (
22+
"id",
23+
"project",
24+
"datetime_created",
25+
)
26+
list_display_links = (
27+
"id",
28+
"project",
29+
"datetime_created",
30+
)
31+
32+
1933
@admin.register(Achievement)
2034
class AchievementAdmin(admin.ModelAdmin):
2135
list_display = ("id", "title", "status", "project")
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Generated by Django 4.2 on 2023-06-08 20:05
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", "0012_projectlink"),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name="ProjectNews",
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+
("text", models.TextField()),
27+
(
28+
"datetime_created",
29+
models.DateTimeField(auto_now_add=True, verbose_name="Дата создания"),
30+
),
31+
(
32+
"datetime_updated",
33+
models.DateTimeField(auto_now=True, verbose_name="Дата изменения"),
34+
),
35+
("views_count", models.PositiveIntegerField(default=0)),
36+
(
37+
"project",
38+
models.ForeignKey(
39+
on_delete=django.db.models.deletion.CASCADE,
40+
related_name="news",
41+
to="projects.project",
42+
),
43+
),
44+
],
45+
),
46+
]

0 commit comments

Comments
 (0)