From 95c9748dc29fc4de1edfa95211e15808e0920ea3 Mon Sep 17 00:00:00 2001 From: Klaus-Uwe Mitterer Date: Wed, 27 May 2020 12:36:49 +0200 Subject: [PATCH] Base logging setup Models for products/services/billables --- core/classes/products.py | 21 +++++++++++++++ core/models/__init__.py | 5 +++- core/models/billable.py | 10 +++++++ core/models/products.py | 37 +++++++++++++++++++++++++ core/models/services.py | 41 ++++++++++++++++++++++++++++ core/tasks/cron.py | 7 ++--- expephalon/custom_settings.dist.py | 6 ++++- expephalon/settings.py | 43 ++++++++++++++++++++++++++++++ 8 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 core/classes/products.py create mode 100644 core/models/billable.py create mode 100644 core/models/products.py create mode 100644 core/models/services.py diff --git a/core/classes/products.py b/core/classes/products.py new file mode 100644 index 0000000..f65b6a7 --- /dev/null +++ b/core/classes/products.py @@ -0,0 +1,21 @@ +class BaseProductHandler: + def __init__(self, product_id): + self.product_id = product_id + + @property + def is_creatable(self): + '''Returns True if this product can be created right now, or False if it cannot. Should return True if the module is correctly configured, the product is in stock (if physical), etc.''' + return False + + @property + def setup_view(self): + '''Returns a view in which the product can be configured, or None if no configuration is possible/necessary.''' + return None + +class FallbackProductHandler(BaseProductHandler): + pass + +class CoreProductHandler(BaseProductHandler): + pass + +ProductHandler = CoreProductHandler \ No newline at end of file diff --git a/core/models/__init__.py b/core/models/__init__.py index f6efecb..ea28532 100644 --- a/core/models/__init__.py +++ b/core/models/__init__.py @@ -2,4 +2,7 @@ from core.models.files import * from core.models.profiles import * from core.models.auth import * from core.models.local import * -from core.models.cron import * \ No newline at end of file +from core.models.cron import * +from core.models.products import * +from core.models.billable import * +from core.models.services import * \ No newline at end of file diff --git a/core/models/billable.py b/core/models/billable.py new file mode 100644 index 0000000..956888f --- /dev/null +++ b/core/models/billable.py @@ -0,0 +1,10 @@ +from django.db.models import IntegerChoices, Model + +class CycleChoices(IntegerChoices): + DAYS = 0, "Days" + WEEKS = 1, "Weeks" + MONTHS = 2, "Months" + YEARS = 3, "Years" + +class Billable(Model): + pass \ No newline at end of file diff --git a/core/models/products.py b/core/models/products.py new file mode 100644 index 0000000..c1b9cbb --- /dev/null +++ b/core/models/products.py @@ -0,0 +1,37 @@ +from core.models.billable import CycleChoices + +from django.db.models import Model, IntegerChoices, PositiveIntegerField, DecimalField, ForeignKey, CASCADE, CharField, TextField, ManyToManyField + +from importlib import import_module + +import logging + +logger = logging.getLogger(__name__) + +class ProductGroup(Model): + name = CharField(max_length=255) + +class Product(Model): + name = CharField(max_length=255) + description = TextField(null=True, blank=True) + handler_module = CharField(max_length=255, null=True, blank=True) + product_groups = ManyToManyField(ProductGroup) + + @property + def handler(self): + if self.handler_module: + try: + handler_module = import_module(self.handler_module) + return handler_module.ProductRouter(self.id) + except Exception as e: + logger.error(f"Could not load product handler {self.handler_module} for product {self.id}: {e}") + return None + +class ProductPlan(Model): + product = ForeignKey(Product, on_delete=CASCADE) + +class ProductPlanItem(Model): + plan = ForeignKey(ProductPlan, on_delete=CASCADE) + cycle = PositiveIntegerField(choices=CycleChoices.choices) + count = PositiveIntegerField() + cost = DecimalField(max_digits=30, decimal_places=2) \ No newline at end of file diff --git a/core/models/services.py b/core/models/services.py new file mode 100644 index 0000000..b67735c --- /dev/null +++ b/core/models/services.py @@ -0,0 +1,41 @@ +from core.models.billable import CycleChoices +from core.models.products import ProductGroup + +from django.db.models import Model, TextField, CharField, ManyToManyField, ForeignKey, CASCADE, PositiveIntegerField, DecimalField, OneToOneField + +from importlib import import_module +from logging import getLogger + +logger = getLogger(__name__) + +class Service(Model): + name = CharField(max_length=255) + description = TextField(null=True, blank=True) + handler_module = CharField(max_length=255, null=True, blank=True) + product_groups = ManyToManyField(ProductGroup) + + @property + def handler(self): + if self.handler_module: + try: + handler_module = import_module(self.handler_module) + return handler_module.ProductRouter(self.id) + except Exception as e: + logger.error(f"Could not load product handler {self.handler_module} for product {self.id}: {e}") + return None + +class ServicePlan(Model): + service = OneToOneField(Service, on_delete=CASCADE) + + @classmethod + def from_productplan(cls, productplan, service): + plan = cls.objects.create(service=service) + + for item in productplan.serviceplanitem_set: + ServicePlanItem.objects.create(plan=plan, cycle=item.cycle, count=item.count, cost=item.cost) + +class ServicePlanItem(Model): + plan = ForeignKey(ServicePlan, on_delete=CASCADE) + cycle = PositiveIntegerField(choices=CycleChoices.choices) + count = PositiveIntegerField() + cost = DecimalField(max_digits=30, decimal_places=2) \ No newline at end of file diff --git a/core/tasks/cron.py b/core/tasks/cron.py index 60fc146..df488da 100644 --- a/core/tasks/cron.py +++ b/core/tasks/cron.py @@ -1,7 +1,8 @@ from celery import shared_task, task -from celery.utils.log import get_task_logger -logger = get_task_logger(__name__) +import logging + +logger = logging.getLogger(__name__) @task(name="cron") def process_crons(): @@ -16,7 +17,7 @@ def run_cron(name, *args, **kwargs): from core.modules.cron import cronfunctions log = CronLog.objects.create(task=name) - + try: output = cronfunctions[name]() if output: diff --git a/expephalon/custom_settings.dist.py b/expephalon/custom_settings.dist.py index d535e55..86c2dc9 100644 --- a/expephalon/custom_settings.dist.py +++ b/expephalon/custom_settings.dist.py @@ -49,4 +49,8 @@ MEMCACHED_LOCATION = ["127.0.0.1:11211"] RABBITMQ_LOCATION = "127.0.0.1:5672" RABBITMQ_VHOST = "" RABBITMQ_USER = "guest" -RABBITMQ_PASS = "guest" \ No newline at end of file +RABBITMQ_PASS = "guest" + +# Logging + +LOG_DIRECTORY = "/var/log/expephalon/" \ No newline at end of file diff --git a/expephalon/settings.py b/expephalon/settings.py index aba5ec2..0c66a65 100644 --- a/expephalon/settings.py +++ b/expephalon/settings.py @@ -155,3 +155,46 @@ CELERY_TASK_RESULT_EXPIRES = 12 * 60 * 60 LOGIN_REDIRECT_URL = reverse_lazy('dashboard') LOGIN_URL = reverse_lazy('login') LOGOUT_URL = reverse_lazy('logout') + +# Logging + +try: + os.makedirs(LOG_DIRECTORY, exist_ok=True) +except: + raise Exception(f"Could not create log directory {LOG_DIRECTORY}, please create it manually and make sure the Expephalon user account has sufficient privileges to write to it.") + +try: + with open(os.path.join(LOG_DIRECTORY, "expephalon.log"), "a") as logfile: + logfile.write("\n----------\n") +except: + raise Exception(f"Unable to write to log file {os.path.join(LOG_DIRECTORY, 'expephalon.log')}, please make sure the Expephalon user account has sufficient privileges to write to the {LOG_DIRECTORY} directory and all files within it.") + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' + }, + 'simple': { + 'format': '%(levelname)s %(message)s' + }, + }, + 'handlers': { + 'expephalon': { + 'level': 'DEBUG', + 'class': 'logging.handlers.TimedRotatingFileHandler', + 'filename': os.path.join(LOG_DIRECTORY, 'expephalon.log'), + 'when': 'midnight', + 'backupCount': 10, + 'formatter': 'verbose', + }, + }, + 'loggers': { + '': { + 'handlers': ['expephalon'], + 'level': 'DEBUG', + 'propagate': False, + }, + }, +} \ No newline at end of file