diff --git a/bfportal/bfportal/settings/base.py b/bfportal/bfportal/settings/base.py index 41e6f4c..263a3c5 100644 --- a/bfportal/bfportal/settings/base.py +++ b/bfportal/bfportal/settings/base.py @@ -14,6 +14,8 @@ import os import platform +from loguricorn.intercept import InterceptHandler + PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(PROJECT_DIR) @@ -258,3 +260,44 @@ "alt", "class", ] + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "intercept": { + "()": InterceptHandler, + "level": 0, + }, + }, + "root": { + "handlers": ["intercept"], + "level": "INFO", + "propagate": False, + }, + "loggers": { + "django": { + "handlers": ["intercept"], + "level": "INFO", + "propagate": False, + }, + }, +} + +LOGGING_FORMAT = ( + "[bfportal] " + "[{time:DD/MM/YY HH:mm:ss}] [{name}:{function}:{line}] " + "[{level}] {message}" +) + + +def setup_logging(): + """Setup logging for the entire project.""" + import sys + + from loguru import logger + + logger.remove() + logger.add( + sys.stdout, colorize=True, level="INFO", backtrace=True, format=LOGGING_FORMAT + ) diff --git a/bfportal/bfportal/wsgi.py b/bfportal/bfportal/wsgi.py index 9528413..07281e8 100644 --- a/bfportal/bfportal/wsgi.py +++ b/bfportal/bfportal/wsgi.py @@ -8,9 +8,33 @@ """ import os +import warnings -from django.core.wsgi import get_wsgi_application +from loguru import logger -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bfportal.settings.production") -application = get_wsgi_application() +def init_project(): + """Initialize the project""" + logger.info("project loaded") + + +def init_wsgi(): + """Initialize the WSGI + + Used to load .env file and set project specific settings + """ + global application + with warnings.catch_warnings(): + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bfportal.settings.production") + from django.core.wsgi import get_wsgi_application + from wagtail.utils.deprecation import RemovedInWagtail50Warning + + warnings.filterwarnings( + "ignore", category=RemovedInWagtail50Warning + ) # supress only wagtail warnings + application = get_wsgi_application() + + +application = None +init_project() +init_wsgi() diff --git a/bfportal/core/migrations/0080_alter_experiencepagetag_tag.py b/bfportal/core/migrations/0080_alter_experiencepagetag_tag.py new file mode 100644 index 0000000..d647590 --- /dev/null +++ b/bfportal/core/migrations/0080_alter_experiencepagetag_tag.py @@ -0,0 +1,24 @@ +# Generated by Django 4.1.7 on 2023-04-21 19:26 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("taggit", "0005_auto_20220424_2025"), + ("core", "0079_remove_experiencepage_likes"), + ] + + operations = [ + migrations.AlterField( + model_name="experiencepagetag", + name="tag", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="%(app_label)s_%(class)s_items", + to="taggit.tag", + ), + ), + ] diff --git a/bfportal/core/models/users.py b/bfportal/core/models/users.py index 349eabd..2f720cd 100644 --- a/bfportal/core/models/users.py +++ b/bfportal/core/models/users.py @@ -87,7 +87,11 @@ def create_user_profile(sender, instance: User, created, **kwargs): @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): """Called when a user data is updated""" - instance.profile.save() + if ( + profile := getattr(instance, "profile", None) + ) is None: # is case a user with no profile tries to log in. + profile = Profile.objects.create(user=instance) + profile.save() class ProfilePage(RoutablePageMixin, CustomBasePage): diff --git a/bfportal/core/templates/core/after_submit.html b/bfportal/core/templates/core/after_submit.html index 7d9031c..ff6b2f5 100644 --- a/bfportal/core/templates/core/after_submit.html +++ b/bfportal/core/templates/core/after_submit.html @@ -1,25 +1,37 @@ {% extends "base.html" %} {% load i18n %} -{% block title %}{% trans "successful" %}{% endblock %} +{% block title %} + {{ exp_name | title | truncatechars:20 }} + {% if after_edit %} + Saved + {% else %} + Submitted + {% endif %} + + {% endblock %} {% block content %} -
+
-
-
+
+
+ {{ exp_name | title }} {% if after_edit %} - {{ exp_name }} {% trans "'s Changes submitted for moderation" %} + Your edits have been saved and sent to moderation for approval {% else %} - {{ exp_name }} {% trans "Submited Successfully for moderation" %} + Your experience has been successfully sent to moderation and is waiting for approval {% endif %} -
-
diff --git a/bfportal/docker-compose.yml b/bfportal/docker-compose.yml index 42f964c..702834e 100644 --- a/bfportal/docker-compose.yml +++ b/bfportal/docker-compose.yml @@ -22,7 +22,7 @@ services: bfportal_gg_production: image: docker.pkg.github.com/battlefield-portal-community/bfportal.gg/main:latest restart: always - command: bash -c "python manage.py migrate --noinput && python manage.py ensure_superuser --username bfportal --email superuser@bfportal.com --password '${SU_PASSWD}' && python manage.py ensure_initialization && gunicorn bfportal.wsgi:application --workers 4 --bind 0.0.0.0:${PRODUCTION_PORT}" + command: bash -c "python manage.py migrate --noinput && python manage.py ensure_superuser --username bfportal --email superuser@bfportal.com --password '${SU_PASSWD}' && python manage.py ensure_initialization && gunicorn --workers 4 --bind 0.0.0.0:${PRODUCTION_PORT}" user: "33:33" ports: - "${PRODUCTION_PORT}:${PRODUCTION_PORT}" @@ -75,7 +75,7 @@ services: bfportal_gg_dev: image: docker.pkg.github.com/battlefield-portal-community/bfportal.gg/dev:latest restart: always - command: bash -c "python manage.py migrate --noinput && python manage.py ensure_superuser --username bfportal --email superuser@bfportal.com --password '${SU_PASSWD}' && python manage.py ensure_initialization && gunicorn bfportal.wsgi:application --workers 4 --bind 0.0.0.0:${DEVEL_PORT}" + command: bash -c "python manage.py migrate --noinput && python manage.py ensure_superuser --username bfportal --email superuser@bfportal.com --password '${SU_PASSWD}' && python manage.py ensure_initialization && gunicorn --workers 4 --bind 0.0.0.0:${DEVEL_PORT}" user: "33:33" ports: - "${DEVEL_PORT}:${DEVEL_PORT}" diff --git a/bfportal/gunicorn.conf.py b/bfportal/gunicorn.conf.py new file mode 100644 index 0000000..1075c20 --- /dev/null +++ b/bfportal/gunicorn.conf.py @@ -0,0 +1,50 @@ +from dotenv import load_dotenv + +load_dotenv() + +from bfportal.settings.base import setup_logging # noqa: E402 + +setup_logging() + +logger_class = "loguricorn.Logger" + +bind = "127.0.0.1:8000" +reload = False +timeout = 30 +errorlog = "-" +loglevel = "info" +wsgi_app = "bfportal.wsgi:application" +capture_output = True + + +def when_ready(server): + """Called just after the master process is initialized.""" + server.log.info("Server is ready. Spawning workers") + + +def worker_int(worker): + """Called when a worker receives the INT or QUIT signal.""" + worker.log.info("worker received INT or QUIT signal") + + # get traceback info + import sys + import threading + import traceback + + id2name = {th.ident: th.name for th in threading.enumerate()} + code = [] + for threadId, stack in sys._current_frames().items(): + code.append("\n# Thread: %s(%d)" % (id2name.get(threadId, ""), threadId)) + for filename, lineno, name, line in traceback.extract_stack(stack): + code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) + if line: + code.append(" %s" % (line.strip())) + worker.log.debug("\n".join(code)) + + +def worker_abort(worker): + """Called when a worker receives the SIGABRT signal.""" + worker.log.info("worker received SIGABRT signal") + + +print("Gunicorn config loaded") diff --git a/bfportal/manage.py b/bfportal/manage.py index db57bf6..1ea6abf 100644 --- a/bfportal/manage.py +++ b/bfportal/manage.py @@ -1,22 +1,22 @@ #!/usr/bin/env python import os import sys +import warnings -from loguru import logger +from dotenv import load_dotenv + +load_dotenv() + +from bfportal.settings.base import setup_logging # noqa: E402 + +setup_logging() if __name__ == "__main__": - logger.remove() - logger.add( - sys.stdout, - colorize=True, - format="[ bfportal ]" - "[{level: ^8}]" - "[{name}.{function}:{line}]" - "[ {message} ]", - level="DEBUG", - ) - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bfportal.settings.dev") + with warnings.catch_warnings(): + from wagtail.utils.deprecation import RemovedInWagtail50Warning - from django.core.management import execute_from_command_line + warnings.filterwarnings("ignore", category=RemovedInWagtail50Warning) + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bfportal.settings.dev") + from django.core.management import execute_from_command_line - execute_from_command_line(sys.argv) + execute_from_command_line(sys.argv) diff --git a/bfportal/requirements.txt b/bfportal/requirements.txt index 5198fb5..6adec85 100644 --- a/bfportal/requirements.txt +++ b/bfportal/requirements.txt @@ -52,6 +52,7 @@ isort==5.12.0 Jinja2==3.1.2 jinja2-time==0.2.0 l18n==2021.3 +loguricorn==0.1.0 loguru==0.6.0 Markdown==3.4.1 MarkupSafe==2.1.2