fanch 1 gadu atpakaļ
vecāks
revīzija
40bc22a427

+ 236 - 0
src/djangotools/cmdline/commands/backup/__init__.py

@@ -0,0 +1,236 @@
+import datetime
+import json
+import re
+import shutil
+import tempfile
+import time
+from zipfile import ZipFile
+from pathlib import Path
+
+from djangotools.cmdline.common.command import Command, Argument
+from djangotools.common.date import CurrentDate
+from djangotools.config import app_dir
+
+from djangotools.config import get_settings
+JOURS = ["Lundi", "Mardi", "Mercredi",  "Jeudi", "Vendredi", "Samedi", "Dimanche"]
+MOIS = ["", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"]
+
+def period_to_str(period, date):
+    if period == "daliy":
+        return f"journalière du {date}"
+    if period == "weekly":
+        return f"hebdomadaire de la semaine {date}"
+    if period == "monthly":
+        return f"mensuelle du mois de {date}"
+
+
+
+class BackupFile:
+
+    def __init__(self, dir, quiet):
+        self.quiet = quiet
+        self.file = Path(dir) / "backup.json"
+        self.log_file = Path(dir) / "backup.log"
+        self.log_messages = []
+        if self.file.is_file():
+            self.content = json.loads(self.file.read_text())
+        else:
+            self.content = {
+                "daily" : {
+                    "last" : None,
+                    "file" : None,
+                    "date" : None
+                },
+                "weekly" : {
+                    "last" : None,
+                    "file" : None,
+                    "date" : None
+                },
+                "monthly" : {
+                    "last" : None,
+                    "file" : None,
+                    "date" : None
+                }
+            }
+
+    @staticmethod
+    def get_wwek_number(now=None):
+        now = now or CurrentDate.now()
+        first_day = datetime.datetime(now.year, 1, 1)
+        nb = (now-first_day).days + first_day.weekday()
+        return nb // 7
+
+
+    @classmethod
+    def get_date(cls, period, now = None):
+        now = now or CurrentDate.now()
+        date = None
+        if period == "daily":
+            date =  JOURS[now.weekday()]
+        elif period == "weekly":
+            date = cls.get_wwek_number()
+        elif period == "monthly":
+            date = MOIS[now.month]
+        return date
+
+    def get_todo(self):
+        periods = ["daily", "weekly", "monthly"]
+        ret = []
+        for period in periods:
+            if self.content[period]["date"] != self.get_date(period):
+                ret.append(period)
+        return ret
+
+    def _log(self, type, *args):
+        line = None
+        if type=="backup":
+            line = f"{args[0]} : Sauvegarde {period_to_str(args[1], args[3])} dans {args[2]}"
+        elif type == "message":
+            line = f"{args[0]} : {args[1]}"
+        else:
+            raise ValueError(f"Erreur le type de message '{type}' est inconnu")
+        self.log_messages.append(line)
+        if not self.quiet: print(line)
+
+    def log(self, message):
+        now = CurrentDate.now()
+        t = now.strftime("%d/%m/%Y %H:%M:%S")
+        self._log("message", t, message)
+
+    def do_backup(self, period, file):
+        if period not in self.content:
+            raise ValueError(f"La période de backup '{period}' est inconnu")
+        now = CurrentDate.now()
+        t = now.strftime("%d/%m/%Y %H:%M:%S")
+        date = self.get_date(period)
+        self._log("backup", t, period, file, date)
+
+        self.content[period] = {
+            "last" : t,
+            "file" : str(file),
+            "date" : date
+        }
+
+    def save(self):
+        log = "\n".join(self.log_messages)+"\n"
+        with open(self.log_file, "a") as fd:
+            fd.write(log)
+        self.file.write_text(json.dumps(self.content, indent=2))
+
+class BackupCommand(Command):
+    NAME = "backup"
+    ALIASES = ["ba"]
+    PREFIX = "backup"
+    HELP = "Execute une sauvegarde"
+
+    ARGUMENT = [
+        Argument("--daily", "-d", action = "store_true", help="Execute le backup journalier"),
+        Argument("--weekly", "-w", action = "store_true",  help="Execute le backup hebdomadaire"),
+        Argument("--monthly", "-m", action = "store_true",  help="Execute le backup mensuel"),
+        Argument("--quiet", "-q", action = "store_true", help="Mode silencieux"),
+        Argument("--prefix", "-p", help="Prefix des fichier zip de backup"),
+
+    ]
+
+    def __init__(self):
+        super().__init__()
+        self.settings = get_settings()
+        self.backup_dir = self.settings.CONFIG.backup_dir
+        self._lock_file = self.backup_dir / "lock"
+        self.backup_dir_daily = self.backup_dir / "daliy"
+        self.backup_dir_weekly = self.backup_dir / "weekly"
+        self.backup_dir_monthly = self.backup_dir / "monthly"
+
+        for dir in [self.backup_dir_daily, self.backup_dir_weekly, self.backup_dir_monthly, self._lock_file.parent]:
+            dir.mkdir(exist_ok=True, parents=True)
+
+
+    def get_name(self):
+        now = CurrentDate.now()
+        return f"{self.PREFIX}-{str(now.year).zfill(4)}_{str(now.month).zfill(2)}_{str(now.day).zfill(2)}.zip"
+
+    def get_date(self, file):
+        file = Path(file)
+        for x in re.findall(r"\d{4}_\d{2}_\d{2}.zip$", file.name):
+            x = [int(n) for n in x.replace(".zip", "").split("_")]
+            return datetime.datetime(*x)
+        return None
+
+    def gen_backup(self, output):
+        root = self.settings.DATA_DIR
+        queue = [root]
+        with ZipFile(output, "w") as zip:
+            while queue:
+                curr = queue.pop(0)
+                for file in curr.iterdir():
+                    if file.is_dir():
+                        if file == self.backup_dir: continue
+                        queue.append(file)
+                    else:
+                        zip.write(file, file.relative_to(root.parent))
+
+    def lock(self):
+        while self._lock_file.is_file():
+            time.sleep(1)
+        self._lock_file.touch()
+
+    def unlock(self):
+        if self._lock_file.is_file():
+            self._lock_file.unlink()
+
+    def __enter__(self):
+        self.lock()
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.unlock()
+
+    def clean(self):
+        now = CurrentDate.now()
+        for file in list(self.backup_dir_daily.iterdir()):
+            date = self.get_date(file)
+            if not date: continue
+            if date + datetime.timedelta(days=8) < now:
+                file.unlink()
+
+        for file in list(self.backup_dir_weekly.iterdir()):
+            date = self.get_date(file)
+            if not date: continue
+            if date + datetime.timedelta(days=32) < now:
+                file.unlink()
+
+        for file in list(self.backup_dir_monthly.iterdir()):
+            date = self.get_date(file)
+            if not date: continue
+            if date + datetime.timedelta(days=366) < now:
+                file.unlink()
+
+    def run(self, data):
+        with tempfile.TemporaryDirectory() as temp:
+            temp = Path(temp) / "data.zip"
+            self.clean()
+            back = BackupFile(self.backup_dir, data.quiet)
+
+            with self:
+                self.gen_backup(temp)
+                if not any(getattr(data, x) for x in ("daily", "weekly", "monthly") ):
+                    todo = set(back.get_todo())
+                    data.daily = data.daily or (todo & {"daily"})
+                    data.weekly = data.weekly or (todo & {"weekly"})
+                    data.monthly = data.monthly or (todo & {"monthly"})
+
+                name = self.get_name()
+
+                if data.daily:
+                    back.do_backup("daily", self.backup_dir_daily / name)
+                    shutil.copy(temp, self.backup_dir_daily / name)
+                if data.weekly:
+                    back.do_backup("weekly", self.backup_dir_weekly / name)
+                    shutil.copy(temp, self.backup_dir_weekly / name)
+                if data.monthly:
+                    back.do_backup("monthly", self.backup_dir_monthly / name)
+                    shutil.copy(temp, self.backup_dir_monthly / name)
+
+                back.save()
+
+
+

+ 0 - 227
src/djangotools/cmdline/commands/backup/base.py

@@ -1,227 +0,0 @@
-import datetime
-import json
-import re
-import shutil
-import tempfile
-import time
-from zipfile import ZipFile
-from pathlib import Path
-
-from djangotools.cmdline.common.command import Command
-from djangotools.common.date import CurrentDate
-from djangotools.config import app_dir
-
-JOURS = ["Lundi", "Mardi", "Mercredi",  "Jeudi", "Vendredi", "Samedi", "Dimanche"]
-MOIS = ["", "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"]
-
-def period_to_str(period, date):
-    if period == "daliy":
-        return f"journalière du {date}"
-    if period == "weekly":
-        return f"hebdomadaire de la semaine {date}"
-    if period == "monthly":
-        return f"mensuelle du mois de {date}"
-
-
-
-class BackupFile:
-
-    def __init__(self, dir, quiet):
-        self.quiet = quiet
-        self.file = Path(dir) / "backup.json"
-        self.log_file = Path(dir) / "backup.log"
-        self.log_messages = []
-        if self.file.is_file():
-            self.content = json.loads(self.file.read_text())
-        else:
-            self.content = {
-                "daily" : {
-                    "last" : None,
-                    "file" : None,
-                    "date" : None
-                },
-                "weekly" : {
-                    "last" : None,
-                    "file" : None,
-                    "date" : None
-                },
-                "monthly" : {
-                    "last" : None,
-                    "file" : None,
-                    "date" : None
-                }
-            }
-
-    @staticmethod
-    def get_wwek_number(now=None):
-        now = now or CurrentDate.now()
-        first_day = datetime.datetime(now.year, 1, 1)
-        nb = (now-first_day).days + first_day.weekday()
-        return nb // 7
-
-
-    @classmethod
-    def get_date(cls, period, now = None):
-        now = now or CurrentDate.now()
-        date = None
-        if period == "daily":
-            date =  JOURS[now.weekday()]
-        elif period == "weekly":
-            date = cls.get_wwek_number()
-        elif period == "monthly":
-            date = MOIS[now.month]
-        return date
-
-    def get_todo(self):
-        periods = ["daily", "weekly", "monthly"]
-        ret = []
-        for period in periods:
-            if self.content[period]["date"] != self.get_date(period):
-                ret.append(period)
-        return ret
-
-    def _log(self, type, *args):
-        line = None
-        if type=="backup":
-            line = f"{args[0]} : Sauvegarde {period_to_str(args[1], args[3])} dans {args[2]}"
-        elif type == "message":
-            line = f"{args[0]} : {args[1]}"
-        else:
-            raise ValueError(f"Erreur le type de message '{type}' est inconnu")
-        self.log_messages.append(line)
-        if not self.quiet: print(line)
-
-    def log(self, message):
-        now = CurrentDate.now()
-        t = now.strftime("%d/%m/%Y %H:%M:%S")
-        self._log("message", t, message)
-
-    def do_backup(self, period, file):
-        if period not in self.content:
-            raise ValueError(f"La période de backup '{period}' est inconnu")
-        now = CurrentDate.now()
-        t = now.strftime("%d/%m/%Y %H:%M:%S")
-        date = self.get_date(period)
-        self._log("backup", t, period, file, date)
-
-        self.content[period] = {
-            "last" : t,
-            "file" : str(file),
-            "date" : date
-        }
-
-    def save(self):
-        log = "\n".join(self.log_messages)+"\n"
-        with open(self.log_file, "a") as fd:
-            fd.write(log)
-        self.file.write_text(json.dumps(self.content, indent=2))
-
-class BackupCommand(Command):
-
-
-    def __init__(self):
-        super().__init__()
-        self.settings = app_dir
-        self.backup_dir = self.settings
-        self._lock_file = self.backup_dir / "lock"
-        self.backup_dir_daily = self.backup_dir / "daliy"
-        self.backup_dir_weekly = self.backup_dir / "weekly"
-        self.backup_dir_monthly = self.backup_dir / "monthly"
-
-        for dir in [self.backup_dir_daily, self.backup_dir_weekly, self.backup_dir_monthly, self._lock_file.parent]:
-            dir.mkdir(exist_ok=True, parents=True)
-
-
-    def get_name(self):
-        now = CurrentDate.now()
-        return f"{self.PREFIX}-{str(now.year).zfill(4)}_{str(now.month).zfill(2)}_{str(now.day).zfill(2)}.zip"
-
-    def get_date(self, file):
-        file = Path(file)
-        for x in re.findall(r"\d{4}_\d{2}_\d{2}.zip$", file.name):
-            x = [int(n) for n in x.replace(".zip", "").split("_")]
-            return datetime.datetime(*x)
-        return None
-
-
-
-    def gen_backup(self, output):
-        root = self.settings.DATA_DIR
-        queue = [root]
-        with ZipFile(output, "w") as zip:
-            while queue:
-                curr = queue.pop(0)
-                for file in curr.iterdir():
-                    if file.is_dir():
-                        if file == self.backup_dir: continue
-                        queue.append(file)
-                    else:
-                        zip.write(file, file.relative_to(root.parent))
-
-    def lock(self):
-        while self._lock_file.is_file():
-            time.sleep(1)
-        self._lock_file.touch()
-
-    def unlock(self):
-        if self._lock_file.is_file():
-            self._lock_file.unlink()
-
-
-    def __enter__(self):
-        self.lock()
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        self.unlock()
-
-    def clean(self):
-        now = CurrentDate.now()
-        for file in list(self.backup_dir_daily.iterdir()):
-            date = self.get_date(file)
-            if not date: continue
-            if date + datetime.timedelta(days=8) < now:
-                file.unlink()
-
-        for file in list(self.backup_dir_weekly.iterdir()):
-            date = self.get_date(file)
-            if not date: continue
-            if date + datetime.timedelta(days=32) < now:
-                file.unlink()
-
-        for file in list(self.backup_dir_monthly.iterdir()):
-            date = self.get_date(file)
-            if not date: continue
-            if date + datetime.timedelta(days=366) < now:
-                file.unlink()
-
-    def run(self, data):
-        with tempfile.TemporaryDirectory() as temp:
-            temp = Path(temp) / "data.zip"
-            self.clean()
-            back = BackupFile(self.backup_dir, data.quiet)
-
-            with self:
-                self.gen_backup(temp)
-                if not any(getattr(data, x) for x in ("daily", "weekly", "monthly") ):
-                    todo = set(back.get_todo())
-                    data.daily = data.daily or (todo & {"daily"})
-                    data.weekly = data.weekly or (todo & {"weekly"})
-                    data.monthly = data.monthly or (todo & {"monthly"})
-
-                name = self.get_name()
-
-                if data.daily:
-                    back.do_backup("daily", self.backup_dir_daily / name)
-                    shutil.copy(temp, self.backup_dir_daily / name)
-                if data.weekly:
-                    back.do_backup("weekly", self.backup_dir_weekly / name)
-                    shutil.copy(temp, self.backup_dir_weekly / name)
-                if data.monthly:
-                    back.do_backup("monthly", self.backup_dir_monthly / name)
-                    shutil.copy(temp, self.backup_dir_monthly / name)
-
-
-                back.save()
-
-
-

+ 37 - 0
src/djangotools/cmdline/commands/cron/__init__.py

@@ -0,0 +1,37 @@
+from collections import defaultdict
+
+from djangotools.cmdline import Command, CronManager, Argument, CommandData
+
+from djangotools.cmdline import tasks
+from djangotools.config import get_settings
+
+
+class CronCommand(Command):
+    NAME = "cron"
+    ALIASES = ["cr"]
+
+    HELP = "Lance le serive de cron"
+    ARGUMENT = [
+        Argument("options", nargs="*", help="Liste des options à passer au cron au format {CRON_NAME}.{Parameter}={Value}")
+    ]
+    def __init__(self):
+        super().__init__()
+        self.settings = get_settings()
+        self.manager = CronManager(resolution=10)
+
+
+
+        for cron in getattr(self.settings, "CRON", None) or []:
+            self.manager.add_task(cron)
+
+    def run(self, data):
+        if not isinstance(data, dict):
+            opt = defaultdict(CommandData)
+            for x in data.options:
+                left, _, value =  x.partition("=")
+                cron_name, name = left.split(".")
+                setattr(opt[cron_name], name, value)
+        else:
+            opt = data
+
+        self.manager.schedule(opt)

+ 53 - 0
src/djangotools/cmdline/commands/run/__init__.py

@@ -0,0 +1,53 @@
+import os
+import subprocess
+import time
+from pathlib import Path
+
+
+from djangotools.cmdline import Command, Argument, CommandData
+
+from djangotools.cmdline.commands.cron import CronCommand
+from djangotools.config import get_settings
+from djangotools.run import Server
+
+
+class RunCommand(Command):
+
+    NAME = "run"
+    HELP = "Lance le serveur avec la config de production"
+
+    ARGUMENT = [
+        Argument("-p", "--pid-file", help="Chemin du ficher PID" ),
+        Argument("-o", "--stdout", nargs=1, help="Crée le server dans un autre processus"),
+        Argument("-e", "--stderr", nargs=1, help="Crée le server dans un autre processus"),
+        Argument("-b", "--bind",  help="Adresse d'écoute du serveur exemple localhost:8080"),
+        Argument("-C", "--no-cron", action="store_true", help="Ne pas lancer le cron"),
+    ]
+
+    def start_cron(self, hostname):
+        self.cron = CronCommand.thread_run(CommandData(url=f"http://{hostname}"))
+
+
+    def wait_cron_ends(self):
+        self.cron.join()
+
+    def run(self, data):
+        settings = get_settings()
+        if data.bind:
+            host_name = data.bind
+        else:
+            host_name = settings.HOSTNAME
+
+        if not data.no_cron:
+            self.start_cron(host_name)
+
+        pid_file = Path(data.pid_file or settings.CONFIG.pid_file)
+        if not pid_file.parent.is_dir():
+            pid_file.parent.mkdir(exist_ok=True, parents=True)
+        pid_file.write_text(str(os.getpid()))
+
+        server = Server()
+        server.handle(addrport=host_name)
+
+        if not data.no_cron:
+            self.wait_cron_ends()

+ 1 - 2
src/djangotools/cmdline/common/args.py

@@ -4,7 +4,7 @@ import sys
 
 from djangotools.cmdline.common.command import Command
 from djangotools.config import load_app
-
+from django.conf import settings
 
 class ArgsParser(argparse.ArgumentParser):
 
@@ -16,7 +16,6 @@ class ArgsParser(argparse.ArgumentParser):
         parser = self.add_subparsers(parser_class=argparse.ArgumentParser)
         self.add_argument("-a", "--app-dir",  help="Dossier de données du serveur")
         self.add_argument("-s", "--settings",  help="Module de settings à utiliser")
-
         for cmd in Command.load(commands_dirs):
             kwargs = {}
             if cmd.HELP: kwargs["help"] = cmd.HELP

+ 14 - 7
src/djangotools/cmdline/common/command.py

@@ -1,6 +1,8 @@
 import threading
 from pathlib import Path
 
+from django.core.exceptions import ImproperlyConfigured
+
 
 class CommandData:
 
@@ -43,13 +45,14 @@ class Command:
     @classmethod
     def thread_run(cls, data):
         cmd = cls()
-        thread = ThreadWrapper(lambda x=data: cmd.run(x))
+        dd = {cmd.NAME: data}
+        thread = ThreadWrapper(lambda x=dd: cmd.run(x))
         thread.start()
         return thread
 
     @staticmethod
     def _load(root_module):
-        ret = set()
+        ret = {}
         root = Path(root_module.__file__).parent
         queue = [root]
         root_module_str = root_module.__name__
@@ -67,22 +70,26 @@ class Command:
                     module = __import__(module_name, fromlist=['object'])
                     for x in dir(module):
                         data = getattr(module, x)
-                        if isinstance(data, type) and issubclass(data, Command) and data != Command and data.NAME is not None:
-                            ret.add(data)
+                        try:
+                            if (isinstance(data, type) and issubclass(data, Command)
+                                    and data != Command and data.NAME is not None):
+                                ret[data.NAME]=data
+                        except ImproperlyConfigured:
+                            pass
         return ret
 
     @staticmethod
     def load(commands_dirs=None):
         if isinstance(commands_dirs, str): commands_dirs = [commands_dirs]
         from djangotools.cmdline import commands
-        ret = set()
+        ret = {}
         commands_dirs = [commands]+list(commands_dirs or [])
         for commands_dir in commands_dirs:
             if isinstance(commands_dir, str):
                 commands_dir = __import__(commands_dir, fromlist=['object'])
-            ret |= Command._load(commands_dir)
+            ret.update(Command._load(commands_dir))
 
-        return ret
+        return set(ret.values())
 
 
 

+ 3 - 2
src/djangotools/cmdline/common/cron.py

@@ -81,7 +81,7 @@ class Task:
             if timer.poll():
                 print(f"Execute task: {self.NAME}")
                 try:
-                    self.run(data)
+                    self.run(data.get(self.NAME))
                 except Exception as err:
                     print(f"Erreur dans l'execution de la tache {self.NAME}", file=sys.stderr)
                     traceback.print_exc()
@@ -116,7 +116,6 @@ class CronManager:
             task = task_classe(*args, **kwargs)
 
             for type, *args in timers:
-                timer_classe = None
                 if type == "daily":
                     timer_classe = CronTimerDaily
                 else:
@@ -132,10 +131,12 @@ class CronManager:
                 next = min(next, task.poll(data))
 
             sleep = next - time.time()
+            print("time to sleep", sleep)
             time.sleep(sleep)
 
     @staticmethod
     def register(task_calsse):
         CronManager.TASK_CLASS[task_calsse.NAME] = task_calsse
+        return task_calsse
 
 

+ 14 - 0
src/djangotools/cmdline/tasks/__init__.py

@@ -0,0 +1,14 @@
+from djangotools.cmdline import CronManager, Task, CommandData
+
+
+@CronManager.register
+class BackupTask(Task):
+    NAME="backup"
+    def run(self, data):
+
+        from djangotools.cmdline.commands.backup import BackupCommand
+        cmd = BackupCommand()
+        cmd.execute(CommandData(daily=None, weekly=None, monthly=None, quiet=None, prefix=None))
+
+
+

+ 5 - 2
src/djangotools/common/route.py

@@ -5,6 +5,7 @@ from django.db.models.base import ModelBase
 from djangotools.common import response
 from djangotools.common.path import PointPath, ModelPath, AttributePath
 from djangotools.model.serializedmodel import SerializableModel
+from djangotools.view.utils import debug_login
 
 
 class Route:
@@ -41,8 +42,10 @@ class RegisteredRoute:
 
     def __call__(self, req, *args, **kwargs):
         obj = None
-        if self._default_user_id_:
-            req.user = User.objects.get(id=self._default_user_id_)
+        debug_login(req, self._default_user_id_)
+        user = req.user
+        if "need_auth" and  not user.is_authenticated:
+            return response.serv_json_not_logged()
 
 
         for part in self.route.path.iter_models():

+ 5 - 0
src/djangotools/config/__init__.py

@@ -14,6 +14,11 @@ def load_settings(module, base_dir=None, **kwargs):
 
 loaded = False
 
+def get_settings():
+    from django.conf import settings
+    return settings
+
+
 def load_app(settings_module, app_dir=None, populate=True):
     global loaded
     if loaded: return

+ 2 - 2
src/djangotools/config/base.py

@@ -108,10 +108,10 @@ class ConfigLoader:
         self.backup_dir = Directory(self.app_dir /  self.BACKUP)
         self.logs_dir = Directory(self.app_dir /  self.LOGS)
         self.run_dir = Directory(self.app_dir /  self.RUN)
-        self.run_file = File(self.app_dir /  self.RUN_FILE)
+        self.pid_file = File(self.app_dir /  self.RUN_FILE)
         self.django_secret_file = File(self.app_dir / self.DJANGO_SECRET_FILE)
 
-        for path in [self.app_dir, self.data_dir, self.backup_dir, self.secret_dir, self.config_dir, self.logs_dir]:
+        for path in [self.app_dir, self.data_dir, self.backup_dir, self.secret_dir, self.config_dir, self.logs_dir, self.run_dir]:
             if not path.exists(): path.mkdir(parents=True)
 
         if not self.config_file.is_file():

+ 20 - 0
src/djangotools/view/utils.py

@@ -0,0 +1,20 @@
+from django.contrib.auth import login
+from django.contrib.auth.models import User
+
+from djangotools.config import settings
+
+def debug_login(request, fallback_id=None):
+    if settings.ALLOW_AUTO_LOGIN and not request.user.is_authenticated and settings.AUTO_LOGIN:
+        try:
+            user = User.objects.get(username=settings.AUTO_LOGIN)
+        except User.DoesNotExist:
+            if fallback_id is not None:
+                user = User.objects.get(id=fallback_id)
+            else:
+                raise Exception()
+        login(request, user)
+
+
+def check_auth(request):
+    debug_login(request)
+    return request.user.is_authenticated