Initial commit

This commit is contained in:
Pedro Rey Anca 2024-12-02 18:19:54 +01:00
commit 8f112c1bb5
Signed by: peprolinbot
GPG key ID: 053EA6E00116533A
69 changed files with 2068 additions and 0 deletions

266
web/.dockerignore Normal file
View file

@ -0,0 +1,266 @@
# Created by https://www.toptal.com/developers/gitignore/api/python,django
# Edit at https://www.toptal.com/developers/gitignore?templates=python,django
### Django ###
*.log
*.pot
*.pyc
__pycache__/
local_settings.py
db.sqlite3
db.sqlite3-journal
media
# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/
# in your Git repository. Update and uncomment the following line accordingly.
# <django-project-name>/staticfiles/
### Django.Python Stack ###
# Byte-compiled / optimized / DLL files
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
# Django stuff:
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python ###
# Byte-compiled / optimized / DLL files
# C extensions
# Distribution / packaging
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
# Installer logs
# Unit test / coverage reports
# Translations
# Django stuff:
# Flask stuff:
# Scrapy stuff:
# Sphinx documentation
# PyBuilder
# Jupyter Notebook
# IPython
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
# Celery stuff
# SageMath parsed files
# Environments
# Spyder project settings
# Rope project settings
# mkdocs documentation
# mypy
# Pyre type checker
# pytype static type analyzer
# Cython debug symbols
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
# End of https://www.toptal.com/developers/gitignore/api/python,django

22
web/Dockerfile Normal file
View file

@ -0,0 +1,22 @@
FROM python:3.11-alpine
RUN apk update && \
apk add --no-cache nginx supervisor
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
COPY requirements.txt /
RUN pip3 install --no-cache-dir -r /requirements.txt
RUN rm /requirements.txt
COPY . /app
WORKDIR /app
RUN python manage.py collectstatic
COPY nginx.conf /etc/nginx/http.d/default.conf
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
ENV DJANGO_DEBUG=false
EXPOSE 80 8080
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

27
web/README.md Normal file
View file

