diff --git a/.gitmodules b/.gitmodules index 0b1ff289423a93278ac8d274890a2b5ae0788e1a..9c04a74362075f927208cfbca8332da1d405e755 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,8 +8,13 @@ ignore = untracked [submodule "apps/official/AlekSIS-App-DashboardFeeds"] path = apps/official/AlekSIS-App-DashboardFeeds - url = https://edugit.org/AlekSIS/Official/AlekSIS-App-DashboardFeeds.git + url = https://edugit.org/AlekSIS/Official/AlekSIS-App-DashboardFeeds ignore = untracked [submodule "apps/official/AlekSIS-App-LDAP"] path = apps/official/AlekSIS-App-LDAP url = https://edugit.org/AlekSIS/official/AlekSIS-App-LDAP + ignore = untracked +[submodule "apps/official/AlekSIS-App-Untis"] + path = apps/official/AlekSIS-App-Untis + url = https://edugit.org/AlekSIS/official/AlekSIS-App-Untis + ignore = untracked diff --git a/README.rst b/README.rst index 36ba5325a73f06493b8c3a862188516c17039a17..5c08b69d1ac8d24ab74c7cdbf74a9e4b8e161d6e 100644 --- a/README.rst +++ b/README.rst @@ -37,8 +37,8 @@ Licence Copyright © 2017, 2018, 2019, 2020 Jonathan Weth <wethjo@katharineum.de> Copyright © 2017, 2018, 2019 Frank Poetzsch-Heffter <p-h@katharineum.de> + Copyright © 2018, 2019, 2020 Julian Leucker <leuckeju@katharineum.de> Copyright © 2018, 2019, 2020 Hangzhi Yu <yuha@katharineum.de> - Copyright © 2018, 2019 Julian Leucker <leuckeju@katharineum.de> Copyright © 2019, 2020 Dominik George <dominik.george@teckids.org> Copyright © 2019, 2020 mirabilos <thorsten.glaser@teckids.org> Copyright © 2019, 2020 Tom Teichler <tom.teichler@teckids.org> diff --git a/aleksis/core/__init__.py b/aleksis/core/__init__.py index 21a49f0785f3977d9a265059a32ec957c9e1eb3c..587b829c611913af41c69f2734a48235956ff787 100644 --- a/aleksis/core/__init__.py +++ b/aleksis/core/__init__.py @@ -1,5 +1,7 @@ import pkg_resources +from django.utils.translation import gettext_lazy as _ + try: from .celery import app as celery_app except ModuleNotFoundError: diff --git a/aleksis/core/apps.py b/aleksis/core/apps.py index 13e3b3ddcf1083e1cff0f8c5e3461103bb12f4b2..648d063a378f30fddbbece6474c3b84a5a65bed6 100644 --- a/aleksis/core/apps.py +++ b/aleksis/core/apps.py @@ -13,6 +13,20 @@ class CoreConfig(AppConfig): name = "aleksis.core" verbose_name = "AlekSIS — The Free School Information System" + urls = { + "Repository": "https://edugit.org/AlekSIS/official/AlekSIS/", + } + licence = "EUPL-1.2+" + copyright = ( + ([2017, 2018, 2019, 2020], "Jonathan Weth", "wethjo@katharineum.de"), + ([2017, 2018, 2019], "Frank Poetzsch-Heffter", "p-h@katharineum.de"), + ([2018, 2019, 2020], "Julian Leucker", "leuckeju@katharineum.de"), + ([2018, 2019, 2020], "Hangzhi Yu", "yuha@katharineum.de"), + ([2019, 2020], "Dominik George", "dominik.george@teckids.org"), + ([2019, 2020], "mirabilos", "thorsten.glaser@teckids.org"), + ([2019, 2020], "Tom Teichler", "tom.teichler@teckids.org"), + ) + def config_updated(self, *args, **kwargs) -> None: clean_scss() diff --git a/aleksis/core/menus.py b/aleksis/core/menus.py index 18cf14ee8d465fdd05b809c21af7faf90bb26a38..33cb12c3bd734f6ffd21c72ac29dfc9feb1a7254 100644 --- a/aleksis/core/menus.py +++ b/aleksis/core/menus.py @@ -50,7 +50,10 @@ MENUS = { "name": _("Me"), "url": "person", "icon": "insert_emoticon", - "validators": ["menu_generator.validators.is_authenticated"], + "validators": [ + "menu_generator.validators.is_authenticated", + "aleksis.core.util.core_helpers.has_person", + ], }, ], }, diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index 463ec58009375ee57562957e8e4a45dd2bb041b5..35758dca54ab27e5a82a7fa5e962e1e4231ef372 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -1,7 +1,9 @@ import os import sys from glob import glob +from importlib import import_module +from django.apps import apps from django.utils.translation import gettext_lazy as _ from calendarweek.django import i18n_day_name_choices_lazy diff --git a/aleksis/core/static/js/main.js b/aleksis/core/static/js/main.js index 403837da22d351d8e97ed3cf6c27c79e30514497..b625c105f4e0e8a51b581104049bd1d76bcbc200 100644 --- a/aleksis/core/static/js/main.js +++ b/aleksis/core/static/js/main.js @@ -66,7 +66,7 @@ $(document).ready( function () { }); // Initialise auto-completion for search bar - window.autocomplete = new Autocomplete({}); + window.autocomplete = new Autocomplete({minimum_length: 2}); window.autocomplete.setup(); // Initialize text collapsibles [MAT, own work] diff --git a/aleksis/core/static/js/search.js b/aleksis/core/static/js/search.js index 7943d2ebfaa07123bf0174b24c055884ceb0bd36..ea1dfb25b061f73a8a74c40edad3e3c8d073278e 100644 --- a/aleksis/core/static/js/search.js +++ b/aleksis/core/static/js/search.js @@ -35,9 +35,20 @@ Autocomplete.prototype.setup = function () { self.query_box.trigger("keydown"); }); + this.query_box.keyup(function () { + var query = self.query_box.val(); + + if (query.length < self.minimum_length) { + $("#search-results").remove(); + return true; + } + + self.fetch(query); + return true; + }); + // Watch the input box. this.query_box.keydown(function (e) { - var query = self.query_box.val(); if (e.which === 38) { // Keypress Up if (!self.selected_element) { @@ -69,14 +80,6 @@ Autocomplete.prototype.setup = function () { e.preventDefault(); window.location.href = self.selected_element.attr("href"); } - - if (query.length < self.minimum_length) { - $("#search-results").remove(); - return true; - } - - self.fetch(query); - return true; }); // // On selecting a result, remove result box diff --git a/aleksis/core/static/style.scss b/aleksis/core/static/style.scss index e1edc75561fb4fe57568f1b148b8ab0f955c1b58..10a00caa35ef329b248b7be2f927cd2714ebd244 100644 --- a/aleksis/core/static/style.scss +++ b/aleksis/core/static/style.scss @@ -189,6 +189,7 @@ a.collection-item.search-item { div#search-results { position: absolute; + margin-top: -10px; width: 100%; } diff --git a/aleksis/core/templates/core/about.html b/aleksis/core/templates/core/about.html new file mode 100644 index 0000000000000000000000000000000000000000..5b9097f8e294b099151d90dc91fbb583bd9e6dc9 --- /dev/null +++ b/aleksis/core/templates/core/about.html @@ -0,0 +1,122 @@ +{# -*- engine:django -*- #} +{% extends "core/base.html" %} +{% load i18n %} + + +{% block browser_title %}{% blocktrans %}About AlekSIS{% endblocktrans %}{% endblock %} +{% block page_title %}{% blocktrans %}AlekSIS – The Free School Information System{% endblocktrans %}{% endblock %} + +{% block content %} + + <div class="row"> + <div class="col s12"> + <div class="card"> + <div class="card-content"> + <span class="card-title">{% blocktrans %}About AlekSIS{% endblocktrans %}</span> + <p> + {% blocktrans %} + This platform is powered by AlekSIS, a web-based school information system (SIS) which can be used + to manage and/or publish organisational subjects of educational institutions. AlekSIS is free software and + can be used by everyone. + {% endblocktrans %} + </p> + </div> + <div class="card-action"> + <a class="" href="https://aleksis.org/">{% trans "Website of AlekSIS" %}</a> + <a class="" href="https://edugit.org/AlekSIS/">{% trans "Source code" %}</a> + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col s12"> + <div class="card"> + <div class="card-content"> + <span class="card-title">{% trans "Licence information" %}</span> + <p> + {% blocktrans %} + The core and the official apps of AlekSIS are licenced under the EUPL, version 1.2 or later. For licence + information from third-party apps, if installed, see directly at the respective components below. The + licences are marked like this: + {% endblocktrans %} + </p> + <br/> + <p> + <span class="chip green white-text">{% trans "Free/Open Source Licence" %}</span> + <span class="chip orange white-text">{% trans "Other Licence" %}</span> + </p> + </div> + <div class="card-action"> + <a href="https://eupl.eu">{% trans "Full licence text" %}</a> + <a href="https://joinup.ec.europa.eu/collection/eupl/guidelines-users-and-developers">{% trans "More information about the EUPL" %}</a> + </div> + </div> + </div> + </div> + + <div class="row"> + {% for app_config in app_configs %} + <div class="col s12 m12 l6"> + <div class="card " id="{{ app_config.name }}"> + <div class="card-content"> + {% if app_config.get_licence.1.isFsfLibre %} + <span class="chip green white-text right">Free Software</span> + {% elif app_config.get_licence.1.isOsiApproved %} + <span class="chip green white-text right">Open Source</span> + {% endif %} + + <span class="card-title">{{ app_config.get_name }} <small>{{ app_config.get_version }}</small></span> + + {% if app_config.get_copyright %} + <p> + {% for holder in app_config.get_copyright %} + Copyright © {{ holder.0 }} + + {% if holder.2 %} + <a href="mailto:{{ holder.2 }}">{{ holder.1 }}</a> + {% else %} + {{ holder.1 }} + {% endif %} + + <br/> + {% endfor %} + </p> + <br/> + {% endif %} + + {% if app_config.get_licence %} + {% with licence=app_config.get_licence %} + <p> + {% blocktrans with licence=licence.0 %} + This app is licenced under {{ licence }}. + {% endblocktrans %} + </p> + <br/> + <p> + {% for l in licence.2 %} + <a class="chip white-text {% if l.isOsiApproved or l.isFsfLibre %}green{% else %}orange{% endif %}" + href="{{ l.url }}"> + {{ l.name }} + </a> + {% endfor %} + </p> + {% endwith %} + {% endif %} + </div> + {% if app_config.get_urls %} + <div class="card-action"> + {% for url_name, url in app_config.get_urls.items %} + <a href="{{ url }}">{{ url_name }}</a> + {% endfor %} + </div> + {% endif %} + </div> + </div> + {% if forloop.counter|divisibleby:2 %} + </div> + <div class="row"> + {% endif %} + {% endfor %} + </div> + +{% endblock %} diff --git a/aleksis/core/templates/core/base.html b/aleksis/core/templates/core/base.html index 8ac5ed74a195be76a558ae30e780d493ae6c2ecf..fe536557737d05a04c93d9bfbedfcc63f1bbe60b 100644 --- a/aleksis/core/templates/core/base.html +++ b/aleksis/core/templates/core/base.html @@ -146,8 +146,8 @@ <div class="footer-copyright"> <div class="container"> <div class="left"> - <a class="blue-text text-lighten-4" href="https://aleksis.org/"> - AlekSIS — The Free School Information System + <a class="blue-text text-lighten-4" href="{% url "about_aleksis" %}"> + {% trans "About AlekSIS — The Free School Information System" %} </a> © The AlekSIS Team </div> diff --git a/aleksis/core/templates/search/search.html b/aleksis/core/templates/search/search.html index babbd70d945f26cbf777ae46ca0add15a24e442d..d463f1569793168d6644c80a1dc63fe60cb06234 100644 --- a/aleksis/core/templates/search/search.html +++ b/aleksis/core/templates/search/search.html @@ -14,7 +14,6 @@ <input type="text" name="{{ form.q.name }}" id="{{ form.q.id }}" value="{% firstof form.q.value "" %}" placeholder="{% trans "Search Term" %}"> - <h6>{{ form.models.label }}</h6> <div> {% for group, items in form.models|select_options %} {% for choice, value, selected in items %} @@ -28,10 +27,12 @@ {% endfor %} </div> - <button type="submit" class="btn waves-effect waves-light green"> - <i class="material-icons left">search</i> - {% blocktrans %}Search{% endblocktrans %} - </button> + <p> + <button type="submit" class="btn waves-effect waves-light green"> + <i class="material-icons left">search</i> + {% blocktrans %}Search{% endblocktrans %} + </button> + </p> <h5>{% trans "Results" %}</h5> @@ -44,7 +45,9 @@ </a> {% empty %} <li class="collection-item"> - {% trans "No search results could be found to your search" %} + <p class="flow-text"> + {% trans "No search results could be found to your search." %} + </p> </li> {% endfor %} </div> @@ -81,11 +84,13 @@ </ul> {% endif %} {% else %} - <div class="collection"> + <ul class="collection"> <li class="collection-item"> - {% trans "Please enter a search term above" %} + <p class="flow-text"> + {% trans "Please enter a search term above." %} + </p> </li> - </div> + </ul> {% endif %} diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py index 4bb7d10fbbaa6774d5f5beed3a1d7e034f020260..5de76472c91da9243edfa13c57c5ce29a7782e08 100644 --- a/aleksis/core/urls.py +++ b/aleksis/core/urls.py @@ -16,6 +16,7 @@ from . import views urlpatterns = [ path("", include("pwa.urls"), name="pwa"), path("offline/", views.offline, name="offline"), + path("about/", views.about, name="about_aleksis"), path("admin/", admin.site.urls), path("data_management/", views.data_management, name="data_management"), path("status/", views.system_status, name="system_status"), diff --git a/aleksis/core/util/apps.py b/aleksis/core/util/apps.py index 7eef538ae05265d3492bda331eaf75875229a4ae..dbf6159252c0b20aee9fcc422fb21360c7fbc1e0 100644 --- a/aleksis/core/util/apps.py +++ b/aleksis/core/util/apps.py @@ -1,5 +1,5 @@ from importlib import import_module -from typing import Any, List, Optional, Tuple +from typing import Any, List, Optional, Tuple, Sequence import django.apps from django.contrib.auth.signals import user_logged_in, user_logged_out @@ -7,6 +7,10 @@ from django.db.models.signals import post_migrate, pre_migrate from django.http import HttpRequest from constance.signals import config_updated +from license_expression import Licensing, LicenseSymbol +from spdx_license_list import LICENSES + +from .core_helpers import copyright_years class AppConfig(django.apps.AppConfig): @@ -41,6 +45,87 @@ class AppConfig(django.apps.AppConfig): # ImportErrors are non-fatal because checks are optional. pass + @classmethod + def get_name(cls): + return getattr(cls, "verbose_name", cls.name) + # TODO Try getting from distribution if not set + + @classmethod + def get_version(cls): + try: + from .. import __version__ # noqa + except ImportError: + __version__ = None + + return getattr(cls, "version", __version__) + + @classmethod + def get_licence(cls) -> Tuple: + licence = getattr(cls, "licence", None) + + default_dict = { + 'isDeprecatedLicenseId': False, + 'isFsfLibre': False, + 'isOsiApproved': False, + 'licenseId': 'unknown', + 'name': 'Unknown Licence', + 'referenceNumber': -1, + 'url': '', + } + + if licence: + licensing = Licensing(LICENSES.keys()) + parsed = licensing.parse(licence).simplify() + readable = parsed.render_as_readable() + + flags = { + "isFsfLibre": True, + "isOsiApproved": True, + } + + licence_dicts = [] + + for symbol in parsed.symbols: + licence_dict = LICENSES.get(symbol.key.rstrip("+"), None) + + if licence_dict is None: + licence_dict = default_dict + else: + licence_dict["url"] = "https://spdx.org/licenses/{}.html".format(licence_dict["licenseId"]) + + flags["isFsfLibre"] = flags["isFsfLibre"] and licence_dict["isFsfLibre"] + flags["isOsiApproved"] = flags["isOsiApproved"] and licence_dict["isOsiApproved"] + + licence_dicts.append(licence_dict) + + return (readable, flags, licence_dicts) + else: + return ("Unknown", [default_dict]) + + @classmethod + def get_urls(cls): + return getattr(cls, "urls", {}) + # TODO Try getting from distribution if not set + + @classmethod + def get_copyright(cls) -> Sequence[Tuple[str, str, str]]: + copyrights = getattr(cls, "copyright", tuple()) + + copyrights_processed = [] + + for copyright in copyrights: + copyrights_processed.append( + ( + copyright[0] if isinstance(copyright[0], str) else copyright_years(copyright[0]), + copyright[1], + copyright[2], + ) + ) + + return copyrights_processed + + # TODO Try getting from distribution if not set + def config_updated( self, key: Optional[str] = "", diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py index 9f91154c30913ae14eff1332b5f6bea3207bfa86..13558233068626c8f288b70624b2646840826819 100644 --- a/aleksis/core/util/core_helpers.py +++ b/aleksis/core/util/core_helpers.py @@ -1,8 +1,10 @@ from datetime import datetime, timedelta +from itertools import groupby +from operator import itemgetter import os import pkgutil from importlib import import_module -from typing import Any, Callable, Sequence, Union +from typing import Any, Callable, Sequence, Union, List from uuid import uuid4 from django.conf import settings @@ -12,6 +14,18 @@ from django.utils import timezone from django.utils.functional import lazy +def copyright_years(years: Sequence[int], seperator: str = ", ", joiner: str = "–") -> str: + """ Takes a sequence of integegers and produces a string with ranges + + >>> copyright_years([1999, 2000, 2001, 2005, 2007, 2008, 2009]) + '1999–2001, 2005, 2007–2009' + """ + + ranges = [list(map(itemgetter(1), group)) for _, group in groupby(enumerate(years), lambda e: e[1]-e[0])] + years_strs = [str(range_[0]) if len(range_) == 1 else joiner.join([str(range_[0]), str(range_[-1])]) for range_ in ranges] + + return seperator.join(years_strs) + def dt_show_toolbar(request: HttpRequest) -> bool: from debug_toolbar.middleware import show_toolbar # noqa diff --git a/aleksis/core/views.py b/aleksis/core/views.py index d566ce328f7fbe5aa73d3261dfcaeecfe0aa4846..0f38a8a0412d7d0702ad05242710ec7c187c49a1 100644 --- a/aleksis/core/views.py +++ b/aleksis/core/views.py @@ -1,5 +1,7 @@ +from importlib import import_module from typing import Optional +from django.apps import apps from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.http import Http404, HttpRequest, HttpResponse @@ -24,6 +26,7 @@ from .forms import ( from .models import Activity, Group, Notification, Person, School, DashboardWidget, Announcement from .tables import GroupsTable, PersonsTable from .util import messages +from .util.apps import AppConfig @permission_required("core.view_dashboard") @@ -54,6 +57,14 @@ def offline(request): return render(request, "core/offline.html") +def about(request): + context = {} + + context["app_configs"] = list(filter(lambda a: isinstance(a, AppConfig), apps.get_app_configs())) + + return render(request, "core/about.html", context) + + @permission_required("core.view_persons") def persons(request: HttpRequest) -> HttpResponse: context = {} diff --git a/apps/official/AlekSIS-App-Chronos b/apps/official/AlekSIS-App-Chronos index 6b05dfc0613ff143fa292aa67eb349c90439d7ee..6833571a02b8df133ea0f3b99f75e93da0c50fc9 160000 --- a/apps/official/AlekSIS-App-Chronos +++ b/apps/official/AlekSIS-App-Chronos @@ -1 +1 @@ -Subproject commit 6b05dfc0613ff143fa292aa67eb349c90439d7ee +Subproject commit 6833571a02b8df133ea0f3b99f75e93da0c50fc9 diff --git a/apps/official/AlekSIS-App-DashboardFeeds b/apps/official/AlekSIS-App-DashboardFeeds index 894dc89ac4fd4f6c33b51020288eabe9b6169256..dc6d80c09193910bf27533ac7d6877839fb62c50 160000 --- a/apps/official/AlekSIS-App-DashboardFeeds +++ b/apps/official/AlekSIS-App-DashboardFeeds @@ -1 +1 @@ -Subproject commit 894dc89ac4fd4f6c33b51020288eabe9b6169256 +Subproject commit dc6d80c09193910bf27533ac7d6877839fb62c50 diff --git a/apps/official/AlekSIS-App-Exlibris b/apps/official/AlekSIS-App-Exlibris index 736a7ea53be4e0fa7de7bf3dd66cd47965e36bed..ab4e3f2d03bba8b4c2b6ad90d08106f423ae32e4 160000 --- a/apps/official/AlekSIS-App-Exlibris +++ b/apps/official/AlekSIS-App-Exlibris @@ -1 +1 @@ -Subproject commit 736a7ea53be4e0fa7de7bf3dd66cd47965e36bed +Subproject commit ab4e3f2d03bba8b4c2b6ad90d08106f423ae32e4 diff --git a/apps/official/AlekSIS-App-LDAP b/apps/official/AlekSIS-App-LDAP index c0bc552d9a7e04560b54c261b5e8d690958d2968..f99aa641eb5cdeaf5421e5297813cbcb3c55eb6c 160000 --- a/apps/official/AlekSIS-App-LDAP +++ b/apps/official/AlekSIS-App-LDAP @@ -1 +1 @@ -Subproject commit c0bc552d9a7e04560b54c261b5e8d690958d2968 +Subproject commit f99aa641eb5cdeaf5421e5297813cbcb3c55eb6c diff --git a/apps/official/AlekSIS-App-Untis b/apps/official/AlekSIS-App-Untis new file mode 160000 index 0000000000000000000000000000000000000000..a567021ee5e66657b3374a76865bab1ee9bdbc33 --- /dev/null +++ b/apps/official/AlekSIS-App-Untis @@ -0,0 +1 @@ +Subproject commit a567021ee5e66657b3374a76865bab1ee9bdbc33 diff --git a/poetry.lock b/poetry.lock index 591849c3413c4492ebc30c577f706574f7c8470a..6893b47254efa4705507f421317319d5a99d8e70 100644 --- a/poetry.lock +++ b/poetry.lock @@ -140,6 +140,14 @@ version = "3.1.4" six = ">=1.9.0" webencodings = "*" +[[package]] +category = "main" +description = "Define boolean algebras, create and parse boolean expressions and create custom boolean DSL." +name = "boolean.py" +optional = false +python-versions = "*" +version = "3.7" + [[package]] category = "main" description = "Utilities for working with calendar weeks in Python and Django" @@ -207,6 +215,17 @@ yaml = ["PyYAML (>=3.10)"] zookeeper = ["kazoo (>=1.3.1)"] zstd = ["zstandard"] +[[package]] +category = "main" +description = "An app for integrating Celery with Haystack." +name = "celery-haystack" +optional = true +python-versions = "*" +version = "0.3.1" + +[package.dependencies] +django-appconf = ">=0.2.1" + [[package]] category = "main" description = "Python package for providing Mozilla's CA Bundle." @@ -437,6 +456,19 @@ version = "*" database = ["django-picklefield"] redis = ["redis"] +[[package]] +category = "main" +description = "Management commands to help backup and restore a project database and media" +name = "django-dbbackup" +optional = false +python-versions = "*" +version = "3.3.0" + +[package.dependencies] +Django = ">=1.5" +pytz = "*" +six = "*" + [[package]] category = "main" description = "A configurable set of panels that display various debug information about the current request/response." @@ -497,6 +529,17 @@ django-bulk-update = ">=2.2.0" six = "*" tqdm = ">=4.23.4" +[[package]] +category = "main" +description = "Pluggable search for Django." +name = "django-haystack" +optional = false +python-versions = "*" +version = "3.0b1" + +[package.dependencies] +Django = ">=2.2" + [[package]] category = "main" description = "A reusable app for cropping images easily and non-destructively in Django" @@ -580,7 +623,7 @@ description = "An implementation of memoization technique for Django." name = "django-memoize" optional = false python-versions = "*" -version = "2.2.1" +version = "2.3.0" [package.dependencies] django = "*" @@ -1179,6 +1222,17 @@ version = "0.19.4" [package.dependencies] six = "*" +[[package]] +category = "main" +description = "license-expression is small utility library to parse, compare, simplify and normalize license expressions (such as SPDX license expressions) using boolean logic." +name = "license-expression" +optional = false +python-versions = "*" +version = "1.2" + +[package.dependencies] +"boolean.py" = ">=3.6,<4.0.0" + [[package]] category = "dev" description = "Safely add untrusted strings to HTML/XML markup." @@ -1261,7 +1315,7 @@ description = "PostgreSQL interface library" name = "pg8000" optional = false python-versions = ">=3.5" -version = "1.15.1" +version = "1.15.2" [package.dependencies] scramp = "1.1.1" @@ -1515,7 +1569,7 @@ description = "Add .env support to your django/flask apps in development and dep name = "python-dotenv" optional = false python-versions = "*" -version = "0.12.0" +version = "0.13.0" [package.extras] cli = ["click (>=5.0)"] @@ -1691,6 +1745,14 @@ optional = false python-versions = "*" version = "1.9.5" +[[package]] +category = "main" +description = "A simple tool/library for working with SPDX license definitions." +name = "spdx-license-list" +optional = false +python-versions = "*" +version = "0.4.0" + [[package]] category = "dev" description = "Python documentation generator" @@ -1932,11 +1994,11 @@ description = "HTTP library with thread-safe connection pooling, file post, and name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.8" +version = "1.25.9" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] @@ -1953,7 +2015,7 @@ description = "Virtual Python Environment builder" name = "virtualenv" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "20.0.17" +version = "20.0.18" [package.dependencies] appdirs = ">=1.4.3,<2" @@ -2007,11 +2069,11 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools", "func-timeout"] [extras] -celery = ["Celery", "django-celery-results", "django-celery-beat", "django-celery-email"] +celery = ["Celery", "django-celery-results", "django-celery-beat", "django-celery-email", "celery-haystack"] ldap = ["django-auth-ldap"] [metadata] -content-hash = "8d698d1e20a7a28bb0f91312abb432565a30e9345f39552a2c2933eb1b4f8072" +content-hash = "afd2f4b69870b913a740e8247dbe3618d40e0b51294203c5e883b9f72427bd71" python-versions = "^3.7" [metadata.files] @@ -2064,6 +2126,10 @@ bleach = [ {file = "bleach-3.1.4-py2.py3-none-any.whl", hash = "sha256:cc8da25076a1fe56c3ac63671e2194458e0c4d9c7becfd52ca251650d517903c"}, {file = "bleach-3.1.4.tar.gz", hash = "sha256:e78e426105ac07026ba098f04de8abe9b6e3e98b5befbf89b51a5ef0a4292b03"}, ] +"boolean.py" = [ + {file = "boolean.py-3.7-py2.py3-none-any.whl", hash = "sha256:82ae181f9c85cb5c893a5a4daba9f24d60b538a7dd27fd0c6752a77eba4fbeff"}, + {file = "boolean.py-3.7.tar.gz", hash = "sha256:bd19b412435611ecc712603d0fd7d0e280e24698e7a6e3d5f610473870c5dd1e"}, +] calendarweek = [ {file = "calendarweek-0.4.5-py3-none-any.whl", hash = "sha256:b35fcc087073969d017cede62a7295bcd714a1304bcb4c4e2b0f23acb0265fb1"}, {file = "calendarweek-0.4.5.tar.gz", hash = "sha256:5b1788ca435022f9348fc81a718974e51dd85d080f9aa3dad717df70a1bc6e1f"}, @@ -2072,6 +2138,9 @@ celery = [ {file = "celery-4.4.2-py2.py3-none-any.whl", hash = "sha256:5b4b37e276033fe47575107a2775469f0b721646a08c96ec2c61531e4fe45f2a"}, {file = "celery-4.4.2.tar.gz", hash = "sha256:108a0bf9018a871620936c33a3ee9f6336a89f8ef0a0f567a9001f4aa361415f"}, ] +celery-haystack = [ + {file = "celery-haystack-0.3.1.tar.gz", hash = "sha256:49992712e67b1f39afd294dca6ba2820f2d262b3137ad14cb0c57a05fa218725"}, +] certifi = [ {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, @@ -2181,6 +2250,9 @@ django-colorfield = [ django-constance = [ {file = "django-constance-2.6.0.tar.gz", hash = "sha256:12d827f9d5552ee39884fb6fb356f231f32b1ab8958acc715e3d1a6ecf913653"}, ] +django-dbbackup = [ + {file = "django-dbbackup-3.3.0.tar.gz", hash = "sha256:bb109735cae98b64ad084e5b461b7aca2d7b39992f10c9ed9435e3ebb6fb76c8"}, +] django-debug-toolbar = [ {file = "django-debug-toolbar-2.2.tar.gz", hash = "sha256:eabbefe89881bbe4ca7c980ff102e3c35c8e8ad6eb725041f538988f2f39a943"}, {file = "django_debug_toolbar-2.2-py3-none-any.whl", hash = "sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"}, @@ -2201,6 +2273,10 @@ django-hattori = [ {file = "django-hattori-0.2.1.tar.gz", hash = "sha256:6953d40881317252f19f62c4e7fe8058924b852c7498bc42beb7bc4d268c252c"}, {file = "django_hattori-0.2.1-py2.py3-none-any.whl", hash = "sha256:e529ed7af8fc34a0169c797c477672b687a205a56f3f5206f90c260acb83b7ac"}, ] +django-haystack = [ + {file = "django-haystack-3.0b1.tar.gz", hash = "sha256:9dba64f5c76cf147ac382d4a4a270f30d30a45a3a7a1738a9d05c96d18777c07"}, + {file = "django_haystack-3.0b1-py3-none-any.whl", hash = "sha256:b83705e1cf8141cd1755fc6683ac65fea4e1281f4b4306bc9224af96495b0df3"}, +] django-image-cropping = [ {file = "django-image-cropping-1.4.0.tar.gz", hash = "sha256:6cc4a6bd8901e69b710caceea29b942fdb202da26626313cd9271ae989a83a52"}, {file = "django_image_cropping-1.4.0-py3-none-any.whl", hash = "sha256:fe6a139c6d5dfc480f2a1d4e7e3e928d5edaefc898e17be66bc5f73140762ad9"}, @@ -2231,7 +2307,7 @@ django-material = [ {file = "django_material-1.6.3-py2.py3-none-any.whl", hash = "sha256:502dc88c2f61f190fdc401666e83b47da00cbda98477af6ed8b7d43944ce6407"}, ] django-memoize = [ - {file = "django-memoize-2.2.1.tar.gz", hash = "sha256:7428e19cb17009ea51120420101a239d83bdf4064e5c72ca8c3dfa9656033f24"}, + {file = "django-memoize-2.3.0.tar.gz", hash = "sha256:85decffbef7d38ffc569dc96527f598e6677bbc01ce29adf722b051da7efd4be"}, ] django-menu-generator = [ {file = "django-menu-generator-1.0.4.tar.gz", hash = "sha256:ce71a5055c16933c8aff64fb36c21e5cf8b6d505733aceed1252f8b99369a378"}, @@ -2419,6 +2495,10 @@ libsass = [ {file = "libsass-0.19.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6a51393d75f6e3c812785b0fa0b7d67c54258c28011921f204643b55f7355ec0"}, {file = "libsass-0.19.4.tar.gz", hash = "sha256:8b5b6d1a7c4ea1d954e0982b04474cc076286493f6af2d0a13c2e950fbe0be95"}, ] +license-expression = [ + {file = "license-expression-1.2.tar.gz", hash = "sha256:7960e1dfdf20d127e75ead931476f2b5c7556df05b117a73880b22ade17d1abc"}, + {file = "license_expression-1.2-py2.py3-none-any.whl", hash = "sha256:6d97906380cecfc758a77f6d38c6760f2afade7e83d2b8295e234fe21f486fb8"}, +] markupsafe = [ {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, @@ -2495,8 +2575,8 @@ pbr = [ {file = "pbr-5.4.5.tar.gz", hash = "sha256:07f558fece33b05caf857474a366dfcc00562bca13dd8b47b2b3e22d9f9bf55c"}, ] pg8000 = [ - {file = "pg8000-1.15.1-py3-none-any.whl", hash = "sha256:1f17917c8e2580581f4f689ed5e6eefef4ba873e7a9550d04afcb07fd43be83d"}, - {file = "pg8000-1.15.1.tar.gz", hash = "sha256:01033498ffb27e780f6fb9ec877655ad97ceb26a50efdd77ca3b39ab2271f37c"}, + {file = "pg8000-1.15.2-py3-none-any.whl", hash = "sha256:2bfdd03c2623302af655ef089a958ff329b2035c9d9aea406b5e4dac9c007524"}, + {file = "pg8000-1.15.2.tar.gz", hash = "sha256:eb42ba62fbc048c91d5cf1ac729e0ea4ee329cc526bddafed4e7a8aa6b57fbbb"}, ] phonenumbers = [ {file = "phonenumbers-8.12.1-py2.py3-none-any.whl", hash = "sha256:bebf881ef0e775b93062fbd107bf164b5baef877a7b8f702e93a9a5d24ae4065"}, @@ -2637,8 +2717,8 @@ python-dateutil = [ {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, ] python-dotenv = [ - {file = "python-dotenv-0.12.0.tar.gz", hash = "sha256:92b3123fb2d58a284f76cc92bfe4ee6c502c32ded73e8b051c4f6afc8b6751ed"}, - {file = "python_dotenv-0.12.0-py2.py3-none-any.whl", hash = "sha256:81822227f771e0cab235a2939f0f265954ac4763cafd806d845801c863bf372f"}, + {file = "python-dotenv-0.13.0.tar.gz", hash = "sha256:3b9909bc96b0edc6b01586e1eed05e71174ef4e04c71da5786370cebea53ad74"}, + {file = "python_dotenv-0.13.0-py2.py3-none-any.whl", hash = "sha256:25c0ff1a3e12f4bde8d592cc254ab075cfe734fc5dd989036716fd17ee7e5ec7"}, ] python-ldap = [ {file = "python-ldap-3.2.0.tar.gz", hash = "sha256:7d1c4b15375a533564aad3d3deade789221e450052b21ebb9720fb822eccdb8e"}, @@ -2730,6 +2810,10 @@ soupsieve = [ {file = "soupsieve-1.9.5-py2.py3-none-any.whl", hash = "sha256:bdb0d917b03a1369ce964056fc195cfdff8819c40de04695a80bc813c3cfa1f5"}, {file = "soupsieve-1.9.5.tar.gz", hash = "sha256:e2c1c5dee4a1c36bcb790e0fabd5492d874b8ebd4617622c4f6a731701060dda"}, ] +spdx-license-list = [ + {file = "spdx_license_list-0.4.0-py3-none-any.whl", hash = "sha256:e5c2d1efc4067ff83609a200c731db6c656fdfd26144ac8b50755d6c72515453"}, + {file = "spdx_license_list-0.4.0.tar.gz", hash = "sha256:f8b5eeda2a1c88d8ce15f6324d5a6128a462932a2e55b032f017ac9a0e61f1c7"}, +] sphinx = [ {file = "Sphinx-2.4.4-py3-none-any.whl", hash = "sha256:fc312670b56cb54920d6cc2ced455a22a547910de10b3142276495ced49231cb"}, {file = "Sphinx-2.4.4.tar.gz", hash = "sha256:b4c750d546ab6d7e05bdff6ac24db8ae3e8b8253a3569b754e445110a0a12b66"}, @@ -2831,16 +2915,16 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, ] urllib3 = [ - {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, - {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, + {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, + {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, ] vine = [ {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"}, {file = "vine-1.3.0.tar.gz", hash = "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87"}, ] virtualenv = [ - {file = "virtualenv-20.0.17-py2.py3-none-any.whl", hash = "sha256:00cfe8605fb97f5a59d52baab78e6070e72c12ca64f51151695407cc0eb8a431"}, - {file = "virtualenv-20.0.17.tar.gz", hash = "sha256:c8364ec469084046c779c9a11ae6340094e8a0bf1d844330fc55c1cefe67c172"}, + {file = "virtualenv-20.0.18-py2.py3-none-any.whl", hash = "sha256:5021396e8f03d0d002a770da90e31e61159684db2859d0ba4850fbea752aa675"}, + {file = "virtualenv-20.0.18.tar.gz", hash = "sha256:ac53ade75ca189bc97b6c1d9ec0f1a50efe33cbf178ae09452dcd9fd309013c1"}, ] virtualenv-clone = [ {file = "virtualenv-clone-0.5.4.tar.gz", hash = "sha256:665e48dd54c84b98b71a657acb49104c54e7652bce9c1c4f6c6976ed4c827a29"}, diff --git a/pyproject.toml b/pyproject.toml index cc3967bcd613a1616e9cfef5e6eb7c0f21ce3588..7ebc0ca15eb5fdbdb8061c7316ce915434e79ffb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,8 +71,11 @@ django-memoize = "^2.2.1" django-guardian = "^2.2.0" rules = "^2.2" django-haystack = "^3.0" +django-haystack = {version="3.0b1", allows-prereleases = true} celery-haystack = {version="^0.3.1", optional=true} django-dbbackup = "^3.3.0" +spdx-license-list = "^0.4.0" +license-expression = "^1.2" [tool.poetry.extras] ldap = ["django-auth-ldap"]