Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • hansegucker/AlekSIS-Core
  • pinguin/AlekSIS-Core
  • AlekSIS/official/AlekSIS-Core
  • sunweaver/AlekSIS-Core
  • sggua/AlekSIS-Core
  • edward/AlekSIS-Core
  • magicfelix/AlekSIS-Core
7 results
Show changes
Commits on Source (870)
Showing
with 3742 additions and 1885 deletions
......@@ -65,6 +65,7 @@ docs/_build/
aleksis/node_modules/
aleksis/static/
aleksis/whoosh_index/
poetry.lock
.coverage
.mypy_cache/
......
include:
- project: "AlekSIS/official/AlekSIS"
file: /ci/general.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/prepare/lock.yml
- project: "AlekSIS/official/AlekSIS"
file: /ci/test/test.yml
- project: "AlekSIS/official/AlekSIS"
......@@ -17,5 +19,3 @@ include:
file: "/ci/deploy/review.yml"
- project: "AlekSIS/official/AlekSIS"
file: "/ci/deploy/trigger_dist.yml"
- project: "AlekSIS/official/AlekSIS"
file: /ci/deploy/pages.yml
......@@ -8,7 +8,9 @@ Jonathan Weth <git@jonathanweth.de> Jonathan Weth <joniweth@gmx.de>
Jonathan Weth <git@jonathanweth.de> Jonathan Weth <mail@jonathanweth.de>
Jonathan Weth <git@jonathanweth.de> Jonathan Weth <wethjo@katharineum.de>
Julian Leucker <leuckerj@gmail.com> Julian <leuckerj@gmail.com>
Lloyd Meins <git@lloydmeins.de> Aithus <lloydmeins@gmx.net>
Silas Della Contrada <s.developer@4-dc.de> sdcieo0330 <silasdc0@gmail.com>
Tom Teichler <tom.teichler@teckids.org> Tom Teichler <t.teichler@babiel.com>
mirabilos <thorsten.glaser@teckids.org> mirabilos <mirabilos@evolvis.org>
mirabilos <thorsten.glaser@teckids.org> mirabilos <t.glaser@tarent.de>
root (Skolelinux) <root@tjener.intern> root <root@tjener.intern>
......
......@@ -6,6 +6,429 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog`_,
and this project adheres to `Semantic Versioning`_.
Unreleased
----------
`2.7.3`_ - 2022-02-03
---------------------
Fixed
~~~~~
* Migration added in 2.7.2 did not work in all scenarios
* [Dev] Field change tracking API for Person was broken in 2.7.2
* [OAuth] Automatic clean-up of expired OAuth tokens could fail
* Allow maskable icons for non-masked use
* Add missing documentation
Known issues
~~~~~~~~~~~~
* Maskable and non-masked icons *purpose) any cannot be separated
`2.7.2`_ - 2022-01-31
---------------------
Changed
~~~~~~~
* [Dev] The (undocumented) setting PDF_CONTEXT_PROCESSORS is now named NON_REQUEST_CONTEXT_PROCESSORS
* [Docker] Cache is now cleared if migrations are applied
* Update German translations.
Fixed
~~~~~
* Celery progress could be inaccurate if recording progress during a transaction
`2.7.1`_ - 2022-01-28
---------------------
Changed
~~~~~~~
* PWA icons can now be marked maskable
* [OAuth] Expired tokens are now cleared in a periodic task
* PDF file jobs are now automatically expired
* Data checks are now scheduled every 15 minutes by default
Fixed
~~~~~
* PDF generation failed with S3 storage due to incompatibility with boto3
* PWA theme colour defaulted to red
* Form for editing group type displayed irrelevant fields
* Permission groups could get outdated if re-assigning a user account to a different person
* User preferences didn't work correctly sometimes due to race conditions.
`2.7`_ - 2022-01-24
-------------------
Added
~~~~~
* Periodic tasks can now have a default schedule, which is automatically created
Fixed
~~~~~
* Signup was forbidden even if it was enabled in settings
* Phone numbers were not properly linked and suboptimally formatted on person page
* Favicon upload failed with S3 storage.
* Some combinations of allowed self-edit fields on persons could cause errors
* Some preferences were required when they shouldn't, and vice versa.
* IO errors on accessing backup directory in health check are now properly reported
* Date picker was not properly initialized if field was already filled.
* The menu item for entering an invitation code received offline was missing
* CleaveJS was not loaded properly when using an external CDN
Changed
-------
* Allow non-superusers with permission to invite persons
`2.6`_ - 2022-01-10
-------------------
Added
~~~~~
* Add option to open entry in new tab for sidebar navigation menu.
* Add preference for configuring the default phone number country code.
* Persons and groups now have two image fields: official photo and public avatar
* Admins recieve an mail for celery tasks with status "FAILURE"
* OpenID Connect RSA keys can now be passed as string in config files
* Views filtering for person names now also search the username of a linked user
* OAuth2 applications now take an icon which is shown in the authorization progress.
* Add support for hiding the main side nav in ``base.html``.
* Provide base template and function for sending emails with a template.
Fixed
~~~~~
* Changing the favicon did not result in all icons being replaced in some cases
* Superusers with a dummy person were able to access the dashboard edit page.
* GroupManager.get_queryset() returned an incomplete QuerySet
* OAuth was broken by a non-semver-adhering django-oauth-toolkit update
* Too long texts in chips didn't result in a larger chip.
* The ``Person`` model had an ``is_active`` flag that was used in unclear ways; it is now removed
* The data check results list view didn't work if a related object had been deleted in the meanwhile.
* Socialaccount login template was not overriden
* Atomic transactions now cause only one Haystack update task to run
* Too long headlines didn't break in another line.
Changed
~~~~~~~
* Configuration files are now deep merged by default
* Improvements for shell_plus module loading
* core.Group model now takes precedence over auth.Group
* Name collisions are resolved by prefixing with the app label
* Apps can extend SHELL_PLUS_APP_PREFIXES and SHELL_PLUS_DONT_LOAD
* [Docker] Base image now contains curl, grep, less, sed, and pspg
* Views raising a 404 error can now customise the message that is displayed on the error page
* OpenID Connect is enabled by default now, without RSA support
* Login and authorization pages for OAuth2/OpenID Connect now indicate that the user is in progress
to authorize an external application.
* Tables can be scrolled horizontally.
* Overhauled person detail page
* Use common base template for all emails.
`2.5`_ – 2022-01-02
-------------------
Added
~~~~~
* Recursive helper methods for group hierarchies
Fixed
~~~~~
* Remove left-over reference to preferences in a form definition that caused
form extensions in downstream apps to break
* Allow non-LDAP users to authenticate if LDAP is used with password handling
* Additional button on progress page for background tasks was shown even if the task failed.
* Register preference for available allowed oauth grants.
`2.4`_ – 2021-12-24
-------------------
Added
~~~~~
* Allow configuration of database options
* User invitations with invite codes and targeted invites for existing
persons
Fixed
~~~~~
* Correctly update theme colours on change again
* Use correct favicon as default AlekSIS favicon
* Show all years in a 200 year range around the current year in date pickers
* Imprint is now called "Imprint" and not "Impress".
* Logo files weren't uploaded to public namespace.
* Limit LDAP network timeouts to not hang indefinitely on login if LDAP
server is unreachable
Changed
~~~~~~~
* Modified the appearance of tables for mobile users to be more user friendly
* [Dev] Remove lock file; locking dependencies is the distribution's
responsibility
Removed
~~~~~~~
* Remove old generated AlekSIS icons
`2.3.1`_ – 2021-12-17
---------------------
Fixed
~~~~~
* Small files could fail to upload to S3 storage due to MemoryFileUploadHandler
* Corrected typos in previous changelog
`2.3`_ – 2021-12-15
-------------------
Added
~~~~~
* [OAuth] Allow apps to fill in their own claim data matching their scopes
Fixed
~~~~~
* View for assigning permissions didn't work with some global permissions.
* PDFs generated in background didn't contain logo or site title.
* Admins were redirected to their user preferences
while they wanted to edit the preferences of another user.
* Some CharFields were using NULL values in database when field is empty
* Optional dependecy `sentry-sdk` was not optional
Changed
~~~~~~~
* Docker base image ships PostgreSQL 14 client binaries for maximum compatibility
* Docker base image contains Sentry client by default (disabled in config by default)
Removed
~~~~~~~
* Remove impersonation page. Use the impersonation button on the person
detail view instead.
`2.2.1`_ – 2021-12-02
--------------------
Fixed
~~~~~
* [Docker] Stop initialisation if migrations fail
* [OAuth] Register `groups` scope and fix claim
* [OAuth] Fix OAuth claims for follow-up requests (e.g. UserInfo)
* [OAuth] Fix grant types checking failing on wrong types under some circumstances
* [OAuth] Re-introduce missing algorithm field in application form
* Remove errornous backup folder check for S3
`2.2`_ - 2021-11-29
-------------------
Added
~~~~~
* Support config files in sub-directories
* Provide views for assigning/managing permissions in frontend
* Support (icon) tabs in the top navbar.
Changed
~~~~~~~
* Update German translations.
Fixed
~~~~~
* Use new MaterializeCSS fork because the old version is no longer maintained.
* Sender wasn't displayed for notifications on dashboard.
* Notifications and activities on dashboard weren't sorted from old to new.
`2.1.1`_ - 2021-11-14
---------------------
Added
~~~~~
* Provide ``SITE_PREFERENCES`` template variable for easier and request-independent access on all site preferences.
Fixed
~~~~~
* Make style.css and favicons cachable.
* Import model extensions from other apps before form extensions.
* Recreate backwards compatiblity for OAuth URLs by using ``oauth/`` again.
* Show correct logo and school title in print template if created in the background.
Removed
~~~~~~~
* Remove fallback code from optional Celery as it's now non-optional.
`2.1`_ - 2021-11-05
-------------------
Added
~~~~~
* Provide an ``ExtensiblePolymorphicModel`` to support the features of extensible models for polymorphic models and vice-versa.
* Implement optional Sentry integration for error and performance tracing.
* Option to limit allowed scopes per application, including mixin to enforce that limit on OAuth resource views
* Support trusted OAuth applications that leave out the authorisation screen.
* Add birthplace to Person model.
Changed
~~~~~~~
* Replace dev.sh helper script with tox environments.
* OAuth Grant Flows are now configured system-wide instead of per app.
* Refactor OAuth2 application management views.
Fixed
~~~~~
* Fix default admin contacts
Credits
~~~~~~~
* We welcome new contributor 🐧 Jonathan Krüger!
* We welcome new contributor 🐭 Lukas Weichelt!
`2.0`_ - 2021-10-29
-------------------
Changed
~~~~~~~
* Refactor views/forms for creating/editing persons.
Fixed
~~~~~
* Fix order of submit buttons in login form and restructure login template
to make 2FA work correctly.
* Fix page title bug on the impersonate page.
* Users were able to edit the linked user if self-editing was activated.
* Users weren't able to edit the allowed fields although they were configured correctly.
* Provide `style.css` and icon files without any authentication to avoid caching issues.
Removed
~~~~~~~
* Remove mass linking of persons to accounts, bevcause the view had performance issues,
but was practically unused.
`2.0rc7`_ - 2021-10-18
----------------------
Fixed
~~~~~
* Configuration mechanisms for OpenID Connect were broken.
* Set a fixed version for django-sass-processor to avoid a bug with searching ``style.css`` in the wrong storage.
* Correct the z-index of the navbar to display the main title again on mobile devices.
Removed
~~~~~~~
* Leftovers from a functionality already dropped in the development process
(custom authentication backends and alternative login views).
`2.0rc6`_ - 2021-10-11
----------------------
Added
~~~~~
* OpenID Connect scope and accompanying claim ``groups``
* Support config files in JSON format
* Allow apps to dynamically generate OAuth scopes
Changed
~~~~~~~
* Do not log or e-mail ALLOWED_HOSTS violations
* Update translations.
* Use initial superuser settings as default contact and from addresses
Fixed
~~~~~
* Show link to imprint in footer
* Fix API for adding OAuth scopes in AppConfigs
* Deleting persons is possible again.
* Removed wrong changelog section
Removed
~~~~~~~
* Dropped data anonymization (django-hattori) support for now
* ``OAUTH2_SCOPES`` setting in apps is not supported anymore. Use ``get_all_scopes`` method
on ``AppConfig`` class instead.
`2.0rc5`_ - 2021-08-25
----------------------
Fixed
~~~~~
* The view for getting the progress of celery tasks didn't respect that there can be anonymous users.
* Updated django to latest 3.2.x
`2.0rc4`_ - 2021-08-01
----------------------
Added
~~~~~
* Allow to configure port for prometheus metrics endpoint.
Fixed
~~~~~
* Correctly deliver server errors to user
* Use text HTTP response for serviceworker.js insteas of binary stream
* Use Django permission instead of rule to prevent performance issues.
`2.0rc3`_ - 2021-07-26
----------------------
Added
~~~~~
* Support PDF generation without available request object (started completely from background).
* Display a loading animation while fetching search results in the sidebar.
Fixed
~~~~~
* Make search suggestions selectable using the arrow keys.
Fixed
~~~~~
* Use correct HTML 5 elements for the search frontend and fix CSS accordingly.
`2.0rc2`_ - 2021-06-24
---------------------
......@@ -23,9 +446,6 @@ Added
* Add option to disable dashboard auto updating as a user and sitewide.
`2.0rc1` - 2021-06-23
----------------------
Changed
~~~~~~~
......@@ -97,14 +517,14 @@ Added
* Allow defining several search configs for LDAP users and groups
* Use setuptools entrypoints to find apps
* Add django-cachalot as query cache
* Add `syncable_fields` property to `ExtensibleModel to discover fields
* Add ``syncable_fields`` property to ``ExtensibleModel`` to discover fields
sync backends can write to
* Add `aleksis-admin` script to wrap django-admin with pre-configured settings
* Add ``aleksis-admin`` script to wrap django-admin with pre-configured settings
* Auto-create persons for users if matching attributes are found
* Add `django-allauth` to allow authentication using OAuth, user registration,
* Add ``django-allauth`` to allow authentication using OAuth, user registration,
password changes and password reset
* Add OAuth2 and OpenID Connect provider support
* Add `django-uwsgi` to use uWSGI and Celery in development
* Add ``django-uwsgi`` to use uWSGI and Celery in development
* Add loading page for displaying Celery task progress
* Implement generic PDF generation using Chromium
* Support Amazon S3 storage for /media files
......@@ -142,7 +562,7 @@ Changed
* Default search index backend is now Whoosh with Redis storage
* Re-style search result page
* Move notifications to separate page with indicator in menu
* Move to `BigAutoField` for all AlekSIS apps
* Move to ``BigAutoField`` for all AlekSIS apps
* Require Django 3.2 and Python 3.9
* Person and group lists can now be filtered
* Allow displaying the default widget to anonymous users
......@@ -291,3 +711,22 @@ Fixed
.. _2.0b2: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0b2
.. _2.0rc1: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc1
.. _2.0rc2: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc2
.. _2.0rc3: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc3
.. _2.0rc4: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc4
.. _2.0rc5: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc5
.. _2.0rc6: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc6
.. _2.0rc7: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0rc7
.. _2.0: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.0
.. _2.1: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.1
.. _2.1.1: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.1.1
.. _2.2: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.2
.. _2.2.1: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.2.1
.. _2.3: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.3
.. _2.3.1: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.3.1
.. _2.4: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.4
.. _2.5: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.5
.. _2.6: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.6
.. _2.7: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.7
.. _2.7.1: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.7.1
.. _2.7.2: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.7.2
.. _2.7.3: https://edugit.org/AlekSIS/Official/AlekSIS/-/tags/2.7.3
FROM debian:bullseye-slim AS core
# Build arguments
ARG EXTRAS="ldap,s3"
ARG EXTRAS="ldap,s3,sentry"
ARG APP_VERSION=""
# Configure Python to be nice inside Docker and pip to stfu
......@@ -19,20 +19,25 @@ ENV ALEKSIS_static__root /usr/share/aleksis/static
ENV ALEKSIS_media__root /var/lib/aleksis/media
ENV ALEKSIS_backup__location /var/lib/aleksis/backups
ENV ALEKSIS_dev__uwsgi__celery false
ENV PSQL_PAGER=pspg
# Install necessary Debian and PyPI packages for build and runtime
RUN apt-get -y update && \
apt-get -y install eatmydata && \
apt-get -y install eatmydata gnupg postgresql-common && \
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y && \
eatmydata apt-get -y upgrade && \
eatmydata apt-get install -y --no-install-recommends \
build-essential \
chromium \
curl \
dumb-init \
gettext \
libpq5 \
grep \
less \
libpq-dev \
libssl-dev \
postgresql-client \
postgresql-client-14 \
pspg \
python3-dev \
python3-magic \
python3-pip \
......@@ -76,6 +81,7 @@ RUN set -e; \
eatmydata apt-get remove --purge -y \
build-essential \
gettext \
gnupg \
libpq-dev \
libssl-dev \
libldap2-dev \
......
......@@ -121,7 +121,7 @@ been modified and the date of modification.
of the Original Works or Derivative Works, this Distribution or
Communication will be done under the terms of this Licence or of a
later version of this Licence unless the Original Work is expressly
distributed only under this version of the Licencefor example by
distributed only under this version of the Licencefor example by
communicating ‘EUPL v. 1.2 only’. The Licensee (becoming Licensor)
cannot offer or impose any additional terms or conditions on the Work
or Derivative Work that alter or restrict the terms of the Licence.
......@@ -306,7 +306,7 @@ Appendix
* Creative Commons Attribution-ShareAlike v. 3.0 Unported
(CC BY-SA 3.0) for works other than software
* European Union Public Licence (EUPL) v. 1.1, v. 1.2
* Québec Free and Open-Source LicenceReciprocity (LiLiQ-R)
* Québec Free and Open-Source LicenceReciprocity (LiLiQ-R)
or Strong Reciprocity (LiLiQ-R+)
The European Commission may update this Appendix to later versions of
......
......@@ -6,7 +6,7 @@ This is the core of the AlekSIS framework and the official distribution
developers and administrators.
If you are looking for the AlekSIS standard distribution, i.e. the complete
software product ready for installation and usage, please visit the `AlekSIS`_
software product ready for installation and usage, please visit the `AlekSIS®`_
website or the distribution repository on `EduGit`_.
Features
......@@ -16,58 +16,61 @@ The AlekSIS core currently provides the following features:
* For users:
* Authentication via OAuth applications
* Configurable dashboard
* Custom menu entries (e.g. in footer)
* Global preferences
* Authentication via local account, LDAP, or social accounts
* Two factor authentication via Yubikey, OTP or SMS
* Configurable dashboard with widgets
* User-specific preferences
* Global search
* Group types
* Manage announcements
* Manage groups
* Manage groups and types of groups
* Manage roles and additional, informative fields per group
* Manage persons
* Notifications via SMS email or dashboard
* Notifications via SMS, email or dashboard
* PWA with offline caching
* Rules and permissions for users, objects and pages
* Two factor authentication via Yubikey, OTP or SMS
* User preferences
* User registration, password changes and password reset
* User invitations with invite codes and targeted invites
* For admins
* Asynchronous tasks with celery
* Authentication via LDAP
* `aleksis-admin` script to wrap django-admin with pre-configured settings
* Manage school terms
* Custom menu entries (e.g. in footer)
* Automatic backup of database, static and media files
* Generic PDF generation with chromium
* OAuth2 and OpenID Connect provider support
* Serve prometheus metrics
* System health and data checks
* Configuration of low-level settings via configuration files
* System-wide preferenes
* Creating dashboard widgets for external links/apps
* For developers
* `aleksis-admin` script to wrap django-admin with pre-configured settings
* Generic PDF generation with chromium
* Caching with Redis
* Django REST framework for apps to use at own discretion
* Injection of fields, methods, permissions and properties via custom `ExtensibleModel`
* K8s compatible, read-only Docker image
* Object-level permissions and rules with `django-guardian` and `django-rules`
* Query caching with `django-cachalot`
* Search with `django-haystack` and `Whoosh` backend
* uWSGI and Celery via `django-uwsgi` in development
* Extensible dashbaord widget system
* Extensible OAuth/OpenID Connect scope and claims system
Licence
-------
::
Copyright © 2017, 2018, 2019, 2020, 2021 Jonathan Weth <dev@jonathanweth.de>
Copyright © 2017, 2018, 2019, 2020, 2021, 2022 Jonathan Weth <dev@jonathanweth.de>
Copyright © 2017, 2018, 2019, 2020 Frank Poetzsch-Heffter <p-h@katharineum.de>
Copyright © 2018, 2019, 2020, 2021, 2022 Hangzhi Yu <yuha@katharineum.de>
Copyright © 2018, 2019, 2020, 2021 Julian Leucker <leuckeju@katharineum.de>
Copyright © 2018, 2019, 2020, 2021 Hangzhi Yu <yuha@katharineum.de>
Copyright © 2019, 2020, 2021 Dominik George <dominik.george@teckids.org>
Copyright © 2019, 2020, 2021 Tom Teichler <tom.teichler@teckids.org>
Copyright © 2019, 2020, 2021, 2022 Dominik George <dominik.george@teckids.org>
Copyright © 2019, 2020, 2021, 2022 Tom Teichler <tom.teichler@teckids.org>
Copyright © 2019 mirabilos <thorsten.glaser@teckids.org>
Copyright © 2021 Lloyd Meins <meinsll@katharineum.de>
Copyright © 2021 magicfelix <felix@felix-zauberer.de>
Copyright © 2022 Benedict Suska <benedict.suska@teckids.org>
Licenced under the EUPL, version 1.2 or later, by Teckids e.V. (Bonn, Germany).
......@@ -76,6 +79,14 @@ full licence text or on the `European Union Public Licence`_ website
https://joinup.ec.europa.eu/collection/eupl/guidelines-users-and-developers
(including all other official language versions).
.. _AlekSIS: https://aleksis.org
Trademark
---------
AlekSIS® is a registered trademark of the AlekSIS open source project, represented
by Teckids e.V. Please refer to the `trademark policy`_ for hints on using the trademark
AlekSIS®.
.. _AlekSIS®: https://aleksis.org
.. _European Union Public Licence: https://eupl.eu/
.. _EduGit: https://edugit.org/AlekSIS/official/AlekSIS
.. _trademark policy: https://aleksis.org/pages/about
from importlib import metadata
try:
from .celery import app as celery_app
except ModuleNotFoundError:
# Celery is not available
celery_app = None
from .celery import app as celery_app # noqa
try:
__version__ = metadata.distribution("AlekSIS-Core").version
......
from hattori.base import BaseAnonymizer, faker
from .models import Person
class PersonAnonymizer(BaseAnonymizer):
model = Person
attributes = [
("first_name", faker.first_name),
("last_name", faker.last_name),
("additional_name", ""),
("short_name", lambda **kwargs: faker.pystr(min_chars=3, max_chars=5, **kwargs)),
("street", faker.street_name),
("housenumber", faker.building_number),
("postal_code", faker.postcode),
("place", faker.city),
("phone_number", ""),
("mobile_number", ""),
("email", faker.email),
(
"date_of_birth",
lambda **kwargs: faker.date_of_birth(minimum_age=8, maximum_age=66, **kwargs),
),
("photo", ""),
]
......@@ -2,11 +2,14 @@ from typing import Any, Optional
import django.apps
from django.apps import apps
from django.conf import settings
from django.http import HttpRequest
from django.utils.module_loading import autodiscover_modules
from django.utils.translation import gettext as _
from dynamic_preferences.registries import preference_models
from health_check.plugins import plugin_dir
from oauthlib.common import Request as OauthlibRequest
from .registries import (
group_preferences_registry,
......@@ -14,7 +17,12 @@ from .registries import (
site_preferences_registry,
)
from .util.apps import AppConfig
from .util.core_helpers import get_or_create_favicon, has_person
from .util.core_helpers import (
create_default_celery_schedule,
get_or_create_favicon,
get_site_preferences,
has_person,
)
from .util.sass_helpers import clean_scss
......@@ -28,15 +36,16 @@ class CoreConfig(AppConfig):
}
licence = "EUPL-1.2+"
copyright_info = (
([2017, 2018, 2019, 2020, 2021], "Jonathan Weth", "wethjo@katharineum.de"),
([2017, 2018, 2019, 2020, 2021, 2022], "Jonathan Weth", "wethjo@katharineum.de"),
([2017, 2018, 2019, 2020], "Frank Poetzsch-Heffter", "p-h@katharineum.de"),
([2018, 2019, 2020, 2021, 2022], "Hangzhi Yu", "yuha@katharineum.de"),
([2018, 2019, 2020, 2021], "Julian Leucker", "leuckeju@katharineum.de"),
([2018, 2019, 2020, 2021], "Hangzhi Yu", "yuha@katharineum.de"),
([2019, 2020, 2021], "Dominik George", "dominik.george@teckids.org"),
([2019, 2020, 2021], "Tom Teichler", "tom.teichler@teckids.org"),
([2019, 2020, 2021, 2022], "Dominik George", "dominik.george@teckids.org"),
([2019, 2020, 2021, 2022], "Tom Teichler", "tom.teichler@teckids.org"),
([2019], "mirabilos", "thorsten.glaser@teckids.org"),
([2021], "Lloyd Meins", "meinsll@katharineum.de"),
([2021], "magicfelix", "felix@felix-zauberer.de"),
([2022], "Benedict Suska", "benedict.suska@teckids.org"),
)
def ready(self):
......@@ -45,7 +54,7 @@ class CoreConfig(AppConfig):
from django.conf import settings # noqa
# Autodiscover various modules defined by AlekSIS
autodiscover_modules("form_extensions", "model_extensions", "checks")
autodiscover_modules("model_extensions", "form_extensions", "checks")
sitepreferencemodel = self.get_model("SitePreferenceModel")
personpreferencemodel = self.get_model("PersonPreferenceModel")
......@@ -94,14 +103,20 @@ class CoreConfig(AppConfig):
if name in ("primary", "secondary"):
clean_scss()
elif name in ("favicon", "pwa_icon"):
from favicon.models import Favicon # noqa
from favicon.models import Favicon, FaviconImg # noqa
is_favicon = name == "favicon"
if new_value:
Favicon.on_site.update_or_create(
title=name, defaults={"isFavicon": is_favicon, "faviconImage": new_value},
)
# Get file object from preferences instead of using new_value
# to prevent problems with special file storages
file_obj = get_site_preferences()[f"{section}__{name}"]
favicon = Favicon.on_site.update_or_create(
title=name,
defaults={"isFavicon": is_favicon, "faviconImage": file_obj},
)[0]
FaviconImg.objects.filter(faviconFK=favicon).delete()
else:
Favicon.on_site.filter(title=name, isFavicon=is_favicon).delete()
if name in settings.DEFAULT_FAVICON_PATHS:
......@@ -130,9 +145,75 @@ class CoreConfig(AppConfig):
for name, default in settings.DEFAULT_FAVICON_PATHS.items():
get_or_create_favicon(name, default, is_favicon=name == "favicon")
# Create default periodic tasks
create_default_celery_schedule()
def user_logged_in(
self, sender: type, request: Optional[HttpRequest], user: "User", **kwargs
) -> None:
if has_person(user):
# Save the associated person to pick up defaults
user.person.save()
@classmethod
def get_all_scopes(cls) -> dict[str, str]:
scopes = {
"read": "Read anything the resource owner can read",
"write": "Write anything the resource owner can write",
}
if settings.OAUTH2_PROVIDER.get("OIDC_ENABLED", False):
scopes |= {
"openid": _("OpenID Connect scope"),
"profile": _("Given name, family name, link to profile and picture if existing."),
"address": _("Full home postal address"),
"email": _("Email address"),
"phone": _("Home and mobile phone"),
"groups": _("Groups"),
}
return scopes
@classmethod
def get_additional_claims(cls, scopes: list[str], request: OauthlibRequest) -> dict[str, Any]:
django_request = HttpRequest()
django_request.META = request.headers
claims = {
"preferred_username": request.user.username,
}
if "profile" in scopes:
if has_person(request.user):
claims["given_name"] = request.user.person.first_name
claims["family_name"] = request.user.person.last_name
claims["profile"] = django_request.build_absolute_uri(
request.user.person.get_absolute_url()
)
if request.user.person.photo:
claims["picture"] = django_request.build_absolute_uri(
request.user.person.photo.url
)
else:
claims["given_name"] = request.user.first_name
claims["family_name"] = request.user.last_name
if "email" in scopes:
if has_person(request.user):
claims["email"] = request.user.person.email
else:
claims["email"] = request.user.email
if "address" in scopes and has_person(request.user):
claims["address"] = {
"street_address": request.user.person.street
+ " "
+ request.user.person.housenumber,
"locality": request.user.person.place,
"postal_code": request.user.person.postal_code,
}
if "groups" in scopes and has_person(request.user):
claims["groups"] = list(
request.user.person.member_of.values_list("name", flat=True).all()
)
return claims
import os
from traceback import format_exception
from django.conf import settings
from celery import Celery
from celery.signals import task_failure
from .util.core_helpers import get_site_preferences
from .util.email import send_email
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aleksis.core.settings")
app = Celery("aleksis") # noqa
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
@task_failure.connect
def task_failure_notifier(
sender=None, task_id=None, exception=None, args=None, kwargs=None, traceback=None, **__
):
recipient_list = [e[1] for e in settings.ADMINS]
send_email(
template_name="celery_failure",
from_email=get_site_preferences()["mail__address"],
recipient_list=recipient_list,
context={
"task_name": sender.name,
"task": str(sender),
"task_id": str(task_id),
"exception": str(exception),
"args": args,
"kwargs": kwargs,
"traceback": "".join(format_exception(type(exception), exception, traceback)),
},
)
import logging
from datetime import timedelta
from django.apps import apps
from django.contrib.contenttypes.models import ContentType
......@@ -8,10 +9,10 @@ from django.utils.translation import gettext as _
import reversion
from reversion import set_comment
from templated_email import send_templated_mail
from .util.celery_progress import ProgressRecorder, recorded_task
from .util.core_helpers import get_site_preferences
from .util.email import send_email
class SolveOption:
......@@ -236,7 +237,7 @@ class DataCheckRegistry:
return [(check.name, check.verbose_name) for check in cls.data_checks]
@recorded_task
@recorded_task(run_every=timedelta(minutes=15))
def check_data(recorder: ProgressRecorder):
"""Execute all registered data checks and send email if activated."""
for check in recorder.iterate(DataCheckRegistry.data_checks):
......@@ -274,9 +275,8 @@ def send_emails_for_data_checks():
for group in get_site_preferences()["general__data_checks_recipient_groups"]:
recipient_list += [p.mail_sender for p in group.announcement_recipients if p.email]
send_templated_mail(
send_email(
template_name="data_checks",
from_email=get_site_preferences()["mail__address"],
recipient_list=recipient_list,
context={"results": results_with_checks},
)
......
from typing import Sequence
from django.contrib.auth.models import Group as DjangoGroup
from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.utils.translation import gettext as _
from django_filters import CharFilter, FilterSet, ModelChoiceFilter, ModelMultipleChoiceFilter
from django_select2.forms import ModelSelect2Widget
from guardian.models import GroupObjectPermission, UserObjectPermission
from material import Layout, Row
from aleksis.core.models import Group, GroupType, Person, SchoolTerm
......@@ -49,6 +54,7 @@ class PersonFilter(FilterSet):
"additional_name__icontains",
"last_name__icontains",
"short_name__icontains",
"user__username__icontains",
],
label=_("Search by name"),
)
......@@ -67,8 +73,99 @@ class PersonFilter(FilterSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form.layout = Layout(Row("name", "contact"), Row("is_active", "sex", "primary_group"))
self.form.layout = Layout(Row("name", "contact"), Row("sex", "primary_group"))
class Meta:
model = Person
fields = ["sex", "is_active", "primary_group"]
fields = ["sex", "primary_group"]
class PermissionFilter(FilterSet):
"""Common filter for permissions."""
permission = ModelChoiceFilter(
queryset=Permission.objects.all(),
widget=ModelSelect2Widget(
search_fields=["name__icontains", "codename__icontains"],
attrs={"data-minimum-input-length": 0, "class": "browser-default"},
),
label=_("Permission"),
)
permission__content_type = ModelChoiceFilter(
queryset=ContentType.objects.all(),
widget=ModelSelect2Widget(
search_fields=["app_label__icontains", "model__icontains"],
attrs={"data-minimum-input-length": 0, "class": "browser-default"},
),
label=_("Content type"),
)
class UserPermissionFilter(PermissionFilter):
"""Common filter for user permissions."""
user = ModelChoiceFilter(
queryset=User.objects.all(),
widget=ModelSelect2Widget(
search_fields=["username__icontains", "first_name__icontains", "last_name__icontains"],
attrs={"data-minimum-input-length": 0, "class": "browser-default"},
),
label=_("User"),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form.layout = Layout(Row("user", "permission", "permission__content_type"))
class Meta:
fields = ["user", "permission", "permission__content_type"]
class GroupPermissionFilter(PermissionFilter):
"""Common filter for group permissions."""
group = ModelChoiceFilter(
queryset=DjangoGroup.objects.all(),
widget=ModelSelect2Widget(
search_fields=[
"name__icontains",
],
attrs={"data-minimum-input-length": 0, "class": "browser-default"},
),
label=_("Group"),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form.layout = Layout(Row("group", "permission", "permission__content_type"))
class Meta:
fields = ["group", "permission", "permission__content_type"]
class UserGlobalPermissionFilter(UserPermissionFilter):
"""Filter for global user permissions."""
class Meta(UserPermissionFilter.Meta):
model = User.user_permissions.through
class GroupGlobalPermissionFilter(GroupPermissionFilter):
"""Filter for global group permissions."""
class Meta(GroupPermissionFilter.Meta):
model = DjangoGroup.permissions.through
class UserObjectPermissionFilter(UserPermissionFilter):
"""Filter for object user permissions."""
class Meta(UserPermissionFilter.Meta):
model = UserObjectPermission
class GroupObjectPermissionFilter(GroupPermissionFilter):
"""Filter for object group permissions."""
class Meta(GroupPermissionFilter.Meta):
model = GroupObjectPermission
This diff is collapsed.
......@@ -33,10 +33,13 @@ class BaseBackupHealthCheck(BaseHealthCheckBackend):
def check_status(self):
storage = get_storage()
backups = storage.list_backups(content_type=self.content_type)
if not storage.storage.exists(""):
self.add_error(_("The backup folder doesn't exist."))
try:
backups = storage.list_backups(content_type=self.content_type)
except Exception as ex:
self.add_error(_("Error accessing backup storage: {}").format(str(ex)))
return
if backups:
last_backup = backups[:1]
last_backup_time = dbbackup_utils.filename_to_date(last_backup[0])
......@@ -44,7 +47,7 @@ class BaseBackupHealthCheck(BaseHealthCheckBackend):
# Check if backup is older than configured time
if time_gone_since_backup.seconds > self.configured_seconds:
self.add_error(_(f"Last backup {time_gone_since_backup}!"))
self.add_error(_("Last backup {}!").format(time_gone_since_backup))
else:
self.add_error(_("No backup found!"))
......@@ -75,4 +78,4 @@ class BackupJobHealthCheck(BaseHealthCheckBackend):
if not task:
self.add_error(_("No backup result found!"))
elif task and task.status != "SUCCESS":
self.add_error(_(f"{task.status} - {task.result}"))
self.add_error(f"{task.status} - {task.result}")
......@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-06-08 16:49+0200\n"
"POT-Creation-Date: 2022-01-31 17:03+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......@@ -18,18 +18,18 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#: aleksis/core/static/js/main.js:15
#: aleksis/core/static/js/main.js:66
msgid "Today"
msgstr ""
#: aleksis/core/static/js/main.js:16
#: aleksis/core/static/js/main.js:67
msgid "Cancel"
msgstr ""
#: aleksis/core/static/js/main.js:17
#: aleksis/core/static/js/main.js:68
msgid "OK"
msgstr ""
#: aleksis/core/static/js/main.js:133
#: aleksis/core/static/js/main.js:191
msgid "This page may contain outdated information since there is no internet connection."
msgstr ""
......@@ -3,32 +3,33 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-06-08 16:49+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"POT-Creation-Date: 2022-01-31 17:03+0100\n"
"PO-Revision-Date: 2021-10-28 14:37+0000\n"
"Last-Translator: Jonathan Weth <teckids@jonathanweth.de>\n"
"Language-Team: German <https://translate.edugit.org/projects/aleksis/aleksis-core-js/de/>\n"
"Language: de_DE\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.8\n"
#: aleksis/core/static/js/main.js:15
#: aleksis/core/static/js/main.js:66
msgid "Today"
msgstr ""
msgstr "Heute"
#: aleksis/core/static/js/main.js:16
#: aleksis/core/static/js/main.js:67
msgid "Cancel"
msgstr ""
msgstr "Abbrechen"
#: aleksis/core/static/js/main.js:17
#: aleksis/core/static/js/main.js:68
msgid "OK"
msgstr ""
msgstr "OK"
#: aleksis/core/static/js/main.js:133
#: aleksis/core/static/js/main.js:191
msgid "This page may contain outdated information since there is no internet connection."
msgstr ""
msgstr "Diese Seite enthält vielleicht veraltete Informationen, da es keine Internetverbindung gibt."