Skip to content
Snippets Groups Projects
Commit b7ba3c62 authored by Jonathan Weth's avatar Jonathan Weth :keyboard:
Browse files

Merge branch '40-allow-selecting-plan-version-and-default-to-newest-version' into 'master'

Resolve "Allow selecting plan version and default to newest version"

Closes #40

See merge request !117
parents 74fb0271 e9406719
Branches 2.1.1
No related tags found
1 merge request!117Resolve "Allow selecting plan version and default to newest version"
Pipeline #65986 failed
...@@ -9,6 +9,16 @@ and this project adheres to `Semantic Versioning`_. ...@@ -9,6 +9,16 @@ and this project adheres to `Semantic Versioning`_.
Unreleased Unreleased
---------- ----------
Added
~~~~~
* Plan version can be explicitly selected (defaulting to newest)
Fixed
~~~~~
* Import now only imports one plan version
`2.1`_ - 2022-01-13 `2.1`_ - 2022-01-13
------------------- -------------------
......
...@@ -32,7 +32,7 @@ Licence ...@@ -32,7 +32,7 @@ Licence
Copyright © 2018, 2019, 2020, 2021 Jonathan Weth <dev@jonathanweth.de> Copyright © 2018, 2019, 2020, 2021 Jonathan Weth <dev@jonathanweth.de>
Copyright © 2018, 2019 Frank Poetzsch-Heffter <p-h@katharineum.de> Copyright © 2018, 2019 Frank Poetzsch-Heffter <p-h@katharineum.de>
Copyright © 2019, 2020, 2021 Dominik George <dominik.george@teckids.org> Copyright © 2019, 2020, 2021, 2022 Dominik George <dominik.george@teckids.org>
Copyright © 2019, 2020 Tom Teichler <tom.teichler@teckids.org> Copyright © 2019, 2020 Tom Teichler <tom.teichler@teckids.org>
Copyright © 2019 Julian Leucker <leuckeju@katharineum.de> Copyright © 2019 Julian Leucker <leuckeju@katharineum.de>
Copyright © 2019 mirabilos <thorsten.glaser@teckids.org> Copyright © 2019 mirabilos <thorsten.glaser@teckids.org>
......
...@@ -12,7 +12,7 @@ class UntisConfig(AppConfig): ...@@ -12,7 +12,7 @@ class UntisConfig(AppConfig):
copyright_info = ( copyright_info = (
([2018, 2019, 2020, 2021], "Jonathan Weth", "dev@jonathanweth.de"), ([2018, 2019, 2020, 2021], "Jonathan Weth", "dev@jonathanweth.de"),
([2018, 2019], "Frank Poetzsch-Heffter", "p-h@katharineum.de"), ([2018, 2019], "Frank Poetzsch-Heffter", "p-h@katharineum.de"),
([2019, 2020, 2021], "Dominik George", "dominik.george@teckids.org"), ([2019, 2020, 2021, 2022], "Dominik George", "dominik.george@teckids.org"),
([2019, 2020], "Tom Teichler", "tom.teichler@teckids.org"), ([2019, 2020], "Tom Teichler", "tom.teichler@teckids.org"),
([2019], "Julian Leucker", "leuckeju@katharineum.de"), ([2019], "Julian Leucker", "leuckeju@katharineum.de"),
([2019], "mirabilos", "thorsten.glaser@teckids.org"), ([2019], "mirabilos", "thorsten.glaser@teckids.org"),
......
...@@ -27,15 +27,15 @@ class ImportCommand: ...@@ -27,15 +27,15 @@ class ImportCommand:
return None return None
@classmethod @classmethod
def run(cls, background: bool = False): def run(cls, background: bool = False, version: Optional[int] = None):
"""Run the import command (foreground/background).""" """Run the import command (foreground/background)."""
if background: if background:
from .tasks import TASKS from .tasks import TASKS
task = TASKS[cls.task_name] task = TASKS[cls.task_name]
task.delay() task.delay(version=version)
else: else:
_untis_import_mysql(cls.get_terms()) _untis_import_mysql(cls.get_terms(), version=version)
class CurrentImportCommand(ImportCommand): class CurrentImportCommand(ImportCommand):
......
...@@ -13,8 +13,13 @@ class Command(BaseCommand): ...@@ -13,8 +13,13 @@ class Command(BaseCommand):
action="store_true", action="store_true",
help="Run import job in background using Celery", help="Run import job in background using Celery",
) )
parser.add_argument(
"--plan-version",
help="Select explicit Untis plan version",
)
def handle(self, *args, **options): def handle(self, *args, **options):
command = COMMANDS_BY_NAME[options["command"]] command = COMMANDS_BY_NAME[options["command"]]
background = options["background"] background = options["background"]
command.run(background=background) version = options.get("plan_version", None)
command.run(background=background, version=version)
...@@ -6,8 +6,8 @@ TASKS = {} ...@@ -6,8 +6,8 @@ TASKS = {}
for import_command in ImportCommand.__subclasses__(): for import_command in ImportCommand.__subclasses__():
@app.task(name=import_command.task_name, bind=True) @app.task(name=import_command.task_name, bind=True)
def _task(self): def _task(self, *args, **kwargs):
import_command = COMMANDS_BY_TASK_NAME[self.name] import_command = COMMANDS_BY_TASK_NAME[self.name]
import_command.run() import_command.run(*args, **kwargs)
TASKS[import_command.task_name] = _task TASKS[import_command.task_name] = _task
...@@ -2,7 +2,7 @@ import logging ...@@ -2,7 +2,7 @@ import logging
from datetime import date from datetime import date
from typing import Dict, Optional from typing import Dict, Optional
from django.db.models import QuerySet from django.db.models import Max, OuterRef, QuerySet, Subquery
from django.utils import timezone from django.utils import timezone
from tqdm import tqdm from tqdm import tqdm
...@@ -49,12 +49,31 @@ logger = logging.getLogger(__name__) ...@@ -49,12 +49,31 @@ logger = logging.getLogger(__name__)
def import_terms( def import_terms(
qs: Optional[QuerySet] = None, qs: Optional[QuerySet] = None,
version: Optional[int] = None,
) -> Dict[int, chronos_models.ValidityRange]: ) -> Dict[int, chronos_models.ValidityRange]:
"""Import terms and school years as validity ranges and school terms.""" """Import terms and school years as validity ranges and school terms."""
ranges_ref = {} ranges_ref = {}
if not isinstance(qs, QuerySet): if not isinstance(qs, QuerySet):
qs = run_using(mysql_models.Terms.objects).all() qs = run_using(mysql_models.Terms.objects)
if version is None:
# Select newest version per term / validity range
sub_qs = (
run_using(mysql_models.Terms.objects)
.filter(
school_id=OuterRef("school_id"),
schoolyear_id=OuterRef("schoolyear_id"),
term_id=OuterRef("term_id"),
)
.values("school_id", "schoolyear_id", "term_id")
.annotate(max_version=Max("version_id"))
.values("max_version")
)
qs = qs.filter(version_id=Subquery(sub_qs))
else:
# Select passed version
qs = qs.filter(version_id=version)
school_terms = {} school_terms = {}
for term in tqdm(qs, desc="Import terms (as validity ranges)", **TQDM_DEFAULTS): for term in tqdm(qs, desc="Import terms (as validity ranges)", **TQDM_DEFAULTS):
......
...@@ -25,9 +25,9 @@ from .importers.lessons import import_lessons ...@@ -25,9 +25,9 @@ from .importers.lessons import import_lessons
from .importers.substitutions import import_substitutions from .importers.substitutions import import_substitutions
def untis_import_mysql(terms: Optional[QuerySet] = None): def untis_import_mysql(terms: Optional[QuerySet] = None, version: Optional[int] = None):
# School terms and validity ranges # School terms and validity ranges
validity_ref = import_terms(terms) validity_ref = import_terms(terms, version=version)
for validity_range in tqdm( for validity_range in tqdm(
validity_ref.values(), desc="Import data for terms", **TQDM_DEFAULTS validity_ref.values(), desc="Import data for terms", **TQDM_DEFAULTS
......
...@@ -14,7 +14,7 @@ Supported Untis features ...@@ -14,7 +14,7 @@ Supported Untis features
------------------------ ------------------------
Not all features of Untis are supported in AlekSIS. The following Not all features of Untis are supported in AlekSIS. The following
information form Untis can be imported into AlekSIS: information from Untis can be imported into AlekSIS:
* Terms * Terms
* Holidays * Holidays
...@@ -26,6 +26,9 @@ information form Untis can be imported into AlekSIS: ...@@ -26,6 +26,9 @@ information form Untis can be imported into AlekSIS:
* Substitutions, extra lessons, cancellations * Substitutions, extra lessons, cancellations
* Events * Events
The Untis integration supports the versioning features of Untis. By default,
the most recent version of each object is imported.
Currently, the following features are known not to be supported: Currently, the following features are known not to be supported:
* Students, student groups, student choices * Students, student groups, student choices
......
...@@ -92,7 +92,9 @@ is also already imported when it becomes reelvant. ...@@ -92,7 +92,9 @@ is also already imported when it becomes reelvant.
In general, all tasks will do nothing if there is no matching Untis term. In general, all tasks will do nothing if there is no matching Untis term.
To use these tasks, you have to add them as periodic tasks. To use these tasks, you have to add them as periodic tasks. By default, they will
import the most recent plan version from Untis. To select a specific version (i.e.
to import an older snapshot), you can pass the ``version`` argument in the tasks.
How existing data is matched How existing data is matched
---------------------------- ----------------------------
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment