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
|
from moku import models
|
||||||
|
|
||||||
|
|
||||||
for model_name in models.__all__:
|
for model_name in models.__all__:
|
||||||
model = getattr(models, model_name)
|
model = getattr(models, model_name)
|
||||||
if model.__name__ != "User":
|
if model.__name__ != "User":
|
||||||
|
|
@ -14,32 +13,11 @@ for model_name in models.__all__:
|
||||||
class UserAdmin(BaseUserAdmin):
|
class UserAdmin(BaseUserAdmin):
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {"fields": ("username", "email", "password")}),
|
(None, {"fields": ("username", "email", "password")}),
|
||||||
(
|
("Profile", {"fields": ("pronouns", "location", "bio")}),
|
||||||
"Profile",
|
("Status", {"fields": ("email_confirmed_at",)}),
|
||||||
{
|
|
||||||
"fields": (
|
|
||||||
"pronouns", "location", "bio"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"Status",
|
|
||||||
{
|
|
||||||
"fields": (
|
|
||||||
"email_confirmed_at",
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
"Permissions",
|
"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
|
from pathlib import Path
|
||||||
|
|
||||||
import environ
|
import environ
|
||||||
|
|
@ -71,9 +70,7 @@ TEMPLATES = [
|
||||||
"django.template.context_processors.tz",
|
"django.template.context_processors.tz",
|
||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
],
|
],
|
||||||
"filters": {
|
"filters": {"unemoji": "moku.filters.unemoji"},
|
||||||
"unemoji": "moku.filters.unemoji",
|
|
||||||
},
|
|
||||||
"policies": {"ext.i18n.trimmed": True},
|
"policies": {"ext.i18n.trimmed": True},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ Including another URLconf
|
||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
@ -50,7 +51,11 @@ urlpatterns = [
|
||||||
path("recipes/<str:uuid>", ShowRecipeView.as_view(), name="recipe.show"),
|
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>/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>", 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:
|
if settings.DEBUG_TOOLBAR:
|
||||||
|
|
|
||||||
|
|
@ -22,53 +22,228 @@ EMOJI_CATEGORIES = [
|
||||||
(
|
(
|
||||||
_("fruit & veg"),
|
_("fruit & veg"),
|
||||||
(
|
(
|
||||||
"🍏", "🍎", "🍐", "🍊", "🍋", "🍌", "🍉", "🍇", "🍓", "🫐", "🍈", "🍒", "🍑", "🥭", "🍍",
|
"🍏",
|
||||||
"🥥", "🥝", "🍅", "🍆", "🥑", "🫛", "🥦", "🥬", "🥒", "🌶️", "🫑", "🌽", "🥕", "🫒", "🧄",
|
"🍎",
|
||||||
"🧅", "🥔", "🍠", "🫚",
|
"🍐",
|
||||||
|
"🍊",
|
||||||
|
"🍋",
|
||||||
|
"🍌",
|
||||||
|
"🍉",
|
||||||
|
"🍇",
|
||||||
|
"🍓",
|
||||||
|
"🫐",
|
||||||
|
"🍈",
|
||||||
|
"🍒",
|
||||||
|
"🍑",
|
||||||
|
"🥭",
|
||||||
|
"🍍",
|
||||||
|
"🥥",
|
||||||
|
"🥝",
|
||||||
|
"🍅",
|
||||||
|
"🍆",
|
||||||
|
"🥑",
|
||||||
|
"🫛",
|
||||||
|
"🥦",
|
||||||
|
"🥬",
|
||||||
|
"🥒",
|
||||||
|
"🌶️",
|
||||||
|
"🫑",
|
||||||
|
"🌽",
|
||||||
|
"🥕",
|
||||||
|
"🫒",
|
||||||
|
"🧄",
|
||||||
|
"🧅",
|
||||||
|
"🥔",
|
||||||
|
"🍠",
|
||||||
|
"🫚",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_("savoury dishes"),
|
_("savoury dishes"),
|
||||||
(
|
(
|
||||||
"🥯", "🍞", "🥖", "🥨", "🧀", "🥚", "🍳", "🧈", "🥞", "🧇", "🥓", "🥩", "🍗", "🍖", "🦴",
|
"🥯",
|
||||||
"🌭", "🍔", "🍟", "🍕", "🫓", "🥪", "🥙", "🧆", "🌮", "🌯", "🫔", "🥗", "🥘", "🫕", "🥫",
|
"🍞",
|
||||||
"🫙", "🍝", "🍜", "🍲", "🍛", "🍣", "🍱", "🥟", "🦪", "🍤", "🍙", "🍚", "🍘", "🍥", "🌰",
|
"🥖",
|
||||||
"🥜", "🫘", "🧊",
|
"🥨",
|
||||||
|
"🧀",
|
||||||
|
"🥚",
|
||||||
|
"🍳",
|
||||||
|
"🧈",
|
||||||
|
"🥞",
|
||||||
|
"🧇",
|
||||||
|
"🥓",
|
||||||
|
"🥩",
|
||||||
|
"🍗",
|
||||||
|
"🍖",
|
||||||
|
"🦴",
|
||||||
|
"🌭",
|
||||||
|
"🍔",
|
||||||
|
"🍟",
|
||||||
|
"🍕",
|
||||||
|
"🫓",
|
||||||
|
"🥪",
|
||||||
|
"🥙",
|
||||||
|
"🧆",
|
||||||
|
"🌮",
|
||||||
|
"🌯",
|
||||||
|
"🫔",
|
||||||
|
"🥗",
|
||||||
|
"🥘",
|
||||||
|
"🫕",
|
||||||
|
"🥫",
|
||||||
|
"🫙",
|
||||||
|
"🍝",
|
||||||
|
"🍜",
|
||||||
|
"🍲",
|
||||||
|
"🍛",
|
||||||
|
"🍣",
|
||||||
|
"🍱",
|
||||||
|
"🥟",
|
||||||
|
"🦪",
|
||||||
|
"🍤",
|
||||||
|
"🍙",
|
||||||
|
"🍚",
|
||||||
|
"🍘",
|
||||||
|
"🍥",
|
||||||
|
"🌰",
|
||||||
|
"🥜",
|
||||||
|
"🫘",
|
||||||
|
"🧊",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_("sweet treats"),
|
_("sweet treats"),
|
||||||
(
|
(
|
||||||
"🥠", "🥮", "🍢", "🍡", "🍧", "🍨", "🍦", "🥧", "🧁", "🍰", "🎂", "🍮", "🍭", "🍬", "🍫",
|
"🥠",
|
||||||
"🥐", "🍿", "🍩", "🍪", "🍯",
|
"🥮",
|
||||||
|
"🍢",
|
||||||
|
"🍡",
|
||||||
|
"🍧",
|
||||||
|
"🍨",
|
||||||
|
"🍦",
|
||||||
|
"🥧",
|
||||||
|
"🧁",
|
||||||
|
"🍰",
|
||||||
|
"🎂",
|
||||||
|
"🍮",
|
||||||
|
"🍭",
|
||||||
|
"🍬",
|
||||||
|
"🍫",
|
||||||
|
"🥐",
|
||||||
|
"🍿",
|
||||||
|
"🍩",
|
||||||
|
"🍪",
|
||||||
|
"🍯",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_("drinks"),
|
_("drinks"),
|
||||||
(
|
(
|
||||||
"🥛", "🫗", "🍼", "🫖", "☕️", "🍵", "🧃", "🥤", "🧋", "🍶", "🍺", "🍻", "🥂", "🍷", "🥃",
|
"🥛",
|
||||||
"🍸", "🍹", "🧉", "🍾",
|
"🫗",
|
||||||
|
"🍼",
|
||||||
|
"🫖",
|
||||||
|
"☕️",
|
||||||
|
"🍵",
|
||||||
|
"🧃",
|
||||||
|
"🥤",
|
||||||
|
"🧋",
|
||||||
|
"🍶",
|
||||||
|
"🍺",
|
||||||
|
"🍻",
|
||||||
|
"🥂",
|
||||||
|
"🍷",
|
||||||
|
"🥃",
|
||||||
|
"🍸",
|
||||||
|
"🍹",
|
||||||
|
"🧉",
|
||||||
|
"🍾",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_("people"),
|
_("people"),
|
||||||
(
|
(
|
||||||
"😀", "😃", "😄", "😁", "😆", "🥹", "😅", "😂", "🤣", "🥲", "😊", "😇", "🙂", "🙃", "😉",
|
"😀",
|
||||||
"😌", "😌", "😍", "🥰", "😘", "😗", "😙", "😚", "😋", "😛", "😝", "😜", "🤪", "🤨", "🧐",
|
"😃",
|
||||||
|
"😄",
|
||||||
|
"😁",
|
||||||
|
"😆",
|
||||||
|
"🥹",
|
||||||
|
"😅",
|
||||||
|
"😂",
|
||||||
|
"🤣",
|
||||||
|
"🥲",
|
||||||
|
"😊",
|
||||||
|
"😇",
|
||||||
|
"🙂",
|
||||||
|
"🙃",
|
||||||
|
"😉",
|
||||||
|
"😌",
|
||||||
|
"😌",
|
||||||
|
"😍",
|
||||||
|
"🥰",
|
||||||
|
"😘",
|
||||||
|
"😗",
|
||||||
|
"😙",
|
||||||
|
"😚",
|
||||||
|
"😋",
|
||||||
|
"😛",
|
||||||
|
"😝",
|
||||||
|
"😜",
|
||||||
|
"🤪",
|
||||||
|
"🤨",
|
||||||
|
"🧐",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_("animals"),
|
_("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 django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from moku.models.recipe import Recipe, RecipeStep
|
from moku.models.recipe import Recipe, RecipeStep
|
||||||
|
|
@ -8,9 +8,7 @@ class RecipeForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Recipe
|
model = Recipe
|
||||||
fields = ("title",)
|
fields = ("title",)
|
||||||
labels = {
|
labels = {"title": _("recipe title")}
|
||||||
"title": _("recipe title"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class RecipeStepForm(ModelForm):
|
class RecipeStepForm(ModelForm):
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from django_recaptcha.fields import ReCaptchaField
|
from django_recaptcha.fields import ReCaptchaField
|
||||||
|
|
||||||
from moku.models.user import User, UserSettings
|
from moku.models.user import User, UserSettings
|
||||||
|
|
@ -14,10 +13,7 @@ class UserForm(UserCreationForm):
|
||||||
class Meta(UserCreationForm.Meta):
|
class Meta(UserCreationForm.Meta):
|
||||||
model = User
|
model = User
|
||||||
fields = ("username", "email", "password1", "password2")
|
fields = ("username", "email", "password1", "password2")
|
||||||
labels = {
|
labels = {"username": _("username"), "email": _("email address")}
|
||||||
"username": _("username"),
|
|
||||||
"email": _("email address"),
|
|
||||||
}
|
|
||||||
help_texts = {
|
help_texts = {
|
||||||
"username": User._meta.get_field("username").help_text,
|
"username": User._meta.get_field("username").help_text,
|
||||||
"email": User._meta.get_field("email").help_text,
|
"email": User._meta.get_field("email").help_text,
|
||||||
|
|
@ -26,10 +22,10 @@ class UserForm(UserCreationForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields["captcha"].error_messages = {
|
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 = {
|
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:
|
class Meta:
|
||||||
model = UserSettings
|
model = UserSettings
|
||||||
fields = ("language",)
|
fields = ("language",)
|
||||||
labels = {
|
labels = {"language": _("language")}
|
||||||
"language": _("language"),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileForm(forms.ModelForm):
|
class ProfileForm(forms.ModelForm):
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,162 @@
|
||||||
|
# ruff: noqa: E501
|
||||||
# Generated by Django 5.0.3 on 2024-03-24 17:24
|
# Generated by Django 5.0.3 on 2024-03-24 17:24
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
import django.contrib.auth.models
|
import django.contrib.auth.models
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
import moku.validators
|
|
||||||
import re
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import moku.validators
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [("auth", "0012_alter_user_first_name_max_length")]
|
||||||
('auth', '0012_alter_user_first_name_max_length'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='User',
|
name="User",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
"id",
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
models.BigAutoField(
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
auto_created=True,
|
||||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
primary_key=True,
|
||||||
('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')),
|
serialize=False,
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
verbose_name="ID",
|
||||||
('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)),
|
("password", models.CharField(max_length=128, verbose_name="password")),
|
||||||
('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')),
|
"last_login",
|
||||||
('bio', models.TextField(blank=True, help_text='write something about yourself!', verbose_name='about me')),
|
models.DateTimeField(
|
||||||
('last_seen_at', models.DateTimeField(blank=True, help_text='the last time this user accessed the site.', null=True, verbose_name='last seen at')),
|
blank=True, null=True, verbose_name="last login"
|
||||||
('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')),
|
),
|
||||||
|
(
|
||||||
|
"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={
|
options={
|
||||||
'verbose_name': 'user',
|
"verbose_name": "user",
|
||||||
'verbose_name_plural': 'users',
|
"verbose_name_plural": "users",
|
||||||
'abstract': False,
|
"abstract": False,
|
||||||
},
|
},
|
||||||
managers=[
|
managers=[("objects", django.contrib.auth.models.UserManager())],
|
||||||
('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
|
# Generated by Django 5.0.3 on 2024-03-25 10:04
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import moku.models.post
|
|
||||||
import moku.validators
|
|
||||||
import shortuuid.django_fields
|
import shortuuid.django_fields
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import moku.models.post
|
||||||
|
import moku.validators
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("moku", "0001_initial")]
|
||||||
dependencies = [
|
|
||||||
('moku', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Post',
|
name="Post",
|
||||||
fields=[
|
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')),
|
"id",
|
||||||
('emoji', models.CharField(help_text='an emoji to accompany your post!', max_length=8, validators=[moku.validators.validate_emoji], verbose_name='emoji')),
|
models.BigAutoField(
|
||||||
('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')),
|
auto_created=True,
|
||||||
('food', models.CharField(help_text='what did you eat?', max_length=128, verbose_name='food')),
|
primary_key=True,
|
||||||
('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')),
|
serialize=False,
|
||||||
('created_at', models.DateTimeField(auto_now_add=True, help_text='when this post was created.')),
|
verbose_name="ID",
|
||||||
('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)),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"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
|
# Generated by Django 5.0.3 on 2024-03-25 13:49
|
||||||
|
|
||||||
import moku.models.user
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import moku.models.user
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("moku", "0002_post")]
|
||||||
dependencies = [
|
|
||||||
('moku', '0002_post'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='user',
|
model_name="user",
|
||||||
name='avatar',
|
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'),
|
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
|
# Generated by Django 5.0.3 on 2024-03-25 15:34
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("moku", "0003_user_avatar")]
|
||||||
dependencies = [
|
|
||||||
('moku', '0003_user_avatar'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='verb',
|
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'),
|
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
|
# Generated by Django 5.0.3 on 2024-03-25 17:02
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
@ -6,18 +7,139 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("moku", "0004_alter_post_verb")]
|
||||||
dependencies = [
|
|
||||||
('moku', '0004_alter_post_verb'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='UserSettings',
|
name="UserSettings",
|
||||||
fields=[
|
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')),
|
"id",
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='settings', to=settings.AUTH_USER_MODEL)),
|
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
|
# Generated by Django 5.0.3 on 2024-03-25 21:09
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
@ -7,36 +8,114 @@ from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [("moku", "0005_usersettings")]
|
||||||
dependencies = [
|
|
||||||
('moku', '0005_usersettings'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Recipe',
|
name="Recipe",
|
||||||
fields=[
|
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')),
|
"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')),
|
models.BigAutoField(
|
||||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
auto_created=True,
|
||||||
('updated_at', models.DateTimeField(auto_now=True)),
|
primary_key=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)),
|
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(
|
migrations.AddField(
|
||||||
model_name='post',
|
model_name="post",
|
||||||
name='recipe',
|
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'),
|
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(
|
migrations.CreateModel(
|
||||||
name='RecipeStep',
|
name="RecipeStep",
|
||||||
fields=[
|
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')),
|
"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')),
|
models.BigAutoField(
|
||||||
('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')),
|
auto_created=True,
|
||||||
('recipe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='steps', to='moku.recipe')),
|
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.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__ = [
|
|
||||||
"Post",
|
|
||||||
"Recipe",
|
|
||||||
"RecipeStep",
|
|
||||||
"User",
|
|
||||||
"UserSettings",
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,17 @@ def post_image_filename(instance, _):
|
||||||
|
|
||||||
class PostManager(models.Manager):
|
class PostManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset().select_related("created_by") \
|
return (
|
||||||
|
super()
|
||||||
|
.get_queryset()
|
||||||
|
.select_related("created_by")
|
||||||
.prefetch_related(
|
.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")
|
.order_by("-created_at")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Post(models.Model):
|
class Post(models.Model):
|
||||||
|
|
@ -41,9 +47,7 @@ class Post(models.Model):
|
||||||
help_text=_("how should we best phrase this entry?"),
|
help_text=_("how should we best phrase this entry?"),
|
||||||
)
|
)
|
||||||
food = models.CharField(
|
food = models.CharField(
|
||||||
verbose_name=_("food"),
|
verbose_name=_("food"), max_length=128, help_text=_("what did you eat?")
|
||||||
max_length=128,
|
|
||||||
help_text=_("what did you eat?"),
|
|
||||||
)
|
)
|
||||||
image = models.ImageField(
|
image = models.ImageField(
|
||||||
verbose_name=_("image"),
|
verbose_name=_("image"),
|
||||||
|
|
@ -68,12 +72,10 @@ class Post(models.Model):
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
created_at = models.DateTimeField(
|
created_at = models.DateTimeField(
|
||||||
auto_now_add=True,
|
auto_now_add=True, help_text=_("when this post was created.")
|
||||||
help_text=_("when this post was created."),
|
|
||||||
)
|
)
|
||||||
updated_at = models.DateTimeField(
|
updated_at = models.DateTimeField(
|
||||||
auto_now=True,
|
auto_now=True, help_text=_("when this post was last updated.")
|
||||||
help_text=_("when this post was last updated."),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = PostManager()
|
objects = PostManager()
|
||||||
|
|
@ -84,6 +86,9 @@ class Post(models.Model):
|
||||||
@property
|
@property
|
||||||
def text(self):
|
def text(self):
|
||||||
return self.get_verb_display() % {
|
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),
|
"food": escape(self.food),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from shortuuid.django_fields import ShortUUIDField
|
from shortuuid.django_fields import ShortUUIDField
|
||||||
|
|
||||||
|
|
||||||
class RecipeManager(models.Manager):
|
class RecipeManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset() \
|
return (
|
||||||
|
super()
|
||||||
|
.get_queryset()
|
||||||
.prefetch_related(
|
.prefetch_related(
|
||||||
models.Prefetch("steps", queryset=RecipeStep.objects.order_by("order"))
|
models.Prefetch("steps", queryset=RecipeStep.objects.order_by("order"))
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Recipe(models.Model):
|
class Recipe(models.Model):
|
||||||
|
|
@ -31,12 +34,8 @@ class Recipe(models.Model):
|
||||||
db_column="created_by_user_id",
|
db_column="created_by_user_id",
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
)
|
)
|
||||||
created_at = models.DateTimeField(
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
auto_now_add=True,
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
)
|
|
||||||
updated_at = models.DateTimeField(
|
|
||||||
auto_now=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
objects = RecipeManager()
|
objects = RecipeManager()
|
||||||
|
|
||||||
|
|
@ -57,19 +56,22 @@ class RecipeStep(models.Model):
|
||||||
instructions = models.CharField(
|
instructions = models.CharField(
|
||||||
verbose_name=_("step instructions"),
|
verbose_name=_("step instructions"),
|
||||||
max_length=128,
|
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(
|
order = models.IntegerField(
|
||||||
verbose_name=_("step number"),
|
verbose_name=_("step number"),
|
||||||
default=0,
|
default=0,
|
||||||
db_index=True,
|
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 = models.ForeignKey(
|
||||||
"Recipe",
|
"Recipe", related_name="steps", db_index=True, on_delete=models.CASCADE
|
||||||
related_name="steps",
|
|
||||||
db_index=True,
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django.urls import reverse
|
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, _):
|
def user_avatar_filename(instance, _):
|
||||||
|
|
@ -21,7 +21,7 @@ class User(AbstractUser):
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"this is the unique identifier you'll use to log in. it may only contain "
|
"this is the unique identifier you'll use to log in. it may only contain "
|
||||||
"letters, numbers, hyphens, dashes and dots."
|
"letters, numbers, hyphens, dashes and dots."
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
email = models.EmailField(
|
email = models.EmailField(
|
||||||
verbose_name=_("email address"),
|
verbose_name=_("email address"),
|
||||||
|
|
@ -30,12 +30,9 @@ class User(AbstractUser):
|
||||||
help_text=_(
|
help_text=_(
|
||||||
"this should be your email address. make sure it's valid and that you have "
|
"this should be your email address. make sure it's valid and that you have "
|
||||||
"access to it."
|
"access to it."
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
email_confirmed_at = models.DateTimeField(blank=True, null=True)
|
||||||
email_confirmed_at = models.DateTimeField(
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
pronouns = models.CharField(
|
pronouns = models.CharField(
|
||||||
verbose_name=_("pronouns"),
|
verbose_name=_("pronouns"),
|
||||||
max_length=64,
|
max_length=64,
|
||||||
|
|
@ -82,9 +79,7 @@ class User(AbstractUser):
|
||||||
|
|
||||||
class UserSettings(models.Model):
|
class UserSettings(models.Model):
|
||||||
user = models.OneToOneField(
|
user = models.OneToOneField(
|
||||||
"User",
|
"User", related_name="settings", on_delete=models.CASCADE
|
||||||
related_name="settings",
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
)
|
)
|
||||||
language = models.CharField(
|
language = models.CharField(
|
||||||
verbose_name=_("language"),
|
verbose_name=_("language"),
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
from django.contrib import messages
|
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.shortcuts import redirect
|
||||||
from django.utils.translation import gettext as _
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from moku.views.base import View
|
from moku.views.base import View
|
||||||
|
|
||||||
|
|
@ -17,7 +18,11 @@ class LoginView(View, BaseLoginView):
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.user.is_authenticated:
|
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"))
|
return self.request.GET.get("next", reverse_lazy("feed"))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@ class View(generic.TemplateView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
return {
|
return {
|
||||||
**super().get_context_data(**kwargs),
|
**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):
|
def form_valid(self, form):
|
||||||
if not self.request.user.is_authenticated:
|
if not self.request.user.is_authenticated:
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
if form.instance.recipe and form.instance.recipe.created_by.id != self.request.user.id:
|
if (
|
||||||
messages.error(self.request, _("you can't add someone else's recipe to your post!"))
|
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")
|
return redirect("feed")
|
||||||
form.instance.created_by = self.request.user
|
form.instance.created_by = self.request.user
|
||||||
if "image" in form.changed_data and form.instance.image is not None:
|
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):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
**super().get_context_data(**kwargs),
|
**super().get_context_data(**kwargs),
|
||||||
"posts": Post.objects.all()[:128]
|
"posts": Post.objects.all()[:128],
|
||||||
}
|
}
|
||||||
if self.request.user.is_authenticated:
|
if self.request.user.is_authenticated:
|
||||||
return self.get_authenticated_context_data(context)
|
return self.get_authenticated_context_data(context)
|
||||||
|
|
@ -47,39 +52,54 @@ class FeedView(FormView):
|
||||||
**context,
|
**context,
|
||||||
"emoji": EMOJI_CATEGORIES,
|
"emoji": EMOJI_CATEGORIES,
|
||||||
"verbs": (
|
"verbs": (
|
||||||
(verb[0], verb[1] % {"user": f"@{self.request.user.username}", "food": "..."})
|
(
|
||||||
for verb in Verbs.CHOICES
|
verb[0],
|
||||||
|
verb[1] % {"user": f"@{self.request.user.username}", "food": "..."},
|
||||||
)
|
)
|
||||||
|
for verb in Verbs.CHOICES
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_form(self, form_class=None):
|
def get_form(self, form_class=None):
|
||||||
form = super().get_form(form_class)
|
form = super().get_form(form_class)
|
||||||
if self.request.user.is_authenticated:
|
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
|
return form
|
||||||
|
|
||||||
|
|
||||||
class LatestPostJSONView(BaseView):
|
class LatestPostJSONView(BaseView):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
post = Post.objects.prefetch_related("recipe__steps") \
|
post = (
|
||||||
.filter(created_by__username=kwargs.get("username")) \
|
Post.objects.prefetch_related("recipe__steps")
|
||||||
.order_by("-created_at").first()
|
.filter(created_by__username=kwargs.get("username"))
|
||||||
|
.order_by("-created_at")
|
||||||
|
.first()
|
||||||
|
)
|
||||||
if not post:
|
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 = {
|
post_data = {
|
||||||
"date": str(post.created_at),
|
"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,
|
"food": post.food,
|
||||||
"verb": {
|
"verb": {
|
||||||
"id": post.verb,
|
"id": post.verb,
|
||||||
"pattern": post.get_verb_display() % {"user": "$1", "food": "$2"},
|
"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": {
|
"user": {
|
||||||
"username": post.created_by.username,
|
"username": post.created_by.username,
|
||||||
"url": f"{settings.SITE_ROOT_URL}{post.created_by.get_absolute_url()}",
|
"url": f"{settings.SITE_ROOT_URL}{post.created_by.get_absolute_url()}",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if post.recipe:
|
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")
|
return HttpResponse(json.dumps(post_data), content_type="application/json")
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,7 @@ class DeleteRecipeView(LoginRequiredMixin, UserPassesTestMixin, View):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def recipe(self):
|
def recipe(self):
|
||||||
return get_object_or_404(
|
return get_object_or_404(Recipe, uuid=self.kwargs.get("uuid"))
|
||||||
Recipe,
|
|
||||||
uuid=self.kwargs.get("uuid"),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
return self.request.user.id == self.recipe.created_by.id
|
return self.request.user.id == self.recipe.created_by.id
|
||||||
|
|
@ -77,7 +74,9 @@ class IndexRecipeView(LoginRequiredMixin, View):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
return {
|
return {
|
||||||
**super().get_context_data(**kwargs),
|
**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):
|
def form_valid(self, form):
|
||||||
form.instance.created_by = self.request.user
|
form.instance.created_by = self.request.user
|
||||||
form.save()
|
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())
|
return redirect(form.instance.get_absolute_url())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -101,12 +103,17 @@ class ShowRecipeView(FormView):
|
||||||
return Recipe.objects.get(uuid=self.kwargs.get("uuid"))
|
return Recipe.objects.get(uuid=self.kwargs.get("uuid"))
|
||||||
|
|
||||||
def form_valid(self, form):
|
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!"))
|
messages.error(self.request, _("that's not yours!"))
|
||||||
return redirect(form.instance.get_absolute_url())
|
return redirect(form.instance.get_absolute_url())
|
||||||
order = self.recipe.steps.count()
|
order = self.recipe.steps.count()
|
||||||
if order >= 16:
|
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())
|
return redirect(self.recipe.get_absolute_url())
|
||||||
form.instance.recipe = self.recipe
|
form.instance.recipe = self.recipe
|
||||||
form.instance.order = order
|
form.instance.order = order
|
||||||
|
|
@ -115,7 +122,4 @@ class ShowRecipeView(FormView):
|
||||||
return redirect(self.recipe.get_absolute_url())
|
return redirect(self.recipe.get_absolute_url())
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
return {
|
return {**super().get_context_data(**kwargs), "recipe": self.recipe}
|
||||||
**super().get_context_data(**kwargs),
|
|
||||||
"recipe": self.recipe,
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ from django.db import IntegrityError
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from moku.images import process_avatar_image
|
|
||||||
from moku.forms.user import ProfileForm, UserForm, UserSettingsForm
|
from moku.forms.user import ProfileForm, UserForm, UserSettingsForm
|
||||||
|
from moku.images import process_avatar_image
|
||||||
from moku.models.user import User
|
from moku.models.user import User
|
||||||
from moku.views.base import FormView, View
|
from moku.views.base import FormView, View
|
||||||
|
|
||||||
|
|
@ -34,14 +34,18 @@ class EditSettingsView(LoginRequiredMixin, FormView):
|
||||||
try:
|
try:
|
||||||
form.save()
|
form.save()
|
||||||
except IntegrityError:
|
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)
|
return self.form_invalid(form)
|
||||||
messages.success(self.request, _("settings updated!"))
|
messages.success(self.request, _("settings updated!"))
|
||||||
return redirect("settings")
|
return redirect("settings")
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
if hasattr(self.request.user, "settings"):
|
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()
|
return super().get_form()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -66,9 +70,13 @@ class SignupView(FormView):
|
||||||
try:
|
try:
|
||||||
form.save()
|
form.save()
|
||||||
except IntegrityError:
|
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)
|
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")
|
return redirect("login")
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue