style: 🎨 make code ruff compliant
This commit is contained in:
parent
11ed6bd2a1
commit
a4f8275383
21 changed files with 819 additions and 238 deletions
|
|
@ -3,7 +3,6 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
|||
|
||||
from moku import models
|
||||
|
||||
|
||||
for model_name in models.__all__:
|
||||
model = getattr(models, model_name)
|
||||
if model.__name__ != "User":
|
||||
|
|
@ -14,32 +13,11 @@ for model_name in models.__all__:
|
|||
class UserAdmin(BaseUserAdmin):
|
||||
fieldsets = (
|
||||
(None, {"fields": ("username", "email", "password")}),
|
||||
(
|
||||
"Profile",
|
||||
{
|
||||
"fields": (
|
||||
"pronouns", "location", "bio"
|
||||
),
|
||||
},
|
||||
),
|
||||
(
|
||||
"Status",
|
||||
{
|
||||
"fields": (
|
||||
"email_confirmed_at",
|
||||
)
|
||||
},
|
||||
),
|
||||
("Profile", {"fields": ("pronouns", "location", "bio")}),
|
||||
("Status", {"fields": ("email_confirmed_at",)}),
|
||||
(
|
||||
"Permissions",
|
||||
{
|
||||
"fields": (
|
||||
"is_staff",
|
||||
"is_superuser",
|
||||
"groups",
|
||||
"user_permissions",
|
||||
),
|
||||
},
|
||||
{"fields": ("is_staff", "is_superuser", "groups", "user_permissions")},
|
||||
),
|
||||
("Dates", {"fields": ("date_joined", "last_seen_at",)}),
|
||||
("Dates", {"fields": ("date_joined", "last_seen_at")}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import environ
|
||||
|
|
@ -71,9 +70,7 @@ TEMPLATES = [
|
|||
"django.template.context_processors.tz",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
"filters": {
|
||||
"unemoji": "moku.filters.unemoji",
|
||||
},
|
||||
"filters": {"unemoji": "moku.filters.unemoji"},
|
||||
"policies": {"ext.i18n.trimmed": True},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ Including another URLconf
|
|||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
from django.contrib import admin
|
||||
|
|
@ -50,7 +51,11 @@ urlpatterns = [
|
|||
path("recipes/<str:uuid>", ShowRecipeView.as_view(), name="recipe.show"),
|
||||
path("recipes/<str:uuid>/delete", DeleteRecipeView.as_view(), name="recipe.delete"),
|
||||
path("recipes/<str:uuid>/<str:step>", EditStepView.as_view(), name="step.edit"),
|
||||
path("recipes/<str:uuid>/<str:step>/delete", DeleteStepView.as_view(), name="step.delete"),
|
||||
path(
|
||||
"recipes/<str:uuid>/<str:step>/delete",
|
||||
DeleteStepView.as_view(),
|
||||
name="step.delete",
|
||||
),
|
||||
]
|
||||
|
||||
if settings.DEBUG_TOOLBAR:
|
||||
|
|
|
|||
|
|
@ -22,53 +22,228 @@ EMOJI_CATEGORIES = [
|
|||
(
|
||||
_("fruit & veg"),
|
||||
(
|
||||
"🍏", "🍎", "🍐", "🍊", "🍋", "🍌", "🍉", "🍇", "🍓", "🫐", "🍈", "🍒", "🍑", "🥭", "🍍",
|
||||
"🥥", "🥝", "🍅", "🍆", "🥑", "🫛", "🥦", "🥬", "🥒", "🌶️", "🫑", "🌽", "🥕", "🫒", "🧄",
|
||||
"🧅", "🥔", "🍠", "🫚",
|
||||
"🍏",
|
||||
"🍎",
|
||||
"🍐",
|
||||
"🍊",
|
||||
"🍋",
|
||||
"🍌",
|
||||
"🍉",
|
||||
"🍇",
|
||||
"🍓",
|
||||
"🫐",
|
||||
"🍈",
|
||||
"🍒",
|
||||
"🍑",
|
||||
"🥭",
|
||||
"🍍",
|
||||
"🥥",
|
||||
"🥝",
|
||||
"🍅",
|
||||
"🍆",
|
||||
"🥑",
|
||||
"🫛",
|
||||
"🥦",
|
||||
"🥬",
|
||||
"🥒",
|
||||
"🌶️",
|
||||
"🫑",
|
||||
"🌽",
|
||||
"🥕",
|
||||
"🫒",
|
||||
"🧄",
|
||||
"🧅",
|
||||
"🥔",
|
||||
"🍠",
|
||||
"🫚",
|
||||
),
|
||||
),
|
||||
(
|
||||
_("savoury dishes"),
|
||||
(
|
||||
"🥯", "🍞", "🥖", "🥨", "🧀", "🥚", "🍳", "🧈", "🥞", "🧇", "🥓", "🥩", "🍗", "🍖", "🦴",
|
||||
"🌭", "🍔", "🍟", "🍕", "🫓", "🥪", "🥙", "🧆", "🌮", "🌯", "🫔", "🥗", "🥘", "🫕", "🥫",
|
||||
"🫙", "🍝", "🍜", "🍲", "🍛", "🍣", "🍱", "🥟", "🦪", "🍤", "🍙", "🍚", "🍘", "🍥", "🌰",
|
||||
"🥜", "🫘", "🧊",
|
||||
"🥯",
|
||||
"🍞",
|
||||
"🥖",
|
||||
"🥨",
|
||||
"🧀",
|
||||
"🥚",
|
||||
"🍳",
|
||||
"🧈",
|
||||
"🥞",
|
||||
"🧇",
|
||||
"🥓",
|
||||
"🥩",
|
||||
"🍗",
|
||||
"🍖",
|
||||
"🦴",
|
||||
"🌭",
|
||||
"🍔",
|
||||
"🍟",
|
||||
"🍕",
|
||||
"🫓",
|
||||
"🥪",
|
||||
"🥙",
|
||||
"🧆",
|
||||
"🌮",
|
||||
"🌯",
|
||||
"🫔",
|
||||
"🥗",
|
||||
"🥘",
|
||||
"🫕",
|
||||
"🥫",
|
||||
"🫙",
|
||||
"🍝",
|
||||
"🍜",
|
||||
"🍲",
|
||||
"🍛",
|
||||
"🍣",
|
||||
"🍱",
|
||||
"🥟",
|
||||
"🦪",
|
||||
"🍤",
|
||||
"🍙",
|
||||
"🍚",
|
||||
"🍘",
|
||||
"🍥",
|
||||
"🌰",
|
||||
"🥜",
|
||||
"🫘",
|
||||
"🧊",
|
||||
),
|
||||
),
|
||||
(
|
||||
_("sweet treats"),
|
||||
(
|
||||
"🥠", "🥮", "🍢", "🍡", "🍧", "🍨", "🍦", "🥧", "🧁", "🍰", "🎂", "🍮", "🍭", "🍬", "🍫",
|
||||
"🥐", "🍿", "🍩", "🍪", "🍯",
|
||||
"🥠",
|
||||
"🥮",
|
||||
"🍢",
|
||||
"🍡",
|
||||
"🍧",
|
||||
"🍨",
|
||||
"🍦",
|
||||
"🥧",
|
||||
"🧁",
|
||||
"🍰",
|
||||
"🎂",
|
||||
"🍮",
|
||||
"🍭",
|
||||
"🍬",
|
||||
"🍫",
|
||||
"🥐",
|
||||
"🍿",
|
||||
"🍩",
|
||||
"🍪",
|
||||
"🍯",
|
||||
),
|
||||
),
|
||||
(
|
||||
_("drinks"),
|
||||
(
|
||||
"🥛", "🫗", "🍼", "🫖", "☕️", "🍵", "🧃", "🥤", "🧋", "🍶", "🍺", "🍻", "🥂", "🍷", "🥃",
|
||||
"🍸", "🍹", "🧉", "🍾",
|
||||
"🥛",
|
||||
"🫗",
|
||||
"🍼",
|
||||
"🫖",
|
||||
"☕️",
|
||||
"🍵",
|
||||
"🧃",
|
||||
"🥤",
|
||||
"🧋",
|
||||
"🍶",
|
||||
"🍺",
|
||||
"🍻",
|
||||
"🥂",
|
||||
"🍷",
|
||||
"🥃",
|
||||
"🍸",
|
||||
"🍹",
|
||||
"🧉",
|
||||
"🍾",
|
||||
),
|
||||
),
|
||||
(
|
||||
_("people"),
|
||||
(
|
||||
"😀", "😃", "😄", "😁", "😆", "🥹", "😅", "😂", "🤣", "🥲", "😊", "😇", "🙂", "🙃", "😉",
|
||||
"😌", "😌", "😍", "🥰", "😘", "😗", "😙", "😚", "😋", "😛", "😝", "😜", "🤪", "🤨", "🧐",
|
||||
"😀",
|
||||
"😃",
|
||||
"😄",
|
||||
"😁",
|
||||
"😆",
|
||||
"🥹",
|
||||
"😅",
|
||||
"😂",
|
||||
"🤣",
|
||||
"🥲",
|
||||
"😊",
|
||||
"😇",
|
||||
"🙂",
|
||||
"🙃",
|
||||
"😉",
|
||||
"😌",
|
||||
"😌",
|
||||
"😍",
|
||||
"🥰",
|
||||
"😘",
|
||||
"😗",
|
||||
"😙",
|
||||
"😚",
|
||||
"😋",
|
||||
"😛",
|
||||
"😝",
|
||||
"😜",
|
||||
"🤪",
|
||||
"🤨",
|
||||
"🧐",
|
||||
),
|
||||
),
|
||||
(
|
||||
_("animals"),
|
||||
(
|
||||
"🐶", "🐱", "🐭", "🐹", "🐰", "🦊", "🐻", "🐼", "🐨", "🐯", "🦁", "🐮", "🐷", "🐽", "🐸",
|
||||
"🐵", "🙈", "🙉", "🙊", "🐒", "🐔", "🐧", "🐦", "🐤", "🐣", "🐥", "🪿", "🦆", "🐦⬛", "🦅",
|
||||
"🦉", "🦇", "🐺", "🐗", "🐴", "🦄", "🫎", "🐝", "🪱", "🐛", "🦋", "🐌", "🐞", "🐜", "🪰",
|
||||
"🐶",
|
||||
"🐱",
|
||||
"🐭",
|
||||
"🐹",
|
||||
"🐰",
|
||||
"🦊",
|
||||
"🐻",
|
||||
"🐼",
|
||||
"🐨",
|
||||
"🐯",
|
||||
"🦁",
|
||||
"🐮",
|
||||
"🐷",
|
||||
"🐽",
|
||||
"🐸",
|
||||
"🐵",
|
||||
"🙈",
|
||||
"🙉",
|
||||
"🙊",
|
||||
"🐒",
|
||||
"🐔",
|
||||
"🐧",
|
||||
"🐦",
|
||||
"🐤",
|
||||
"🐣",
|
||||
"🐥",
|
||||
"🪿",
|
||||
"🦆",
|
||||
"🐦⬛",
|
||||
"🦅",
|
||||
"🦉",
|
||||
"🦇",
|
||||
"🐺",
|
||||
"🐗",
|
||||
"🐴",
|
||||
"🦄",
|
||||
"🫎",
|
||||
"🐝",
|
||||
"🪱",
|
||||
"🐛",
|
||||
"🦋",
|
||||
"🐌",
|
||||
"🐞",
|
||||
"🐜",
|
||||
"🪰",
|
||||
),
|
||||
),
|
||||
(
|
||||
_("tools & things"),
|
||||
(
|
||||
"🥄", "🍴", "🍽️", "🥣", "🥡", "🥢", "🧂", "🔪", "🪓",
|
||||
)
|
||||
)
|
||||
(_("tools & things"), ("🥄", "🍴", "🍽️", "🥣", "🥡", "🥢", "🧂", "🔪", "🪓")),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from django.forms import Form, ModelForm
|
||||
from django.forms import ModelForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from moku.models.recipe import Recipe, RecipeStep
|
||||
|
|
@ -8,9 +8,7 @@ class RecipeForm(ModelForm):
|
|||
class Meta:
|
||||
model = Recipe
|
||||
fields = ("title",)
|
||||
labels = {
|
||||
"title": _("recipe title"),
|
||||
}
|
||||
labels = {"title": _("recipe title")}
|
||||
|
||||
|
||||
class RecipeStepForm(ModelForm):
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from django import forms
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from django_recaptcha.fields import ReCaptchaField
|
||||
|
||||
from moku.models.user import User, UserSettings
|
||||
|
|
@ -14,10 +13,7 @@ class UserForm(UserCreationForm):
|
|||
class Meta(UserCreationForm.Meta):
|
||||
model = User
|
||||
fields = ("username", "email", "password1", "password2")
|
||||
labels = {
|
||||
"username": _("username"),
|
||||
"email": _("email address"),
|
||||
}
|
||||
labels = {"username": _("username"), "email": _("email address")}
|
||||
help_texts = {
|
||||
"username": User._meta.get_field("username").help_text,
|
||||
"email": User._meta.get_field("email").help_text,
|
||||
|
|
@ -26,10 +22,10 @@ class UserForm(UserCreationForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["captcha"].error_messages = {
|
||||
"required": _("make sure you've ticked the captcha."),
|
||||
"required": _("make sure you've ticked the captcha.")
|
||||
}
|
||||
self.fields["check"].error_messages = {
|
||||
"required": _("you must agree to the terms of use and privacy policy."),
|
||||
"required": _("you must agree to the terms of use and privacy policy.")
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -37,9 +33,7 @@ class UserSettingsForm(forms.ModelForm):
|
|||
class Meta:
|
||||
model = UserSettings
|
||||
fields = ("language",)
|
||||
labels = {
|
||||
"language": _("language"),
|
||||
}
|
||||
labels = {"language": _("language")}
|
||||
|
||||
|
||||
class ProfileForm(forms.ModelForm):
|
||||
|
|
|
|||
|
|
@ -1,49 +1,162 @@
|
|||
# ruff: noqa: E501
|
||||
# Generated by Django 5.0.3 on 2024-03-24 17:24
|
||||
|
||||
import re
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.core.validators
|
||||
import django.utils.timezone
|
||||
import moku.validators
|
||||
import re
|
||||
from django.db import migrations, models
|
||||
|
||||
import moku.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
dependencies = [("auth", "0012_alter_user_first_name_max_length")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='User',
|
||||
name="User",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('username', models.CharField(db_index=True, help_text="this is the unique identifier you'll use to log in. it may only contain letters, numbers, hyphens, dashes and dots.", max_length=64, unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[a-zA-Z0-9-_.]+\\Z'), 'Username may only contain letters, numbers, hyphens, underscores and dots.', 'invalid'), moku.validators.validate_username_length], verbose_name='username')),
|
||||
('email', models.EmailField(help_text="this should be your email address. make sure it's valid and that you have access to it.", max_length=128, unique=True, verbose_name='email address')),
|
||||
('email_confirmed_at', models.DateTimeField(blank=True, null=True)),
|
||||
('pronouns', models.CharField(blank=True, help_text='what pronouns should people use when referring to you?', max_length=64, verbose_name='pronouns')),
|
||||
('location', models.CharField(blank=True, help_text='where in the world are you?', max_length=64, verbose_name='location')),
|
||||
('bio', models.TextField(blank=True, help_text='write something about yourself!', verbose_name='about me')),
|
||||
('last_seen_at', models.DateTimeField(blank=True, help_text='the last time this user accessed the site.', null=True, verbose_name='last seen at')),
|
||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
|
||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||
(
|
||||
"last_login",
|
||||
models.DateTimeField(
|
||||
blank=True, null=True, verbose_name="last login"
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_superuser",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates that this user has all permissions without explicitly assigning them.",
|
||||
verbose_name="superuser status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_staff",
|
||||
models.BooleanField(
|
||||
default=False,
|
||||
help_text="Designates whether the user can log into this admin site.",
|
||||
verbose_name="staff status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"is_active",
|
||||
models.BooleanField(
|
||||
default=True,
|
||||
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
|
||||
verbose_name="active",
|
||||
),
|
||||
),
|
||||
(
|
||||
"date_joined",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now, verbose_name="date joined"
|
||||
),
|
||||
),
|
||||
(
|
||||
"username",
|
||||
models.CharField(
|
||||
db_index=True,
|
||||
help_text="this is the unique identifier you'll use to log in. it may only contain letters, numbers, hyphens, dashes and dots.",
|
||||
max_length=64,
|
||||
unique=True,
|
||||
validators=[
|
||||
django.core.validators.RegexValidator(
|
||||
re.compile("^[a-zA-Z0-9-_.]+\\Z"),
|
||||
"Username may only contain letters, numbers, hyphens, underscores and dots.",
|
||||
"invalid",
|
||||
),
|
||||
moku.validators.validate_username_length,
|
||||
],
|
||||
verbose_name="username",
|
||||
),
|
||||
),
|
||||
(
|
||||
"email",
|
||||
models.EmailField(
|
||||
help_text="this should be your email address. make sure it's valid and that you have access to it.",
|
||||
max_length=128,
|
||||
unique=True,
|
||||
verbose_name="email address",
|
||||
),
|
||||
),
|
||||
("email_confirmed_at", models.DateTimeField(blank=True, null=True)),
|
||||
(
|
||||
"pronouns",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="what pronouns should people use when referring to you?",
|
||||
max_length=64,
|
||||
verbose_name="pronouns",
|
||||
),
|
||||
),
|
||||
(
|
||||
"location",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
help_text="where in the world are you?",
|
||||
max_length=64,
|
||||
verbose_name="location",
|
||||
),
|
||||
),
|
||||
(
|
||||
"bio",
|
||||
models.TextField(
|
||||
blank=True,
|
||||
help_text="write something about yourself!",
|
||||
verbose_name="about me",
|
||||
),
|
||||
),
|
||||
(
|
||||
"last_seen_at",
|
||||
models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="the last time this user accessed the site.",
|
||||
null=True,
|
||||
verbose_name="last seen at",
|
||||
),
|
||||
),
|
||||
(
|
||||
"groups",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.group",
|
||||
verbose_name="groups",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user_permissions",
|
||||
models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Specific permissions for this user.",
|
||||
related_name="user_set",
|
||||
related_query_name="user",
|
||||
to="auth.permission",
|
||||
verbose_name="user permissions",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'user',
|
||||
'verbose_name_plural': 'users',
|
||||
'abstract': False,
|
||||
"verbose_name": "user",
|
||||
"verbose_name_plural": "users",
|
||||
"abstract": False,
|
||||
},
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.UserManager()),
|
||||
],
|
||||
),
|
||||
managers=[("objects", django.contrib.auth.models.UserManager())],
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,32 +1,104 @@
|
|||
# ruff: noqa: E501
|
||||
# Generated by Django 5.0.3 on 2024-03-25 10:04
|
||||
|
||||
import django.db.models.deletion
|
||||
import moku.models.post
|
||||
import moku.validators
|
||||
import shortuuid.django_fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import moku.models.post
|
||||
import moku.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('moku', '0001_initial'),
|
||||
]
|
||||
dependencies = [("moku", "0001_initial")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Post',
|
||||
name="Post",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('uuid', shortuuid.django_fields.ShortUUIDField(alphabet=None, help_text='the unique id that identifies this post.', length=22, max_length=22, prefix='', verbose_name='unique id')),
|
||||
('emoji', models.CharField(help_text='an emoji to accompany your post!', max_length=8, validators=[moku.validators.validate_emoji], verbose_name='emoji')),
|
||||
('verb', models.CharField(choices=[('ate', '%(user)s ate %(food)s'), ('made', '%(user)s made %(food)s'), ('cooked', '%(user)s cooked %(food)s'), ('baked', '%(user)s baked %(food)s'), ('ordered', '%(user)s ordered %(food)s')], help_text='how should we best phrase this entry?', max_length=32, verbose_name='verb')),
|
||||
('food', models.CharField(help_text='what did you eat?', max_length=128, verbose_name='food')),
|
||||
('image', models.ImageField(blank=True, help_text='here you can upload a picture of what you ate!', upload_to=moku.models.post.post_image_filename, verbose_name='image')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='when this post was created.')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, help_text='when this post was last updated.')),
|
||||
('created_by', models.ForeignKey(db_column='created_by_user_id', on_delete=django.db.models.deletion.CASCADE, related_name='posts', to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"uuid",
|
||||
shortuuid.django_fields.ShortUUIDField(
|
||||
alphabet=None,
|
||||
help_text="the unique id that identifies this post.",
|
||||
length=22,
|
||||
max_length=22,
|
||||
prefix="",
|
||||
verbose_name="unique id",
|
||||
),
|
||||
),
|
||||
(
|
||||
"emoji",
|
||||
models.CharField(
|
||||
help_text="an emoji to accompany your post!",
|
||||
max_length=8,
|
||||
validators=[moku.validators.validate_emoji],
|
||||
verbose_name="emoji",
|
||||
),
|
||||
),
|
||||
(
|
||||
"verb",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("ate", "%(user)s ate %(food)s"),
|
||||
("made", "%(user)s made %(food)s"),
|
||||
("cooked", "%(user)s cooked %(food)s"),
|
||||
("baked", "%(user)s baked %(food)s"),
|
||||
("ordered", "%(user)s ordered %(food)s"),
|
||||
],
|
||||
help_text="how should we best phrase this entry?",
|
||||
max_length=32,
|
||||
verbose_name="verb",
|
||||
),
|
||||
),
|
||||
(
|
||||
"food",
|
||||
models.CharField(
|
||||
help_text="what did you eat?",
|
||||
max_length=128,
|
||||
verbose_name="food",
|
||||
),
|
||||
),
|
||||
(
|
||||
"image",
|
||||
models.ImageField(
|
||||
blank=True,
|
||||
help_text="here you can upload a picture of what you ate!",
|
||||
upload_to=moku.models.post.post_image_filename,
|
||||
verbose_name="image",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_at",
|
||||
models.DateTimeField(
|
||||
auto_now_add=True, help_text="when this post was created."
|
||||
),
|
||||
),
|
||||
(
|
||||
"updated_at",
|
||||
models.DateTimeField(
|
||||
auto_now=True, help_text="when this post was last updated."
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
db_column="created_by_user_id",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="posts",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,19 +1,23 @@
|
|||
# ruff: noqa: E501
|
||||
# Generated by Django 5.0.3 on 2024-03-25 13:49
|
||||
|
||||
import moku.models.user
|
||||
from django.db import migrations, models
|
||||
|
||||
import moku.models.user
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('moku', '0002_post'),
|
||||
]
|
||||
dependencies = [("moku", "0002_post")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='avatar',
|
||||
field=models.ImageField(blank=True, help_text='a little picture to show up on your profile.', upload_to=moku.models.user.user_avatar_filename, verbose_name='avatar'),
|
||||
),
|
||||
model_name="user",
|
||||
name="avatar",
|
||||
field=models.ImageField(
|
||||
blank=True,
|
||||
help_text="a little picture to show up on your profile.",
|
||||
upload_to=moku.models.user.user_avatar_filename,
|
||||
verbose_name="avatar",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
# ruff: noqa: E501
|
||||
# Generated by Django 5.0.3 on 2024-03-25 15:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('moku', '0003_user_avatar'),
|
||||
]
|
||||
dependencies = [("moku", "0003_user_avatar")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='post',
|
||||
name='verb',
|
||||
field=models.CharField(choices=[('ate', '%(user)s ate %(food)s'), ('drank', '%(user)s drank %(food)s'), ('made', '%(user)s made %(food)s'), ('cooked', '%(user)s cooked %(food)s'), ('baked', '%(user)s baked %(food)s'), ('ordered', '%(user)s ordered %(food)s')], help_text='how should we best phrase this entry?', max_length=32, verbose_name='verb'),
|
||||
),
|
||||
model_name="post",
|
||||
name="verb",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("ate", "%(user)s ate %(food)s"),
|
||||
("drank", "%(user)s drank %(food)s"),
|
||||
("made", "%(user)s made %(food)s"),
|
||||
("cooked", "%(user)s cooked %(food)s"),
|
||||
("baked", "%(user)s baked %(food)s"),
|
||||
("ordered", "%(user)s ordered %(food)s"),
|
||||
],
|
||||
help_text="how should we best phrase this entry?",
|
||||
max_length=32,
|
||||
verbose_name="verb",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# ruff: noqa: E501
|
||||
# Generated by Django 5.0.3 on 2024-03-25 17:02
|
||||
|
||||
import django.db.models.deletion
|
||||
|
|
@ -6,18 +7,139 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('moku', '0004_alter_post_verb'),
|
||||
]
|
||||
dependencies = [("moku", "0004_alter_post_verb")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserSettings',
|
||||
name="UserSettings",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('language', models.CharField(choices=[('af', 'Afrikaans'), ('ar', 'Arabic'), ('ar-dz', 'Algerian Arabic'), ('ast', 'Asturian'), ('az', 'Azerbaijani'), ('bg', 'Bulgarian'), ('be', 'Belarusian'), ('bn', 'Bengali'), ('br', 'Breton'), ('bs', 'Bosnian'), ('ca', 'Catalan'), ('ckb', 'Central Kurdish (Sorani)'), ('cs', 'Czech'), ('cy', 'Welsh'), ('da', 'Danish'), ('de', 'German'), ('dsb', 'Lower Sorbian'), ('el', 'Greek'), ('en', 'English'), ('en-au', 'Australian English'), ('en-gb', 'British English'), ('eo', 'Esperanto'), ('es', 'Spanish'), ('es-ar', 'Argentinian Spanish'), ('es-co', 'Colombian Spanish'), ('es-mx', 'Mexican Spanish'), ('es-ni', 'Nicaraguan Spanish'), ('es-ve', 'Venezuelan Spanish'), ('et', 'Estonian'), ('eu', 'Basque'), ('fa', 'Persian'), ('fi', 'Finnish'), ('fr', 'French'), ('fy', 'Frisian'), ('ga', 'Irish'), ('gd', 'Scottish Gaelic'), ('gl', 'Galician'), ('he', 'Hebrew'), ('hi', 'Hindi'), ('hr', 'Croatian'), ('hsb', 'Upper Sorbian'), ('hu', 'Hungarian'), ('hy', 'Armenian'), ('ia', 'Interlingua'), ('id', 'Indonesian'), ('ig', 'Igbo'), ('io', 'Ido'), ('is', 'Icelandic'), ('it', 'Italian'), ('ja', 'Japanese'), ('ka', 'Georgian'), ('kab', 'Kabyle'), ('kk', 'Kazakh'), ('km', 'Khmer'), ('kn', 'Kannada'), ('ko', 'Korean'), ('ky', 'Kyrgyz'), ('lb', 'Luxembourgish'), ('lt', 'Lithuanian'), ('lv', 'Latvian'), ('mk', 'Macedonian'), ('ml', 'Malayalam'), ('mn', 'Mongolian'), ('mr', 'Marathi'), ('ms', 'Malay'), ('my', 'Burmese'), ('nb', 'Norwegian Bokmål'), ('ne', 'Nepali'), ('nl', 'Dutch'), ('nn', 'Norwegian Nynorsk'), ('os', 'Ossetic'), ('pa', 'Punjabi'), ('pl', 'Polish'), ('pt', 'Portuguese'), ('pt-br', 'Brazilian Portuguese'), ('ro', 'Romanian'), ('ru', 'Russian'), ('sk', 'Slovak'), ('sl', 'Slovenian'), ('sq', 'Albanian'), ('sr', 'Serbian'), ('sr-latn', 'Serbian Latin'), ('sv', 'Swedish'), ('sw', 'Swahili'), ('ta', 'Tamil'), ('te', 'Telugu'), ('tg', 'Tajik'), ('th', 'Thai'), ('tk', 'Turkmen'), ('tr', 'Turkish'), ('tt', 'Tatar'), ('udm', 'Udmurt'), ('ug', 'Uyghur'), ('uk', 'Ukrainian'), ('ur', 'Urdu'), ('uz', 'Uzbek'), ('vi', 'Vietnamese'), ('zh-hans', 'Simplified Chinese'), ('zh-hant', 'Traditional Chinese')], default='en', help_text='what language do you want to use moku.blog in?', max_length=16, verbose_name='language')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='settings', to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"language",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("af", "Afrikaans"),
|
||||
("ar", "Arabic"),
|
||||
("ar-dz", "Algerian Arabic"),
|
||||
("ast", "Asturian"),
|
||||
("az", "Azerbaijani"),
|
||||
("bg", "Bulgarian"),
|
||||
("be", "Belarusian"),
|
||||
("bn", "Bengali"),
|
||||
("br", "Breton"),
|
||||
("bs", "Bosnian"),
|
||||
("ca", "Catalan"),
|
||||
("ckb", "Central Kurdish (Sorani)"),
|
||||
("cs", "Czech"),
|
||||
("cy", "Welsh"),
|
||||
("da", "Danish"),
|
||||
("de", "German"),
|
||||
("dsb", "Lower Sorbian"),
|
||||
("el", "Greek"),
|
||||
("en", "English"),
|
||||
("en-au", "Australian English"),
|
||||
("en-gb", "British English"),
|
||||
("eo", "Esperanto"),
|
||||
("es", "Spanish"),
|
||||
("es-ar", "Argentinian Spanish"),
|
||||
("es-co", "Colombian Spanish"),
|
||||
("es-mx", "Mexican Spanish"),
|
||||
("es-ni", "Nicaraguan Spanish"),
|
||||
("es-ve", "Venezuelan Spanish"),
|
||||
("et", "Estonian"),
|
||||
("eu", "Basque"),
|
||||
("fa", "Persian"),
|
||||
("fi", "Finnish"),
|
||||
("fr", "French"),
|
||||
("fy", "Frisian"),
|
||||
("ga", "Irish"),
|
||||
("gd", "Scottish Gaelic"),
|
||||
("gl", "Galician"),
|
||||
("he", "Hebrew"),
|
||||
("hi", "Hindi"),
|
||||
("hr", "Croatian"),
|
||||
("hsb", "Upper Sorbian"),
|
||||
("hu", "Hungarian"),
|
||||
("hy", "Armenian"),
|
||||
("ia", "Interlingua"),
|
||||
("id", "Indonesian"),
|
||||
("ig", "Igbo"),
|
||||
("io", "Ido"),
|
||||
("is", "Icelandic"),
|
||||
("it", "Italian"),
|
||||
("ja", "Japanese"),
|
||||
("ka", "Georgian"),
|
||||
("kab", "Kabyle"),
|
||||
("kk", "Kazakh"),
|
||||
("km", "Khmer"),
|
||||
("kn", "Kannada"),
|
||||
("ko", "Korean"),
|
||||
("ky", "Kyrgyz"),
|
||||
("lb", "Luxembourgish"),
|
||||
("lt", "Lithuanian"),
|
||||
("lv", "Latvian"),
|
||||
("mk", "Macedonian"),
|
||||
("ml", "Malayalam"),
|
||||
("mn", "Mongolian"),
|
||||
("mr", "Marathi"),
|
||||
("ms", "Malay"),
|
||||
("my", "Burmese"),
|
||||
("nb", "Norwegian Bokmål"),
|
||||
("ne", "Nepali"),
|
||||
("nl", "Dutch"),
|
||||
("nn", "Norwegian Nynorsk"),
|
||||
("os", "Ossetic"),
|
||||
("pa", "Punjabi"),
|
||||
("pl", "Polish"),
|
||||
("pt", "Portuguese"),
|
||||
("pt-br", "Brazilian Portuguese"),
|
||||
("ro", "Romanian"),
|
||||
("ru", "Russian"),
|
||||
("sk", "Slovak"),
|
||||
("sl", "Slovenian"),
|
||||
("sq", "Albanian"),
|
||||
("sr", "Serbian"),
|
||||
("sr-latn", "Serbian Latin"),
|
||||
("sv", "Swedish"),
|
||||
("sw", "Swahili"),
|
||||
("ta", "Tamil"),
|
||||
("te", "Telugu"),
|
||||
("tg", "Tajik"),
|
||||
("th", "Thai"),
|
||||
("tk", "Turkmen"),
|
||||
("tr", "Turkish"),
|
||||
("tt", "Tatar"),
|
||||
("udm", "Udmurt"),
|
||||
("ug", "Uyghur"),
|
||||
("uk", "Ukrainian"),
|
||||
("ur", "Urdu"),
|
||||
("uz", "Uzbek"),
|
||||
("vi", "Vietnamese"),
|
||||
("zh-hans", "Simplified Chinese"),
|
||||
("zh-hant", "Traditional Chinese"),
|
||||
],
|
||||
default="en",
|
||||
help_text="what language do you want to use moku.blog in?",
|
||||
max_length=16,
|
||||
verbose_name="language",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="settings",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# ruff: noqa: E501
|
||||
# Generated by Django 5.0.3 on 2024-03-25 21:09
|
||||
|
||||
import django.db.models.deletion
|
||||
|
|
@ -7,36 +8,114 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('moku', '0005_usersettings'),
|
||||
]
|
||||
dependencies = [("moku", "0005_usersettings")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Recipe',
|
||||
name="Recipe",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('uuid', shortuuid.django_fields.ShortUUIDField(alphabet=None, help_text='the unique id that identifies this recipe.', length=22, max_length=22, prefix='', verbose_name='unique id')),
|
||||
('title', models.CharField(help_text='give the recipe a title, just so you know the recipe is for.', max_length=64, verbose_name='recipe title')),
|
||||
('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.CASCADE, related_name='recipes', to=settings.AUTH_USER_MODEL)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"uuid",
|
||||
shortuuid.django_fields.ShortUUIDField(
|
||||
alphabet=None,
|
||||
help_text="the unique id that identifies this recipe.",
|
||||
length=22,
|
||||
max_length=22,
|
||||
prefix="",
|
||||
verbose_name="unique id",
|
||||
),
|
||||
),
|
||||
(
|
||||
"title",
|
||||
models.CharField(
|
||||
help_text="give the recipe a title, just so you know the recipe is for.",
|
||||
max_length=64,
|
||||
verbose_name="recipe title",
|
||||
),
|
||||
),
|
||||
("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.CASCADE,
|
||||
related_name="recipes",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='post',
|
||||
name='recipe',
|
||||
field=models.ForeignKey(blank=True, help_text='the recipe for what you ate, if you have one.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='moku.recipe', verbose_name='recipe'),
|
||||
model_name="post",
|
||||
name="recipe",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="the recipe for what you ate, if you have one.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="+",
|
||||
to="moku.recipe",
|
||||
verbose_name="recipe",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RecipeStep',
|
||||
name="RecipeStep",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('uuid', shortuuid.django_fields.ShortUUIDField(alphabet=None, help_text='the unique id that identifies this step.', length=22, max_length=22, prefix='', verbose_name='step id')),
|
||||
('instructions', models.CharField(help_text='the instructions for this step of the recipe. try to keep it clear and concise!', max_length=128, verbose_name='step instructions')),
|
||||
('order', models.IntegerField(db_index=True, default=0, help_text='which step in the recipe is this. this affects the order the recipe steps are shown.', verbose_name='step number')),
|
||||
('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='steps', to='moku.recipe')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"uuid",
|
||||
shortuuid.django_fields.ShortUUIDField(
|
||||
alphabet=None,
|
||||
help_text="the unique id that identifies this step.",
|
||||
length=22,
|
||||
max_length=22,
|
||||
prefix="",
|
||||
verbose_name="step id",
|
||||
),
|
||||
),
|
||||
(
|
||||
"instructions",
|
||||
models.CharField(
|
||||
help_text="the instructions for this step of the recipe. try to keep it clear and concise!",
|
||||
max_length=128,
|
||||
verbose_name="step instructions",
|
||||
),
|
||||
),
|
||||
(
|
||||
"order",
|
||||
models.IntegerField(
|
||||
db_index=True,
|
||||
default=0,
|
||||
help_text="which step in the recipe is this. this affects the order the recipe steps are shown.",
|
||||
verbose_name="step number",
|
||||
),
|
||||
),
|
||||
(
|
||||
"recipe",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="steps",
|
||||
to="moku.recipe",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -2,11 +2,4 @@ from moku.models.post import Post
|
|||
from moku.models.recipe import Recipe, RecipeStep
|
||||
from moku.models.user import User, UserSettings
|
||||
|
||||
|
||||
__all__ = [
|
||||
"Post",
|
||||
"Recipe",
|
||||
"RecipeStep",
|
||||
"User",
|
||||
"UserSettings",
|
||||
]
|
||||
__all__ = ["Post", "Recipe", "RecipeStep", "User", "UserSettings"]
|
||||
|
|
|
|||
|
|
@ -14,11 +14,17 @@ def post_image_filename(instance, _):
|
|||
|
||||
class PostManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().select_related("created_by") \
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.select_related("created_by")
|
||||
.prefetch_related(
|
||||
models.Prefetch("recipe__steps", queryset=RecipeStep.objects.order_by("order"))
|
||||
) \
|
||||
models.Prefetch(
|
||||
"recipe__steps", queryset=RecipeStep.objects.order_by("order")
|
||||
)
|
||||
)
|
||||
.order_by("-created_at")
|
||||
)
|
||||
|
||||
|
||||
class Post(models.Model):
|
||||
|
|
@ -41,9 +47,7 @@ class Post(models.Model):
|
|||
help_text=_("how should we best phrase this entry?"),
|
||||
)
|
||||
food = models.CharField(
|
||||
verbose_name=_("food"),
|
||||
max_length=128,
|
||||
help_text=_("what did you eat?"),
|
||||
verbose_name=_("food"), max_length=128, help_text=_("what did you eat?")
|
||||
)
|
||||
image = models.ImageField(
|
||||
verbose_name=_("image"),
|
||||
|
|
@ -68,12 +72,10 @@ class Post(models.Model):
|
|||
on_delete=models.CASCADE,
|
||||
)
|
||||
created_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
help_text=_("when this post was created."),
|
||||
auto_now_add=True, help_text=_("when this post was created.")
|
||||
)
|
||||
updated_at = models.DateTimeField(
|
||||
auto_now=True,
|
||||
help_text=_("when this post was last updated."),
|
||||
auto_now=True, help_text=_("when this post was last updated.")
|
||||
)
|
||||
|
||||
objects = PostManager()
|
||||
|
|
@ -84,6 +86,9 @@ class Post(models.Model):
|
|||
@property
|
||||
def text(self):
|
||||
return self.get_verb_display() % {
|
||||
"user": f"<a href=\"{self.created_by.get_absolute_url()}\">@{self.created_by.username}</a>",
|
||||
"user": (
|
||||
f'<a href="{self.created_by.get_absolute_url()}">'
|
||||
f"@{self.created_by.username}</a>"
|
||||
),
|
||||
"food": escape(self.food),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from shortuuid.django_fields import ShortUUIDField
|
||||
|
||||
|
||||
class RecipeManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return super().get_queryset() \
|
||||
return (
|
||||
super()
|
||||
.get_queryset()
|
||||
.prefetch_related(
|
||||
models.Prefetch("steps", queryset=RecipeStep.objects.order_by("order"))
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Recipe(models.Model):
|
||||
|
|
@ -31,12 +34,8 @@ class Recipe(models.Model):
|
|||
db_column="created_by_user_id",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
created_at = models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
)
|
||||
updated_at = models.DateTimeField(
|
||||
auto_now=True,
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
objects = RecipeManager()
|
||||
|
||||
|
|
@ -57,19 +56,22 @@ class RecipeStep(models.Model):
|
|||
instructions = models.CharField(
|
||||
verbose_name=_("step instructions"),
|
||||
max_length=128,
|
||||
help_text=_("the instructions for this step of the recipe. try to keep it clear and concise!"),
|
||||
help_text=_(
|
||||
"the instructions for this step of the recipe. try to keep it clear and "
|
||||
"concise!"
|
||||
),
|
||||
)
|
||||
order = models.IntegerField(
|
||||
verbose_name=_("step number"),
|
||||
default=0,
|
||||
db_index=True,
|
||||
help_text=_("which step in the recipe is this. this affects the order the recipe steps are shown."),
|
||||
help_text=_(
|
||||
"which step in the recipe is this. this affects the order the recipe steps "
|
||||
"are shown."
|
||||
),
|
||||
)
|
||||
recipe = models.ForeignKey(
|
||||
"Recipe",
|
||||
related_name="steps",
|
||||
db_index=True,
|
||||
on_delete=models.CASCADE,
|
||||
"Recipe", related_name="steps", db_index=True, on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from moku.validators import validate_username_regex, validate_username_length
|
||||
from moku.validators import validate_username_length, validate_username_regex
|
||||
|
||||
|
||||
def user_avatar_filename(instance, _):
|
||||
|
|
@ -21,7 +21,7 @@ class User(AbstractUser):
|
|||
help_text=_(
|
||||
"this is the unique identifier you'll use to log in. it may only contain "
|
||||
"letters, numbers, hyphens, dashes and dots."
|
||||
)
|
||||
),
|
||||
)
|
||||
email = models.EmailField(
|
||||
verbose_name=_("email address"),
|
||||
|
|
@ -30,12 +30,9 @@ class User(AbstractUser):
|
|||
help_text=_(
|
||||
"this should be your email address. make sure it's valid and that you have "
|
||||
"access to it."
|
||||
)
|
||||
)
|
||||
email_confirmed_at = models.DateTimeField(
|
||||
blank=True,
|
||||
null=True,
|
||||
),
|
||||
)
|
||||
email_confirmed_at = models.DateTimeField(blank=True, null=True)
|
||||
pronouns = models.CharField(
|
||||
verbose_name=_("pronouns"),
|
||||
max_length=64,
|
||||
|
|
@ -82,9 +79,7 @@ class User(AbstractUser):
|
|||
|
||||
class UserSettings(models.Model):
|
||||
user = models.OneToOneField(
|
||||
"User",
|
||||
related_name="settings",
|
||||
on_delete=models.CASCADE,
|
||||
"User", related_name="settings", on_delete=models.CASCADE
|
||||
)
|
||||
language = models.CharField(
|
||||
verbose_name=_("language"),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.views import LoginView as BaseLoginView, LogoutView as BaseLogoutView
|
||||
from django.contrib.auth.views import LoginView as BaseLoginView
|
||||
from django.contrib.auth.views import LogoutView as BaseLogoutView
|
||||
from django.shortcuts import redirect
|
||||
from django.utils.translation import gettext as _
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from moku.views.base import View
|
||||
|
||||
|
|
@ -17,7 +18,11 @@ class LoginView(View, BaseLoginView):
|
|||
|
||||
def get_success_url(self):
|
||||
if self.request.user.is_authenticated:
|
||||
messages.success(self.request, _("welcome back, %(username)s!") % {"username": self.request.user.username})
|
||||
messages.success(
|
||||
self.request,
|
||||
_("welcome back, %(username)s!")
|
||||
% {"username": self.request.user.username},
|
||||
)
|
||||
return self.request.GET.get("next", reverse_lazy("feed"))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ class View(generic.TemplateView):
|
|||
def get_context_data(self, **kwargs):
|
||||
return {
|
||||
**super().get_context_data(**kwargs),
|
||||
"header_emoji": random.choice(["🍔", "🍕", "🍟", "🥪", "🥘", "🍰", "🍻", "🧁", "🍞", "🥯", "🥐"])
|
||||
"header_emoji": random.choice(
|
||||
["🍔", "🍕", "🍟", "🥪", "🥘", "🍰", "🍻", "🧁", "🍞", "🥯", "🥐"]
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,13 @@ class FeedView(FormView):
|
|||
def form_valid(self, form):
|
||||
if not self.request.user.is_authenticated:
|
||||
raise PermissionDenied
|
||||
if form.instance.recipe and form.instance.recipe.created_by.id != self.request.user.id:
|
||||
messages.error(self.request, _("you can't add someone else's recipe to your post!"))
|
||||
if (
|
||||
form.instance.recipe
|
||||
and form.instance.recipe.created_by.id != self.request.user.id
|
||||
):
|
||||
messages.error(
|
||||
self.request, _("you can't add someone else's recipe to your post!")
|
||||
)
|
||||
return redirect("feed")
|
||||
form.instance.created_by = self.request.user
|
||||
if "image" in form.changed_data and form.instance.image is not None:
|
||||
|
|
@ -36,7 +41,7 @@ class FeedView(FormView):
|
|||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
**super().get_context_data(**kwargs),
|
||||
"posts": Post.objects.all()[:128]
|
||||
"posts": Post.objects.all()[:128],
|
||||
}
|
||||
if self.request.user.is_authenticated:
|
||||
return self.get_authenticated_context_data(context)
|
||||
|
|
@ -47,39 +52,54 @@ class FeedView(FormView):
|
|||
**context,
|
||||
"emoji": EMOJI_CATEGORIES,
|
||||
"verbs": (
|
||||
(verb[0], verb[1] % {"user": f"@{self.request.user.username}", "food": "..."})
|
||||
(
|
||||
verb[0],
|
||||
verb[1] % {"user": f"@{self.request.user.username}", "food": "..."},
|
||||
)
|
||||
for verb in Verbs.CHOICES
|
||||
)
|
||||
),
|
||||
}
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
form = super().get_form(form_class)
|
||||
if self.request.user.is_authenticated:
|
||||
form.fields["recipe"].queryset = Recipe.objects.filter(created_by=self.request.user)
|
||||
form.fields["recipe"].queryset = Recipe.objects.filter(
|
||||
created_by=self.request.user
|
||||
)
|
||||
return form
|
||||
|
||||
|
||||
class LatestPostJSONView(BaseView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
post = Post.objects.prefetch_related("recipe__steps") \
|
||||
.filter(created_by__username=kwargs.get("username")) \
|
||||
.order_by("-created_at").first()
|
||||
post = (
|
||||
Post.objects.prefetch_related("recipe__steps")
|
||||
.filter(created_by__username=kwargs.get("username"))
|
||||
.order_by("-created_at")
|
||||
.first()
|
||||
)
|
||||
if not post:
|
||||
return HttpResponse(json.dumps({"post": None}), content_type="application/json")
|
||||
return HttpResponse(
|
||||
json.dumps({"post": None}), content_type="application/json"
|
||||
)
|
||||
post_data = {
|
||||
"date": str(post.created_at),
|
||||
"text": post.get_verb_display() % {"user": f"@{post.created_by.username}", "food": post.food},
|
||||
"text": post.get_verb_display()
|
||||
% {"user": f"@{post.created_by.username}", "food": post.food},
|
||||
"food": post.food,
|
||||
"verb": {
|
||||
"id": post.verb,
|
||||
"pattern": post.get_verb_display() % {"user": "$1", "food": "$2"},
|
||||
},
|
||||
"image": f"{settings.SITE_ROOT_URL}{post.image.url}" if post.image else None,
|
||||
"image": f"{settings.SITE_ROOT_URL}{post.image.url}"
|
||||
if post.image
|
||||
else None,
|
||||
"user": {
|
||||
"username": post.created_by.username,
|
||||
"url": f"{settings.SITE_ROOT_URL}{post.created_by.get_absolute_url()}",
|
||||
},
|
||||
}
|
||||
if post.recipe:
|
||||
post_data["recipe"] = [step.instructions for step in post.recipe.steps.all()]
|
||||
post_data["recipe"] = [
|
||||
step.instructions for step in post.recipe.steps.all()
|
||||
]
|
||||
return HttpResponse(json.dumps(post_data), content_type="application/json")
|
||||
|
|
|
|||
|
|
@ -17,10 +17,7 @@ class DeleteRecipeView(LoginRequiredMixin, UserPassesTestMixin, View):
|
|||
|
||||
@cached_property
|
||||
def recipe(self):
|
||||
return get_object_or_404(
|
||||
Recipe,
|
||||
uuid=self.kwargs.get("uuid"),
|
||||
)
|
||||
return get_object_or_404(Recipe, uuid=self.kwargs.get("uuid"))
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.id == self.recipe.created_by.id
|
||||
|
|
@ -77,7 +74,9 @@ class IndexRecipeView(LoginRequiredMixin, View):
|
|||
def get_context_data(self, **kwargs):
|
||||
return {
|
||||
**super().get_context_data(**kwargs),
|
||||
"recipes": Recipe.objects.filter(created_by=self.request.user).order_by("-created_by"),
|
||||
"recipes": Recipe.objects.filter(created_by=self.request.user).order_by(
|
||||
"-created_by"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -88,7 +87,10 @@ class NewRecipeView(LoginRequiredMixin, FormView):
|
|||
def form_valid(self, form):
|
||||
form.instance.created_by = self.request.user
|
||||
form.save()
|
||||
messages.success(self.request, _("recipe made successfully! now you can start adding the steps."))
|
||||
messages.success(
|
||||
self.request,
|
||||
_("recipe made successfully! now you can start adding the steps."),
|
||||
)
|
||||
return redirect(form.instance.get_absolute_url())
|
||||
|
||||
|
||||
|
|
@ -101,12 +103,17 @@ class ShowRecipeView(FormView):
|
|||
return Recipe.objects.get(uuid=self.kwargs.get("uuid"))
|
||||
|
||||
def form_valid(self, form):
|
||||
if not self.request.user.is_authenticated or self.request.user.id != self.recipe.created_by.id:
|
||||
if (
|
||||
not self.request.user.is_authenticated
|
||||
or self.request.user.id != self.recipe.created_by.id
|
||||
):
|
||||
messages.error(self.request, _("that's not yours!"))
|
||||
return redirect(form.instance.get_absolute_url())
|
||||
order = self.recipe.steps.count()
|
||||
if order >= 16:
|
||||
messages.error(self.request, _("sorry! you can't add any more steps to this recipe."))
|
||||
messages.error(
|
||||
self.request, _("sorry! you can't add any more steps to this recipe.")
|
||||
)
|
||||
return redirect(self.recipe.get_absolute_url())
|
||||
form.instance.recipe = self.recipe
|
||||
form.instance.order = order
|
||||
|
|
@ -115,7 +122,4 @@ class ShowRecipeView(FormView):
|
|||
return redirect(self.recipe.get_absolute_url())
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return {
|
||||
**super().get_context_data(**kwargs),
|
||||
"recipe": self.recipe,
|
||||
}
|
||||
return {**super().get_context_data(**kwargs), "recipe": self.recipe}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ from django.db import IntegrityError
|
|||
from django.shortcuts import redirect
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from moku.images import process_avatar_image
|
||||
from moku.forms.user import ProfileForm, UserForm, UserSettingsForm
|
||||
from moku.images import process_avatar_image
|
||||
from moku.models.user import User
|
||||
from moku.views.base import FormView, View
|
||||
|
||||
|
|
@ -34,14 +34,18 @@ class EditSettingsView(LoginRequiredMixin, FormView):
|
|||
try:
|
||||
form.save()
|
||||
except IntegrityError:
|
||||
messages.error(self.request, _("uh oh. i think something went a little bit oopsie."))
|
||||
messages.error(
|
||||
self.request, _("uh oh. i think something went a little bit oopsie.")
|
||||
)
|
||||
return self.form_invalid(form)
|
||||
messages.success(self.request, _("settings updated!"))
|
||||
return redirect("settings")
|
||||
|
||||
def get_form(self):
|
||||
if hasattr(self.request.user, "settings"):
|
||||
return self.form_class(instance=self.request.user.settings, **self.get_form_kwargs())
|
||||
return self.form_class(
|
||||
instance=self.request.user.settings, **self.get_form_kwargs()
|
||||
)
|
||||
return super().get_form()
|
||||
|
||||
|
||||
|
|
@ -66,9 +70,13 @@ class SignupView(FormView):
|
|||
try:
|
||||
form.save()
|
||||
except IntegrityError:
|
||||
messages.error(self.request, _("sorry! someone else got to that username first."))
|
||||
messages.error(
|
||||
self.request, _("sorry! someone else got to that username first.")
|
||||
)
|
||||
return self.form_invalid(form)
|
||||
messages.success(self.request, _("that's it! just log in, and you're ready to go."))
|
||||
messages.success(
|
||||
self.request, _("that's it! just log in, and you're ready to go.")
|
||||
)
|
||||
return redirect("login")
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
|
|
|||
Loading…
Reference in a new issue