123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- from uuid import uuid4
- import requests
- from django.apps import apps
- from django.core.files.base import ContentFile
- from django.db import models
- from django.urls import reverse
- from django_extensions.db.models import TimeStampedModel
- from imagekit.models import ImageSpecField
- from imagekit.processors import ResizeToFit
- from puzzles.sources import ipdb
- from scrobbles.dataclasses import PuzzleLogData
- from scrobbles.mixins import ScrobblableConstants, ScrobblableMixin
- BNULL = {"blank": True, "null": True}
- class PuzzleManufacturer(TimeStampedModel):
- uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
- name = models.CharField(max_length=255)
- ipdb_id = models.CharField(max_length=200, **BNULL)
- description = models.TextField(**BNULL)
- def __str__(self) -> str:
- return str(self.name)
- class Puzzle(ScrobblableMixin):
- description = models.TextField(**BNULL)
- orientation = models.CharField(max_length=50, **BNULL)
- dimensions_in_inches = models.CharField(max_length=30, **BNULL)
- publish_year = models.IntegerField(**BNULL)
- material = models.CharField(max_length=50, **BNULL)
- cut_style = models.CharField(max_length=100, **BNULL)
- pieces_count = models.IntegerField(**BNULL)
- ipdb_id = models.CharField(max_length=255, **BNULL)
- barcode = models.CharField(max_length=13, **BNULL)
- ipdb_image = models.ImageField(upload_to="puzzles/ipdb/", **BNULL)
- ipdb_image_small = ImageSpecField(
- source="ipdb_image",
- processors=[ResizeToFit(100, 100)],
- format="JPEG",
- options={"quality": 60},
- )
- ipdb_image_medium = ImageSpecField(
- source="ipdb_image",
- processors=[ResizeToFit(300, 300)],
- format="JPEG",
- options={"quality": 75},
- )
- manufacturer = models.ForeignKey(
- PuzzleManufacturer, on_delete=models.DO_NOTHING, **BNULL
- )
- def get_absolute_url(self) -> str:
- return reverse("puzzles:puzzle_detail", kwargs={"slug": self.uuid})
- def __str__(self):
- return f"{self.title} ({self.pieces_count}) by {self.manufacturer}"
- @property
- def subtitle(self):
- return self.manufacturer.name
- @property
- def strings(self) -> ScrobblableConstants:
- return ScrobblableConstants(verb="Solving", tags="puzzle")
- @property
- def ipdb_link(self) -> str:
- link = ""
- if self.ipdb_id:
- link = f"https://www.ipdb.plus/IPDb/puzzle.php?id={self.ipdb_id}"
- return link
- @property
- def primary_image_url(self) -> str:
- url = ""
- if self.ipdb_image:
- url = self.ipdb_image.url
- return url
- @property
- def logdata_cls(self):
- return PuzzleLogData
- @classmethod
- def find_or_create(cls, ipdb_id: str) -> "Puzzle":
- puzzle = cls.objects.filter(ipdb_id=ipdb_id).first()
- if not puzzle:
- puzzle_dict = ipdb.get_puzzle_from_ipdb_id(ipdb_id)
- manufacturer_name = puzzle_dict.pop("manufacturer", None)
- if manufacturer_name:
- (
- manufacturer,
- _created,
- ) = PuzzleManufacturer.objects.get_or_create(
- name=manufacturer_name
- )
- puzzle_dict["manufacturer_id"] = manufacturer.id
- genres = puzzle_dict.pop("genres", None)
- cover_url = puzzle_dict.pop("ipdb_image_url", None)
- puzzle = Puzzle.objects.create(**puzzle_dict)
- if genres:
- puzzle.genre.add(*genres)
- if cover_url:
- r = requests.get(cover_url)
- if r.status_code == 200:
- fname = f"{puzzle.title}_{puzzle.uuid}.jpg"
- puzzle.ipdb_image.save(
- fname, ContentFile(r.content), save=True
- )
- return puzzle
- def scrobbles(self, user_id):
- Scrobble = apps.get_model("scrobbles", "Scrobble")
- return Scrobble.objects.filter(user_id=user_id, puzzle=self).order_by(
- "-timestamp"
- )
|