diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d67a50560c92e815b5b779dd651f3b1dbb4f4250..955750958d170e723e9714295750d0e1204e878f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,9 @@ include: - - local: "/ci/general.yml" - - local: "/ci/test.yml" - - local: "/ci/build_dist.yml" - - local: "/ci/build_docker.yml" - - local: "/ci/pages.yml" - - local: "/ci/deploy_pypi.yml" - - local: "/ci/deploy.yml" + - project: "AlekSIS/official/AlekSIS" + file: /ci/general.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/test.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/build_dist.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/deploy_pypi.yml diff --git a/.gitmodules b/.gitmodules index a7fa3c3c15f5415169a0f2b0ce67876831caf5f7..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,20 +0,0 @@ -[submodule "apps/official/AlekSIS-App-Chronos"] - path = apps/official/AlekSIS-App-Chronos - url = https://edugit.org/AlekSIS/Official/AlekSIS-App-Chronos - ignore = untracked -[submodule "apps/official/AlekSIS-App-DashboardFeeds"] - path = apps/official/AlekSIS-App-DashboardFeeds - 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 -[submodule "apps/official/AlekSIS-App-Hjelp"] - path = apps/official/AlekSIS-App-Hjelp - url = https://edugit.org/AlekSIS/official/AlekSIS-App-Hjelp - ignore = untracked diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst deleted file mode 100644 index 9618c5f7d4285f366f05a5f8b2fd4cef43cf829b..0000000000000000000000000000000000000000 --- a/CODE_OF_CONDUCT.rst +++ /dev/null @@ -1,144 +0,0 @@ -Contributor Covenant Code of Conduct -==================================== - -Our Pledge ----------- - -We as members, contributors, and leaders pledge to make participation in -our community a harassment-free experience for everyone, regardless of -age, body size, visible or invisible disability, ethnicity, sex -characteristics, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, -race, religion, or sexual identity and orientation. - -We pledge to act and interact in ways that contribute to an open, -welcoming, diverse, inclusive, and healthy community. - -Our Standards -------------- - -Examples of behavior that contributes to a positive environment for our -community include: - -- Demonstrating empathy and kindness toward other people -- Being respectful of differing opinions, viewpoints, and experiences -- Giving and gracefully accepting constructive feedback -- Accepting responsibility and apologizing to those affected by our - mistakes, and learning from the experience -- Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -- The use of sexualized language or imagery, and sexual attention or - advances of any kind -- Trolling, insulting or derogatory comments, and personal or political - attacks -- Public or private harassment -- Publishing others’ private information, such as a physical or email - address, without their explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -Enforcement Responsibilities ----------------------------- - -Community leaders are responsible for clarifying and enforcing our -standards of acceptable behavior and will take appropriate and fair -corrective action in response to any behavior that they deem -inappropriate, threatening, offensive, or harmful. - -Community leaders have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other -contributions that are not aligned to this Code of Conduct, and will -communicate reasons for moderation decisions when appropriate. - -Scope ------ - -This Code of Conduct applies within all community spaces, and also -applies when an individual is officially representing the community in -public spaces. Examples of representing our community include using an -official e-mail address, posting via an official social media account, -or acting as an appointed representative at an online or offline event. - -Enforcement ------------ - -Instances of abusive, harassing, or otherwise unacceptable behavior may -be reported to the community leaders responsible for enforcement at -foss@teckids.org. All complaints will be reviewed and investigated -promptly and fairly. - -All community leaders are obligated to respect the privacy and security -of the reporter of any incident. - -Enforcement Guidelines ----------------------- - -Community leaders will follow these Community Impact Guidelines in -determining the consequences for any action they deem in violation of -this Code of Conduct: - -1. Correction -~~~~~~~~~~~~~ - -**Community Impact**: Use of inappropriate language or other behavior -deemed unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, -providing clarity around the nature of the violation and an explanation -of why the behavior was inappropriate. A public apology may be -requested. - -2. Warning -~~~~~~~~~~ - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, for a specified period of -time. This includes avoiding interactions in community spaces as well as -external channels like social media. Violating these terms may lead to a -temporary or permanent ban. - -3. Temporary Ban -~~~~~~~~~~~~~~~~ - -**Community Impact**: A serious violation of community standards, -including sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No -public or private interaction with the people involved, including -unsolicited interaction with those enforcing the Code of Conduct, is -allowed during this period. Violating these terms may lead to a -permanent ban. - -4. Permanent Ban -~~~~~~~~~~~~~~~~ - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of -individuals. - -**Consequence**: A permanent ban from any sort of public interaction -within the project community. - -Attribution ------------ - -This Code of Conduct is adapted from the `Contributor -Covenant <https://www.contributor-covenant.org>`__, version 2.0, -available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by `Mozilla’s code of conduct -enforcement ladder <https://github.com/mozilla/diversity>`__. - -For answers to common questions about this code of conduct, see the FAQ -at https://www.contributor-covenant.org/faq. Translations are available -at https://www.contributor-covenant.org/translations. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index be12afc1552dc2b6d6cb398bc2a456392ef21b9d..0000000000000000000000000000000000000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,232 +0,0 @@ -Development principles and contribution guidelines -================================================== - -In order to create a high-quality software product, the AlekSIS developers -have agreed upon fundamental principles governing the code layout, coding -style and repository management for AlekSIS and all official apps. - - -Coding layout and style ------------------------ - -The coding style is defined in `PEP 8`_, with the following differences and -decisions: - -- The defaults of the `black`_ code formatter are used - - This implies all string literals usin double-quotes, if it does not lead - to more escaping. As proposed by `black`: "My recommendation here is to - keep using whatever is faster to type and let Black handle the transformation." -- The maximum line length is 100 characters -- Imports are structured in five blocks, each of them sorted as defined in - PEP 8 and the Django style guide: - - 1. Standard library imports - 2. Django imports - 3. Third-party imports - 4. Imports from AlekSIS core and other apps (absolute imports) - 5. Imports from the same AlekSIS app (realtive imports) - - Use `isort` to take care of this - -For the layout of source trees and style recommendations specific to Django, -the `Django coding style`_ is a good source of information, together with -the `Django Best Practices`_ collection. - -To ensure code is styled correctly, before commiting, run:: - - tox -e reformat - -Text documents -~~~~~~~~~~~~~~ - -If there is no objective reason against it, all text documents accompanying -the source use `reStructuredText`_. - - -Working with the Git repository -------------------------------- - -The Git repository shall be used as a historic documentation of development -and as change management. It is important that the Git commit history -describes what was changed, by whom and why. - -Help and information on Git for beginners are available in the `Git guide`_ - -Feature and issue branches -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -All features and bug fixes should be developed in their own branch and later -merged into the master branch as a whole. Of course, sometimes, it is -sensible to not do that, e.g. for fixing mere typos and the like. - -Within the feature branch, every logical step should be commited separately. -It is neither required nor desired to do micro-commits about every -development step. The commit history should describe the trains of thought -the design and implementation is based on. - -If you work on multiple issues at the same time, you have to change between -branches. Never work on unrelated issues in the same branch. - -Branches should either contain the number and title of the related issue (as -generated by GitLab), or follow the naming convention type/name, where type -is one of bugfix, feature, or refactor. - -All changes on the code should be commited and pushed before stopping work on -in order to prevent data loss. If a logical step is continued later, you -should amend and force-push the commit. - -Issue branches should be rebased onto the current master regularly to avoid -merge conflicts. - -Commit messages -~~~~~~~~~~~~~~~ - -Commit messages should be written as described in `How to Write a Git Commit -Message`_. - -Commit messages should mention or even close any related issues. For merely -mentioning progress on an issue, use the keyword `advances`; for closing an -issue, use `closes`; for referring to a related issue for informational -purposes, use `cf.`. This should be done in the body of the commit message. - -The subject of a commit message can (and should) be prepended with a tag in -square brackets if it relates to a certain part of the repository, e.g. [CI] -when changing CI/CD configuration or support code, [Dev] when changing -something in the development utilities, etc. - -Example:: - - Solve LDAP connection problems - - - Add the ldap-with-unicorn-dust dependency - - Configure settings.py to accept the correct groups from LDAP - - Closes #10. - -Merge Requests -~~~~~~~~~~~~~~ - -If you think that the work on your feature branch is finished, you have to -create a merge request on EduGit in order to let other developers and the -maintainers take a look at it. - -See below on how to submit patches if you cannot use the development -platform. - -Manifestos governing development --------------------------------- - -The FOSS community has created some manifestos describing several aspects of -software development, to agree upon a baseline for these aspects. The -AlekSIS developers have agreed to adhere to the following manifestos: - -- The `Sane software manifesto`_ -- The `Accessibility Manifesto`_ -- The `User Data Manifesto`_ - -Not all theses from these manifestos are applicable. For example, most data -about persons in a school information system are dictated by the school and -probably governed by laws defining what and when to store. In that case, -giving the user control over these decisions is not possible. Developers -need to decide what should resonably be followed. - -The case on supporting non-free services -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Defined by the `Free Software Definition`_, it is an essential freedom to -be allowed to use free software for any purpose, without limitation. Thus, -interoperability with non-free services shall not be ruled out, and the -AlekSIS project explicitly welcomes implementing support for -interoperability with non-free services. - -However, to purposefully foster free software and services, if -interoperability for a certain kind of non-free service is implemented, this -must be done in a generalised manner (i.e. using open protocols and -interfaces). For example, if implementing interoperability with some -cloud-hosted calendar provider can be implemented either through a -proprietary API, or through a standard iCalendar/Webcal interfaces, the -latter is to be preferred. Lacking such support, if a proprietary service -is connected through a proprietary, single-purpose interface, measures shall -be taken to also support alternative free services. - - -Documentation -------------- - -The documentation in the AlekSIS project shall consist of three layers. - -Source code comments -~~~~~~~~~~~~~~~~~~~~ - -The parts of your code that are not self-explaining have to be commented. -Ideally, source code is self-explaining, in the sense that its logical -structure, naming of variables, and the like makes it easy to read and -understand, for a reasonably talented programmer, to follow what it does. - -Docstrings -~~~~~~~~~~ - -All functions, methods, classes and modules that are newly added (or changed -extensively) must contain a docstring for other developers to understand -what it does. Docstrings of public elements will be included in the -developer documentation. - -Sphinx documentation -~~~~~~~~~~~~~~~~~~~~ - -In addition to that you should document the function or the way the app -works in the project documentation (`docs/` directory). Use that especially -for functionality which is shared by your app for other apps (public APIs). - -Your Sphinx documentation should contain what the API can and shall be sued -for, and how other apps can benefit from it. - -When creating a new app, also include documentation about it targeted at -administrators and users. At least you have to document what new developers -and users have to do in order to get a working instance of the app. - -Sphinx documentation for all official apps will be published together. - - -Contributing to upstream ------------------------- - -If possible and reasonable, code that can be of use to others in the general -Django ecosystem shall be contributed to any upstream dependency, or a new -generalised upstream dependency be created, under the most permissive -licence possible. - - -How to contact the team ------------------------ - -Development platform -~~~~~~~~~~~~~~~~~~~~ - -Main development of AlekSIS is done on the `EduGit`_ platform in the -`AlekSIS group`_ and discussions are held on the linked `Mattermost team`_. - -All platforms and tools mandated for development are free software and -freely usable. EduGit accepts a variety of sources for login, so -contributors are free to decide where they want to register in order to -participate. - -If any contributor cannot use the platforms for whatever reasons, patches and -questions directed at the developers can also be e-mailed to -<aleksis-dev@lists.teckids.org>. - - -.. _PEP 8: https://pep8.org/ -.. _Django coding style: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/ -.. _black: https://black.readthedocs.io/en/stable/ -.. _Django Best Practices: https://django-best-practices.readthedocs.io/en/latest/index.html -.. _Git guide: https://rogerdudler.github.io/git-guide/ -.. _How to Write a Git Commit Message: https://chris.beams.io/posts/git-commit/ -.. _Sane software manifesto: https://sane-software.globalcode.info/ -.. _Accessibility Manifesto: http://accessibilitymanifesto.com/ -.. _User Data Manifesto: https://userdatamanifesto.org/ -.. _Free Software Definition: https://www.gnu.org/philosophy/free-sw.en.html -.. _reStructuredText: http://docutils.sourceforge.net/rst.html -.. _EduGit: https://edugit.org/ -.. _AlekSIS group: https://edugit.org/AlekSIS/ -.. _Mattermost team: https://mattermost.edugit.org/biscuit/ diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 0c4f3b52ededb87de3ea36f7814d155aaa20026d..0000000000000000000000000000000000000000 --- a/Dockerfile +++ /dev/null @@ -1,97 +0,0 @@ -FROM python:3.8-buster AS core - -# Configure Python to be nice inside Docker and pip to stfu -ENV PYTHONUNBUFFERED 1 -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PIP_DEFAULT_TIMEOUT 100 -ENV PIP_DISABLE_PIP_VERSION_CHECK 1 -ENV PIP_NO_CACHE_DIR 1 - -# Configure app settings for build and runtime -ENV ALEKSIS_static__root /usr/share/aleksis/static -ENV ALEKSIS_media__root /var/lib/aleksis/media -ENV ALEKSIS_backup__location /var/lib/aleksis/backups - -# Install necessary Debian packages for build and runtime -RUN apt-get -y update && \ - apt-get -y install eatmydata && \ - eatmydata apt-get -y upgrade && \ - eatmydata apt-get install -y --no-install-recommends \ - build-essential \ - gettext \ - libpq5 \ - libpq-dev \ - libssl-dev \ - netcat-openbsd \ - yarnpkg - -# Install core -WORKDIR /usr/src/app -COPY LICENCE.rst README.rst manage.py poetry.lock pyproject.toml ./ -COPY aleksis ./aleksis/ -RUN set -e; \ - mkdir -p /var/lib/aleksis/media /usr/share/aleksis/static /var/lib/aleksis/backups; \ - eatmydata pip install poetry; \ - poetry config virtualenvs.create false; \ - eatmydata poetry install; \ - eatmydata pip install gunicorn django-compressor - -# Declare a persistent volume for all data -VOLUME /var/lib/aleksis - -# Define entrypoint and gunicorn running on port 8000 -EXPOSE 8000 -COPY docker/entrypoint.sh /usr/local/bin/ -ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] - -# Install core extras -FROM core AS core-extras -ARG EXTRA_LDAP=1 -ARG EXTRA_CELERY=1 -WORKDIR /usr/src/app - -# LDAP -RUN if [ $EXTRA_LDAP = 1 ] ; then \ - eatmydata apt-get install -y --no-install-recommends \ - libldap2-dev \ - libsasl2-dev \ - ldap-utils; \ - eatmydata poetry install -E ldap; \ - fi; - -# Celery -RUN if [ $EXTRA_CELERY = 1 ] ; then \ - eatmydata poetry install -E celery; \ - fi; - -# Install official apps -FROM core-extras AS apps -COPY apps ./apps/ -RUN set -e; \ - for d in apps/official/*; do \ - cd $d; \ - rm -rf .git; \ - poetry install; \ - cd ../../..; \ - done - -# Build messages and assets -FROM apps as assets -RUN eatmydata python manage.py compilemessages && \ - eatmydata python manage.py yarn install && \ - eatmydata python manage.py collectstatic --no-input --clear - -# Clean up build dependencies -FROM assets AS clean -RUN set -e; \ - eatmydata apt-get remove --purge -y \ - build-essential \ - gettext \ - libpq-dev \ - libssl-dev \ - yarnpkg; \ - eatmydata apt-get autoremove --purge -y; \ - apt-get clean -y; \ - eatmydata pip uninstall -y poetry; \ - rm -f /var/lib/apt/lists/*_*; \ - rm -rf /root/.cache diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index c550a0421567c521a494f19124ac59542e83946a..45571b0db5e19ee996162b5549b4aaad4652bf44 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -368,6 +368,7 @@ SASS_PROCESSOR_CUSTOM_FUNCTIONS = { } SASS_PROCESSOR_INCLUDE_DIRS = [ _settings.get("materialize.sass_path", JS_ROOT + "/materialize-css/sass/"), + STATIC_ROOT + "/materialize-css/sass/", STATIC_ROOT, ] diff --git a/aleksis/core/util/core_helpers.py b/aleksis/core/util/core_helpers.py index aeffad13fb6d1d869a8b6e2793b18f36a9063096..6b5c01c6f7cb5dc1aa5511aa249c765dce2744e6 100644 --- a/aleksis/core/util/core_helpers.py +++ b/aleksis/core/util/core_helpers.py @@ -1,5 +1,4 @@ import os -import pkgutil import time from datetime import datetime, timedelta from importlib import import_module @@ -8,6 +7,11 @@ from operator import itemgetter from typing import Any, Callable, Optional, Sequence, Union from uuid import uuid4 +try: + from importlib import metadata +except ImportError: + import importlib_metadata as metadata + from django.conf import settings from django.db.models import Model, QuerySet from django.http import HttpRequest @@ -59,14 +63,8 @@ def dt_show_toolbar(request: HttpRequest) -> bool: def get_app_packages() -> Sequence[str]: - """Find all packages within the aleksis.apps namespace.""" - # Import error are non-fatal here because probably simply no app is installed. - try: - import aleksis.apps - except ImportError: - return [] - - return [f"aleksis.apps.{pkg[1]}" for pkg in pkgutil.iter_modules(aleksis.apps.__path__)] + """Find all registered apps from the setuptools entrypoint.""" + return [f"{ep.module}.{ep.attr}" for ep in metadata.entry_points()["aleksis.app"]] def merge_app_settings( @@ -81,11 +79,19 @@ def merge_app_settings( Note: Only selected names will be imported frm it to minimise impact of potentially malicious apps! """ - for pkg in get_app_packages(): - try: - mod_settings = import_module(pkg + ".settings") - except ImportError: - # Import errors are non-fatal. They mean that the app has no settings.py. + for app in get_app_packages(): + pkg = ".".join(app.split(".")[:-2]) + mod_settings = None + while "." in pkg: + try: + mod_settings = import_module(pkg + ".settings") + except ImportError: + # Import errors are non-fatal. + pkg = ".".join(pkg.split(".")[:-1]) + continue + break + if not mod_settings: + # The app does not have settings continue app_setting = getattr(mod_settings, setting, None) diff --git a/apps/official/AlekSIS-App-Chronos b/apps/official/AlekSIS-App-Chronos deleted file mode 160000 index 0be06de63d5f56eab6f9c1e814a82c69c318ffd1..0000000000000000000000000000000000000000 --- a/apps/official/AlekSIS-App-Chronos +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0be06de63d5f56eab6f9c1e814a82c69c318ffd1 diff --git a/apps/official/AlekSIS-App-DashboardFeeds b/apps/official/AlekSIS-App-DashboardFeeds deleted file mode 160000 index 1cf18722553a016b8a9165de556bb00329f10173..0000000000000000000000000000000000000000 --- a/apps/official/AlekSIS-App-DashboardFeeds +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1cf18722553a016b8a9165de556bb00329f10173 diff --git a/apps/official/AlekSIS-App-Hjelp b/apps/official/AlekSIS-App-Hjelp deleted file mode 160000 index 0898d261d95df2079767cf58a316d4804a2e230e..0000000000000000000000000000000000000000 --- a/apps/official/AlekSIS-App-Hjelp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0898d261d95df2079767cf58a316d4804a2e230e diff --git a/apps/official/AlekSIS-App-LDAP b/apps/official/AlekSIS-App-LDAP deleted file mode 160000 index 412631fb73abf30c931c3f1951def102720e3f51..0000000000000000000000000000000000000000 --- a/apps/official/AlekSIS-App-LDAP +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 412631fb73abf30c931c3f1951def102720e3f51 diff --git a/apps/official/AlekSIS-App-Untis b/apps/official/AlekSIS-App-Untis deleted file mode 160000 index 2f22b31c19a0bd7f479eac7f11d0943f8e297bae..0000000000000000000000000000000000000000 --- a/apps/official/AlekSIS-App-Untis +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2f22b31c19a0bd7f479eac7f11d0943f8e297bae diff --git a/ci/build_dist.yml b/ci/build_dist.yml deleted file mode 100644 index ec4a102bffeb9f86032fac4bf50b16e48a1fcddd..0000000000000000000000000000000000000000 --- a/ci/build_dist.yml +++ /dev/null @@ -1,18 +0,0 @@ -build_dist: - stage: build - script: - - if [ $CI_COMMIT_REF_NAME = master ]; then - poetry version $(poetry version | cut -d" " -f2)+$(date +%s).${CI_COMMIT_SHORT_SHA} ; - elif [ x$CI_OMMIT_REF_NAME = x$CI_COMMIT_TAG ]; then - if ! [ "$(poetry version | cut -d" " -f2)" = $CI_COMMIT_REF_NAME ]; then - echo "Package version does not match tag. Aborting build of tag!" >/dev/fd/2 ; - exit 1 ; - fi ; - fi - - tox -e build - artifacts: - paths: - - dist/ - only: - - master - - tags diff --git a/ci/build_docker.yml b/ci/build_docker.yml deleted file mode 100644 index 92a1572c6ac4d1878110500f458262a6a7c5bdf4..0000000000000000000000000000000000000000 --- a/ci/build_docker.yml +++ /dev/null @@ -1,22 +0,0 @@ -build_docker: - stage: build - image: - name: gcr.io/kaniko-project/executor:debug - entrypoint: [""] - script: - - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" >/kaniko/.docker/config.json - - /kaniko/executor - --context $CI_PROJECT_DIR - --dockerfile $CI_PROJECT_DIR/Dockerfile - --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME - --cache=true - --cleanup - - /kaniko/executor - --context $CI_PROJECT_DIR/docker/nginx - --dockerfile $CI_PROJECT_DIR/docker/nginx/Dockerfile - --destination $CI_REGISTRY_IMAGE/nginx:$CI_COMMIT_REF_NAME - --cache=true - --cleanup - only: - - master - - tags diff --git a/ci/deploy.yml b/ci/deploy.yml deleted file mode 100644 index 249e4c3333cf7c8800600a7801727110305a487e..0000000000000000000000000000000000000000 --- a/ci/deploy.yml +++ /dev/null @@ -1,30 +0,0 @@ -deploy_demo-master: - stage: deploy - environment: - name: demo/master - url: http://demo-master.aleksis.org - before_script: - - 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )' - - eval $(ssh-agent -s) - - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo "$SSH_KNOWN_HOSTS" >~/.ssh/known_hosts - - chmod 644 ~/.ssh/known_hosts - script: - - grep -v "build:" docker-compose.yml | ssh root@demo-master.aleksis.org - env ALEKSIS_IMAGE_TAG=${CI_COMMIT_REF_NAME} - docker-compose - -p aleksis-${CI_ENVIRONMENT_SLUG} - -f /dev/stdin - pull - - grep -v "build:" docker-compose.yml | ssh root@demo-master.aleksis.org - env ALEKSIS_IMAGE_TAG=${CI_COMMIT_REF_NAME} - NGINX_HTTP_PORT=80 - ALEKSIS_maintenance__debug=true - docker-compose - -p aleksis-${CI_ENVIRONMENT_SLUG} - -f /dev/stdin - up -d - only: - - master diff --git a/ci/deploy_pypi.yml b/ci/deploy_pypi.yml deleted file mode 100644 index 6b235ad05fe3eb2d70f706a93fedd91219cd6605..0000000000000000000000000000000000000000 --- a/ci/deploy_pypi.yml +++ /dev/null @@ -1,11 +0,0 @@ -deploy_pypi: - stage: deploy - script: - - if [ $CI_COMMIT_REF_NAME = master ]; then - poetry publish -r gitlab ; - elif [ x$CI_OMMIT_REF_NAME = x$CI_COMMIT_TAG ]; then - poetry publish ; - fi - only: - - master - - tags diff --git a/ci/general.yml b/ci/general.yml deleted file mode 100644 index 03d096526e19baf680d381ef16ce9cfca716fd6b..0000000000000000000000000000000000000000 --- a/ci/general.yml +++ /dev/null @@ -1,24 +0,0 @@ -image: registry.edugit.org/teckids/team-sysadmin/docker-images/python-pimped:latest - -stages: - - test - - build - - deploy - -variables: - GIT_SUBMODULE_STRATEGY: recursive - PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" - FF_NETWORK_PER_BUILD: "true" - POETRY_REPOSITORIES_GITLAB_URL: "$CI_API_V4_URL/projects/$CI_PROJECT_ID/packages/pypi" - POETRY_HTTP_BASIC_GITLAB_USERNAME: gitlab-ci-token - POETRY_HTTP_BASIC_GITLAB_PASSWORD: "$CI_JOB_TOKEN" - POETRY_PYPI_TOKEN_PYPI: "$PYPI_TOKEN" - -cache: - key: - files: - - poetry.lock - - pyproject.toml - paths: - - .cache/pip - - .tox diff --git a/ci/pages.yml b/ci/pages.yml deleted file mode 100644 index 31d8866e1d1c1b665d12ce15da9a7c918440aa7a..0000000000000000000000000000000000000000 --- a/ci/pages.yml +++ /dev/null @@ -1,12 +0,0 @@ -pages: - stage: deploy - before_script: - - cp -r .tox/screenshots/firefox docs/screenshots - script: - - export LC_ALL=en_GB.utf8 - - tox -e docs -- BUILDDIR=../public/docs - artifacts: - paths: - - public/ - only: - - master diff --git a/ci/test.yml b/ci/test.yml deleted file mode 100644 index 2ab64bc324536c8716c5cb8641d09d9c43dbf844..0000000000000000000000000000000000000000 --- a/ci/test.yml +++ /dev/null @@ -1,26 +0,0 @@ -test: - stage: test - services: - - name: selenium/standalone-firefox - alias: selenium - before_script: - - adduser --disabled-password --gecos "Test User" testuser - - chown -R testuser . - script: - - sudo apt update - - sudo apt install python3-ldap libldap2-dev libssl-dev libsasl2-dev python3.7-dev -y - - sudo -u testuser - env TEST_SELENIUM_HUB=http://selenium:4444/wd/hub - TEST_SELENIUM_BROWSERS=firefox - TEST_HOST=build - tox -e selenium -- --junitxml=.tox/junit.xml - artifacts: - paths: - - .tox/screenshots - reports: - junit: .tox/junit.xml - -lint: - stage: test - script: - - tox -e lint,security diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 56d9d1edb57546360eaf73a18d2a95097b950288..0000000000000000000000000000000000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,74 +0,0 @@ -version: '3' - -services: - db: - image: postgres:12 - volumes: - - postgres_data:/var/lib/postgresql/data/ - environment: - - POSTGRES_USER=aleksis - - POSTGRES_DB=aleksis - memcached: - image: memcached:latest - app: - build: . - image: registry.edugit.org/aleksis/official/aleksis:${ALEKSIS_IMAGE_TAG:-latest} - volumes: - - aleksis_data:/var/lib/aleksis/ - - aleksis_static:/usr/share/aleksis/static/ - environment: - - ALEKSIS_http__allowed_hosts="['*']" - - ALEKSIS_caching__memcached__address=memcached:11211 - - ALEKSIS_caching__memcached__enabled=true - - ALEKSIS_database__host=db - - ALEKSIS_maintenance__debug=${ALEKSIS_maintenance__debug:-false} - - ALEKSIS_backup__location=/var/lib/aleksis/backups - depends_on: - - db - - memcached - worker: - build: . - image: registry.edugit.org/aleksis/official/aleksis:${ALEKSIS_IMAGE_TAG:-latest} - volumes: - - aleksis_data:/var/lib/aleksis/ - - aleksis_static:/usr/share/aleksis/static/ - command: celery_worker - environment: - - ALEKSIS_http__allowed_hosts="['*']" - - ALEKSIS_caching__memcached__address=memcached:11211 - - ALEKSIS_caching__memcached__enabled=true - - ALEKSIS_database__host=db - - ALEKSIS_maintenance__debug=${ALEKSIS_maintenance__debug:-false} - - ALEKSIS_backup__location=/var/lib/aleksis/backups - depends_on: - - app - scheduler: - build: . - image: registry.edugit.org/aleksis/official/aleksis:${ALEKSIS_IMAGE_TAG:-latest} - volumes: - - aleksis_data:/var/lib/aleksis/ - - aleksis_static:/usr/share/aleksis/static/ - command: celery_beat - environment: - - ALEKSIS_http__allowed_hosts="['*']" - - ALEKSIS_caching__memcached__address=memcached:11211 - - ALEKSIS_caching__memcached__enabled=true - - ALEKSIS_database__host=db - - ALEKSIS_maintenance__debug=${ALEKSIS_maintenance__debug:-false} - depends_on: - - worker - web: - build: ./docker/nginx - image: registry.edugit.org/aleksis/official/aleksis/nginx:${ALEKSIS_IMAGE_TAG:-latest} - volumes: - - aleksis_data:/var/lib/aleksis/ - - aleksis_static:/usr/share/aleksis/static/:ro - ports: - - ${NGINX_HTTP_PORT:-8080}:80 - depends_on: - - app - -volumes: - postgres_data: - aleksis_data: - aleksis_static: diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh deleted file mode 100755 index 4b68fa884420b1a40ed34d4bd4410aabd2ac1e3f..0000000000000000000000000000000000000000 --- a/docker/entrypoint.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -GUNICORN_BIND=${GUNICORN_BIND:-0.0.0.0:8000} - -export ALEKSIS_database__host=${ALEKSIS_database__host:-127.0.0.1} -export ALEKSIS_database__port=${ALEKSIS_database__port:-5432} - -if [[ -z $ALEKSIS_secret_key ]]; then - if [[ ! -e /var/lib/aleksis/secret_key ]]; then - touch /var/lib/aleksis/secret_key; chmod 600 /var/lib/aleksis/secret_key - LC_ALL=C tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_`{|}~' </dev/urandom | head -c 64 >/var/lib/aleksis/secret_key - fi - ALEKSIS_secret_key=$(</var/lib/aleksis/secret_key) -fi - -while ! nc -z $ALEKSIS_database__host $ALEKSIS_database__port; do - sleep 0.1 -done - -python manage.py compilescss -python manage.py collectstatic --no-input --clear -python manage.py migrate -python manage.py createinitialrevisions - -ARG=${$1:-"gunicorn"} - -if [ $ARG = "celery_worker" ]; then - exec celery -A aleksis.core worker -l info -elif [ $ARG = "celery_beat" ]; then - exec celery -A aleksis.core beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler -else - exec gunicorn aleksis.core.wsgi --bind ${GUNICORN_BIND} -fi diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile deleted file mode 100644 index 18b91b5f17398ee5b2dc6e95bdedc225eb934821..0000000000000000000000000000000000000000 --- a/docker/nginx/Dockerfile +++ /dev/null @@ -1,6 +0,0 @@ -FROM nginx - -RUN rm /etc/nginx/conf.d/default.conf -COPY nginx.conf /etc/nginx/conf.d/default.conf - -RUN mkdir /var/lib/aleksis diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf deleted file mode 100644 index 759f385041ce7bd7dc06b487ff2dfb2c43635482..0000000000000000000000000000000000000000 --- a/docker/nginx/nginx.conf +++ /dev/null @@ -1,23 +0,0 @@ -upstream aleksis { - server app:8000; -} - -server { - listen 80; - - location /media/ { - alias /var/lib/aleksis/media/; - } - - location /static/ { - alias /usr/share/aleksis/static/; - } - - location / { - proxy_pass http://aleksis; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_redirect off; - } - -} diff --git a/manage.py b/manage.py deleted file mode 100755 index 023e9fd47cbc4c0308997db1061aace8bd8afb61..0000000000000000000000000000000000000000 --- a/manage.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys - -if __name__ == "__main__": - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aleksis.core.settings") - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) diff --git a/poetry.lock b/poetry.lock index 2b1410b2e2d9779cf4fcb1e46364abaef7f846b5..29d94c7f1e176cc100173d4e118bec0aa34c62a7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6,6 +6,44 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "aleksis-builddeps" +version = "1" +description = "AlekSIS (School Information System) — Build/Dev dependencies for apps" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +black = ">=19.10b0,<20.0" +django-stubs = ">=1.1,<2.0" +flake8 = ">=3.7.9,<4.0.0" +flake8-bandit = ">=2.1.2,<3.0.0" +flake8-black = ">=0.2.0,<0.3.0" +flake8-builtins = ">=1.4.1,<2.0.0" +flake8-django = ">=1.0.0,<2.0.0" +flake8-docstrings = ">=1.5.0,<2.0.0" +flake8-fixme = ">=1.1.1,<2.0.0" +flake8-isort = ">=4.0.0,<5.0.0" +flake8-mypy = ">=17.8.0,<18.0.0" +flake8-rst-docstrings = ">=0.0.13,<0.0.14" +isort = ">=5.0.0,<6.0.0" +pytest = ">=6.0,<7.0" +pytest-cov = ">=2.8.1,<3.0.0" +pytest-django = ">=3.7,<4.0" +pytest-django-testing-postgresql = ">=0.1,<0.2" +pytest-sugar = ">=0.9.2,<0.10.0" +safety = ">=1.8.5,<2.0.0" +selenium = ">=3.141.0,<4.0.0" +sphinx = ">=3.0,<4.0" +sphinx-autodoc-typehints = ">=1.7,<2.0" +sphinxcontrib-django = ">=0.5.0,<0.6.0" + +[package.source] +type = "legacy" +url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple" +reference = "gitlab" + [[package]] name = "amqp" version = "2.6.1" @@ -222,7 +260,7 @@ django-appconf = ">=0.4.1" [[package]] name = "celery-progress" -version = "0.0.12" +version = "0.0.14" description = "Drop in, configurable, dependency-free progress bars for your Django/Celery applications." category = "main" optional = false @@ -580,17 +618,6 @@ python-versions = "*" [package.dependencies] django = ">=1.11" -[[package]] -name = "django-image-cropping" -version = "1.5.0" -description = "A reusable app for cropping images easily and non-destructively in Django" -category = "main" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -django-appconf = ">=1.0.2" - [[package]] name = "django-impersonate" version = "1.5.1" @@ -951,18 +978,6 @@ toml = ["toml"] vault = ["hvac"] yaml = ["ruamel.yaml"] -[[package]] -name = "easy-thumbnails" -version = "2.7" -description = "Easy thumbnails for Django" -category = "main" -optional = false -python-versions = ">=3.5" - -[package.dependencies] -django = ">=1.11,<4.0" -pillow = "*" - [[package]] name = "faker" version = "4.14.2" @@ -1347,7 +1362,7 @@ scramp = "1.2.0" [[package]] name = "phonenumbers" -version = "8.12.12" +version = "8.12.13" description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." category = "main" optional = false @@ -1670,7 +1685,7 @@ hiredis = ["hiredis (>=0.1.3)"] [[package]] name = "regex" -version = "2020.11.11" +version = "2020.11.13" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -1811,7 +1826,7 @@ python-versions = "*" [[package]] name = "sphinx" -version = "3.3.0" +version = "3.3.1" description = "Python documentation generator" category = "dev" optional = false @@ -2060,7 +2075,7 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.1" +version = "1.26.2" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -2117,13 +2132,16 @@ ldap = ["django-auth-ldap"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "f92e91f0541f9d10f25ba28110c66ccad38f513c811319f512efabde376a6c2a" +content-hash = "ad08a984daa918b60656e0ae43f82cf7833097a121f783fdf6ad8d2603fdc60b" [metadata.files] alabaster = [ {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] +aleksis-builddeps = [ + {file = "AlekSIS-Builddeps-1.tar.gz", hash = "sha256:97a19597f422593cbdc438aabf17f95748126c8951df6ac7db7991fc99c108c4"}, +] amqp = [ {file = "amqp-2.6.1-py2.py3-none-any.whl", hash = "sha256:aa7f313fb887c91f15474c1229907a04dac0b8135822d6603437803424c0aa59"}, {file = "amqp-2.6.1.tar.gz", hash = "sha256:70cdb10628468ff14e57ec2f751c7aa9e48e7e3651cfd62d431213c0c4e58f21"}, @@ -2186,8 +2204,8 @@ celery-haystack = [ {file = "celery_haystack-0.10-py2.py3-none-any.whl", hash = "sha256:ec1f39050661e033f554de99cb9393c2e94427667ff5401f16393b2a68f888fc"}, ] celery-progress = [ - {file = "celery-progress-0.0.12.tar.gz", hash = "sha256:df61d61ac2b29e51b61a2cbd070d28b69f9f538d31e5f4b8076d9721251d6c59"}, - {file = "celery_progress-0.0.12-py3-none-any.whl", hash = "sha256:b3727b1b65c79ec072513eb42f1903eaec64a75d2f691b5664fa660f2bd319ad"}, + {file = "celery-progress-0.0.14.tar.gz", hash = "sha256:002ead0d3fa3602bd74cf328206b8e2352994ab599711dc20058a5cf2b4db2d1"}, + {file = "celery_progress-0.0.14-py3-none-any.whl", hash = "sha256:6d95c01fe044dd5dbb1e2d507724f9ace70bde796bc6db51ba19c8a95e94da07"}, ] certifi = [ {file = "certifi-2020.11.8-py2.py3-none-any.whl", hash = "sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd"}, @@ -2342,10 +2360,6 @@ django-health-check = [ {file = "django-health-check-3.16.1.tar.gz", hash = "sha256:2cb3944e313e435bdf299288e109f398b6c08b610e09cc90d7f5f6a2bcf469fc"}, {file = "django_health_check-3.16.1-py2.py3-none-any.whl", hash = "sha256:8b0835f04ebaeb0d12498a5ef47dd22196237c3987ff28bcce9ed28b5a169d5e"}, ] -django-image-cropping = [ - {file = "django-image-cropping-1.5.0.tar.gz", hash = "sha256:59744e8df88db7e46e37b526fc715fdde665d9efa345922745f50411a6dadb3f"}, - {file = "django_image_cropping-1.5.0-py3-none-any.whl", hash = "sha256:81dbcabb6421c5a1e88fac9d96f336d6109a23dcb8fa6c678329d3688c9973c4"}, -] django-impersonate = [ {file = "django-impersonate-1.5.1.tar.gz", hash = "sha256:7c786ffaa7a5dd430f9277b53a64676c470b684eee5aa52c3b483298860d09b4"}, ] @@ -2457,9 +2471,6 @@ dynaconf = [ {file = "dynaconf-3.1.2-py2.py3-none-any.whl", hash = "sha256:808adfe964f10695846dbf8dad7632e47fc3bc38860fd1887ed57dddffc4eff2"}, {file = "dynaconf-3.1.2.tar.gz", hash = "sha256:9b34ab2f811a81755f5eb4beac77a69e1e0887528c7e37fc4bc83fed52dcf502"}, ] -easy-thumbnails = [ - {file = "easy-thumbnails-2.7.tar.gz", hash = "sha256:e4e7a0dd4001f56bfd4058428f2c91eafe27d33ef3b8b33ac4e013b159b9ff91"}, -] faker = [ {file = "Faker-4.14.2-py3-none-any.whl", hash = "sha256:ce1c38823eb0f927567cde5bf2e7c8ca565c7a70316139342050ce2ca74b4026"}, {file = "Faker-4.14.2.tar.gz", hash = "sha256:6afc461ab3f779c9c16e299fc731d775e39ea7e8e063b3053ee359ae198a15ca"}, @@ -2643,8 +2654,8 @@ pg8000 = [ {file = "pg8000-1.16.6.tar.gz", hash = "sha256:8fc1e6a62ccb7c9830f1e7e9288e2d20eaf373cc8875b5c55b7d5d9b7717be91"}, ] phonenumbers = [ - {file = "phonenumbers-8.12.12-py2.py3-none-any.whl", hash = "sha256:23944f9e628f32a975d3b221b6d76e6ba8ae618d53cb3d82fc23d9e100a59b29"}, - {file = "phonenumbers-8.12.12.tar.gz", hash = "sha256:70aa98a50ba7bc7f6bf17851f806c927107e7c44e7d21eb46bdbec07b99d23ae"}, + {file = "phonenumbers-8.12.13-py2.py3-none-any.whl", hash = "sha256:9de2937034deb040eb9ac56519b0887e0fe89811e57f6f5c88359e3be20ae3b5"}, + {file = "phonenumbers-8.12.13.tar.gz", hash = "sha256:96d02120a3481e22d8a8eb5e4595ceec1930855749f6e4a06ef931881f59f562"}, ] pillow = [ {file = "Pillow-7.2.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae"}, @@ -2671,8 +2682,6 @@ pillow = [ {file = "Pillow-7.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8"}, {file = "Pillow-7.2.0-cp38-cp38-win32.whl", hash = "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f"}, {file = "Pillow-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6"}, - {file = "Pillow-7.2.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:9c87ef410a58dd54b92424ffd7e28fd2ec65d2f7fc02b76f5e9b2067e355ebf6"}, - {file = "Pillow-7.2.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:e901964262a56d9ea3c2693df68bc9860b8bdda2b04768821e4c44ae797de117"}, {file = "Pillow-7.2.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d"}, {file = "Pillow-7.2.0.tar.gz", hash = "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626"}, ] @@ -2866,47 +2875,47 @@ redis = [ {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, ] regex = [ - {file = "regex-2020.11.11-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dd7bee615680d940dd44ac0a479f2bc5f73d6ca63a5915cd8d30739c14ca522c"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3002ee2d4e8bbe4656237627203d8290a562d1fc1962deee470905ab63570345"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:064d2fc83ab4ee0055fcc1ef38ec60e505742850a40061f854ac64cb3d8d6dd3"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:83a390a653c13be1ab26287240df1fd9324ca8a0d31b603fa57cd7d9520648fa"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:412969d58ecd4f576510ec88bcb7602e9e582bbef78859ed8c9ca4de4f9e891c"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:ccfea4911ac28a8f744096bce1559e0bd86b09a53c8a9d5856ca8e1f5f4de1f5"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:cefcdb2ac3b67fd9f7244820ce1965c8cf352366199cc1358d67c6cc3c5c8bbc"}, - {file = "regex-2020.11.11-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9e8b3187f6beea8e56cb4b33c35049cbe376cf69aefaee5bc035309d88c98ca5"}, - {file = "regex-2020.11.11-cp36-cp36m-win32.whl", hash = "sha256:787e44e5f4fd027dd90b5ee0240b05dc1752cb43c2903617f25baa495fe551e9"}, - {file = "regex-2020.11.11-cp36-cp36m-win_amd64.whl", hash = "sha256:a9f76d9122359b09e38f27cd9c41729169171cf0fd73ec5b22cc4628f9e486ca"}, - {file = "regex-2020.11.11-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6d128368def4b0cd95c0fc9d99a89ae73c083b25e67f27a410830e30f9df0edc"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:df50ba964812606663ca9d23d374036bc5ae3d71e86168409cdd84ca7948d8a3"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d1e57c16c4840f1c3543507742e99b8398609474a0e6a6925476914479de3488"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6e50b3b417ab2fd67bfa6235f0df4782fe2ff8be83f0c4435e1dc43d25052ee8"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bb17a7fe9c47167337009ce18cd6e6b3edf3ca0063bf6bed6ce02515129c016a"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:826d0119f14f9a9ce25999a13ed5922c785b50e469800f6e5a6721318650ef49"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:8cc3717146ce4040419639cf45455663a002a554806ddac46304acc5bd41dae2"}, - {file = "regex-2020.11.11-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:86ad88c7c2512094a85b0a01ce053bab1e28eafb8f3868bb8c22f4903e33f147"}, - {file = "regex-2020.11.11-cp37-cp37m-win32.whl", hash = "sha256:e03867f3baf64ecab47dfc9ddb58afc67acb6a0f80f6cf8ff9fa82962ec4d1cd"}, - {file = "regex-2020.11.11-cp37-cp37m-win_amd64.whl", hash = "sha256:56d1e298bb6482d0466399a6383181bf2627c37ad414e205b3ce0f85aa140be7"}, - {file = "regex-2020.11.11-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:19ac2bf0048a2f4d460ee20647e84ca160512a7ee8af844dc9207720778470f1"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux1_i686.whl", hash = "sha256:84ab584dcb5e81815040d86148805a808acb0bee303d19638fe2f9488d704bc1"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:4159ecf20dffea07f4a7241b2a236f90eb622c7e8caab9f43caba5f27ca37284"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:8060be04baec546fe3afa6975d2998e15d1b655d7255f0e6b0ed3f482cccc218"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:cdb98be55db1b94c950822cbc10d3d768f01e184365851ebb42cd377486ced7b"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:11d9100bd874ce8b2a037db9150e732cd768359fc25fe5f77973208aa24eb13e"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0951c78fa4cb26d1278a4b3784fcf973fc97ec39c07483328a74b034b0cc569c"}, - {file = "regex-2020.11.11-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:c8b1ad791debd67221fb1266f8d09730ae927acacb32d0dad9fd07a7d341a28f"}, - {file = "regex-2020.11.11-cp38-cp38-win32.whl", hash = "sha256:beae9db1545f8116cfc9301a9601e9c975bb56ca22a38ac0fe06a72c3460f31a"}, - {file = "regex-2020.11.11-cp38-cp38-win_amd64.whl", hash = "sha256:48e94218f06317b6d32feb4ecff8b6025695450009bcb3291fb23daf79689431"}, - {file = "regex-2020.11.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c67fd5f3ad81f8301184354014e8e7510ab77e0c7e450a427d77f28ae8effbef"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux1_i686.whl", hash = "sha256:e7cdd5ee8053c82607432b7ebad37e2ece54548fef2b254f7bce6f7831904586"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:394b5be4fa72354a78763b317f82997ad881896dd4a860e429a6fa74afaacb07"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3b46a4c73ec1f25361147a7a0fd86084f3627dc78d09bcbe14e70db12683efec"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:267d1b13f863e664150948ce2a9ed4927bf4ac7a068780f1ee8af83352aa17a2"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:68267a7a5fb0bd9676b86f967143b6a6ecefb3eed4042ecc9e7f0e014aef8f74"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:e899b69dd5d26655cb454835ea2fceb18832c9ee9c4fb45dc4cf8a6089d35312"}, - {file = "regex-2020.11.11-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:396411bb5a7849aeda9c49873b8295919fdc118c50b57122b09cb2097047c118"}, - {file = "regex-2020.11.11-cp39-cp39-win32.whl", hash = "sha256:32f8714c4bcc4b0d2aa259b1647e3c5b6cfe2e923c6c124234a5e03408224227"}, - {file = "regex-2020.11.11-cp39-cp39-win_amd64.whl", hash = "sha256:bf02ab95ff5261ba108725dbd795bf6395eaac1b8468b41472d82d35b12b0295"}, - {file = "regex-2020.11.11.tar.gz", hash = "sha256:0a235841237d4487329bcabcb5b902858f7967f5e684e08e968367f25b2c3d37"}, + {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, + {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, + {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, + {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, + {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, + {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, + {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, + {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, + {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, + {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, + {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, + {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, + {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, + {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, + {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, + {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, + {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, ] requests = [ {file = "requests-2.25.0-py2.py3-none-any.whl", hash = "sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"}, @@ -2941,6 +2950,8 @@ restructuredtext-lint = [ {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5254af7d8bdf4d5484c089f929cb7f5bafa59b4f01d4f48adda4be41e6d29f99"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win32.whl", hash = "sha256:74161d827407f4db9072011adcfb825b5258a5ccb3d2cd518dd6c9edea9e30f1"}, {file = "ruamel.yaml.clib-0.2.2-cp38-cp38-win_amd64.whl", hash = "sha256:058a1cc3df2a8aecc12f983a48bda99315cebf55a3b3a5463e37bb599b05727b"}, + {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c6ac7e45367b1317e56f1461719c853fd6825226f45b835df7436bb04031fd8a"}, + {file = "ruamel.yaml.clib-0.2.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b4b0d31f2052b3f9f9b5327024dc629a253a83d8649d4734ca7f35b60ec3e9e5"}, {file = "ruamel.yaml.clib-0.2.2.tar.gz", hash = "sha256:2d24bd98af676f4990c4d715bcdc2a60b19c56a3fb3a763164d2d8ca0e806ba7"}, ] rules = [ @@ -2979,8 +2990,8 @@ spdx-license-list = [ {file = "spdx_license_list-0.5.1.tar.gz", hash = "sha256:64cb5de37724c64cdeccafa2ae68667ff8ccdb7b688f51c1c2be82d7ebe3a112"}, ] sphinx = [ - {file = "Sphinx-3.3.0-py3-none-any.whl", hash = "sha256:3abdb2c57a65afaaa4f8573cbabd5465078eb6fd282c1e4f87f006875a7ec0c7"}, - {file = "Sphinx-3.3.0.tar.gz", hash = "sha256:1c21e7c5481a31b531e6cbf59c3292852ccde175b504b00ce2ff0b8f4adc3649"}, + {file = "Sphinx-3.3.1-py3-none-any.whl", hash = "sha256:d4e59ad4ea55efbb3c05cde3bfc83bfc14f0c95aa95c3d75346fcce186a47960"}, + {file = "Sphinx-3.3.1.tar.gz", hash = "sha256:1e8d592225447104d1172be415bc2972bd1357e3e12fdc76edf2261105db4300"}, ] sphinx-autodoc-typehints = [ {file = "sphinx-autodoc-typehints-1.11.1.tar.gz", hash = "sha256:244ba6d3e2fdb854622f643c7763d6f95b6886eba24bec28e86edf205e4ddb20"}, @@ -3081,8 +3092,8 @@ typing-extensions = [ {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, ] urllib3 = [ - {file = "urllib3-1.26.1-py2.py3-none-any.whl", hash = "sha256:61ad24434555a42c0439770462df38b47d05d9e8e353d93ec3742900975e3e65"}, - {file = "urllib3-1.26.1.tar.gz", hash = "sha256:097116a6f16f13482d2a2e56792088b9b2920f4eb6b4f84a2c90555fb673db74"}, + {file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"}, + {file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"}, ] vine = [ {file = "vine-1.3.0-py2.py3-none-any.whl", hash = "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af"}, diff --git a/pyproject.toml b/pyproject.toml index 48f3b0fa4f1ded56d02f851be33bb2f33213cc94..8aed0db473956c158c48e68a39330daac0480f6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,19 +1,19 @@ [tool.poetry] -name = "AlekSIS" +name = "AlekSIS-Core" version = "2.0a3.dev0" packages = [ { include = "aleksis" } ] readme = "README.rst" -include = ["CHANGELOG.rst", "CODE_OF_CONDUCT.rst", "CONTRIBUTING.rst", "Dockerfile", "LICENCE.rst", "manage.py", "docker/*", "docker/**/*", "docker-compose.yml", "docs/*", "docs/**/*", "tox.ini"] +include = ["CHANGELOG.rst", "LICENCE.rst", "docs/*", "docs/**/*", "aleksis/**/*.mo", "tox.ini"] description = "AlekSIS (School Information System) — Core" authors = ["Dominik George <dominik.george@teckids.org>", "Julian Leucker <leuckeju@katharineum.de>", "mirabilos <thorsten.glaser@teckids.org>", "Frank Poetzsch-Heffter <p-h@katharineum.de>", "Tom Teichler <tom.teichler@teckids.org>", "Jonathan Weth <wethjo@katharineum.de>", "Hangzhi Yu <yuha@katharineum.de>"] maintainers = ["Jonathan Weth <wethjo@katharineum.de>", "Dominik George <dominik.george@teckids.org>"] license = "EUPL-1.2-or-later" homepage = "https://aleksis.org/" -repository = "https://edugit.org/AlekSIS/official/AlekSIS" -documentation = "https://aleksis.org/AlekSIS/docs/html/" +repository = "https://edugit.org/AlekSIS/official/AlekSIS-Core" +documentation = "https://aleksis.org/AlekSIS-Core/docs/html/" keywords = ["SIS", "education", "school", "digitisation", "school apps"] classifiers = [ "Development Status :: 3 - Alpha", @@ -27,6 +27,11 @@ classifiers = [ "Typing :: Typed", ] +[[tool.poetry.source]] +name = "gitlab" +url = "https://edugit.org/api/v4/projects/461/packages/pypi/simple" +secondary = true + [tool.poetry.dependencies] python = "^3.7" Django = "^3.0" @@ -45,8 +50,6 @@ django-settings-context-processor = "^0.2" django-auth-ldap = { version = "^2.2", optional = true } django-maintenance-mode = "^0.15.0" django-ipware = "^3.0" -easy-thumbnails = "^2.6" -django-image-cropping = "^1.2" django-impersonate = "^1.4" python-memcached = "^1.59" django-hattori = "^0.2" @@ -85,37 +88,16 @@ django-reversion = "^3.0.7" django-favicon-plus-reloaded = "^1.0.4" django-health-check = "^3.12.1" psutil = "^5.7.0" -celery-progress = "^0.0.12" +celery-progress = "^0.0.14" django-prometheus = "^2.1.0" +importlib-metadata = {version = "^2.0.0", python = "<3.8"} [tool.poetry.extras] ldap = ["django-auth-ldap"] celery = ["Celery", "django-celery-results", "django-celery-beat", "django-celery-email", "celery-haystack"] [tool.poetry.dev-dependencies] -sphinx = "^3.0" -sphinxcontrib-django = "^0.5.0" -sphinx-autodoc-typehints = "^1.7" -django-stubs = "^1.1" -pytest = "^6.0" -pytest-django = "^3.7" -pytest-django-testing-postgresql = "^0.1" -selenium = "^3.141.0" -safety = "^1.8.5" -flake8 = "^3.7.9" -flake8-django = "^1.0.0" -flake8-fixme = "^1.1.1" -flake8-mypy = "^17.8.0" -flake8-bandit = "^2.1.2" -flake8-builtins = "^1.4.1" -flake8-docstrings = "^1.5.0" -flake8-rst-docstrings = "^0.0.13" -black = "^19.10b0" -flake8-black = "^0.2.0" -isort = "^5.0.0" -flake8-isort = "^4.0.0" -pytest-cov = "^2.8.1" -pytest-sugar = "^0.9.2" +aleksis-builddeps = "*" [tool.black] line-length = 100