feat: 📜 flesh out blog system for site updates
This commit is contained in:
parent
83ce6e887e
commit
4a3bb0ec56
15 changed files with 273 additions and 68 deletions
|
|
@ -4,6 +4,7 @@ from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
from moku.views.auth import LoginView, LogoutView
|
from moku.views.auth import LoginView, LogoutView
|
||||||
|
from moku.views.blog import IndexBlogView
|
||||||
from moku.views.post import FeedView
|
from moku.views.post import FeedView
|
||||||
from moku.views.recipe import (
|
from moku.views.recipe import (
|
||||||
DeleteRecipeView,
|
DeleteRecipeView,
|
||||||
|
|
@ -13,7 +14,7 @@ from moku.views.recipe import (
|
||||||
NewRecipeView,
|
NewRecipeView,
|
||||||
ShowRecipeView,
|
ShowRecipeView,
|
||||||
)
|
)
|
||||||
from moku.views.static import ChangelogView, PrivacyView, TermsView
|
from moku.views.static import PrivacyView, TermsView
|
||||||
from moku.views.user import (
|
from moku.views.user import (
|
||||||
EditProfileView,
|
EditProfileView,
|
||||||
EditSettingsView,
|
EditSettingsView,
|
||||||
|
|
@ -30,7 +31,7 @@ urlpatterns = [
|
||||||
path("signup", SignupView.as_view(), name="signup"),
|
path("signup", SignupView.as_view(), name="signup"),
|
||||||
path("profile", EditProfileView.as_view(), name="profile.edit"),
|
path("profile", EditProfileView.as_view(), name="profile.edit"),
|
||||||
path("settings", EditSettingsView.as_view(), name="settings"),
|
path("settings", EditSettingsView.as_view(), name="settings"),
|
||||||
path("changelog", ChangelogView.as_view(), name="changelog"),
|
path("blog", IndexBlogView.as_view(), name="blog.index"),
|
||||||
path("privacy", PrivacyView.as_view(), name="privacy"),
|
path("privacy", PrivacyView.as_view(), name="privacy"),
|
||||||
path("terms", TermsView.as_view(), name="terms"),
|
path("terms", TermsView.as_view(), name="terms"),
|
||||||
path("user/<str:username>", ProfileView.as_view(), name="profile"),
|
path("user/<str:username>", ProfileView.as_view(), name="profile"),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-26 18:45+0000\n"
|
"POT-Creation-Date: 2024-03-27 12:13+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: m5ka <m5ka@posteo.de>\n"
|
"Last-Translator: m5ka <m5ka@posteo.de>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -15,11 +15,11 @@ msgstr ""
|
||||||
msgid "english"
|
msgid "english"
|
||||||
msgstr "lami english"
|
msgstr "lami english"
|
||||||
|
|
||||||
#: moku/config/settings.py:144
|
#: moku/config/settings.py:143
|
||||||
msgid "lami lioa"
|
msgid "lami lioa"
|
||||||
msgstr "lami lioa"
|
msgstr "lami lioa"
|
||||||
|
|
||||||
#: moku/config/settings.py:145
|
#: moku/config/settings.py:143
|
||||||
msgid "toki pona"
|
msgid "toki pona"
|
||||||
msgstr "lami tokipona"
|
msgstr "lami tokipona"
|
||||||
|
|
||||||
|
|
@ -154,6 +154,22 @@ msgstr "noli"
|
||||||
msgid "about me"
|
msgid "about me"
|
||||||
msgstr "oisa nai"
|
msgstr "oisa nai"
|
||||||
|
|
||||||
|
#: moku/models/blog.py:9
|
||||||
|
msgid "title"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: moku/models/blog.py:11
|
||||||
|
msgid "the title of the blog post."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: moku/models/blog.py:14
|
||||||
|
msgid "content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: moku/models/blog.py:15
|
||||||
|
msgid "the content of the blog post. markdown is allowed here."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: moku/models/post.py:37 moku/models/recipe.py:24
|
#: moku/models/post.py:37 moku/models/recipe.py:24
|
||||||
msgid "unique id"
|
msgid "unique id"
|
||||||
msgstr "oioa mini"
|
msgstr "oioa mini"
|
||||||
|
|
@ -286,23 +302,24 @@ msgstr "haoa"
|
||||||
msgid "log in"
|
msgid "log in"
|
||||||
msgstr "mimi"
|
msgstr "mimi"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:37 moku/views/user.py:86
|
#: moku/templates/moku/base.jinja:37 moku/views/user.py:93
|
||||||
msgid "sign up"
|
msgid "sign up"
|
||||||
msgstr "holo hono"
|
msgstr "holo hono"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:55
|
#: moku/templates/moku/base.jinja:55 moku/templates/moku/blog.jinja:5
|
||||||
|
#: moku/views/blog.py:9
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "pali oiki"
|
msgstr "pali oiki"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:56 moku/views/user.py:38
|
#: moku/templates/moku/base.jinja:56 moku/views/user.py:45
|
||||||
msgid "settings"
|
msgid "settings"
|
||||||
msgstr "oiki laia"
|
msgstr "oiki laia"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:57 moku/views/static.py:24
|
#: moku/templates/moku/base.jinja:57 moku/views/static.py:17
|
||||||
msgid "terms of use"
|
msgid "terms of use"
|
||||||
msgstr "pali koko"
|
msgstr "pali koko"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:58 moku/views/static.py:17
|
#: moku/templates/moku/base.jinja:58 moku/views/static.py:10
|
||||||
msgid "privacy policy"
|
msgid "privacy policy"
|
||||||
msgstr "pali pamo"
|
msgstr "pali pamo"
|
||||||
|
|
||||||
|
|
@ -310,6 +327,10 @@ msgstr "pali pamo"
|
||||||
msgid "donate"
|
msgid "donate"
|
||||||
msgstr "hana kipi"
|
msgstr "hana kipi"
|
||||||
|
|
||||||
|
#: moku/templates/moku/blog.jinja:7
|
||||||
|
msgid "no blog posts yet..."
|
||||||
|
msgstr "ka koma iapa..."
|
||||||
|
|
||||||
#: moku/templates/moku/feed.jinja:52
|
#: moku/templates/moku/feed.jinja:52
|
||||||
msgid "post!"
|
msgid "post!"
|
||||||
msgstr "si iapa!"
|
msgstr "si iapa!"
|
||||||
|
|
@ -429,18 +450,19 @@ msgstr "ko oioa haino ia iapa ia koka ia '-' ia '_' ia '.'."
|
||||||
#: moku/validators.py:30
|
#: moku/validators.py:30
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Username must be between %(min_length)d and %(max_length)d characters."
|
msgid "Username must be between %(min_length)d and %(max_length)d characters."
|
||||||
msgstr "ko homa nao na kino %(min_length)d. ko oioi nao na kino %(max_length)d."
|
msgstr ""
|
||||||
|
"ko homa nao na kino %(min_length)d. ko oioi nao na kino %(max_length)d."
|
||||||
|
|
||||||
#: moku/views/auth.py:28
|
#: moku/views/auth.py:28
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "welcome back, %(username)s!"
|
msgid "welcome back, %(username)s!"
|
||||||
msgstr "ka maio li kai %(username)s sa mai!"
|
msgstr "ka maio li kai %(username)s sa mai!"
|
||||||
|
|
||||||
#: moku/views/post.py:33
|
#: moku/views/post.py:28
|
||||||
msgid "you can't add someone else's recipe to your post!"
|
msgid "you can't add someone else's recipe to your post!"
|
||||||
msgstr "ko lisa sai io iapa ia haiki na haino oiki mo kai!"
|
msgstr "ko lisa sai io iapa ia haiki na haino oiki mo kai!"
|
||||||
|
|
||||||
#: moku/views/post.py:40
|
#: moku/views/post.py:35
|
||||||
msgid "your post was made!"
|
msgid "your post was made!"
|
||||||
msgstr "ka haika ni iapa sa hali!"
|
msgstr "ka haika ni iapa sa hali!"
|
||||||
|
|
||||||
|
|
@ -480,30 +502,29 @@ msgstr "ko poli sai io iaoa li haiki hina ni sia sioa sa laka."
|
||||||
msgid "step added successfully!"
|
msgid "step added successfully!"
|
||||||
msgstr "ka iaio ni sia haiki sa hali!"
|
msgstr "ka iaio ni sia haiki sa hali!"
|
||||||
|
|
||||||
#: moku/views/static.py:10
|
#: moku/views/user.py:27
|
||||||
msgid "changelog"
|
|
||||||
msgstr "pali oiki"
|
|
||||||
|
|
||||||
#: moku/views/user.py:20
|
|
||||||
msgid "edit profile"
|
msgid "edit profile"
|
||||||
msgstr "oiki na pali haino"
|
msgstr "oiki na pali haino"
|
||||||
|
|
||||||
#: moku/views/user.py:26
|
#: moku/views/user.py:33
|
||||||
msgid "profile updated successfully!"
|
msgid "profile updated successfully!"
|
||||||
msgstr "ka sioa ni pali haino sa hali!"
|
msgstr "ka sioa ni pali haino sa hali!"
|
||||||
|
|
||||||
#: moku/views/user.py:46
|
#: moku/views/user.py:53
|
||||||
msgid "uh oh. i think something went a little bit oopsie."
|
msgid "uh oh. i think something went a little bit oopsie."
|
||||||
msgstr "haia. ko kaki lo mia mo mia sa laka nai."
|
msgstr "haia. ko kaki lo mia mo mia sa laka nai."
|
||||||
|
|
||||||
#: moku/views/user.py:49
|
#: moku/views/user.py:56
|
||||||
msgid "settings updated!"
|
msgid "settings updated!"
|
||||||
msgstr "ka sioa ni maoa kai sa hali!"
|
msgstr "ka sioa ni maoa kai sa hali!"
|
||||||
|
|
||||||
#: moku/views/user.py:94
|
#: moku/views/user.py:101
|
||||||
msgid "sorry! someone else got to that username first."
|
msgid "sorry! someone else got to that username first."
|
||||||
msgstr "ko kami ni oioa hina mo haino oiki sa laka."
|
msgstr "ko kami ni oioa hina mo haino oiki sa laka."
|
||||||
|
|
||||||
#: moku/views/user.py:98
|
#: moku/views/user.py:105
|
||||||
msgid "that's it! just log in, and you're ready to go."
|
msgid "that's it! just log in, and you're ready to go."
|
||||||
msgstr "poi! si iapa ni oioa ni oioa pamo li io oima ni lia kai ha."
|
msgstr "poi! si iapa ni oioa ni oioa pamo li io oima ni lia kai ha."
|
||||||
|
|
||||||
|
#~ msgid "changelog"
|
||||||
|
#~ msgstr "pali oiki"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: 0.1.0\n"
|
"Project-Id-Version: 0.1.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-03-26 18:45+0000\n"
|
"POT-Creation-Date: 2024-03-27 12:13+0000\n"
|
||||||
"PO-Revision-Date: 2024-03-26 18:28+0000\n"
|
"PO-Revision-Date: 2024-03-26 18:28+0000\n"
|
||||||
"Last-Translator: m5ka <m5ka@posteo.de>\n"
|
"Last-Translator: m5ka <m5ka@posteo.de>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -15,11 +15,11 @@ msgstr ""
|
||||||
msgid "english"
|
msgid "english"
|
||||||
msgstr "toki inli"
|
msgstr "toki inli"
|
||||||
|
|
||||||
#: moku/config/settings.py:144
|
#: moku/config/settings.py:143
|
||||||
msgid "lami lioa"
|
msgid "lami lioa"
|
||||||
msgstr "toki liwa"
|
msgstr "toki liwa"
|
||||||
|
|
||||||
#: moku/config/settings.py:145
|
#: moku/config/settings.py:143
|
||||||
msgid "toki pona"
|
msgid "toki pona"
|
||||||
msgstr "toki pona"
|
msgstr "toki pona"
|
||||||
|
|
||||||
|
|
@ -154,6 +154,22 @@ msgstr "ma"
|
||||||
msgid "about me"
|
msgid "about me"
|
||||||
msgstr "mi sama ni"
|
msgstr "mi sama ni"
|
||||||
|
|
||||||
|
#: moku/models/blog.py:9
|
||||||
|
msgid "title"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: moku/models/blog.py:11
|
||||||
|
msgid "the title of the blog post."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: moku/models/blog.py:14
|
||||||
|
msgid "content"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: moku/models/blog.py:15
|
||||||
|
msgid "the content of the blog post. markdown is allowed here."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: moku/models/post.py:37 moku/models/recipe.py:24
|
#: moku/models/post.py:37 moku/models/recipe.py:24
|
||||||
msgid "unique id"
|
msgid "unique id"
|
||||||
msgstr "nimi wan"
|
msgstr "nimi wan"
|
||||||
|
|
@ -290,23 +306,24 @@ msgstr "weka"
|
||||||
msgid "log in"
|
msgid "log in"
|
||||||
msgstr "insa"
|
msgstr "insa"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:37 moku/views/user.py:86
|
#: moku/templates/moku/base.jinja:37 moku/views/user.py:93
|
||||||
msgid "sign up"
|
msgid "sign up"
|
||||||
msgstr "pali e lipu jan"
|
msgstr "pali e lipu jan"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:55
|
#: moku/templates/moku/base.jinja:55 moku/templates/moku/blog.jinja:5
|
||||||
|
#: moku/views/blog.py:9
|
||||||
msgid "blog"
|
msgid "blog"
|
||||||
msgstr "lipu ante"
|
msgstr "lipu ante"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:56 moku/views/user.py:38
|
#: moku/templates/moku/base.jinja:56 moku/views/user.py:45
|
||||||
msgid "settings"
|
msgid "settings"
|
||||||
msgstr "ante linluwi"
|
msgstr "ante linluwi"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:57 moku/views/static.py:24
|
#: moku/templates/moku/base.jinja:57 moku/views/static.py:17
|
||||||
msgid "terms of use"
|
msgid "terms of use"
|
||||||
msgstr "lipu kepeken"
|
msgstr "lipu kepeken"
|
||||||
|
|
||||||
#: moku/templates/moku/base.jinja:58 moku/views/static.py:17
|
#: moku/templates/moku/base.jinja:58 moku/views/static.py:10
|
||||||
msgid "privacy policy"
|
msgid "privacy policy"
|
||||||
msgstr "lipu len"
|
msgstr "lipu len"
|
||||||
|
|
||||||
|
|
@ -314,6 +331,10 @@ msgstr "lipu len"
|
||||||
msgid "donate"
|
msgid "donate"
|
||||||
msgstr "pana mani"
|
msgstr "pana mani"
|
||||||
|
|
||||||
|
#: moku/templates/moku/blog.jinja:7
|
||||||
|
msgid "no blog posts yet..."
|
||||||
|
msgstr "sitelen li lon ala..."
|
||||||
|
|
||||||
#: moku/templates/moku/feed.jinja:52
|
#: moku/templates/moku/feed.jinja:52
|
||||||
msgid "post!"
|
msgid "post!"
|
||||||
msgstr "o pali!"
|
msgstr "o pali!"
|
||||||
|
|
@ -446,11 +467,11 @@ msgstr ""
|
||||||
msgid "welcome back, %(username)s!"
|
msgid "welcome back, %(username)s!"
|
||||||
msgstr "jan %(username)s o toki!"
|
msgstr "jan %(username)s o toki!"
|
||||||
|
|
||||||
#: moku/views/post.py:33
|
#: moku/views/post.py:28
|
||||||
msgid "you can't add someone else's recipe to your post!"
|
msgid "you can't add someone else's recipe to your post!"
|
||||||
msgstr "sina ken ala pana e sitelen kepeken nasin pali pi jan ante!"
|
msgstr "sina ken ala pana e sitelen kepeken nasin pali pi jan ante!"
|
||||||
|
|
||||||
#: moku/views/post.py:40
|
#: moku/views/post.py:35
|
||||||
msgid "your post was made!"
|
msgid "your post was made!"
|
||||||
msgstr "sitelen sina li lon!"
|
msgstr "sitelen sina li lon!"
|
||||||
|
|
||||||
|
|
@ -490,30 +511,29 @@ msgstr "nasin pali ni li ken ala kama suli kin."
|
||||||
msgid "step added successfully!"
|
msgid "step added successfully!"
|
||||||
msgstr "kipisi pi nasin pali li lon!"
|
msgstr "kipisi pi nasin pali li lon!"
|
||||||
|
|
||||||
#: moku/views/static.py:10
|
#: moku/views/user.py:27
|
||||||
msgid "changelog"
|
|
||||||
msgstr "lipu ante"
|
|
||||||
|
|
||||||
#: moku/views/user.py:20
|
|
||||||
msgid "edit profile"
|
msgid "edit profile"
|
||||||
msgstr "ante pi lipu jan"
|
msgstr "ante pi lipu jan"
|
||||||
|
|
||||||
#: moku/views/user.py:26
|
#: moku/views/user.py:33
|
||||||
msgid "profile updated successfully!"
|
msgid "profile updated successfully!"
|
||||||
msgstr "lipu jan li ante!"
|
msgstr "lipu jan li ante!"
|
||||||
|
|
||||||
#: moku/views/user.py:46
|
#: moku/views/user.py:53
|
||||||
msgid "uh oh. i think something went a little bit oopsie."
|
msgid "uh oh. i think something went a little bit oopsie."
|
||||||
msgstr "a! ike li kama."
|
msgstr "a! ike li kama."
|
||||||
|
|
||||||
#: moku/views/user.py:49
|
#: moku/views/user.py:56
|
||||||
msgid "settings updated!"
|
msgid "settings updated!"
|
||||||
msgstr "wile sina li ante!"
|
msgstr "wile sina li ante!"
|
||||||
|
|
||||||
#: moku/views/user.py:94
|
#: moku/views/user.py:101
|
||||||
msgid "sorry! someone else got to that username first."
|
msgid "sorry! someone else got to that username first."
|
||||||
msgstr "jan ante li jo e nimi ni."
|
msgstr "jan ante li jo e nimi ni."
|
||||||
|
|
||||||
#: moku/views/user.py:98
|
#: moku/views/user.py:105
|
||||||
msgid "that's it! just log in, and you're ready to go."
|
msgid "that's it! just log in, and you're ready to go."
|
||||||
msgstr "pona a! o sitelen e nimi sin ni la sina ken lon insa."
|
msgstr "pona a! o sitelen e nimi sin ni la sina ken lon insa."
|
||||||
|
|
||||||
|
#~ msgid "changelog"
|
||||||
|
#~ msgstr "lipu ante"
|
||||||
|
|
|
||||||
52
moku/markdown.py
Normal file
52
moku/markdown.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
from django.apps import apps
|
||||||
|
from django.conf import settings
|
||||||
|
from mistune import HTMLRenderer, Markdown
|
||||||
|
from mistune.plugins.formatting import strikethrough, subscript, superscript
|
||||||
|
from mistune.plugins.url import url
|
||||||
|
|
||||||
|
USERNAME_PATTERN = (
|
||||||
|
r"@[a-z0-9-_.]{"
|
||||||
|
+ str(settings.USERNAME_MIN_LENGTH)
|
||||||
|
+ r","
|
||||||
|
+ str(settings.USERNAME_MAX_LENGTH)
|
||||||
|
+ r"}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_username_link(inline, m, state):
|
||||||
|
User = apps.get_model("moku", "User")
|
||||||
|
|
||||||
|
text = m.group(0)
|
||||||
|
pos = m.end()
|
||||||
|
if state.in_link:
|
||||||
|
inline.process_text(text, state)
|
||||||
|
return pos
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = User.objects.get(username=text[1:])
|
||||||
|
except User.DoesNotExist:
|
||||||
|
inline.process_text(text, state)
|
||||||
|
return pos
|
||||||
|
|
||||||
|
state.append_token(
|
||||||
|
{
|
||||||
|
"type": "link",
|
||||||
|
"children": [{"type": "text", "raw": f"@{user.username}"}],
|
||||||
|
"attrs": {"url": user.get_absolute_url()},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return pos
|
||||||
|
|
||||||
|
|
||||||
|
def _username(md):
|
||||||
|
md.inline.register("username", USERNAME_PATTERN, _parse_username_link)
|
||||||
|
|
||||||
|
|
||||||
|
full_markdown = Markdown(
|
||||||
|
renderer=HTMLRenderer(),
|
||||||
|
plugins=[strikethrough, subscript, superscript, url, _username],
|
||||||
|
)
|
||||||
|
|
||||||
|
basic_markdown = Markdown(
|
||||||
|
renderer=HTMLRenderer(), plugins=[strikethrough, subscript, superscript, url]
|
||||||
|
)
|
||||||
26
moku/migrations/0008_blogpost.py
Normal file
26
moku/migrations/0008_blogpost.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Generated by Django 5.0.3 on 2024-03-27 11:35
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('moku', '0007_add_lami_lioa_to_languages'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='BlogPost',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('title', models.CharField(help_text='the title of the blog post.', max_length=128, verbose_name='title')),
|
||||||
|
('text', models.TextField(help_text='the content of the blog post. markdown is allowed here.', verbose_name='content')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('created_by', models.ForeignKey(db_column='created_by_user_id', on_delete=django.db.models.deletion.PROTECT, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
from moku.models.blog import BlogPost
|
||||||
from moku.models.post import Post
|
from moku.models.post import Post
|
||||||
from moku.models.recipe import Recipe, RecipeStep
|
from moku.models.recipe import Recipe, RecipeStep
|
||||||
from moku.models.user import User, UserSettings
|
from moku.models.user import User, UserSettings
|
||||||
|
|
||||||
__all__ = ["Post", "Recipe", "RecipeStep", "User", "UserSettings"]
|
__all__ = ["BlogPost", "Post", "Recipe", "RecipeStep", "User", "UserSettings"]
|
||||||
|
|
|
||||||
30
moku/models/blog.py
Normal file
30
moku/models/blog.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from moku.markdown import full_markdown
|
||||||
|
|
||||||
|
|
||||||
|
class BlogPost(models.Model):
|
||||||
|
title = models.CharField(
|
||||||
|
verbose_name=_("title"),
|
||||||
|
max_length=128,
|
||||||
|
help_text=_("the title of the blog post."),
|
||||||
|
)
|
||||||
|
text = models.TextField(
|
||||||
|
verbose_name=_("content"),
|
||||||
|
help_text=_("the content of the blog post. markdown is allowed here."),
|
||||||
|
)
|
||||||
|
created_by = models.ForeignKey(
|
||||||
|
"User",
|
||||||
|
related_name="+",
|
||||||
|
db_column="created_by_user_id",
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.title
|
||||||
|
|
||||||
|
def as_html(self):
|
||||||
|
return full_markdown(self.text)
|
||||||
|
|
@ -308,6 +308,32 @@ header nav ul {
|
||||||
row-gap: .8rem;
|
row-gap: .8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blog {
|
||||||
|
display: grid;
|
||||||
|
row-gap: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog > h2 {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-post {
|
||||||
|
display: grid;
|
||||||
|
row-gap: .4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-post > h3 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog-post .post-metadata {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: var(--charcoal);
|
||||||
|
margin-block-end: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.grid-content {
|
.grid-content {
|
||||||
display: grid;
|
display: grid;
|
||||||
row-gap: 1.2rem;
|
row-gap: 1.2rem;
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
<footer>
|
<footer>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{{ url('changelog') }}">{% trans %}blog{% endtrans %}</a></li>
|
<li><a href="{{ url('blog.index') }}">{% trans %}blog{% endtrans %}</a></li>
|
||||||
{% if request.user.is_authenticated %}<li><a href="{{ url('settings') }}">{% trans %}settings{% endtrans %}</a></li>{% endif %}
|
{% if request.user.is_authenticated %}<li><a href="{{ url('settings') }}">{% trans %}settings{% endtrans %}</a></li>{% endif %}
|
||||||
<li><a href="{{ url('terms') }}">{% trans %}terms of use{% endtrans %}</a></li>
|
<li><a href="{{ url('terms') }}">{% trans %}terms of use{% endtrans %}</a></li>
|
||||||
<li><a href="{{ url('privacy') }}">{% trans %}privacy policy{% endtrans %}</a></li>
|
<li><a href="{{ url('privacy') }}">{% trans %}privacy policy{% endtrans %}</a></li>
|
||||||
|
|
|
||||||
19
moku/templates/moku/blog.jinja
Normal file
19
moku/templates/moku/blog.jinja
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends "moku/base.jinja" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="content blog">
|
||||||
|
<h2>{% trans %}blog{% endtrans %} 📜</h2>
|
||||||
|
{% if not posts %}
|
||||||
|
<p>{% trans %}no blog posts yet...{% endtrans %} 🥱</p>
|
||||||
|
{% endif %}
|
||||||
|
{% for post in posts %}
|
||||||
|
<article class="blog-post">
|
||||||
|
<h3>{{ post.title }}</h3>
|
||||||
|
<span class="post-metadata">{{ post.created_at|naturaltime }} · <a href="{{ post.created_by.get_absolute_url() }}">@{{ post.created_by.username }}</a></span>
|
||||||
|
<div class="block">
|
||||||
|
{{ post.as_html()|safe }}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
{% extends "moku/base.jinja" %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="content block">
|
|
||||||
<h2>changelog 📜</h2>
|
|
||||||
<h3>2024-03-25</h3>
|
|
||||||
<ul>
|
|
||||||
<li>moku.blog launched! 🎉</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
|
||||||
15
moku/views/blog.py
Normal file
15
moku/views/blog.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
from django.utils.translation import gettext_lazy
|
||||||
|
|
||||||
|
from moku.models.blog import BlogPost
|
||||||
|
from moku.views.base import View
|
||||||
|
|
||||||
|
|
||||||
|
class IndexBlogView(View):
|
||||||
|
template_name = "moku/blog.jinja"
|
||||||
|
page_title = gettext_lazy("blog")
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
return {
|
||||||
|
**super().get_context_data(**kwargs),
|
||||||
|
"posts": BlogPost.objects.order_by("-created_at").all(),
|
||||||
|
}
|
||||||
|
|
@ -3,13 +3,6 @@ from django.utils.translation import gettext_lazy
|
||||||
from moku.views.base import View
|
from moku.views.base import View
|
||||||
|
|
||||||
|
|
||||||
class ChangelogView(View):
|
|
||||||
"""Displays the static changelog page."""
|
|
||||||
|
|
||||||
template_name = "moku/changelog.jinja"
|
|
||||||
page_title = gettext_lazy("changelog")
|
|
||||||
|
|
||||||
|
|
||||||
class PrivacyView(View):
|
class PrivacyView(View):
|
||||||
"""Displays the static privacy policy page."""
|
"""Displays the static privacy policy page."""
|
||||||
|
|
||||||
|
|
|
||||||
21
poetry.lock
generated
21
poetry.lock
generated
|
|
@ -107,13 +107,13 @@ django = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "emoji"
|
name = "emoji"
|
||||||
version = "2.10.1"
|
version = "2.11.0"
|
||||||
description = "Emoji for Python"
|
description = "Emoji for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
||||||
files = [
|
files = [
|
||||||
{file = "emoji-2.10.1-py2.py3-none-any.whl", hash = "sha256:11fb369ea79d20c14efa4362c732d67126df294a7959a2c98bfd7447c12a218e"},
|
{file = "emoji-2.11.0-py2.py3-none-any.whl", hash = "sha256:63fc9107f06c6c2e48e5078ce9575cef98518f5ac09474f6148a43e989989582"},
|
||||||
{file = "emoji-2.10.1.tar.gz", hash = "sha256:16287283518fb7141bde00198f9ffff4e1c1cb570efb68b2f1ec50975c3a581d"},
|
{file = "emoji-2.11.0.tar.gz", hash = "sha256:772eaa30f4e0b1ce95148a092df4c7dc97644532c03225326b0fd05e8a9f72a3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
|
|
@ -236,6 +236,17 @@ files = [
|
||||||
{file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
|
{file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mistune"
|
||||||
|
version = "3.0.2"
|
||||||
|
description = "A sane and fast Markdown parser with useful plugins and renderers"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"},
|
||||||
|
{file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
version = "24.0"
|
version = "24.0"
|
||||||
|
|
@ -474,4 +485,4 @@ files = [
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.12"
|
python-versions = "^3.12"
|
||||||
content-hash = "a2d30838ebf562b336e3c1b80401aadbfd231979f3619645d94a45484bc04f40"
|
content-hash = "e759f693fe3fafe547634271da1f0ba2c3de523581edd40dd78299cf7fb97c00"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ django-jinja = "^2.11.0"
|
||||||
django-recaptcha = "^4.0.0"
|
django-recaptcha = "^4.0.0"
|
||||||
emoji = "^2.10.1"
|
emoji = "^2.10.1"
|
||||||
gunicorn = "^21.2.0"
|
gunicorn = "^21.2.0"
|
||||||
|
mistune = "^3.0.2"
|
||||||
pillow = "^10.2.0"
|
pillow = "^10.2.0"
|
||||||
psycopg2 = "^2.9.9"
|
psycopg2 = "^2.9.9"
|
||||||
python = "^3.12"
|
python = "^3.12"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue