from django.db import models from ft.models import User, Org from encrypted_id.models import EncryptedIDModel from slides import utils VISIBILITY_EVERYONE = "everyone" VISIBILITY_ORG = "org" VISIBILITY_ONLY_ME = "only_me" class SlideSnapshot(models.Model): preview = models.BinaryField() # this is the PNG content thumbnail = models.BinaryField() # this is the PNG content class Meta: db_table = "slides_slide_snapshot" class OrgTemplate(models.Model): org = models.ForeignKey(Org, on_delete=models.PROTECT, related_name="+") template = models.ForeignKey( "Presentation", on_delete=models.PROTECT, related_name="+" ) custom_data = models.JSONField(default=dict) # Needs Org, User class Presentation(EncryptedIDModel): # template = models.ForeignKey("Presentation", on_delete=models.PROTECT, related_name="+") # `snapshot` is redundant, but it's a performance optimization # snapshot = models.ForeignKey(SlideSnapshot, on_delete=models.PROTECT, related_name="+") title = models.TextField(max_length=200) slug = models.SlugField(max_length=200) org = models.ForeignKey(Org, on_delete=models.PROTECT, related_name="+") owner = models.ForeignKey(User, on_delete=models.PROTECT, related_name="+") # we will store a `settings.ftd` file in the database, it will be auto imported in each slide, and can define # color scheme and other global data. setting_ftd = models.TextField() # FTD fastn_ftd = models.TextField() # FTD created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) STATUS_CHOICES = [ ("draft", "Draft"), ("approved", "Approved"), ] status = models.TextField(max_length=10, choices=STATUS_CHOICES, default="draft") issue_count = models.IntegerField(default=0) # can be calculated from comments is_template = models.BooleanField(default=False) # only me, with Org, with everyone VISIBILITY_CHOICES = [ (VISIBILITY_ONLY_ME, "Only Me"), (VISIBILITY_ORG, "Org"), (VISIBILITY_EVERYONE, "Everyone"), ] visibility = models.TextField( max_length=10, choices=VISIBILITY_CHOICES, default=VISIBILITY_ORG ) class Meta: db_table = "slides_presentation" unique_together = [("org", "slug")] def dashboard_view(self): return { "title": self.title, "thumbnail": self.thumbnail_url(), "updated-on": "Edited 18 min ago", # TODO: calculate this "url": self.presentation_url(), } def thumbnail_url(self): return self.slides.get(order=1).thumbnail_url() def preview_url(self): return self.slides.get(order=1).preview_url() def to_public_presentation(self): # record definition in templates.ftd return { "id": self.id, "url": self.template_url(), "title": self.title, "org": self.org.name, "owner_name": self.owner.username, "thumbnail": self.thumbnail_url(), "owner_avatar": "/-/ui.fifthtry.com/slides/assets/avatar.svg", } def to_detail_presentation(self): # record definition in template.ftd """ :return: caption template-name: x string template-slug: x integer id: x string owner-name: x string org-name: x string org-slug: x string org-initials: x string preview: x string thumbnail: x string org-avatar: x? string list slides: x """ return { "id": self.id, "template-name": self.title, "org-name": self.org.name, "owner-name": self.owner.username, "owner-initials": utils.get_initials(self.owner.username), "org-slug": self.org.slug, "org-initials": utils.get_initials(self.org.name), "template-slug": self.slug, "preview": self.preview_url(), "thumbnail": self.thumbnail_url(), "org-avatar": "/-/ui.fifthtry.com/slides/assets/avatar.svg", "slides": [s.thumbnail_url() for s in self.slides.all()], } def get_slide_by_order(self, order): return Slide.objects.get(presentation=self, order=order) def __str__(self) -> str: return "Id: " + str(self.id) + " " + self.title def template_url(self) -> str: return f"/t/{self.org.slug}/{self.slug}/" def presentation_url(self, order=1) -> str: if order == 1: return f"/p/{self.org.slug}/{self.slug}/" else: return f"/p/{self.org.slug}/{self.slug}/{order}/" def settings_url(self) -> str: return f"/p/{self.org.slug}/{self.slug}/settings/" def present_url(self) -> str: return f"/p/{self.org.slug}/{self.slug}/present/" class RawAsset(models.Model): content = models.BinaryField() # this is the PNG content dark_content = models.BinaryField() # this is the PNG content class Meta: db_table = "slides_raw_asset" class Asset(models.Model): presentation = models.ForeignKey( Presentation, on_delete=models.PROTECT, related_name="assets" ) # org = models.ForeignKey(Org, on_delete=models.PROTECT, related_name="+") name = models.TextField(max_length=200) # this will be the root relative file name # we will store the dark version raw = models.ForeignKey(RawAsset, on_delete=models.PROTECT, related_name="+") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) visibility = models.TextField( max_length=10, choices=Presentation.VISIBILITY_CHOICES, default=VISIBILITY_ORG ) class Meta: db_table = "slides_asset" def url(self): return "/asset/%s.png" % self.ekey class Slide(EncryptedIDModel): # template = models.ForeignKey("Slide", on_delete=models.PROTECT, related_name="+") # this is the last successful snapshot, in case of error we will not update this. snapshot = models.ForeignKey( SlideSnapshot, on_delete=models.PROTECT, related_name="snapshots" ) # this will be template presentation for slide templates presentation = models.ForeignKey( Presentation, on_delete=models.PROTECT, related_name="slides" ) title = models.TextField(max_length=200) slug = models.SlugField(max_length=200) order = models.IntegerField() content = models.TextField() # FTD """ -- import: foo -- foo.slide-1: Hello This is a slide. """ # if there is any error in the content we will store it here. error = models.TextField(null=True) STATUS_CHOICES = [ ("draft", "Draft"), ("approved", "Approved"), ] status = models.TextField(max_length=10, choices=STATUS_CHOICES, default="draft") created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) issue_count = models.IntegerField(default=0) # can be calculated from comments class Meta: db_table = "slides_slide" unique_together = [("presentation", "order")] def to_detail_slide(self): return { "content": self.content, "preview-url": self.preview_url(), # todo: "is-valid": not self.error, "is-valid": True, } def to_slide_thumbnail(self): return { "url": self.presentation.presentation_url(self.order), "thumbnail-url": self.thumbnail_url(), # todo: "is-valid": not self.error, "is-valid": True, } def to_template_slide_data(self): return { "title": self.title, "slug": self.slug, "presentation-slug": self.presentation.slug, "thumbnail": self.thumbnail_url(), } def preview_url(self): # todo # return "/preview/%s.png" % self.ekey return f"/page/serve-image/?slide={self.id}&preview=true" def thumbnail_url(self): return f"/page/serve-image/?slide={self.id}&preview=false" def to_public_slide_preview(self, current_slide): # string ekey: # string order: # boolean is-current: # string preview-url: # slide-status status: return { "ekey": self.ekey, "order": self.order, "is-current": self.order == current_slide, "preview-url": self.preview_url(), "status": self.status, } def to_public_slide(self, ekey, presentation): return { "ekey": ekey, "presentation": presentation.to_public_presentation(), } def url(self): self.presentation.url() + f"/{self.order}/" def __str__(self): return ( "Id: " + str(self.id) + " " + self.presentation.title + ": " + str(self.order) ) class Comment(models.Model): slide = models.ForeignKey(Slide, on_delete=models.PROTECT, related_name="comments") user = models.ForeignKey(User, on_delete=models.PROTECT, related_name="comments") content = models.TextField() issue = models.BooleanField(default=False) resolved = models.BooleanField(default=False) position_x = models.IntegerField(null=True) position_y = models.IntegerField(null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = "slides_comment" class CommentResolution(models.Model): comment = models.ForeignKey( Comment, on_delete=models.PROTECT, related_name="resolutions" ) user = models.ForeignKey(User, on_delete=models.PROTECT, related_name="resolutions") content = models.TextField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: db_table = "slides_comment_resolution"