@ -0,0 +1,27 @@
# caFICtería-aaS (web)
This is the [Django](https://www.djangoproject.com/) web that serves the daily menu data and other functionalities.
## 🔧 Environment Variables
| Name | Description |
|--------------------------|-------------|
| `DJANGO_DEBUG` (bool) | Whether to enable Django's debug mode. Leave it false in production. _(Default: False)_ |
| `DJANGO_ALLOWED_HOSTS` | Space-separated list of host/domain names that Django can serve. Not needed in debug mode (**otherwise is needed**). _(Default: "")_ |
| `DJANGO_SECRET_KEY` | The key to securing signed data. Must be randomly generated and kept secure. _(Default: "django-insecure-(krka)#p79n81tjf-)dy9f1!k^4*j&+qf5_eurt7)o%8%mr1ce")_ |
| `DJANGO_CSRF_TRUSTED_ORIGINS` | Space-separated list of trusted origins for unsafe requests. Not needed in debug mode, and when running on port 80/443. _(Default: "")_ |
| `MENU_HISTORY_FILE_PATH` | The place where the JSON file with the menu history is stored. _(Default: "/tmp/menu_history.json")_ |
_**Note🗒:**_ Booleans are only true when their value is the string "true" (not case sensitive)
_**Tip💡:**_ You can generate a secret key with `openssl rand -hex 32`
_**Tip💡:**_ You can check [Django's documentation](https://docs.djangoproject.com/en/5.1/) to better understand these variables
## 🐳 Building the Docker image
```bash
git clone https://git.peprolinbot.com/peprolinbot/caFICteria-aaS.git
cd caFICteria-aaS/web
docker build -t caficteria-web .
```

View file

View file

@ -0,0 +1,16 @@
"""
ASGI config for caFICteria_aaS project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caFICteria_aaS.settings')
application = get_asgi_application()

View file

@ -0,0 +1,143 @@
"""
Django settings for caFICteria_aaS project.
Generated by 'django-admin startproject' using Django 5.1.3.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY',
'django-insecure-uq7od9!2_9e840883ydo%$))piue&d!xye26=(v^avv_^ny@1(')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv('DJANGO_DEBUG', "true").lower() == "true"
ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', "").split()
# Application definition
INSTALLED_APPS = [
'main',
'daily_menu',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_bootstrap5'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'caFICteria_aaS.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'caFICteria_aaS.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = 'es-ES'
TIME_ZONE = 'Europe/Madrid'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# For HTTPS to work
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
CSRF_TRUSTED_ORIGINS = os.getenv('DJANGO_CSRF_TRUSTED_ORIGINS', "").split()
# Bootstrap5
BOOTSTRAP5 = {
"css_url": f"/{STATIC_URL}main/css/libs/bootstrap.min.css",
"javascript_url": f"/{STATIC_URL}main/js/libs/bootstrap.bundle.min.js"
}
MENU_HISTORY_FILE_PATH = os.getenv(
"MENU_HISTORY_FILE_PATH", "/tmp/menu_history.json")

View file

@ -0,0 +1,25 @@
"""
URL configuration for caFICteria_aaS project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
from main import views as main_views
urlpatterns = [
path('admin/', admin.site.urls),
path('menu/', include("daily_menu.urls")),
path('', main_views.index, name="index"),
]

View file

@ -0,0 +1,16 @@
"""
WSGI config for caFICteria_aaS project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caFICteria_aaS.settings')
application = get_wsgi_application()

View file

6
web/daily_menu/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class DailyMenuConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'daily_menu'

10
web/daily_menu/forms.py Normal file
View file

@ -0,0 +1,10 @@
from django import forms
import datetime
class DateSelectionForm(forms.Form):
def get_current_date_formatted():
return datetime.date.today().strftime("%Y-%m-%d")
date = forms.DateField(required=True, label='Fecha', initial=datetime.date.today, widget=forms.DateInput(attrs={
'class': 'bg-white text-black', 'type': 'date', 'max': get_current_date_formatted})) # type=date for the bootstrap+system datepicker to appear

View file

View file

@ -0,0 +1,52 @@
{% extends 'main/base.html' %}
{% block content %}
<div class="container mt-5">
<h1 class="text-center mb-4">Menú del día 🗓️ {{ date|date:"d/m/Y" }}</h1>
<div class="row">
<div class="col-md-6 mb-4">
<h2>Primero</h2>
<ul class="list-group mb-4">
{% for course in first_courses %}
<li class="list-group-item">{{ course }}</li>
{% endfor %}
</ul>
<h2>Segundo</h2>
<ul class="list-group">
{% for course in second_courses %}
<li class="list-group-item">{{ course }}</li>
{% endfor %}
</ul>
</div>
<div class="col-md-6 mb-4">
<h2>Mensaje original</h2>
<div id="tgMsgDiv" class="border pt-3 px-3 pb-0" style="display: none;">
{{ tg_message|linebreaks }}
</div>
<button id="toggleTgMsgButton" class="btn btn-primary mt-2 mb-4">Mostrar mensaje</button>
<h2>API</h2>
<a href="{{ request.path|add:'/json' }}" target="_blank" class="btn btn-warning mt-2">Ver JSON</a>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#toggleTgMsgButton').click(function () {
var textDiv = $('#tgMsgDiv');
textDiv.toggle();
if (textDiv.is(':visible')) {
$(this).text('Ocultar');
$(this).removeClass('btn-primary');
$(this).addClass('btn-danger');
} else {
$(this).text('Mostrar mensaje');
$(this).removeClass('btn-danger');
$(this).addClass('btn-primary');
}
});
});
</script>
{% endblock %}

3
web/daily_menu/tests.py Normal file
View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

11
web/daily_menu/urls.py Normal file
View file

@ -0,0 +1,11 @@
from django.urls import path
from . import views
app_name = "daily_menu"
urlpatterns = [
path("historic", views.select_menu_form, name="select_menu_form"),
path("<str:date>", views.show_menu, name="show_menu"),
path("<str:date>/json", views.get_menu_json, name="get_menu_json"),
]

15
web/daily_menu/utils.py Normal file
View file

@ -0,0 +1,15 @@
import json
from datetime import datetime
from django.conf import settings
def get_menu(date="today"):
if date == "today":
date = datetime.now()
else:
date = datetime.strptime(date, "%d-%m-%Y")
with open(settings.MENU_HISTORY_FILE_PATH, "r", encoding='utf-8') as f:
menus = json.load(f)
return date, menus[date.strftime("%d-%m-%Y")]

47
web/daily_menu/views.py Normal file
View file

