From ea08f337d7e00c02f4c07952bf89e8bd90353712 Mon Sep 17 00:00:00 2001 From: Junwei Zhao Date: Mon, 4 Nov 2024 15:20:18 +1100 Subject: [PATCH] Add logic to display thumbnails --- Dockerfile.worker | 23 +++ README.md | 31 ++++ celery_beat.sh | 2 +- celerybeat-schedule | Bin 16384 -> 16384 bytes {url_manager => core}/celery.py | 4 +- {url_manager => core}/middleware.py | 0 {url_manager => core}/settings.py | 15 +- {url_manager => core}/tailwind.config.js | 0 {url_manager => core}/urls.py | 8 +- {url_manager => core}/wsgi.py | 2 +- data/db.sqlite3 | Bin 204800 -> 204800 bytes docker-compose.yml | 27 ++-- init.sh | 3 + links/migrations/0012_page_screenshot_path.py | 18 +++ links/models.py | 12 +- links/page_views.py | 60 ++++++-- links/tasks.py | 48 +++++- links/templates/links/page_detail.html | 18 +++ links/templates/links/page_form.html | 82 +++++++---- links/templates/links/page_list.html | 139 +++++++++++------- links/urls.py | 3 +- locale/en/LC_MESSAGES/django.po | 55 +------ locale/zh_Hans/LC_MESSAGES/django.po | 57 +------ manage-docker.sh | 6 +- manage.py | 2 +- requirements.txt | 1 + worker.sh | 2 +- 27 files changed, 388 insertions(+), 230 deletions(-) create mode 100644 Dockerfile.worker rename {url_manager => core}/celery.py (56%) rename {url_manager => core}/middleware.py (100%) rename {url_manager => core}/settings.py (93%) rename {url_manager => core}/tailwind.config.js (100%) rename {url_manager => core}/urls.py (80%) rename {url_manager => core}/wsgi.py (57%) create mode 100644 init.sh create mode 100644 links/migrations/0012_page_screenshot_path.py diff --git a/Dockerfile.worker b/Dockerfile.worker new file mode 100644 index 0000000..2e93377 --- /dev/null +++ b/Dockerfile.worker @@ -0,0 +1,23 @@ +FROM python:3.12-slim + +# Install Chrome and dependencies +RUN apt-get update && apt-get install -y \ + wget \ + gnupg \ + chromium \ + chromium-driver \ + && rm -rf /var/lib/apt/lists/* + +# Set environment variables +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 + +# Set work directory +WORKDIR /app + +# Install Python dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy project +COPY . . diff --git a/README.md b/README.md index 54772c9..b482471 100644 --- a/README.md +++ b/README.md @@ -180,3 +180,34 @@ Flower provides: - Runtime - Result - Stack traces for failed tasks + + +## Why we have `core` folder and what it is? + +The core folder is the Django project's root configuration directory, created when you first run django-admin startproject core. It serves several essential purposes: +Project-wide settings (settings.py): +Database configuration +Installed apps +Middleware +Static/media files settings +Other global settings +Root URL configuration (urls.py): +Main URL routing +Admin site URLs +Including app-specific URLs +3. WSGI/ASGI configuration: +For production deployment +Server integration +Celery configuration (celery.py): +Project-wide Celery settings +Task discovery +We can't completely remove it because Django requires this project-level configuration. The links folder is an app within the project, and you could have multiple apps in one project. +Think of it this way: +core/ = Project configuration (can contain multiple apps) +links/ = One specific app's code +This separation allows you to: +1. Have multiple apps in one project +Reuse apps across different projects +Keep project-wide settings separate from app-specific code +If you want to simplify, you could rename core to something shorter like config or core, but you can't eliminate it entirely as it's a fundamental part of Django's project structure. +Would you like me to show you how to rename it to something shorter and cleaner? diff --git a/celery_beat.sh b/celery_beat.sh index fcb4c02..ec500db 100755 --- a/celery_beat.sh +++ b/celery_beat.sh @@ -2,4 +2,4 @@ set -eu source 3.12/bin/activate echo "Starting Django development server..." -celery -A url_manager beat -l info +celery -A core beat -l info diff --git a/celerybeat-schedule b/celerybeat-schedule index c3f159d9add3334ddad4b7344449342e3e418350..36b459f5c4863b2f394ba03a115442e65417109b 100644 GIT binary patch delta 27 icmZo@U~Fh$+@NN}#v*9R_9(LQUkj!__^#O6AqCSCw;TL;Gg diff --git a/url_manager/celery.py b/core/celery.py similarity index 56% rename from url_manager/celery.py rename to core/celery.py index d6a0c58..1e3d331 100644 --- a/url_manager/celery.py +++ b/core/celery.py @@ -1,8 +1,8 @@ import os from celery import Celery -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'url_manager.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') -app = Celery('url_manager') +app = Celery('core') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() diff --git a/url_manager/middleware.py b/core/middleware.py similarity index 100% rename from url_manager/middleware.py rename to core/middleware.py diff --git a/url_manager/settings.py b/core/settings.py similarity index 93% rename from url_manager/settings.py rename to core/settings.py index 715b446..0f38c4e 100644 --- a/url_manager/settings.py +++ b/core/settings.py @@ -22,12 +22,12 @@ INSTALLED_APPS = [ 'markdown', # 只需要基本的markdown包 ] -ROOT_URLCONF = 'url_manager.urls' +ROOT_URLCONF = 'core.urls' MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', - 'url_manager.middleware.CustomLocaleMiddleware', # 替换原来的 LocaleMiddleware + 'core.middleware.CustomLocaleMiddleware', # 替换原来的 LocaleMiddleware 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -97,7 +97,7 @@ USE_TZ = True # ... 其他设置 ... -ROOT_URLCONF = 'url_manager.urls' +ROOT_URLCONF = 'core.urls' # ... 其他设置 ... @@ -176,7 +176,7 @@ LOCALE_INDEPENDENT_PATHS = [ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', - 'url_manager.middleware.CustomLocaleMiddleware', # 使用自定义中间件 + 'core.middleware.CustomLocaleMiddleware', # 使用自定义中间件 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -212,3 +212,10 @@ CELERY_BEAT_SCHEDULE = { 'schedule': 60.0, # 每60秒运行一次 }, } + +# Media files configuration +MEDIA_URL = '/media/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'media') + +# Ensure media files are served in all environments +SERVE_MEDIA = True diff --git a/url_manager/tailwind.config.js b/core/tailwind.config.js similarity index 100% rename from url_manager/tailwind.config.js rename to core/tailwind.config.js diff --git a/url_manager/urls.py b/core/urls.py similarity index 80% rename from url_manager/urls.py rename to core/urls.py index 8705d68..6cb7a12 100644 --- a/url_manager/urls.py +++ b/core/urls.py @@ -1,9 +1,10 @@ from django.contrib import admin -from django.urls import path, include +from django.urls import path, include, re_path from django.conf.urls.i18n import i18n_patterns from django.conf import settings from django.conf.urls.static import static from links.views import LinkDetailView, LinkUpdateView, CustomLinkView +from django.views.static import serve urlpatterns = [ path('i18n/', include('django.conf.urls.i18n')), @@ -11,8 +12,11 @@ urlpatterns = [ path('link//', LinkDetailView.as_view(), name='link_detail'), path('link//edit/', LinkUpdateView.as_view(), name='link_update'), path('custom//', CustomLinkView.as_view(), name='custom_link'), + # Serve media files directly + re_path(r'^media/(?P.*)$', serve, { + 'document_root': settings.MEDIA_ROOT, + }), ] - urlpatterns += i18n_patterns( path('admin/', admin.site.urls), path('', include('links.urls')), diff --git a/url_manager/wsgi.py b/core/wsgi.py similarity index 57% rename from url_manager/wsgi.py rename to core/wsgi.py index 2800bf9..4157369 100644 --- a/url_manager/wsgi.py +++ b/core/wsgi.py @@ -1,6 +1,6 @@ import os from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'url_manager.settings') +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings') application = get_wsgi_application() diff --git a/data/db.sqlite3 b/data/db.sqlite3 index 72f7ca27a87993eaf7392cb2bb0ff2bc262a9339..9d4ba2e09eae53a2fdaf4105c1bbb07c0721d72c 100644 GIT binary patch delta 1435 zcmZvc&u<$=6vua+q;?wrN(IEIQka0+19H~u^{>PQHLfa>NVJf;Z4^WaOKMdj_rPU5PTXJ=>U``*0$yti-n zX>|8#^qY&bj}=8Ra9qMMg@f*=bL!(?KL0r}F(0WNgp*f7k=m1u zyDg#XS!3IyP1qJD2XKYOB(9}p=th1qn_blNM9-D+pI_FDC8L-#p8S;h@{L4lVnGc& z1lAW0mNI{+^L_nDSN}=HBF~j`VONPqqR(cI&g)@!dg9#cVHc18Z)!5~T;0OEJL+tI zD;Za=yt&6>l}b!`D-t_=7MqystuoehV6{zcXT6P~iK^XniS1SaNSkrE4i3oS^%i)H zOWdTM$C<}%DuH+$>b5Cu=88&3NKPG_R%)yxEA{)pr7di?d98z25MqsWNfjtJEz)JY zB|hdo`#v>yZUb+NDoBZ1oCARvF3}BjO{fzQJl|p+PU=)r3}fhPXkghwGQKlff#X%d zt&;{oy++N}b;?^rTF{0v`KZwtA}M>hc z-rq0u`tQ!hl}e|d89}wA^h7z6>2|vs9)>_QG}34%^C7|#l3XU&IM5cpD7gt;L2iJ9 zu(%6pau+c&gi034Z3{@H3B!q4RQRD2=h%nCOzIF9x;;Ud`zjY2xdpUNZc;xls11&4 zaMmU#IZBgF#vRmP6lpTb(6N#txA8E2v^EIsESr3}m(|M!Ln{`HrK~=_HQLGNma-?< z`XUxrO0B&+FXIv()`wOHfyI|OyFeDf65mH4CKCklgIjkSjJIjee?4tXZws>Hmq^3r zNZZ%eeC)@@1g!{l9Ksp_Py5)7@5Q(JYxg^jkQocogIbMz;4^E23s~1gGS4Fetmh8Gga;m&(pNNWJlX<|c^!+-Po<54IgUm)fmqCgz&_BQc%vA{alQM6 zf{`qorHd`1R4$Y>y=>%{ONCc%mGUKH=@fh_nou5HyzyvrM1Jter=jy|;?hh^DQ&Ng zo*wdhp>HP>RQd5>Bl-Po|L$~L>2CHV!kS1@x)HV+{Ts1X_wnG2@`afIS!ixX^ delta 630 zcmZoTz|(MmXM(g~Jp%)S5fG~aF)I+qP1G@FtlyZhgr8ZKW8q|W0qf0*3h^A97fN)9 z@ryGnGUjCFWf#X6B&MhGOt#QJ&M4btu*`t*!*<31rvLog|LZeJ2rw#dmvCTu!7s+k z-ORws^^}3@Dc=e{F5YAwPcD1TnLq>EI2o5s4is1lCKuH=O0)4WSenN2Iy&+)$a7?r zloS+O>Fbx5m+KX01F2Y2ZLD(!KsNw$r%c+dFh#XsVE$UwEQB4l8jUZ&%Bb< zqP)}+h5R&ykc`Z{^kO3eBNJUiLtO(C1p@;s0~0GlV?9eF19NjDkc=`+%FxQt#LCD( z&&a~e*wi99Ker$!wInqK7%aztu015!B+kRf&?xQO7!Gym_8r @@ -108,6 +109,23 @@ {% endif %} + + +
+

{% trans "Screenshot" %}

+
+ {% if page.screenshot_path %} + Page screenshot + {% else %} + Default screenshot + {% endif %} +
+
diff --git a/links/templates/links/page_form.html b/links/templates/links/page_form.html index d0e87ce..05fea62 100644 --- a/links/templates/links/page_form.html +++ b/links/templates/links/page_form.html @@ -3,14 +3,32 @@ {% block extra_css %}