125 lines
4.0 KiB
Python
125 lines
4.0 KiB
Python
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"
|
|
)
|