Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions core/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.contrib import admin
from core.models import Like, View


@admin.register(Like)
class LikeAdmin(admin.ModelAdmin):
list_display = ("id", "user", "content_type", "object_id", "content_object")
list_display_links = ("id", "user", "content_type", "object_id", "content_object")


@admin.register(View)
class ViewAdmin(admin.ModelAdmin):
list_display = ("id", "user", "content_type", "object_id", "content_object")
list_display_links = ("id", "user", "content_type", "object_id", "content_object")
54 changes: 54 additions & 0 deletions core/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Generated by Django 4.2 on 2023-06-08 20:05

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("contenttypes", "0002_remove_content_type_name"),
]

operations = [
migrations.CreateModel(
name="Like",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("object_id", models.PositiveIntegerField()),
(
"content_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="likes",
to="contenttypes.contenttype",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="likes",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "Лайк",
"verbose_name_plural": "Лайки",
"unique_together": {("user", "content_type", "object_id")},
},
),
]
53 changes: 53 additions & 0 deletions core/migrations/0002_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 4.2 on 2023-06-11 10:28

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("contenttypes", "0002_remove_content_type_name"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("core", "0001_initial"),
]

operations = [
migrations.CreateModel(
name="View",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("object_id", models.PositiveIntegerField()),
(
"content_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="views",
to="contenttypes.contenttype",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="views",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name": "Просмотр",
"verbose_name_plural": "Просмотры",
"unique_together": {("user", "content_type", "object_id")},
},
),
]
Empty file added core/migrations/__init__.py
Empty file.
65 changes: 65 additions & 0 deletions core/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model
from django.db import models

User = get_user_model()


class Like(Model):
"""
Generic Like model based on contenttype
"""

user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="likes",
)
content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
related_name="likes",
)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
# is liked?

class Meta:
unique_together = ("user", "content_type", "object_id")
verbose_name = "Лайк"
verbose_name_plural = "Лайки"

def __str__(self):
return f"Like<{self.user} - {self.content_object}>"


class View(Model):
"""
Generic View model based on contenttype

Indicates if user has viewed the object

"""

user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="views",
)
content_type = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
related_name="views",
)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")

class Meta:
unique_together = ("user", "content_type", "object_id")
verbose_name = "Просмотр"
verbose_name_plural = "Просмотры"

def __str__(self):
return f"View<{self.user} - {self.content_object}>"
9 changes: 9 additions & 0 deletions core/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from rest_framework import serializers


class SetLikedSerializer(serializers.Serializer):
is_liked = serializers.BooleanField()


class SetViewedSerializer(serializers.Serializer):
is_viewed = serializers.BooleanField()
86 changes: 86 additions & 0 deletions core/services.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType

from core.models import Like, View

User = get_user_model()


def add_like(obj, user):
obj_type = ContentType.objects.get_for_model(obj)
like, is_created = Like.objects.get_or_create(
content_type=obj_type, object_id=obj.id, user=user
)
return like


def remove_like(obj, user):
obj_type = ContentType.objects.get_for_model(obj)
Like.objects.filter(content_type=obj_type, object_id=obj.id, user=user).delete()


def is_fan(obj, user) -> bool:
if not user.is_authenticated:
return False
obj_type = ContentType.objects.get_for_model(obj)
likes = Like.objects.filter(content_type=obj_type, object_id=obj.id, user=user)
return likes.exists()


def get_fans(obj):
obj_type = ContentType.objects.get_for_model(obj)
return User.objects.filter(likes__content_type=obj_type, likes__object_id=obj.id)


def get_likes_count(obj):
obj_type = ContentType.objects.get_for_model(obj)
return User.objects.filter(
likes__content_type=obj_type, likes__object_id=obj.id
).count()


def set_like(obj, user, is_liked):
if is_liked:
add_like(obj, user)
else:
remove_like(obj, user)


def add_view(obj, user):
obj_type = ContentType.objects.get_for_model(obj)
view, is_created = View.objects.get_or_create(
content_type=obj_type, object_id=obj.id, user=user
)
return view


def remove_view(obj, user):
obj_type = ContentType.objects.get_for_model(obj)
View.objects.filter(content_type=obj_type, object_id=obj.id, user=user).delete()


def is_viewer(obj, user) -> bool:
if not user.is_authenticated:
return False
obj_type = ContentType.objects.get_for_model(obj)
views = View.objects.filter(content_type=obj_type, object_id=obj.id, user=user)
return views.exists()


def get_viewers(obj):
obj_type = ContentType.objects.get_for_model(obj)
return User.objects.filter(views__content_type=obj_type, views__object_id=obj.id)


def get_views_count(obj):
obj_type = ContentType.objects.get_for_model(obj)
return User.objects.filter(
views__content_type=obj_type, views__object_id=obj.id
).count()


def set_viewed(obj, user, is_viewed):
if is_viewed:
add_view(obj, user)
else:
remove_view(obj, user)
1 change: 1 addition & 0 deletions procollab/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"debug_toolbar",
"django_rest_passwordreset",
# My apps
"core.apps.CoreConfig",
"industries.apps.IndustriesConfig",
"users.apps.UsersConfig",
"projects.apps.ProjectsConfig",
Expand Down
16 changes: 15 additions & 1 deletion projects/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.contrib import admin

from projects.models import Project, Achievement, Collaborator, ProjectLink
from projects.models import Project, Achievement, Collaborator, ProjectLink, ProjectNews


@admin.register(Project)
Expand All @@ -16,6 +16,20 @@ class ProjectAdmin(admin.ModelAdmin):
)


@admin.register(ProjectNews)
class ProjectNewsAdmin(admin.ModelAdmin):
list_display = (
"id",
"project",
"datetime_created",
)
list_display_links = (
"id",
"project",
"datetime_created",
)


@admin.register(Achievement)
class AchievementAdmin(admin.ModelAdmin):
list_display = ("id", "title", "status", "project")
Expand Down
46 changes: 46 additions & 0 deletions projects/migrations/0013_projectnews.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 4.2 on 2023-06-08 20:05

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
("projects", "0012_projectlink"),
]

operations = [
migrations.CreateModel(
name="ProjectNews",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("text", models.TextField()),
(
"datetime_created",
models.DateTimeField(auto_now_add=True, verbose_name="Дата создания"),
),
(
"datetime_updated",
models.DateTimeField(auto_now=True, verbose_name="Дата изменения"),
),
("views_count", models.PositiveIntegerField(default=0)),
(
"project",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="news",
to="projects.project",
),
),
],
),
]
24 changes: 24 additions & 0 deletions projects/migrations/0014_alter_projectnews_options_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2 on 2023-06-11 10:28

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("projects", "0013_projectnews"),
]

operations = [
migrations.AlterModelOptions(
name="projectnews",
options={
"verbose_name": "Новость проекта",
"verbose_name_plural": "Новости проекта",
},
),
migrations.RemoveField(
model_name="projectnews",
name="views_count",
),
]
Loading