2025.09.14-18:02:28
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -439,6 +439,8 @@ pip-selfcheck.json
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
djangocourse/privsettings.py
|
||||
|
||||
.venv*
|
||||
|
||||
django_project/local/
|
||||
.data
|
||||
db.sqlite
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
FROM docker.io/library/python:3.13-trixie
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
RUN apt-update \
|
||||
&& apt-upgrade -y \
|
||||
ENV DEBUG="1"
|
||||
ENV DATABASE_URL="sqlite:////data/database/tinywiki.sqlite"
|
||||
ENV MEDIA_URL="media/"
|
||||
ENV MEDIA_ROOT="/data/media"
|
||||
ENV STATIC_URL="static/"
|
||||
ENV STATIC_ROOT="/data/static"
|
||||
|
||||
RUN apt update \
|
||||
&& apt upgrade -y \
|
||||
&& apt install -y gettext libxmlsec1-dev xmlsec1\
|
||||
#&& python -m pip install upgrade pip \
|
||||
&& python -m pip install --upgrade pip \
|
||||
&& pip install poetry \
|
||||
&& mkdir /app \
|
||||
&& mkdir -p /data/static /data/media
|
||||
&& mkdir -p /data/static /data/media /data/database
|
||||
VOLUME "/data"
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
@@ -16,4 +24,3 @@ RUN poetry install --all-groups \
|
||||
|
||||
EXPOSE 8000
|
||||
ENTRYPOINT ["/app/start-django.sh"]
|
||||
|
||||
|
||||
0
django_project/local/__init__.py
Normal file
0
django_project/local/__init__.py
Normal file
@@ -11,6 +11,8 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from environ import Env
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
@@ -20,12 +22,24 @@ ENV = Env(
|
||||
ALLOWED_HOSTS=(list,['*']),
|
||||
STATIC_URL=(str,"static/"),
|
||||
STATIC_ROOT=(Path,BASE_DIR/".static"),
|
||||
MEDIA_URL=("media/")
|
||||
MEDIA_URL=(str,"media/"),
|
||||
MEDIA_ROOT=(Path,BASE_DIR/".media"),
|
||||
SECRET_KEY=(str,'django-insecure-tqis9c9@z_=cq36ic4h-l7h!ln8*@_*+e96z0m^-^mx_avdcw*')
|
||||
SECRET_KEY=(str,'django-insecure-tqis9c9@z_=cq36ic4h-l7h!ln8*@_*+e96z0m^-^mx_avdcw*'),
|
||||
EMAIL_BACKEND=(str,"console"),
|
||||
)
|
||||
|
||||
DEBUG = True
|
||||
DEBUG = ENV.bool("DEBUG")
|
||||
|
||||
DEBUG = ENV.bool("DEBUG")
|
||||
if DEBUG:
|
||||
_env_file = Path(ENV.path("DOTENV",str(BASE_DIR/'.env.dev'))).resolve()
|
||||
if _env_file.is_file():
|
||||
ENV.read_env(_env_file)
|
||||
else:
|
||||
_env_file = Path(ENV.path("DOTENV",str(BASE_DIR/'.env.prod'))).resolve()
|
||||
if _env_file.is_file():
|
||||
ENV.read_env(_env_file)
|
||||
del _env_file
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||
@@ -40,8 +54,7 @@ ALLOWED_HOSTS = ENV.list("ALLOWED_HOSTS")
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
django_apps= [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@@ -50,6 +63,23 @@ INSTALLED_APPS = [
|
||||
'django.contrib.staticfiles',
|
||||
]
|
||||
|
||||
third_party_apps = [
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'allauth.socialaccount.providers.oauth2', # required for github
|
||||
'allauth.socialaccount.providers.github',
|
||||
'allauth.socialaccount.providers.google',
|
||||
'allauth.socialaccount.providers.openid',
|
||||
'allauth.socialaccount.providers.steam',
|
||||
'widget_tweaks',
|
||||
]
|
||||
|
||||
project_apps = [
|
||||
'user',
|
||||
'tinywiki',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
@@ -58,6 +88,30 @@ MIDDLEWARE = [
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'allauth.account.middleware.AccountMiddleware',
|
||||
]
|
||||
|
||||
if DEBUG:
|
||||
third_party_apps += [
|
||||
"django_browser_reload",
|
||||
"debug_toolbar",
|
||||
]
|
||||
MIDDLEWARE = [
|
||||
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||
*MIDDLEWARE,
|
||||
'django_browser_reload.middleware.BrowserReloadMiddleware',
|
||||
]
|
||||
import socket
|
||||
hostname, _x, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||
podman_ips = [ip for ip in ips]
|
||||
docker_ips = [ip[:-1] + "1" for ip in ips]
|
||||
INTERNAL_IPS = podman_ips + docker_ips + ["127.0.0.1", "localhost"] + ["192.168.65.1"]
|
||||
|
||||
INSTALLED_APPS = [
|
||||
*django_apps,
|
||||
*third_party_apps,
|
||||
*project_apps,
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'django_project.urls'
|
||||
@@ -91,6 +145,8 @@ DATABASES = {
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_USER_MODEL = "user.UserProfile"
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
@@ -130,3 +186,19 @@ MEDIA_ROOT = ENV("MEDIA_ROOT")
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
if ENV("EMAIL_BACKEND") == 'smtp':
|
||||
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||
EMAIL_HOST = ENV("EMAIL_HOST","localhost")
|
||||
EMAIL_PORT = ENV.int("EMAIL_PORT",25)
|
||||
EMAIL_HOST_USER = ENV("EMAIL_HOST_USER","")
|
||||
EMAIL_HOST_PASSWORD = ENV("EMAIL_HOST_PASSWORD","")
|
||||
EMAIL_SSL_KEYFILE = ENV("EMAIL_SSL_KEYFILE",None)
|
||||
EMAIL_SSL_CERTFILE = ENV("EMAIL_SSL_CERTFILE",None)
|
||||
EMAIL_TIMEOUT = ENV("EMAIL_TIMEOUT", 60)
|
||||
else:
|
||||
if ENV("EMAIL_BACKEND") != 'console':
|
||||
print("Email backend not known falling back to console!",file=sys.stderr)
|
||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ from django.contrib import admin
|
||||
from django.urls import path,include
|
||||
from django.conf import settings
|
||||
urlpatterns = [
|
||||
path('',include("tinywiki.urls")),
|
||||
path("user/",include("user.urls")),
|
||||
path('admin/', admin.site.urls),
|
||||
]
|
||||
|
||||
@@ -28,5 +30,5 @@ if settings.DEBUG:
|
||||
*debug_toolbar_urls(),
|
||||
*static(settings.STATIC_URL, document_root=settings.STATIC_ROOT),
|
||||
*static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT),
|
||||
path('__reload__/',include("django_browser_relaod.urls"))
|
||||
path('__reload__/',include("django_browser_reload.urls"))
|
||||
]
|
||||
167
poetry.lock
generated
167
poetry.lock
generated
@@ -80,6 +80,18 @@ files = [
|
||||
[package.extras]
|
||||
visualize = ["Twisted (>=16.1.1)", "graphviz (>0.5.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "bbcode"
|
||||
version = "1.1.0"
|
||||
description = "A pure python bbcode parser and formatter."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "bbcode-1.1.0-py2.py3-none-any.whl", hash = "sha256:83802f4b40c92426841a98350bd6ff9ea8fdf8f9b37df1968a88c5864fd225fa"},
|
||||
{file = "bbcode-1.1.0.tar.gz", hash = "sha256:eac4fb1d0f6c7ce5c41e4b5c0522562b15a1ac036fb9131adc59e9a28c7dc1d0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.8.3"
|
||||
@@ -410,13 +422,13 @@ bcrypt = ["bcrypt"]
|
||||
|
||||
[[package]]
|
||||
name = "django-allauth"
|
||||
version = "65.11.0"
|
||||
version = "65.11.2"
|
||||
description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "django_allauth-65.11.0.tar.gz", hash = "sha256:d08ee0b60a1a54f84720bb749518628c517c9af40b6cfb3bc980206e182745ab"},
|
||||
{file = "django_allauth-65.11.2.tar.gz", hash = "sha256:7b7e771d3384d0e247d0d6aef31b0cb589f92305b7e975e70056a513525906e7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -438,14 +450,14 @@ steam = ["python3-openid (>=3.0.8,<4)"]
|
||||
|
||||
[[package]]
|
||||
name = "django-browser-reload"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
description = "Automatically reload your browser in development."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["dev"]
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "django_browser_reload-1.18.0-py3-none-any.whl", hash = "sha256:ed4cc2fb83c3bf6c30b54107a1a6736c0b896e62e4eba666d81005b9f2ecf6f8"},
|
||||
{file = "django_browser_reload-1.18.0.tar.gz", hash = "sha256:c5f0b134723cbf2a0dc9ae1ee1d38e42db28fe23c74cdee613ba3ef286d04735"},
|
||||
{file = "django_browser_reload-1.19.0-py3-none-any.whl", hash = "sha256:ac67c304654b77811abb4ebfa3802554a4e4b4ab030f8623b21e7b606efea160"},
|
||||
{file = "django_browser_reload-1.19.0.tar.gz", hash = "sha256:034939f770832fde374035e9e4d904c6f990d75598edb777626b5202587315d7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -560,6 +572,22 @@ setuptools = ">=61.0"
|
||||
[package.extras]
|
||||
scripts = ["click (>=6.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "3.9"
|
||||
description = "Python implementation of John Gruber's Markdown."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280"},
|
||||
{file = "markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
|
||||
testing = ["coverage", "pyyaml"]
|
||||
|
||||
[[package]]
|
||||
name = "oauthlib"
|
||||
version = "3.3.1"
|
||||
@@ -577,6 +605,131 @@ rsa = ["cryptography (>=3.0.0)"]
|
||||
signals = ["blinker (>=1.4.0)"]
|
||||
signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "11.3.0"
|
||||
description = "Python Imaging Library (Fork)"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"},
|
||||
{file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"},
|
||||
{file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"},
|
||||
{file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"},
|
||||
{file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"},
|
||||
{file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"},
|
||||
{file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"},
|
||||
{file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"},
|
||||
{file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"},
|
||||
{file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"},
|
||||
{file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"},
|
||||
{file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"]
|
||||
fpx = ["olefile"]
|
||||
mic = ["olefile"]
|
||||
test-arrow = ["pyarrow"]
|
||||
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"]
|
||||
typing = ["typing-extensions ; python_version < \"3.10\""]
|
||||
xmp = ["defusedxml"]
|
||||
|
||||
[[package]]
|
||||
name = "pyasn1"
|
||||
version = "0.6.1"
|
||||
@@ -931,4 +1084,4 @@ testing = ["coverage[toml]", "zope.event", "zope.testing"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.12,<3.14"
|
||||
content-hash = "84268673ea099e0b577d38525faa67b358098040438c30985c376d71c7326fa0"
|
||||
content-hash = "cdc572d2076797697db50f74bfecc2a67620b6a7bcc8eb3a799e816848c0c261"
|
||||
|
||||
@@ -7,10 +7,14 @@ authors = [
|
||||
requires-python = ">=3.12,<3.14"
|
||||
dependencies = [
|
||||
"django (>=5.2.4,<6.0.0)",
|
||||
"django-allauth[saml2,socialaccount,steam] (>=65.11.0,<66.0.0)",
|
||||
"django-extensions (>=4.1,<5.0)",
|
||||
"django-widget-tweaks (>=1.5.0,<2.0.0)",
|
||||
"django-environ (>=0.12.0,<0.13.0)",
|
||||
"django-allauth[socialaccount,steam] (>=65.11.2,<66.0.0)",
|
||||
"django-browser-reload (>=1.19.0,<2.0.0)",
|
||||
"pillow (>=11.3.0,<12.0.0)",
|
||||
"bbcode (>=1.1.0,<2.0.0)",
|
||||
"markdown (>=3.9,<4.0)",
|
||||
]
|
||||
|
||||
[tool.poetry]
|
||||
|
||||
@@ -1,4 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Migrating database ..."
|
||||
poetry run python manage.py migrate
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Unable to migrate database!" >&2
|
||||
exit 5
|
||||
fi
|
||||
|
||||
echo "Running collectstatic ..."
|
||||
yes yes | poetry run python manage.py collectstatic
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Unable to collect static files!" >&2
|
||||
exit 5
|
||||
fi
|
||||
|
||||
if [ -z "$DEBUG" -o $DEBUG != "1" ]; then
|
||||
echo "Starting UWSGI server ..."
|
||||
venv="$(poetry env info | head -n 6 | grep Path | awk '{print $2}')"
|
||||
poetry run uwsgi \
|
||||
--chdir /app \
|
||||
--module django_project.wsgi:application \
|
||||
--master --pidfile /data/run/uwsgi.pid \
|
||||
--http-socket '0.0.0.0:8000' \
|
||||
--socket /data/run/uwsgi.sock \
|
||||
--processes 5 \
|
||||
--harakiri 60 \
|
||||
--max-requests 5000 \
|
||||
--vacuum \
|
||||
--venv "$venv" \
|
||||
--home "$venv"
|
||||
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "UWSGI Server not started" >&2
|
||||
exit $rc
|
||||
fi
|
||||
else
|
||||
echo "Starting development server ..."
|
||||
poetry run python manage.py runserver 0.0.0.0:8000
|
||||
rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
echo "Developemnt server was not started!" >&2
|
||||
exit $rc
|
||||
fi
|
||||
fi
|
||||
|
||||
0
tinywiki/__init__.py
Normal file
0
tinywiki/__init__.py
Normal file
3
tinywiki/admin.py
Normal file
3
tinywiki/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
tinywiki/apps.py
Normal file
6
tinywiki/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class TinywikiConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'tinywiki'
|
||||
42
tinywiki/enums.py
Normal file
42
tinywiki/enums.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from enum import StrEnum
|
||||
from django.utils.translation import gettext,gettext_lazy,gettext_noop as _
|
||||
|
||||
class WikiContentType(StrEnum):
|
||||
MARKDOWN = "markdown"
|
||||
BBCODE = "bbcode"
|
||||
|
||||
@property
|
||||
def str_raw(self)->str:
|
||||
mapping = {
|
||||
WikiContentType.MARKDOWN: _("Markdown"),
|
||||
WikiContentType.BBCODE: _("BBCode")
|
||||
}
|
||||
return mapping[self]
|
||||
|
||||
@staticmethod
|
||||
def from_string(string:str)->"WikiContentType":
|
||||
mapping = {
|
||||
WikiContentType.MARKDOWN.value: WikiContentType.MARKDOWN,
|
||||
WikiContentType.BBCODE.value: WikiContentType.BBCODE,
|
||||
}
|
||||
return mapping[string.lower()]
|
||||
|
||||
@property
|
||||
def str_lazy(self)->str:
|
||||
return gettext_lazy(self.str_raw)
|
||||
|
||||
@property
|
||||
def str(self)->str:
|
||||
return gettext(self.str_raw)
|
||||
|
||||
def __str__(self):
|
||||
return self.str
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__qualname__}: {self.value.upper()}>"
|
||||
|
||||
|
||||
WIKI_CONTENT_TYPES = (
|
||||
WikiContentType.MARKDOWN,
|
||||
WikiContentType.BBCODE,
|
||||
)
|
||||
44
tinywiki/migrations/0001_initial.py
Normal file
44
tinywiki/migrations/0001_initial.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# Generated by Django 5.2.4 on 2025-09-14 13:31
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Image',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.SlugField(max_length=255, verbose_name='slug')),
|
||||
('alt', models.CharField(max_length=511, verbose_name='alternative text')),
|
||||
('description', models.CharField(blank=True, max_length=1023, null=True, verbose_name='description')),
|
||||
('image', models.ImageField(upload_to='tinywiki/img', verbose_name='image file')),
|
||||
('uploaded_at', models.DateTimeField(auto_now_add=True, verbose_name='upladed at')),
|
||||
('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tinywiki_image_uploads', to=settings.AUTH_USER_MODEL, verbose_name='uploaded by')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Page',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.SlugField(max_length=255, unique=True, verbose_name='slug')),
|
||||
('title', models.CharField(max_length=255, verbose_name='title')),
|
||||
('content_type_data', models.CharField(choices=[('markdown', 'Markdown'), ('bbcode', 'BBCode')], default='bbcode', verbose_name='content type')),
|
||||
('content', models.TextField(verbose_name='Page content')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='created at')),
|
||||
('last_edited_at', models.DateTimeField(auto_now=True, verbose_name='last edited at')),
|
||||
('author', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tinywiki_athors', to=settings.AUTH_USER_MODEL, verbose_name='author')),
|
||||
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tinywiki_created', to=settings.AUTH_USER_MODEL, verbose_name='created by')),
|
||||
('last_edited_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='tinywiki_last_edited', to=settings.AUTH_USER_MODEL, verbose_name='last edited by')),
|
||||
],
|
||||
),
|
||||
]
|
||||
26
tinywiki/migrations/0002_initial_data.py
Normal file
26
tinywiki/migrations/0002_initial_data.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.2.4 on 2025-09-14 13:15
|
||||
|
||||
from django.db import migrations
|
||||
from .. import settings
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('tinywiki', '0001_initial'),
|
||||
]
|
||||
|
||||
def init_tinywiki_user(apps,schema_editor):
|
||||
from django.contrib.auth import get_user_model
|
||||
user = get_user_model.objects.create_user(**settings.TINYWIKI_USER_CONFIG)
|
||||
|
||||
def init_default_pages(apps,schema_editor)->None:
|
||||
from ..models import Page,Image
|
||||
#TODO
|
||||
|
||||
def init_user_pages(apps,schema_edit)->None:
|
||||
from ..models import Page,Image
|
||||
#TODO
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(init_tinywiki_user),
|
||||
migrations.RunPython(init_default_pages)
|
||||
]
|
||||
|
||||
0
tinywiki/migrations/__init__.py
Normal file
0
tinywiki/migrations/__init__.py
Normal file
91
tinywiki/models.py
Normal file
91
tinywiki/models.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from tabnanny import verbose
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.utils.safestring import mark_safe,SafeText
|
||||
|
||||
from tinywiki.enums import WIKI_CONTENT_TYPES, WikiContentType
|
||||
import markdown
|
||||
import bbcode
|
||||
|
||||
class Page(models.Model):
|
||||
slug = models.SlugField(_("slug"),
|
||||
max_length=255,
|
||||
null=False,
|
||||
blank=False,
|
||||
unique=True)
|
||||
title = models.CharField(_("title"),
|
||||
max_length=255,
|
||||
null=False,
|
||||
blank=False)
|
||||
author = models.ForeignKey(get_user_model(),
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("author"),
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="tinywiki_athors")
|
||||
content_type_data = models.CharField(_("content type"),
|
||||
choices=[(i.value,i.str_lazy) for i in WIKI_CONTENT_TYPES],
|
||||
default=WikiContentType.BBCODE.value)
|
||||
|
||||
content = models.TextField(_("Page content"),
|
||||
null=False,
|
||||
blank=False)
|
||||
|
||||
|
||||
created_at = models.DateTimeField(_("created at"),
|
||||
auto_now_add=True)
|
||||
created_by = models.ForeignKey(get_user_model(),
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("created by"),
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="tinywiki_created")
|
||||
|
||||
last_edited_at = models.DateTimeField(_("last edited at"),
|
||||
auto_now=True)
|
||||
last_edited_by = models.ForeignKey(get_user_model(),
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("last edited by"),
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="tinywiki_last_edited")
|
||||
|
||||
@property
|
||||
def content_type(self)->WikiContentType:
|
||||
return WikiContentType.from_string(self.content_type_data)
|
||||
|
||||
@property
|
||||
def html_content(self)->SafeText|str:
|
||||
if self.content_type == WikiContentType.MARKDOWN:
|
||||
return mark_safe(markdown.markdown(self.content))
|
||||
elif self.content_type == WikiContentType.BBCODE:
|
||||
return mark_safe(bbcode.render_html(self.content))
|
||||
return self.content
|
||||
|
||||
|
||||
class Image(models.Model):
|
||||
models.ManyToManyField(Page, verbose_name=_(""))
|
||||
slug = models.SlugField(_("slug"),
|
||||
max_length=255)
|
||||
alt = models.CharField(_("alternative text"),
|
||||
max_length=511,
|
||||
null=False,
|
||||
blank=False)
|
||||
description = models.CharField(_("description"),
|
||||
max_length=1023,
|
||||
null=True,
|
||||
blank=True)
|
||||
image = models.ImageField(_("image file"),
|
||||
upload_to="tinywiki/img")
|
||||
|
||||
uploaded_by = models.ForeignKey(get_user_model(),
|
||||
on_delete=models.SET_NULL,
|
||||
verbose_name=_("uploaded by"),
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name="tinywiki_image_uploads")
|
||||
uploaded_at = models.DateTimeField(_("uploaded at"),
|
||||
auto_now_add=True)
|
||||
|
||||
19
tinywiki/settings.py
Normal file
19
tinywiki/settings.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from pathlib import Path
|
||||
from django.conf import settings
|
||||
|
||||
TINYWIKI_USER_CONFIG = getattr(settings,
|
||||
"TINYWIKI_USER_CONFIG",
|
||||
{
|
||||
"username":"TinyWiki",
|
||||
"email":"tinywiki@example.com"
|
||||
})
|
||||
|
||||
TINYWIKI_USER_LOOKUP = getattr(settings,
|
||||
"TINYWIKI_USER_LOOKUP",
|
||||
{'username':"TinyWiki"})
|
||||
|
||||
TINYWIKI_BOOSTRAP_TAGS = {
|
||||
'img': {
|
||||
'class':'img-fluid',
|
||||
}
|
||||
}
|
||||
0
tinywiki/templates/tinywiki/base.html
Normal file
0
tinywiki/templates/tinywiki/base.html
Normal file
3
tinywiki/tests.py
Normal file
3
tinywiki/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
7
tinywiki/urls.py
Normal file
7
tinywiki/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.urls import path
|
||||
|
||||
app_name = "tinywiki"
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
]
|
||||
3
tinywiki/views.py
Normal file
3
tinywiki/views.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
0
user/__init__.py
Normal file
0
user/__init__.py
Normal file
3
user/admin.py
Normal file
3
user/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
user/apps.py
Normal file
6
user/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class UserConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'user'
|
||||
29
user/managers.py
Normal file
29
user/managers.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from django.contrib.auth.models import BaseUserManager
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
class UserProfileManager(BaseUserManager):
|
||||
def create_user(self,username:str, email:str,password=None,**extra_fields):
|
||||
if not email:
|
||||
raise ValueError(_("The email must be set!"))
|
||||
if not username:
|
||||
raise ValueError(_("Username must be set!"))
|
||||
|
||||
email = self.normalize_email(email)
|
||||
user = self.model(username=username,email=email,**extra_fields)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
|
||||
return user
|
||||
|
||||
def create_superuser(self, username:str, email:str, password=None,**extra_fields):
|
||||
extra_fields.setdefault('is_staff',True)
|
||||
extra_fields.setdefault('is_superuser',True)
|
||||
|
||||
if extra_fields.get('is_staff') is not True:
|
||||
raise ValueError(_("Superuser must have is_staff=True"))
|
||||
if extra_fields.get('is_superuser') is not True:
|
||||
raise ValueError(_("Superuser must have is_superuser=True"))
|
||||
|
||||
|
||||
return self.create_user(username,email,password,**extra_fields)
|
||||
|
||||
39
user/migrations/0001_initial.py
Normal file
39
user/migrations/0001_initial.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# Generated by Django 5.2.4 on 2025-09-13 21:38
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
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')),
|
||||
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
||||
('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')),
|
||||
('email', models.EmailField(max_length=255, unique=True, verbose_name='email address')),
|
||||
('username', models.CharField(max_length=63, unique=True, verbose_name='username')),
|
||||
('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,
|
||||
},
|
||||
),
|
||||
]
|
||||
76
user/migrations/0002_default_superuser.py
Normal file
76
user/migrations/0002_default_superuser.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# Generated by Django 5.2.4 on 2025-08-26 05:22
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
def create_debug_superuser(apps,schema_editor):
|
||||
from django.conf import settings
|
||||
from user.models import UserProfile
|
||||
from allauth.account.models import EmailAddress
|
||||
|
||||
if settings.DEBUG and UserProfile.objects.count() == 0:
|
||||
user = UserProfile.objects.create_superuser("debug-admin","debug-admin@example.com","Pa55w.rd")
|
||||
account_emailaddress = EmailAddress.objects.create(user=user,email=user.email,verified=True,primary=True)
|
||||
|
||||
def create_superuser(apps,schema_editor):
|
||||
from django.conf import settings
|
||||
from user.models import UserProfile
|
||||
from allauth.account.models import EmailAddress
|
||||
|
||||
username = settings.ENV.str("SUPERUSER_USERNAME",default="")
|
||||
email = settings.ENV.str("SUPERUSER_EMAIL",default="")
|
||||
password = settings.ENV.str("SUPERUSER_PASSWORD",default="")
|
||||
|
||||
|
||||
if username and email:
|
||||
if not password:
|
||||
password = None
|
||||
user = UserProfile.objects.create_superuser(username,email,password)
|
||||
account_emailaddress = EmailAddress.objects.create(user=user,email=user.email,verified=True,primary=True)
|
||||
|
||||
for i in range(0,100):
|
||||
username = settings.ENV.str(f"SUPERUSER{i:d}_USERNAME",default="")
|
||||
email = settings.ENV.str(f"SUPERUSER{i:d}_EMAIL",default="")
|
||||
password = settings.ENV.str(f"SUPERUSER{i:d}_PASSWORD",default="")
|
||||
if username and email:
|
||||
if not password:
|
||||
password = None
|
||||
user = UserProfile.objects.create_superuser(username,email,password)
|
||||
account_emailaddress = EmailAddress.objects.create(user=user,email=user.email,verified=True,primary=True)
|
||||
|
||||
def create_staffuser(apps,schema_editor):
|
||||
from django.conf import settings
|
||||
from user.models import UserProfile
|
||||
from allauth.account.models import EmailAddress
|
||||
|
||||
username = settings.ENV.str("STAFFUSER_USERNAME",default="")
|
||||
email = settings.ENV.str("STAFFUSER_EMAIL",default="")
|
||||
password = settings.ENV.str("STAFFUSER_PASSWORD",default="")
|
||||
|
||||
|
||||
if username and email:
|
||||
if not password:
|
||||
password = None
|
||||
user = UserProfile.objects.create_user(username,email,password,is_staff=True)
|
||||
account_emailaddress = EmailAddress.objects.create(user=user,email=user.email,verified=True,primary=True)
|
||||
|
||||
for i in range(0,100):
|
||||
username = settings.ENV.str(f"STAFFUSER{i:d}_USERNAME",default="")
|
||||
email = settings.ENV.str(f"STAFFUSER{i:d}_EMAIL",default="")
|
||||
password = settings.ENV.str(f"STAFFUSER{i:d}_PASSWORD",default="")
|
||||
if username and email:
|
||||
if not password:
|
||||
password = None
|
||||
user = UserProfile.objects.create_user(username,email,password,is_staff=True)
|
||||
account_emailaddress = EmailAddress.objects.create(user=user,email=user.email,verified=True,primary=True)
|
||||
|
||||
dependencies = [
|
||||
('user', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(create_superuser),
|
||||
migrations.RunPython(create_debug_superuser),
|
||||
]
|
||||
0
user/migrations/__init__.py
Normal file
0
user/migrations/__init__.py
Normal file
19
user/models.py
Normal file
19
user/models.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.conf import settings
|
||||
from .managers import UserProfileManager
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
class UserProfile(AbstractUser):
|
||||
email = models.EmailField(_("email address"),
|
||||
max_length=255,
|
||||
unique=True)
|
||||
username = models.CharField(_("username"),
|
||||
max_length=63,
|
||||
unique=True)
|
||||
USERNAME_FIELD = 'email'
|
||||
REQUIRED_FIELDS = ['username']
|
||||
|
||||
objects = UserProfileManager()
|
||||
|
||||
3
user/tests.py
Normal file
3
user/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
7
user/urls.py
Normal file
7
user/urls.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.urls import path
|
||||
from .views import *
|
||||
|
||||
app_name = "user"
|
||||
urlpatterns = [
|
||||
|
||||
]
|
||||
3
user/views.py
Normal file
3
user/views.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
Reference in New Issue
Block a user