Skip to content

Commit

Permalink
renaming and added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
etchegom committed Jan 16, 2025
1 parent 4b5f88f commit 377518a
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 30 deletions.
16 changes: 14 additions & 2 deletions recoco/apps/hitcount/admin.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
from django.contrib import admin
from django.db.models import Count

from .models import Hit, HitCount


@admin.register(HitCount)
class HitCountAdmin(admin.ModelAdmin):
list_display = (
"name",
"hit_count",
"site",
"content_object",
"context_object",
"created",
)
list_filter = (
"site",
"created",
)

def get_queryset(self, request):
return super().get_queryset(request).annotate(hit_count=Count("hits"))

@admin.display(description="Name")
def name(self, obj):
return str(obj)

@admin.display(description="Number of Hits")
def hit_count(self, obj):
return obj.hit_count


@admin.register(Hit)
class HitAdmin(admin.ModelAdmin):
Expand Down
12 changes: 6 additions & 6 deletions recoco/apps/hitcount/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.17 on 2025-01-08 08:12
# Generated by Django 4.2.17 on 2025-01-08 08:39

from django.conf import settings
from django.db import migrations, models
Expand All @@ -12,8 +12,8 @@ class Migration(migrations.Migration):
initial = True

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

Expand Down Expand Up @@ -52,15 +52,15 @@ class Migration(migrations.Migration):
models.PositiveIntegerField(blank=True, null=True),
),
(
"content_ct",
"content_object_ct",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="hitcount_set_for_content",
to="contenttypes.contenttype",
),
),
(
"context_ct",
"context_object_ct",
models.ForeignKey(
blank=True,
null=True,
Expand All @@ -84,9 +84,9 @@ class Migration(migrations.Migration):
"unique_together": {
(
"site",
"content_ct",
"content_object_ct",
"content_object_id",
"context_ct",
"context_object_ct",
"context_object_id",
)
},
Expand Down
20 changes: 14 additions & 6 deletions recoco/apps/hitcount/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@
class HitCount(TimeStampedModel):
site = models.ForeignKey(Site, on_delete=models.CASCADE)

content_ct = models.ForeignKey(
content_object_ct = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
related_name="hitcount_set_for_content",
)
content_object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_ct", "content_object_id")
content_object = GenericForeignKey("content_object_ct", "content_object_id")

context_ct = models.ForeignKey(
context_object_ct = models.ForeignKey(
ContentType,
on_delete=models.CASCADE,
related_name="hitcount_set_for_context",
null=True,
blank=True,
)
context_object_id = models.PositiveIntegerField(null=True, blank=True)
context_object = GenericForeignKey("context_ct", "context_object_id")
context_object = GenericForeignKey("context_object_ct", "context_object_id")

class Meta:
verbose_name = _("hit count")
Expand All @@ -35,12 +35,20 @@ class Meta:
get_latest_by = "modified"
unique_together = (
"site",
"content_ct",
"content_object_ct",
"content_object_id",
"context_ct",
"context_object_ct",
"context_object_id",
)

def __str__(self):
hit_count_str = f"{self.content_object_ct.name}-{self.content_object_id}"
if self.context_object and self.context_object_id:
hit_count_str += (
f" ({self.context_object_ct.name}-{self.context_object_id})"
)
return hit_count_str


class Hit(TimeStampedModel):
user_agent = models.CharField(max_length=255, editable=False)
Expand Down
32 changes: 18 additions & 14 deletions recoco/apps/hitcount/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,35 @@


class HitInputSerializer(serializers.Serializer):
content_ct = serializers.CharField()
content_object_ct = serializers.CharField()
content_object_id = serializers.IntegerField()
context_ct = serializers.CharField(required=False)
context_object_ct = serializers.CharField(required=False)
context_object_id = serializers.IntegerField(required=False)

def validate(self, data):
content_ct = data.get("content_ct")
content_object_ct = data.get("content_object_ct")
content_object_id = data.get("content_object_id")
context_ct = data.get("context_ct")
context_object_ct = data.get("context_object_ct")
context_object_id = data.get("context_object_id")

if context_ct and not context_object_id:
if context_object_ct and not context_object_id:
raise serializers.ValidationError(
"context_ct is required when context_object_id is provided"
"context_object_ct is required when context_object_id is provided"
)

if context_object_id and not context_ct:
if context_object_id and not context_object_ct:
raise serializers.ValidationError(
"context_object_id is required when context_ct is provided"
"context_object_id is required when context_object_ct is provided"
)

content_obj_model = apps.get_model(content_ct)
content_obj_model = apps.get_model(content_object_ct)
try:
content_obj_model.objects.get(id=content_object_id)
except content_obj_model.DoesNotExist as exc:
raise serializers.ValidationError("Invalid content_object_id") from exc

if context_ct:
context_object_model = apps.get_model(context_ct)
if context_object_ct:
context_object_model = apps.get_model(context_object_ct)
try:
context_object_model.objects.get(id=data.get("context_object_id"))
except context_object_model.DoesNotExist as exc:
Expand All @@ -46,13 +46,17 @@ def validate(self, data):
@property
def output_data(self) -> dict[str, Any]:
data = {
"content_ct": ct_from_label(self.validated_data["content_ct"]),
"content_object_ct": ct_from_label(
self.validated_data["content_object_ct"]
),
"content_object_id": self.validated_data["content_object_id"],
}
if not self.validated_data.get("context_ct"):
if not self.validated_data.get("context_object_ct"):
data.update(
{
"context_ct": ct_from_label(self.validated_data["context_ct"]),
"context_object_ct": ct_from_label(
self.validated_data["context_object_ct"]
),
"context_object_id": self.validated_data["context_object_id"],
}
)
Expand Down
18 changes: 18 additions & 0 deletions recoco/apps/hitcount/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest
from model_bakery import baker

from recoco.apps.addressbook.models import Contact
from recoco.apps.hitcount.models import HitCount
from recoco.apps.projects.models import Project


@pytest.mark.django_db
def test_hitcount_str():
contact = baker.make(Contact)
hitcount = baker.make(HitCount, content_object=contact)
assert str(hitcount) == f"contact-{contact.id}"

project = baker.make(Project)
hitcount.context_object = project
hitcount.save()
assert str(hitcount) == f"contact-{contact.id} (project-{project.id})"
4 changes: 2 additions & 2 deletions recoco/apps/hitcount/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def test_hit_view():
headers = {"user-agent": "Mozilla/5.0"}
payload = json.dumps(
{
"content_ct": ct_label(contact),
"content_object_ct": ct_label(contact),
"content_object_id": contact.id,
"context_ct": ct_label(recommendation),
"context_object_ct": ct_label(recommendation),
"context_object_id": recommendation.id,
}
)
Expand Down

0 comments on commit 377518a

Please sign in to comment.