from django.db import models from django.utils.translation import gettext_lazy as _ from django.conf import settings from django.contrib.auth import get_user_model from django.utils.safestring import mark_safe, SafeText from django.utils.html import escape from django.urls import reverse from tinywiki.enums import ( WIKI_CONTENT_TYPES, WIKI_PAGE_STATUS, WikiContentType, WikiPageStatus, ) import markdown import bbcode as _bbcode from tinywiki.parser import bbcode from .parser import parse_bbcode from . import settings import tinywiki def get_tinywiki_default_user(): UserModel = get_user_model() try: user = UserModel.objects.get(**settings.TINYWIKI_USER_LOOKUP) except UserModel.DoesNotExist: user = UserModel.objects.filter(is_superuser=True).order_by('pk')[0] return user class Page(models.Model): slug = models.SlugField(_("slug"), max_length=255, null=False, blank=False, unique=True) title = models.CharField(_("title"), max_length=255, null=False, blank=False) author = models.ForeignKey(get_user_model(), on_delete=models.SET_DEFAULT, default=get_tinywiki_default_user, verbose_name=_("author"), related_name="tinywiki_athors") status_data = models.CharField(_("status"), choices=[(i.value,i.str_lazy) for i in WIKI_PAGE_STATUS], max_length=15, null=False, blank=False, default=WikiPageStatus.IN_PROGRESS.value) content_type_data = models.CharField(_("content type"), choices=[(i.value,i.str_lazy) for i in WIKI_CONTENT_TYPES], default=WikiContentType.BBCODE.value) content = models.TextField(_("Page content"), null=False, blank=False) created_at = models.DateTimeField(_("created at"), auto_now_add=True) created_by = models.ForeignKey(get_user_model(), on_delete=models.SET_DEFAULT, verbose_name=_("created by"), default=get_tinywiki_default_user, related_name="tinywiki_created") last_edited_at = models.DateTimeField(_("last edited at"), auto_now=True) last_edited_by = models.ForeignKey(get_user_model(), on_delete=models.SET_DEFAULT, verbose_name=_("last edited by"), default=get_tinywiki_default_user, related_name="tinywiki_last_edited") @property def content_type(self)->WikiContentType: return WikiContentType.from_string(self.content_type_data) @content_type.setter def content_type(self, content_type: str | WikiContentType): if isinstance(content_type, str): self.content_type_data = WikiContentType.from_string(content_type).value elif isinstance(content_type, WikiContentType): self.content_type_data = content_type.value else: raise TypeError("content_type") @property def status(self)->WikiPageStatus: return WikiPageStatus.from_string(self.status_data) @status.setter def status(self, status: str | WikiPageStatus): if isinstance(status, str): self.status_data = WikiPageStatus.from_string(status).value elif isinstance(status, WikiPageStatus): self.status_data = status.value else: raise TypeError("status") @property def html_content(self) -> SafeText | str: if self.content_type == WikiContentType.MARKDOWN: return mark_safe(markdown.markdown(self.content)) elif self.content_type == WikiContentType.BBCODE: return mark_safe(parse_bbcode(self.content)) return self.content class Image(models.Model): models.ManyToManyField(Page, verbose_name=_("")) slug = models.SlugField(_("slug"), max_length=255) alt = models.CharField(_("alternative text"), max_length=511, null=False, blank=False) description = models.CharField(_("description"), max_length=1023, null=True, blank=True) image = models.ImageField(_("image file"), upload_to="tinywiki/img") uploaded_by = models.ForeignKey(get_user_model(), on_delete=models.SET_DEFAULT, verbose_name=_("uploaded by"), default=get_tinywiki_default_user, related_name="tinywiki_image_uploads") uploaded_at = models.DateTimeField(_("uploaded at"), auto_now_add=True) @property def description_html(self) -> str: return _bbcode.render_html(self.description) @property def description_html_safe(self) -> SafeText: return mark_safe(self.description_html) class SidebarSection(models.Model): title = models.CharField(_("title"), max_length=255, null=False, blank=False) priority = models.PositiveIntegerField(_("priority")) is_visible = models.BooleanField(_("is visible"), default=True) @property def widget(self) -> SafeText: if settings.USE_BOOTSTRAP: lines = [ "" ] else: lines = [ "" ] return mark_safe("\n".join(lines)) class SidebarEntry(models.Model): section = models.ForeignKey(SidebarSection, on_delete=models.CASCADE, verbose_name=_("Section"), related_name="items") title = models.CharField(_("Title"), max_length=255, null=False, blank=False) is_visible = models.BooleanField(_("is visible"), default=True) priority = models.PositiveIntegerField(_("Priority")) wiki_slug = models.CharField(_("Wiki slug"), max_length=255, null=True, blank=True) url = models.CharField(_("Link URL"), max_length=512, null=True, blank=True) widget = models.TextField(_("Widget"), blank=True, null=True) @property def link(self) -> SafeText: if self.wiki_slug: return mark_safe(f"{escape(self.title)}") # noqa: E501 elif self.url: return mark_safe(f"{escape(self.title)}") # noqa E501 return mark_safe(f"{escape(self.title)}") # noqa E501 @property def item(self) -> SafeText: if settings.USE_BOOTSTRAP: if self.widget: return mark_safe(f"
  • {self.widget}
  • ") # noqa: E501 else: return mark_safe(f"
  • {self.link}
  • ") # noqa: E501 if self.widget: return mark_safe(f"
  • {self.widget}
  • ") else: return mark_safe(f"
  • {self.link}
  • ") class BuiltinPages(models.Model): app = models.CharField(_("app"), max_length=255, unique=True) version = models.PositiveIntegerField(_("version")) prefix = models.CharField(_("prefix")) class BuiltinImages(models.Model): app = models.CharField(_("app"), max_length=255, unique=True) version = models.PositiveIntegerField(_("version")) prefix = models.CharField(_("prefix"))