@ -0,0 +1,47 @@
from django.shortcuts import render, redirect
from django.contrib import messages
from django.http import JsonResponse, Http404
from .utils import get_menu
from .forms import DateSelectionForm
def select_menu_form(request):
if request.method == 'POST':
form = DateSelectionForm(request.POST)
if form.is_valid():
return redirect('daily_menu:show_menu', form.cleaned_data['date'].strftime("%d-%m-%Y"))
else:
form = DateSelectionForm()
return render(request, 'main/show_form.html', {'form_header': 'Introduce una fecha para ver el menú', 'form': form})
def show_menu(request, date):
try:
date, menu = get_menu(date)
except KeyError:
if date == "today":
messages.error(
request, "El menú de hoy (aún) no está disponible")
else:
messages.error(
request, "No hay ningún menú ese día")
return redirect('daily_menu:select_menu_form')
courses = menu["courses"]
return render(request, 'daily_menu/show_menu.html', {'date': date,
'first_courses': courses[0],
'second_courses': courses[1],
'tg_message': menu["message"]})
def get_menu_json(request, date):
try:
date, menu = get_menu(date)
except KeyError:
return JsonResponse({"error": "There is no menu for that date"}, status=404)
return JsonResponse(menu)

View file

View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class LazaroQuotesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'lazaro_quotes'

View file

View file

@ -0,0 +1,13 @@
from django.db import models
class Quote(models.Model):
text = models.TextField()
quoted_name = models.CharField(null=True, blank=True, max_length=254)
suggester = models.ForeignKey(
Suggester, on_delete=models.SET_NULL, null=True, blank=True)
class Suggester(models.model):
name = models.CharField(null=True, blank=True, max_length=254)
email = models.CharField(null=True, blank=True, max_length=254)

View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View file

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

0
web/main/__init__.py Normal file
View file

6
web/main/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class MainConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'main'

View file

View file

