2020-01-21 06:35:58 +00:00
|
|
|
import re
|
|
|
|
|
|
|
|
from django.core.exceptions import ValidationError
|
|
|
|
from django.db import models
|
|
|
|
from django.urls import reverse
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
2023-02-20 23:15:13 +00:00
|
|
|
from django.utils.functional import cached_property
|
|
|
|
from django.contrib.contenttypes.fields import GenericRelation
|
2020-01-21 06:35:58 +00:00
|
|
|
from mptt.fields import TreeForeignKey
|
|
|
|
from mptt.models import MPTTModel
|
|
|
|
|
2020-12-28 05:45:58 +00:00
|
|
|
from judge.models.profile import Organization, Profile
|
2023-08-03 16:19:45 +00:00
|
|
|
from judge.models.pagevote import PageVotable
|
|
|
|
from judge.models.bookmark import Bookmarkable
|
2024-04-13 22:02:54 +00:00
|
|
|
from judge.caching import cache_wrapper
|
2020-01-21 06:35:58 +00:00
|
|
|
|
2022-05-14 17:57:27 +00:00
|
|
|
__all__ = ["MiscConfig", "validate_regex", "NavigationBar", "BlogPost"]
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
class MiscConfig(models.Model):
|
|
|
|
key = models.CharField(max_length=30, db_index=True)
|
|
|
|
value = models.TextField(blank=True)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.key
|
|
|
|
|
|
|
|
class Meta:
|
2022-05-14 17:57:27 +00:00
|
|
|
verbose_name = _("configuration item")
|
|
|
|
verbose_name_plural = _("miscellaneous configuration")
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
def validate_regex(regex):
|
|
|
|
try:
|
|
|
|
re.compile(regex, re.VERBOSE)
|
|
|
|
except re.error as e:
|
2022-05-14 17:57:27 +00:00
|
|
|
raise ValidationError("Invalid regex: %s" % e.message)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
class NavigationBar(MPTTModel):
|
|
|
|
class Meta:
|
2022-05-14 17:57:27 +00:00
|
|
|
verbose_name = _("navigation item")
|
|
|
|
verbose_name_plural = _("navigation bar")
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
class MPTTMeta:
|
2022-05-14 17:57:27 +00:00
|
|
|
order_insertion_by = ["order"]
|
|
|
|
|
|
|
|
order = models.PositiveIntegerField(db_index=True, verbose_name=_("order"))
|
|
|
|
key = models.CharField(max_length=10, unique=True, verbose_name=_("identifier"))
|
|
|
|
label = models.CharField(max_length=20, verbose_name=_("label"))
|
|
|
|
path = models.CharField(max_length=255, verbose_name=_("link path"))
|
|
|
|
regex = models.TextField(
|
|
|
|
verbose_name=_("highlight regex"), validators=[validate_regex]
|
|
|
|
)
|
|
|
|
parent = TreeForeignKey(
|
|
|
|
"self",
|
|
|
|
verbose_name=_("parent item"),
|
|
|
|
null=True,
|
|
|
|
blank=True,
|
|
|
|
related_name="children",
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.label
|
|
|
|
|
|
|
|
@property
|
|
|
|
def pattern(self, cache={}):
|
|
|
|
# A cache with a bad policy is an alias for memory leak
|
|
|
|
# Thankfully, there will never be too many regexes to cache.
|
|
|
|
if self.regex in cache:
|
|
|
|
return cache[self.regex]
|
|
|
|
else:
|
|
|
|
pattern = cache[self.regex] = re.compile(self.regex, re.VERBOSE)
|
|
|
|
return pattern
|
|
|
|
|
|
|
|
|
2023-08-03 16:19:45 +00:00
|
|
|
class BlogPost(models.Model, PageVotable, Bookmarkable):
|
2022-05-14 17:57:27 +00:00
|
|
|
title = models.CharField(verbose_name=_("post title"), max_length=100)
|
|
|
|
authors = models.ManyToManyField(Profile, verbose_name=_("authors"), blank=True)
|
|
|
|
slug = models.SlugField(verbose_name=_("slug"))
|
|
|
|
visible = models.BooleanField(verbose_name=_("public visibility"), default=False)
|
|
|
|
sticky = models.BooleanField(verbose_name=_("sticky"), default=False)
|
|
|
|
publish_on = models.DateTimeField(verbose_name=_("publish after"))
|
|
|
|
content = models.TextField(verbose_name=_("post content"))
|
|
|
|
summary = models.TextField(verbose_name=_("post summary"), blank=True)
|
|
|
|
og_image = models.CharField(
|
|
|
|
verbose_name=_("openGraph image"), default="", max_length=150, blank=True
|
|
|
|
)
|
|
|
|
organizations = models.ManyToManyField(
|
|
|
|
Organization,
|
|
|
|
blank=True,
|
|
|
|
verbose_name=_("organizations"),
|
|
|
|
help_text=_("If private, only these organizations may see the blog post."),
|
|
|
|
)
|
|
|
|
is_organization_private = models.BooleanField(
|
|
|
|
verbose_name=_("private to organizations"), default=False
|
|
|
|
)
|
2023-02-20 23:15:13 +00:00
|
|
|
comments = GenericRelation("Comment")
|
2023-08-03 09:04:39 +00:00
|
|
|
pagevote = GenericRelation("PageVote")
|
|
|
|
bookmark = GenericRelation("BookMark")
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.title
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
2022-05-14 17:57:27 +00:00
|
|
|
return reverse("blog_post", args=(self.id, self.slug))
|
2020-01-21 06:35:58 +00:00
|
|
|
|
2024-04-13 22:02:54 +00:00
|
|
|
def is_accessible_by(self, user):
|
2020-01-21 06:35:58 +00:00
|
|
|
if self.visible and self.publish_on <= timezone.now():
|
2020-12-28 05:45:58 +00:00
|
|
|
if not self.is_organization_private:
|
|
|
|
return True
|
2022-05-14 17:57:27 +00:00
|
|
|
if (
|
|
|
|
user.is_authenticated
|
|
|
|
and self.organizations.filter(
|
|
|
|
id__in=user.profile.organizations.all()
|
|
|
|
).exists()
|
|
|
|
):
|
2020-12-28 05:45:58 +00:00
|
|
|
return True
|
2022-05-14 17:57:27 +00:00
|
|
|
if user.has_perm("judge.edit_all_post"):
|
2020-01-21 06:35:58 +00:00
|
|
|
return True
|
2022-05-14 17:57:27 +00:00
|
|
|
return (
|
|
|
|
user.is_authenticated and self.authors.filter(id=user.profile.id).exists()
|
|
|
|
)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
2020-12-28 05:45:58 +00:00
|
|
|
def is_editable_by(self, user):
|
2022-05-14 17:57:27 +00:00
|
|
|
if not user.is_authenticated:
|
|
|
|
return False
|
|
|
|
if user.has_perm("judge.edit_all_post"):
|
|
|
|
return True
|
|
|
|
return (
|
|
|
|
user.has_perm("judge.change_blogpost")
|
|
|
|
and self.authors.filter(id=user.profile.id).exists()
|
|
|
|
)
|
2020-12-28 05:45:58 +00:00
|
|
|
|
2024-04-13 22:02:54 +00:00
|
|
|
@cache_wrapper(prefix="BPga")
|
|
|
|
def get_authors(self):
|
|
|
|
return self.authors.only("id")
|
|
|
|
|
2020-01-21 06:35:58 +00:00
|
|
|
class Meta:
|
2022-05-14 17:57:27 +00:00
|
|
|
permissions = (("edit_all_post", _("Edit all posts")),)
|
|
|
|
verbose_name = _("blog post")
|
|
|
|
verbose_name_plural = _("blog posts")
|