@ -0,0 +1,15 @@
body {
position: relative;
min-height: 100vh;
}
#content-wrapper {
padding-bottom: 75px;
}
.footer {
position: absolute;
height: 75px;
bottom: 0;
width: 100%;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,27 @@
.bi {
width: 1em;
height: 1em;
fill: currentcolor;
}
.color-modes {
.dropdown-menu {
padding: .25rem;
li+li {
margin-top: .125rem;
}
}
.dropdown-item {
@include border-radius(.25rem);
}
.active {
font-weight: 600;
.bi {
display: block !important; // stylelint-disable-line declaration-no-important
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1080"
height="1080"
viewBox="0 0 1080 1080"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="0.2848069"
inkscape:cx="651.31849"
inkscape:cy="677.65213"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
d="m 1055.6796,496.49715 c -16.5445,-29.2184 -42.5065,-53.92117 -77.93633,-66.34015 -14.953,-5.26117 -30.65539,-7.92267 -46.22257,-8.04627 h -1.04683 c -42.04298,0.008 -80.903,17.1857 -112.2537,43.39497 -31.71765,26.5917 -56.99984,63.18038 -72.28504,106.45174 l -3.86282,10.92794 h 0.28198 c -7.24665,23.70615 -10.81205,47.4123 -11.03995,70.29955 -0.0193,0.73779 -0.0193,1.47559 -0.0193,2.18635 0.0193,35.64615 8.07717,69.44973 24.33967,98.16984 16.54447,29.25317 42.52583,53.95594 77.93635,66.35947 l 2.78896,-7.72565 -2.78896,7.74883 c 14.88733,5.20708 30.5395,7.84925 46.09123,7.99218 h 0.15065 0.197 c 0.18542,-0.0193 0.49831,0 0.88073,0 42.04685,-0.0193 80.8721,-17.17798 112.18803,-43.36408 31.6172,-26.54146 56.8685,-63.01426 72.2,-106.16974 l 0.066,-0.13134 0.1005,-0.28971 c 9.5682,-27.26382 14.2538,-54.71692 14.5551,-81.1116 v -2.08592 c 0,-35.68092 -8.054,-69.50381 -24.3203,-98.26641 z M 801.56367,653.86478 c 0.1661,-20.50002 3.84352,-42.25544 11.48805,-63.8834 l 0.0193,-0.0695 0.0502,-0.13905 0.0348,-0.0618 c 12.10223,-34.53752 32.2121,-62.57776 54.19545,-80.93005 21.76701,-18.22866 44.44566,-26.39468 62.6975,-26.36763 h 0.8112 c 7.06511,0.0888 13.60873,1.17815 20.39185,3.54607 15.69853,5.45431 30.28841,17.57199 41.31291,36.92861 10.66147,18.6922 17.20887,43.71945 17.17417,71.25753 v 2.0782 c -0.1661,20.39185 -3.8474,42.08934 -11.42242,63.71343 l -0.0155,0.0657 -0.10048,0.23563 -0.0502,0.15065 c -12.10224,34.49117 -32.2121,62.52755 -54.19544,80.82962 -21.76701,18.2364 -44.48043,26.42558 -62.68593,26.39855 h -0.89231 c -6.96467,-0.0812 -13.56237,-1.20135 -20.4073,-3.53835 -15.6174,-5.435 -30.20729,-17.59132 -41.2318,-36.90543 -10.69615,-18.75789 -17.22434,-43.81603 -17.20889,-71.38502 v -1.88891 l -8.28961,-0.11585 z"
fill="#231f20"
id="path1"
style="fill:#006e77;fill-opacity:1;stroke-width:3.86283" />
<path
d="m 893.5723,714.22142 c 35.95904,-93.59239 43.86625,-195.77956 43.89715,-315.97522 0,-5.77107 -2.38336,-11.4301 -6.56295,-15.4938 -4.17571,-4.12163 -9.912,-6.46637 -15.81826,-6.46637 H 103.54733 c -5.925575,0 -11.685046,2.34474 -15.841446,6.42389 -4.195028,4.10231 -6.566803,9.76521 -6.566803,15.53241 0.02318,120.58582 10.927931,227.49336 48.308489,323.25279 18.26344,46.90242 43.03187,90.89227 75.60707,132.05067 h 606.84982 c 36.39168,-44.43793 62.88293,-90.4944 81.63694,-139.32437 z"
fill="#231f20"
id="path2"
style="fill:#006e77;fill-opacity:1;stroke-width:3.86283" />
<path
d="m 1020.3888,894.30632 c -3.3799,-8.28575 -11.6386,-13.76325 -20.77422,-13.76325 H 22.397101 c -9.062188,0 -17.2397885,5.33843 -20.6738399,13.55466 -3.488131,8.19692 -1.58375824,17.63766 4.8323941,23.9302 38.7518598,37.63167 59.2286958,71.38117 100.2441748,100.74627 41.16613,29.0949 98.66041,48.7992 206.18214,61.0597 L 315.5662,1080 h 390.87927 l 3.21774,-0.2318 c 105.65598,-15.0225 161.87168,-34.6881 202.77127,-62.8365 40.80302,-28.4303 62.08719,-60.7352 102.68932,-98.59088 6.5861,-6.19983 8.6721,-15.74102 5.2573,-24.0345 z"
fill="#231f20"
id="path3"
style="fill:#006e77;fill-opacity:1;stroke-width:3.86283" />
<path
d="m 417.76886,345.21808 c -28.68788,-33.20459 -41.81228,-63.21706 -41.81228,-91.57167 0.071,-30.01974 14.58503,-53.42618 29.38276,-72.37168 14.99271,-19.06909 31.06318,-35.45143 40.22402,-50.87758 6.16158,-10.32168 9.33455,-19.41086 9.36646,-29.31079 0.0532,-14.626305 -7.36696,-35.567771 -36.46609,-66.143773 -7.84911,-8.223882 -7.57613,-21.323212 0.60977,-29.187166 8.20718,-7.8930467 21.21811,-7.6458248 29.07786,0.607152 32.79679,34.320739 47.83915,65.067614 47.89942,94.723787 -0.0993,29.4453 -14.77292,52.20097 -29.4643,70.80106 -14.92535,18.77098 -30.86464,35.12424 -40.01838,50.92486 -6.19351,10.5798 -9.45511,20.14888 -9.47992,30.83049 -0.007,14.97898 6.69338,35.38964 31.76869,64.52228 7.41658,8.65289 6.47356,21.68314 -2.12358,29.13989 -3.87848,3.38845 -8.6468,5.05724 -13.42574,5.05724 -5.7468,0.003 -11.47587,-2.42501 -15.53869,-7.1441 z"
fill="#999"
id="path4"
style="fill:#f29111;fill-opacity:1;stroke-width:3.59016" />
<path
d="m 510.14301,345.23877 c -28.70562,-33.23003 -41.79809,-63.2425 -41.80518,-91.59347 0.0674,-30.03064 14.58501,-53.41165 29.35084,-72.36441 14.99271,-19.07637 31.06318,-35.42962 40.2382,-50.88484 6.17931,-10.30715 9.31683,-19.38904 9.34164,-29.30352 0.0815,-14.637211 -7.35632,-35.538696 -36.43418,-66.114695 -7.84912,-8.2457 -7.57612,-21.359572 0.62396,-29.2271632 8.19299,-7.8966743 21.20038,-7.6312724 29.07077,0.614428 32.7897,34.3134732 47.80369,65.0748932 47.86041,94.7237802 -0.0815,29.4744 -14.75164,52.17189 -29.43592,70.81926 -14.936,18.74915 -30.87174,35.10241 -40.03968,50.90667 -6.16867,10.57254 -9.46218,20.14526 -9.46218,30.82686 -0.0248,14.97169 6.7111,35.38963 31.75451,64.55135 7.44141,8.62018 6.49837,21.67951 -2.06687,29.13992 -3.8891,3.3957 -8.67514,5.04993 -13.45056,5.04993 -5.75388,0.003 -11.49712,-2.42135 -15.54576,-7.1441 z"
fill="#999"
id="path5"
style="fill:#f29111;fill-opacity:1;stroke-width:3.59016" />
<path
d="m 611.73117,345.21697 c -28.66661,-33.17915 -41.77682,-63.18798 -41.77682,-91.53167 0.0248,-30.0452 14.57083,-53.45165 29.35084,-72.40441 14.98918,-19.05818 31.0809,-35.42962 40.2382,-50.88484 6.16159,-10.29987 9.3381,-19.38904 9.35938,-29.30352 0.0567,-14.615403 -7.35633,-35.538696 -36.48028,-66.114695 -7.82784,-8.2457 -7.55485,-21.359572 0.63459,-29.2271632 8.18591,-7.8966743 21.18976,-7.6312724 29.07432,0.614428 32.76842,34.3134732 47.83914,65.0748932 47.87106,94.7237802 -0.0922,29.4744 -14.74457,52.17189 -29.43594,70.81926 -14.936,18.74915 -30.87174,35.12421 -40.04675,50.93939 -6.16159,10.56526 -9.45156,20.11254 -9.47282,30.83413 0,14.9317 6.71818,35.34964 31.76867,64.515 7.44142,8.62018 6.49839,21.6795 -2.0775,29.1399 -3.89618,3.39571 -8.67868,5.02451 -13.44345,5.02451 -5.75388,0.003 -11.51841,-2.39955 -15.5635,-7.1441 z"
fill="#999"
id="path6"
style="fill:#f29111;fill-opacity:1;stroke-width:3.59016" />
<text
xml:space="preserve"
style="font-weight:bold;font-size:467.286px;font-family:'Ubuntu Nerd Font';-inkscape-font-specification:'Ubuntu Nerd Font Bold';fill:#ffffff;fill-opacity:1;stroke-width:5.47605"
x="258.03479"
y="791.28717"
id="text6"><tspan
sodipodi:role="line"
x="258.03479"
y="791.28717"
id="tspan7"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'Ubuntu Nerd Font';-inkscape-font-specification:'Ubuntu Nerd Font';fill:#ffffff;fill-opacity:1;stroke-width:5.47605"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto;fill:#ffffff;fill-opacity:1;stroke-width:5.47605"
id="tspan8">f</tspan>ic</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.9 KiB

View file

@ -0,0 +1,62 @@
/*!
* Color mode toggler for Bootstrap's docs (https://getbootstrap.com/)
* Copyright 2011-2022 The Bootstrap Authors
* Licensed under the Creative Commons Attribution 3.0 Unported License.
*/
(() => {
'use strict'
const storedTheme = localStorage.getItem('theme')
const getPreferredTheme = () => {
if (storedTheme) {
return storedTheme
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
}
const setTheme = function (theme) {
if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-bs-theme', 'dark')
} else {
document.documentElement.setAttribute('data-bs-theme', theme)
}
}
setTheme(getPreferredTheme())
const showActiveTheme = theme => {
const activeThemeIcon = document.querySelector('.theme-icon-active use')
const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`)
const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href')
document.querySelectorAll('[data-bs-theme-value]').forEach(element => {
element.classList.remove('active')
})
btnToActive.classList.add('active')
activeThemeIcon.setAttribute('href', svgOfActiveBtn)
}
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (storedTheme !== 'light' || storedTheme !== 'dark') {
setTheme(getPreferredTheme())
}
})
window.addEventListener('load', () => {
showActiveTheme(getPreferredTheme())
document.querySelectorAll('[data-bs-theme-value]')
.forEach(toggle => {
toggle.addEventListener('click', () => {
const theme = toggle.getAttribute('data-bs-theme-value')
localStorage.setItem('theme', theme)
setTheme(theme)
showActiveTheme(theme)
})
})
})
})()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
{% extends 'main/base.html' %}
{% load django_bootstrap5 %}
{% load static %}
{% block content %}
<div class="container text-center mt-5">
<div style="font-size: 8rem;"">😕</div>
<h1>Oops! 404</h1>
<p>No hemos encontrado la página que buscabas.</p>
<a class=" btn btn-primary" href="/">Volver al Inicio</a>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,13 @@
{% extends 'main/base.html' %}
{% load django_bootstrap5 %}
{% load static %}
{% block content %}
<div class="container text-center mt-5">
<div style="font-size: 8rem;"">🤔</div>
<h1>Oops! 500</h1>
<p>El servidor ha tenido problemas procesando tu petición.</p>
<a class=" btn btn-primary" href="/">Volver al Inicio</a>
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,120 @@
{% load static %}
<!-- Bootstrap icons-->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="bootstrap" viewBox="0 0 512 408" fill="currentcolor">
<path
d="M106.342 0c-29.214 0-50.827 25.58-49.86 53.32.927 26.647-.278 61.165-8.966 89.31C38.802 170.862 24.07 188.707 0 191v26c24.069 2.293 38.802 20.138 47.516 48.37 8.688 28.145 9.893 62.663 8.965 89.311C55.515 382.42 77.128 408 106.342 408h299.353c29.214 0 50.827-25.58 49.861-53.319-.928-26.648.277-61.166 8.964-89.311 8.715-28.232 23.411-46.077 47.48-48.37v-26c-24.069-2.293-38.765-20.138-47.48-48.37-8.687-28.145-9.892-62.663-8.964-89.31C456.522 25.58 434.909 0 405.695 0H106.342zm236.559 251.102c0 38.197-28.501 61.355-75.798 61.355h-87.202a2 2 0 01-2-2v-213a2 2 0 012-2h86.74c39.439 0 65.322 21.354 65.322 54.138 0 23.008-17.409 43.61-39.594 47.219v1.203c30.196 3.309 50.532 24.212 50.532 53.085zm-84.58-128.125h-45.91v64.814h38.669c29.888 0 46.373-12.03 46.373-33.535 0-20.151-14.174-31.279-39.132-31.279zm-45.91 90.53v71.431h47.605c31.12 0 47.605-12.482 47.605-35.941 0-23.46-16.947-35.49-49.608-35.49h-45.602z" />
</symbol>
<symbol id="check2" viewBox="0 0 16 16">
<path
d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z" />
</symbol>
<symbol id="circle-half" viewBox="0 0 16 16">
<path d="M8 15A7 7 0 1 0 8 1v14zm0 1A8 8 0 1 1 8 0a8 8 0 0 1 0 16z" />
</symbol>
<symbol id="moon-stars-fill" viewBox="0 0 16 16">
<path
d="M6 .278a.768.768 0 0 1 .08.858 7.208 7.208 0 0 0-.878 3.46c0 4.021 3.278 7.277 7.318 7.277.527 0 1.04-.055 1.533-.16a.787.787 0 0 1 .81.316.733.733 0 0 1-.031.893A8.349 8.349 0 0 1 8.344 16C3.734 16 0 12.286 0 7.71 0 4.266 2.114 1.312 5.124.06A.752.752 0 0 1 6 .278z" />
<path
d="M10.794 3.148a.217.217 0 0 1 .412 0l.387 1.162c.173.518.579.924 1.097 1.097l1.162.387a.217.217 0 0 1 0 .412l-1.162.387a1.734 1.734 0 0 0-1.097 1.097l-.387 1.162a.217.217 0 0 1-.412 0l-.387-1.162A1.734 1.734 0 0 0 9.31 6.593l-1.162-.387a.217.217 0 0 1 0-.412l1.162-.387a1.734 1.734 0 0 0 1.097-1.097l.387-1.162zM13.863.099a.145.145 0 0 1 .274 0l.258.774c.115.346.386.617.732.732l.774.258a.145.145 0 0 1 0 .274l-.774.258a1.156 1.156 0 0 0-.732.732l-.258.774a.145.145 0 0 1-.274 0l-.258-.774a1.156 1.156 0 0 0-.732-.732l-.774-.258a.145.145 0 0 1 0-.274l.774-.258c.346-.115.617-.386.732-.732L13.863.1z" />
</symbol>
<symbol id="sun-fill" viewBox="0 0 16 16">
<path
d="M8 12a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM8 0a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 0zm0 13a.5.5 0 0 1 .5.5v2a.5.5 0 0 1-1 0v-2A.5.5 0 0 1 8 13zm8-5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2a.5.5 0 0 1 .5.5zM3 8a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1 0-1h2A.5.5 0 0 1 3 8zm10.657-5.657a.5.5 0 0 1 0 .707l-1.414 1.415a.5.5 0 1 1-.707-.708l1.414-1.414a.5.5 0 0 1 .707 0zm-9.193 9.193a.5.5 0 0 1 0 .707L3.05 13.657a.5.5 0 0 1-.707-.707l1.414-1.414a.5.5 0 0 1 .707 0zm9.193 2.121a.5.5 0 0 1-.707 0l-1.414-1.414a.5.5 0 0 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .707zM4.464 4.465a.5.5 0 0 1-.707 0L2.343 3.05a.5.5 0 1 1 .707-.707l1.414 1.414a.5.5 0 0 1 0 .708z" />
</symbol>
</svg>
<link href="{% static 'main/css/navbar.css' %}" rel="stylesheet">
<script src="{% static 'main/js/color-modes.js' %}"></script>
<nav class="navbar navbar-expand-lg border-bottom">
<div class="container-fluid">
<a href="/" class="navbar-brand">
<img class="d-inline-block align-text-center me-2" src="{% static 'main/img/logo.svg' %}" width="40"
height="40" alt="GaliBus logo">
caFICtería-aaS
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<div class="dropdown nav-item">
<a class="nav-link dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"
aria-haspopup="true">Menú
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item nav-link"
href="{% url 'daily_menu:show_menu' date='today' %}">Hoy</a></li>
<li><a class="dropdown-item nav-link"
href="{% url 'daily_menu:select_menu_form' %}">Histórico</a></li>
</ul>
</div>
<div class="dropdown nav-item">
<a class="nav-link dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"
aria-haspopup="true">Lázaro-aaS
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item nav-link" href="">Ver frases</a></li>
<li><a class="dropdown-item nav-link" href="">Sugerir frases</a></li>
</ul>
</div>
<!-- Theme selector -->
<li class="nav-item dropdown">
<button class="btn btn-link px-0 text-decoration-none dropdown-toggle d-flex align-items-center"
id="bd-theme" type="button" aria-expanded="false" data-bs-toggle="dropdown"
data-bs-display="static">
<svg class="bi my-1 me-2 theme-icon-active">
<use href="#circle-half"></use>
</svg>
Toggle theme
</button>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-theme"
style="--bs-dropdown-min-width: 8rem;">
<li>
<button type="button" class="dropdown-item d-flex align-items-center"
data-bs-theme-value="light">
<svg class="bi me-2 opacity-50 theme-icon">
<use href="#sun-fill"></use>
</svg>
Light
<svg class="bi ms-auto d-none">
<use href="#check2"></use>
</svg>
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center"
data-bs-theme-value="dark">
<svg class="bi me-2 opacity-50 theme-icon">
<use href="#moon-stars-fill"></use>
</svg>
Dark
<svg class="bi ms-auto d-none">
<use href="#check2"></use>
</svg>
</button>
</li>
<li>
<button type="button" class="dropdown-item d-flex align-items-center active"
data-bs-theme-value="auto">
<svg class="bi me-2 opacity-50 theme-icon">
<use href="#circle-half"></use>
</svg>
Auto
<svg class="bi ms-auto d-none">
<use href="#check2"></use>
</svg>
</button>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>

View file

@ -0,0 +1,111 @@
{% load static %}
<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
<head>
<meta charset="utf-8">
<meta content='maximum-scale=1.0, initial-scale=1.0, width=device-width' name='viewport'>
<meta name="description"
content="Página para consultar el menú del día de la fic, frases de nuestro querido camarero Lázaro, y otras funcionalidades">
<meta name="author" content="peprolinbot">
<!-- Favicon -->
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'main/img/favicon/apple-touch-icon.png' %}">
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'main/img/favicon/favicon-32x32.png' %}">
<link rel="icon" type="image/png" sizes="16x16" href="{% static 'main/img/favicon/favicon-16x16.png' %}">
<link rel="manifest" href="{% static 'main/img/favicon/site.webmanifest' %}">
<title>{% block title %}caFICtería-aaS{% endblock %}</title>
<!-- CSS stuff
================================================== -->
<!-- Bootstrap -->
{% load django_bootstrap5 %}
{% bootstrap_css %}
<!-- Select2 -->
<link href="{% static 'main/css/libs/select2.min.css' %}" rel="stylesheet">
<link href="{% static 'main/css/libs/select2-bootstrap-5-theme.min.css' %}" rel="stylesheet">
<!-- Custom CSS -->
<link href="{% static 'main/css/base.css' %}" rel="stylesheet">
{% block css %}{% endblock %}
<!-- JavaScript stuff
================================================== -->
<!-- jQuery -->
<script src="{% static 'main/js/libs/jquery.min.js' %}"></script>
<!-- Bootstrap -->
{% bootstrap_javascript %}
<!-- Select2 -->
<script src="{% static 'main/js/libs/select2.min.js' %}"></script>
<!-- Popper -->
<script src="{% static 'main/js/libs/popper.min.js' %}"></script>
<!-- Custom JS -->
{% block js %}{% endblock %}
</head>
<body>
{% block navbar %}
{% include 'main/_items/navbar.html' %}
{% endblock %}
<div id="content-wrapper" class="container-fluid">
<div id="bootstrapMessagesDiv" class="px-2 pt-3">{% bootstrap_messages %}</div>
{% block content %}{% endblock %}
</div>
<footer class="footer text-center">
<hr class="mx-5">
<p>Hecho con ❤️ por <b>peprolinbot</b> - <a href="https://git.peprolinbot.com/peprolinbot/caFICteria-aaS"
target="_blank">Código fuente</a>
</p>
</footer>
<!-- Enable popovers -->
<script>
jQuery(document).ready(function ($) {
const popoverTriggerList = $('[data-bs-toggle="popover"]').toArray()
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))
// For django alerts to not take space
function checkIfAlertsEmpty() {
if ($.trim($('#bootstrapMessagesDiv').text()) === '') { // Check if the div is empty
$('#bootstrapMessagesDiv').css('display', 'none'); // Set height to 0 if empty
}
}
// Intial check
checkIfAlertsEmpty();
const alertsDivObserver = new MutationObserver(checkIfAlertsEmpty);
// Start observing the target node for configured mutations
alertsDivObserver.observe($('#bootstrapMessagesDiv')[0], {
childList: true, // Observe direct children
subtree: true // Observe all descendants
});
});
// Hide popovers when you open another one
$('[data-bs-toggle="popover"]').click(function () {
$('[data-bs-toggle="popover"]').not(this).popover('hide'); //all but this
});
</script>
</body>
</html>

View file

@ -0,0 +1,14 @@
{% extends 'main/base.html' %}
{% load django_bootstrap5 %}
{% load static %}
{% block content %}
<div class="container col-md-6 mt-5">
<h1 class="text-center">{{ form_header }}</h1>
<form action="" method="post">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="Enviar" extra_classes="w-100 mt-3" %}
</form>
</div>
{% endblock %}

5
web/main/views.py Normal file
View file

@ -0,0 +1,5 @@
from django.shortcuts import redirect
def index(request):
return redirect('daily_menu:show_menu', "today")

22
web/manage.py Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'caFICteria_aaS.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

15
web/nginx.conf Normal file
View file

@ -0,0 +1,15 @@
server {
listen 80;
location /static {
alias /app/staticfiles;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

3
web/requirements.txt Normal file
View file

@ -0,0 +1,3 @@
Django==5.1.3
django-bootstrap5==24.3
gunicorn==23.0.0

21
web/supervisord.conf Normal file
View file

@ -0,0 +1,21 @@
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
[program:nginx]
command=nginx -g "daemon off;"
autostart=true
autorestart=true
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
[program:gunicorn]
command=gunicorn --preload --bind 0.0.0.0:8000 caFICteria_aaS.wsgi
directory=/app
autostart=true
autorestart=true
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true