Compare commits

...

144 Commits

Author SHA1 Message Date
8f5c1e36a5 Attempt to patch publishing workflow 2025-05-23 12:39:16 +01:00
1992a4cee0 Version Increment 2025-05-23 12:36:23 +01:00
40ed1aa4f9 Set publish to trigger on tagging 2025-05-23 12:35:57 +01:00
51f11bd910 Added automatic publishing to pypi 2025-05-23 12:31:16 +01:00
f4c8cbea03 Fixed mistake in tagging workflow 2025-05-23 12:19:25 +01:00
56f7739ae4 Tweaked tagging workflow to only run after successful tests 2025-05-23 12:18:12 +01:00
f2bcb03cd0 Version increment 2025-05-23 12:14:00 +01:00
9646985e7c AddedAdded auto-tagging workflow 2025-05-23 12:11:58 +01:00
b514df9d48 Updated tests workflow 2025-05-23 12:11:58 +01:00
e1d975dc98 Version increment 2025-05-20 11:22:01 +01:00
d4f6efe5a2 Removed unnecessary git hook 2025-05-20 11:21:52 +01:00
9b7aa9a217 Improved check_version_increment script 2025-05-20 11:19:10 +01:00
a0da4cf05f Added version check script and pre-push hooks 2025-05-20 10:10:47 +01:00
84595fa54f Switched to calver managed by hatch 2025-05-20 10:01:19 +01:00
2cf44242fa Update devenv 2025-05-08 14:35:52 +01:00
899b391e29 Version bump 2025-05-02 14:05:20 +01:00
610ea83652 Re-added entrypoints 2025-05-02 13:52:53 +01:00
28aa1eb9a3 Updated to run on python 3.13 2025-05-01 09:02:07 +01:00
98f37fc6d7 Added license header 2025-04-29 14:35:26 +01:00
7c938751e6 Version bump 2025-04-29 14:12:54 +01:00
7bd474a247 Fixed testing workflow 2025-04-29 14:05:50 +01:00
8582c8ce23 Switched tests to be managed by package manager 2025-04-29 14:03:16 +01:00
3ba2169591 Fixed policies 2025-04-29 13:29:06 +01:00
3e566699c6 Updated test settings 2025-04-29 12:49:31 +01:00
811bf6514d Renamed test file 2025-04-29 12:15:48 +01:00
668ae1e34c Switched build system from setuptools to hatchling 2025-04-29 12:13:57 +01:00
60085e90ab Removed deprecated ruff rules 2025-04-29 08:48:05 +01:00
cb836a1d6d Updated devenv 2025-04-29 08:43:20 +01:00
5fea611ab4 Added act to test actions locally 2025-04-29 08:42:09 +01:00
e8df1e4541 Removed manifest from package 2025-04-28 18:50:42 +01:00
069bb11033 Added test script logging 2025-04-28 18:45:20 +01:00
cd35917894 UV tests fix? 2025-04-28 18:39:51 +01:00
302ff471fd Trying again 2025-04-28 18:36:53 +01:00
e2e6a32c08 Another fix attempt 2025-04-28 18:34:15 +01:00
32f0c0af61 Another fix attempt 2025-04-28 18:27:49 +01:00
d26e8cae6f Another tests.yml fix 2025-04-28 18:26:14 +01:00
f537f0e383 Attempted tests.yml fix 2025-04-28 18:13:31 +01:00
3e82144fd3 Another attempt to fix tests.yml 2025-04-28 18:12:18 +01:00
b925eaa678 Fixed tests workflow 2025-04-28 18:08:04 +01:00
5b2eb94994 FIxed tests workflow and removed automatic publishing 2025-04-28 18:01:35 +01:00
7c7a281a5f Configured for build and publish 2025-04-28 17:51:28 +01:00
8e3b48ab52 Added devenv definition 2025-04-28 17:51:28 +01:00
Cian Hughes
8746d704a1 Update pypi-publish.yml 2025-04-25 16:52:25 +01:00
Cian Hughes
a7b474bb78 Update tests.yml 2025-04-25 16:50:18 +01:00
969b16fe4a Updated README.rst 2025-04-25 16:43:07 +01:00
d452fca79e Update README.rst 2025-04-25 16:40:41 +01:00
2069f0826d Updated README.rst 2025-04-25 16:29:06 +01:00
98893598f8 Update README.rst 2025-04-25 16:26:59 +01:00
4e20d6a5fe Lint and format according to new codestyle 2025-04-25 16:24:31 +01:00
58a7e2f3a8 Switched from black to ruff 2025-04-25 16:22:11 +01:00
5665b01979 Migrate from setup.py to uv 2025-04-25 15:51:27 +01:00
b6cbd03f9c Changed names for new fork 2025-04-25 15:51:08 +01:00
Christoph Ladurner
04ca3f5661 release v0.12.5 2024-07-29 09:46:39 +02:00
Christoph Ladurner
5d84b08e26 fix: permission for ip 2024-07-29 09:36:36 +02:00
Christoph Ladurner
5e4fcca0ed release v0.12.3 2024-07-25 23:04:28 +02:00
Christoph Ladurner
c934a4952b fix(tugraz_authenticated): missmatch of role name 2024-07-25 23:04:01 +02:00
Christoph Ladurner
c91d056a56 release v0.12.2 2024-07-19 09:27:39 +02:00
Christoph Ladurner
583a67d0cf setup: introduce ruff
* remove unused .tx. the translation is done without transifex

* remove unused files

* remove unused checks because ruff took over
2024-07-19 09:25:08 +02:00
Christoph Ladurner
760363b4a5 perm: implement single-ip and ip-network
* with that addition it is possible to restrict records to an special ip
  or an ip network
2024-07-19 09:25:08 +02:00
Martin Obersteiner
52fb93cc43 utils: add invenio_saml-compatible account-setup 2024-07-08 10:03:01 +02:00
Martin Obersteiner
41db3186df add new permission-policy, add new role 2024-06-25 14:35:08 +02:00
Martin Obersteiner
20bdff0b79 fix deprecated before_app_first_request 2024-06-11 13:27:08 +02:00
Christoph Ladurner
99705d7a25 setup: add support for python3.11 and 3.12
* pytest-black -> pytest-black-ng, former unsupported

* add invenio-app to test install requires
2024-04-02 14:06:44 +02:00
Christoph Ladurner
d4df756ebf release v0.12.1 2024-03-08 12:57:11 +01:00
Christoph Ladurner
a10dccba22 setup: remove upper limit of rdm-records 2024-03-08 12:56:37 +01:00
Christoph Ladurner
8b84077e83 release v0.12.0 2023-11-10 09:01:40 +01:00
Christoph Ladurner
08d745d367 setup: remove python3.8 support 2023-11-10 09:01:16 +01:00
Christoph Ladurner
bf62abff3f global: make it compatible with v12 2023-11-10 09:01:16 +01:00
Christoph Ladurner
40a47ed36d release v0.11.0 2023-04-20 22:23:20 +02:00
mojib
129b331603 global: make package compatible with v11 2023-04-20 22:22:23 +02:00
Christoph Ladurner
328abd1306 release v0.10.4 2023-02-10 10:41:27 +01:00
Christoph Ladurner
7ce124cdb9 setup: invenio-search is not optional 2023-02-10 10:36:44 +01:00
Christoph Ladurner
75d78cf09a setup: change to reusable github workflows
* move check_manifest configuration to setup.cfg

* remove upper constraint for pytest-black
2023-02-10 10:36:44 +01:00
Christoph Ladurner
2e5fbcb4f9 setup: remove 3.7 and add 3.10 support 2023-02-10 10:36:44 +01:00
Christoph Ladurner
4c4279965a guide: update 2023-02-10 10:36:44 +01:00
Christoph Ladurner
0ee0df4ee1 release v0.10.2 2023-02-02 09:03:42 +01:00
mojib
8df08c09bf change version name 2023-02-01 15:36:57 +01:00
mojib
3a508ac3f0 footer: update guid 2023-02-01 15:36:57 +01:00
Christoph Ladurner
087cafa3ae release v0.10.1 2022-11-17 10:00:20 +01:00
Christoph Ladurner
14e9e0557a global: add function
* this function was moved from invenio-alma
2022-11-17 09:55:56 +01:00
Mojib Wali
8669f5dcda release: v0.10.0 2022-10-13 11:23:15 +02:00
Mojib Wali
62256b346f global: migrate to v10 2022-10-13 11:12:14 +02:00
Mojib Wali
4a8b02ec4a release: v0.9.1 2022-05-30 14:18:33 +02:00
Mojib Wali
8a592e3fdf ci(publish): ping babel version (#99) 2022-05-30 14:11:36 +02:00
Mojib Wali
42d5e2db05 release: v0.9.0 2022-05-30 13:38:10 +02:00
Mojib Wali
3db870784b config: adds accounts config var 2022-05-30 13:28:34 +02:00
Mojib Wali
73bc8b4575 dep: compatible to v9 rdm
black: formated
2022-05-25 18:49:16 +02:00
David
7fd5a7df3f config: add deposit form quota variable (#91) 2022-05-25 18:39:32 +02:00
Christoph Ladurner
79fe24511a bump invenio-rdm-records version 2022-05-25 12:46:45 +02:00
Christoph Ladurner
5b7a1718fc migrate setup py to cfg (#94)
* global: migrate setup.py to setup.cfg

* global: clean up copyright notices and tests

* migrate to use black as opinionated auto formater

* add .git-blame-ignore-revs
2022-05-12 08:58:50 +02:00
David
9192107e99 fix: update email welcome template with SITE_UI_URL (#93) 2022-04-20 08:31:42 +02:00
Mojib Wali
c43c36ece3 v0.8.4 2022-03-11 10:47:10 +01:00
Mojib Wali
3acbaf65ef revert: use gettext 2022-03-11 10:40:58 +01:00
Mojib Wali
408bdc47b1 v0.8.3 2022-03-10 10:25:35 +01:00
Mojib Wali
6c6138b682 config: fix comment & import 2022-03-10 09:31:15 +01:00
Mojib Wali
cc2c462057 README: update links 2022-03-03 10:17:52 +01:00
Mojib Wali
3f2cf9f800 v0.8.2 2022-03-03 10:12:43 +01:00
Mojib Wali
db0c7a4e21 config: introduced in v8 of invenioRDM 2022-03-03 10:03:20 +01:00
Mojib Wali
91464bbd7c v0.8.1 2022-02-28 15:05:59 +01:00
Mojib Wali
d7fe2926c7 gloabl: changes to pre-v8
* config: set samesite cookie to strict
* dep: bump in base
2022-02-28 14:55:20 +01:00
Mojib Wali
d5fcf60cf7 v0.8.0 2022-02-09 16:29:35 +01:00
David Eckhard
772b21c93a config: add OAISERVER_ADMIN_EMAIL 2021-12-16 11:54:46 +01:00
mb-wali
c39221378f v0.7.1 2021-12-07 09:54:26 +01:00
mb-wali
a42f86fcdf configs: adds new & changed configs for v7 2021-12-06 14:44:05 +01:00
mb-wali
0dd0db04e2 v0.7.0 2021-12-06 09:45:11 +01:00
David Eckhard
b02ce8a755 fix: update blueprint reorder 2021-11-08 10:21:28 +01:00
Mojib
41dcb8f437 docs: adjust sphinx to flask 2
* Add werkzeug to intersphinx for additional type hints
* Describe type hints in bullet points rather than function signatures
* Remove 'warnings as errors' flag from documentation building, as some type hints aren't resolved properly and result in a warning
2021-11-04 10:55:33 +01:00
Mojib
35854691bd config: adds oai prefix 2021-11-04 10:55:33 +01:00
Mojib
f2e18b95c3 dep: upgrade rdm-records version
migrated allowed host to gitlab
2021-11-04 10:55:33 +01:00
Mojib Wali
16c10593d6 v0.6.2 2021-08-05 08:22:37 +02:00
mb-wali
dbd870d106 doi: remove doi 'datacite' suffix 2021-08-04 16:21:04 +02:00
mb-wali
f02e992acd dep: global dep bump
config: adds i18n vars & extracted from gitlab configs
config: form defaults and tighter CSP
2021-08-04 16:21:04 +02:00
Mojib Wali
a7abb0bc5e v0.6.1 2021-06-04 11:46:57 +02:00
mb-wali
7ca398efdd global: adds routes for tug
This: migrated from invenio-theme-tugraz
2021-06-04 11:46:08 +02:00
Mojib Wali
b33c7e09c3 v0.6.0 2021-05-31 13:12:06 +02:00
mb-wali
0c775851d8 refactor: removes search guide
due: added to core module. This closes #64
2021-05-31 13:09:30 +02:00
mb-wali
89f6aee814 migrate: invenioRDM v4
deb: bump in app-rdm
2021-05-31 13:09:30 +02:00
Mojib Wali
44e5857143 v0.5.9 2021-05-07 12:01:04 +02:00
mb-wali
460de9fc35 feature: adds searchguide german 2021-05-07 11:02:25 +02:00
Mojib Wali
b1d7a6558e v0.5.8 2021-04-30 13:32:46 +02:00
mb-wali
890fded625 dep: installing invenio-app-rdm 2021-04-30 13:32:23 +02:00
Mojib Wali
1304563a3e v0.5.7 2021-04-28 09:01:04 +02:00
mb-wali
a08201041a bugfix: search guide url 2021-04-28 08:54:48 +02:00
Mojib Wali
548896be11 v0.5.6 2021-04-27 15:53:59 +02:00
Mojib Wali
a10433aba3 email: welcome email template 2021-04-27 15:48:05 +02:00
Mojib Wali
f0fbabbaa8 v0.5.5 2021-04-22 09:46:08 +02:00
Mojib Wali
5e2a58c764 i18n: adds translation
* babel: adds a wildcard to extract txt files.
* refactor txt file
2021-04-22 09:45:42 +02:00
Mojib Wali
9af1beff88 v0.5.4 2021-04-21 16:11:09 +02:00
rekt-hard
80575cbced feature: override email welcome template
* overrides flask-security welcome template
2021-04-21 16:10:30 +02:00
Unix
60b85e6ad5 global: repo cleanup 2021-03-31 14:22:32 +02:00
Mojib Wali
10f68379b5 v0.5.3 2021-03-29 10:06:21 +02:00
Mojib Wali
49766790d7 config: refactor email subject. 2021-03-24 09:42:41 +01:00
Mojib Wali
977d5588f4 refactor: changed the link to point correct repo. 2021-03-18 13:55:35 +01:00
Mojib Wali
ded93fabeb v0.5.2 2021-03-18 10:26:00 +01:00
Mojib Wali
c2ee5fa4b7 configs(db): adds SQLALCHEMY configs
* configs(db): adds SQLALCHEMY configs
configs: adds fixture user
2021-03-18 10:24:55 +01:00
Unix
cf3ffa1543 config: adds default rdm depsit fields empty
refactor: removes saml configs
2021-03-18 09:53:59 +01:00
Mojib Wali
927fb44f95 v0.5.1 2021-03-10 20:24:42 +01:00
Mojib Wali
d7c91765b4 config: shibboleth default not configured 2021-03-10 20:24:13 +01:00
Mojib Wali
dba1cd5d62 v0.5.0 2021-03-09 09:34:59 +01:00
rekt-hard
49b5477ebc fix: extend csp to allow datacite and zammad (#48) 2021-03-09 09:04:24 +01:00
Mojib Wali
92cfad940f v0.4.2 2021-03-02 15:25:02 +01:00
Mojib Wali
93ad527061 config: disable registration
* vocab: remove override vocab
* global: disable user registration
2021-03-02 15:24:18 +01:00
Mojib Wali
9d2ad34601 v0.4.1 2021-01-18 10:54:09 +01:00
Mojib Wali
1eb836aec8 permission: restriction to only open access 2021-01-18 10:28:34 +01:00
90 changed files with 7560 additions and 1552 deletions

View File

@@ -2,7 +2,7 @@
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
@@ -15,15 +15,6 @@ insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
# Python files
[*.py]
indent_size = 4
# isort plugin configuration
known_first_party = invenio_config_tugraz
multi_line_output = 2
default_section = THIRDPARTY
skip = .eggs
# RST files (used by sphinx)
[*.rst]
indent_size = 4

5
.envrc Normal file
View File

@@ -0,0 +1,5 @@
export DIRENV_WARN_TIMEOUT=20s
eval "$(devenv direnvrc)"
use devenv

1
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1 @@
766b2cafae4dc74393b103389e6978eca5a9cfd2

21
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Publish to PyPI
on:
workflow_run:
workflows:
- Auto Version Tag
types:
- completed
jobs:
publish:
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/checkout@v4
- name: Install uv
run: pip install uv
- name: Build package
run: uv build
- name: Publish to PyPI
run: uv publish

View File

@@ -1,26 +0,0 @@
on:
push:
tags:
- v*
jobs:
build-n-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v2
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel
- name: Build package
run: |
python setup.py compile_catalog sdist bdist_wheel
- name: pypi-publish
uses: pypa/gh-action-pypi-publish@v1.3.1
with:
user: __token__
password: ${{ secrets.pypi_password }}

20
.github/workflows/tagging.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Auto Version Tag
on:
workflow_run:
workflows:
- Tests
types:
- completed
jobs:
tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Version tag
uses: Jorricks/action-python-autotagging@1.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
path: invenio_config_iform/__about__.py
variable: __version__

View File

@@ -1,54 +1,86 @@
name: CI
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 I-Form Advanced Manufacturing Research Centre.
#
# invenio-theme-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
name: Tests
on:
push:
branches: master
branches:
- master
pull_request:
branches: master
schedule:
# * is a special character in YAML so you have to quote this string
- cron: '0 3 * * 6'
branches:
- master
workflow_dispatch:
inputs:
reason:
description: 'Reason'
description: "Reason"
required: false
default: 'Manual trigger'
default: "Manual trigger"
jobs:
Tests:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
requirements-level: [min, pypi]
create-strategy:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.requirements.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Generate dependencies
- name: requirements
id: requirements
run: |
python -m pip install --upgrade pip setuptools py wheel requirements-builder
requirements-builder -e all --level=${{ matrix.requirements-level }} setup.py > .${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt
# Define a simple matrix with your Python version
# Since we're using pyproject.toml with Python 3.12 requirement
echo "matrix={\"include\": [{\"python-version\": \"3.12\"}]}" >> $GITHUB_OUTPUT
- name: Cache pip
uses: actions/cache@v2
# Print the matrix for debugging
echo "-------------------"
echo "Matrix: {\"include\": [{\"python-version\": \"3.12\"}]}"
echo "-------------------"
tests:
needs: create-strategy
runs-on: ubuntu-latest
name: Test (Python ${{matrix.python-version}})
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.create-strategy.outputs.matrix) }}
# Simplified environment without service variables
env:
PYTHON_VERSION: ${{ matrix.python-version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('.${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt') }}
python-version: "${{ matrix.python-version }}"
enable-cache: true
cache-dependency-glob: |
pyproject.toml
cache-suffix: ${{ matrix.python-version }}
- name: Show configuration
run: |
uv --version
uv run python --version
docker --version
docker ps
- name: Install dependencies
run: |
pip install -r .${{matrix.requirements-level}}-${{ matrix.python-version }}-requirements.txt
pip install .[all]
pip freeze
uv sync --group tests
- name: Run tests
run: |
./run-tests.sh
uv run test

10
.gitignore vendored
View File

@@ -60,3 +60,13 @@ target/
# Vim swapfiles
.*.sw?
# Devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# python version lock
.python-version

24
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,24 @@
repos:
- repo: local
hooks:
- id: check-version-increment
name: Check Version Increment
entry: python scripts/hooks/pre-push/check_version_increment.py
language: system
pass_filenames: false
stages: [pre-push]
- id: tests
name: Run Python Tests
entry: uv run test
language: system
pass_filenames: false
stages: [pre-push]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.9
hooks:
- id: ruff
stages: [pre-push]
- id: ruff-format
stages: [pre-push]

View File

@@ -1,33 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
# TODO: Transifex integration
#
# 1) Create message catalog:
# $ python setup.py extract_messages
# $ python setup.py init_catalog -l <lang>
# $ python setup.py compile_catalog
# 2) Ensure project has been created on Transifex under the inveniosoftware
# organisation.
# 3) Install the transifex-client
# $ pip install transifex-client
# 4) Push source (.pot) and translations (.po) to Transifex
# $ tx push -s -t
# 5) Pull translations for a single language from Transifex
# $ tx pull -l <lang>
# 6) Pull translations for all languages from Transifex
# $ tx pull -a
[main]
host = https://www.transifex.com
[invenio.invenio-config-tugraz-messages]
file_filter = invenio_config_tugraz/translations/<lang>/LC_MESSAGES/messages.po
source_file = invenio_config_tugraz/translations/messages.pot
source_lang = en
type = PO

View File

@@ -1,13 +1,15 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
Authors
=======
invenio module that adds tugraz configs.
invenio module that adds I-Form configs.
- Mojib Wali <mojib.wali@tugraz.at>
- Cian Hughes <cian.hughes@dcu.ie>
Forked from https://github.com/tu-graz-library/invenio-theme-tugraz

View File

@@ -1,13 +1,110 @@
..
Copyright (C) 2020 Mojib Wali.
Copyright (C) 2020 - 2022 Graz University of Technology.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
Changes
=======
Version v0.12.5 (release 2024-07-29)
- fix: permission for ip
Version v0.12.3 (release 2024-07-25)
- fix(iform_authenticated): missmatch of role name
Version v0.12.2 (release 2024-07-19)
- setup: introduce ruff
- perm: implement single-ip and ip-network
- utils: add invenio_saml-compatible account-setup
- add new permission-policy, add new role
- fix deprecated `before_app_first_request`
- setup: add support for python3.11 and 3.12
Version v0.12.1 (release 2024-03-08)
- setup: remove upper limit of rdm-records
Version v0.12.0 (release 2023-11-10)
- setup: remove python3.8 support
- global: make it compatible with v12
Version v0.11.0 (release 2023-04-20)
- global: make package compatible with v11
Version v0.10.4 (release 2023-02-10)
Version v0.10.2 (release 2023-02-02)
- change version name
- footer: update guid
Version v0.10.1 (release 2022-11-17)
- global: add function
Version 0.10.0 (released 2022-10-13)
- global: migrate to v10 (#101)
Version 0.9.1 (released 2022-05-30)
- ci(publish): ping babel version (#99)
Version 0.9.0 (released 2022-05-30)
- config: adds new introduced configs v9
- dep: compatible to v9 rdm
- config: add deposit form quota variable (#91)
- migrate setup py to cfg (#94)
- fix: update email welcome template with SITE_UI_URL (#93)
Version 0.8.4 (released 2022-03-11)
- config: use gettext
Version 0.8.3 (released 2022-03-10)
- config: fix comment & import
Version 0.8.2 (released 2022-03-03)
- config: new introduced to v8 of invenioRDM
Version 0.8.1 (released 2022-02-28)
- config: set samesite cookie to strict
- dep: bump in base dependencies
Version 0.8.0 (released 2022-02-09)
- dep: bump rdm-records version
Version 0.7.1 (released 2021-12-07)
- configs: adds new & changed configs for v7 #76
Version 0.7.0 (released 2021-12-06)
- fix: update blueprint reorder #74
- dep: upgrade rdm-records version & OAI #72
Version 0.1.0 (released TBD)
- Initial public release.

View File

@@ -10,7 +10,7 @@ Types of Contributions
Report Bugs
~~~~~~~~~~~
Report bugs at https://github.com/tu-graz-library/invenio-config-tugraz/issues.
Report bugs at https://github.com/Cian-H/invenio-config-iform/issues.
If you are reporting a bug, please include:
@@ -33,15 +33,15 @@ is open to whoever wants to implement it.
Write Documentation
~~~~~~~~~~~~~~~~~~~
invenio-config-tugraz could always use more documentation, whether as part of the
official invenio-config-tugraz docs, in docstrings, or even on the web in blog posts,
invenio-config-iform could always use more documentation, whether as part of the
official invenio-config-iform docs, in docstrings, or even on the web in blog posts,
articles, and such.
Submit Feedback
~~~~~~~~~~~~~~~
The best way to send feedback is to file an issue at
https://github.com/tu-graz-library/invenio-config-tugraz/issues.
https://github.com/Cian-H/invenio-config-iform/issues.
If you are proposing a feature:
@@ -53,14 +53,14 @@ If you are proposing a feature:
Get Started!
------------
Ready to contribute? Here's how to set up `invenio-config-tugraz` for local development.
Ready to contribute? Here's how to set up `invenio-config-iform` for local development.
1. Fork the `https://github.com/https://github.com/mb-` repo on GitHub.
2. Clone your fork locally:
.. code-block:: console
$ git clone git@github.com:your_name_here/invenio-config-tugraz.git
$ git clone git@github.com:your_name_here/invenio-config-iform.git
3. Install your local copy into a virtualenv. Assuming you have
virtualenvwrapper installed, this is how you set up your fork for local
@@ -68,8 +68,8 @@ Ready to contribute? Here's how to set up `invenio-config-tugraz` for local deve
.. code-block:: console
$ mkvirtualenv invenio-config-tugraz
$ cd invenio-config-tugraz/
$ mkvirtualenv invenio-config-iform
$ cd invenio-config-iform/
$ pip install -e .[all]
4. Create a branch for local development:
@@ -114,5 +114,5 @@ Before you submit a pull request, check that it meets these guidelines:
2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring.
3. The pull request should work for Python 3.6 and 3.7. Check
https://github.com/github/tu-graz-library/invenio-config-tugraz//actions?query=event%3Apull_request
https://github.com/github/Cian-H/invenio-config-iform//actions?query=event%3Apull_request
and make sure that the tests pass for all supported Python versions.

View File

@@ -1,8 +1,8 @@
Installation
============
invenio-config-tugraz is on PyPI so all you need is:
invenio-config-iform is on PyPI so all you need is:
.. code-block:: console
$ pip install invenio-config-tugraz
$ pip install invenio-config-iform

View File

@@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
# TODO: Generate this manifest file by running the following commands:
# (please sort the lines in this file after running below commands)
#
# git init
# git add -A
# pip install -e .[all]
# check-manifest -u
include .dockerignore
include .editorconfig
include .tx/config
prune docs/_build
recursive-include invenio_config_tugraz/translations *.po *.pot *.mo
# added by check_manifest.py
include *.md
include *.rst
include *.sh
include *.txt
include *.rst
include LICENSE
include babel.ini
include pytest.ini
recursive-include docs *.bat
recursive-include docs *.py
recursive-include docs *.rst
recursive-include docs *.txt
recursive-include docs Makefile
recursive-include invenio_config_tugraz *.html
recursive-include tests *.py
# added by check_manifest.py
recursive-include invenio_config_tugraz *.crt
recursive-include invenio_config_tugraz *.json
recursive-include invenio_config_tugraz *.key
recursive-include invenio_config_tugraz *.xml
recursive-include invenio_config_tugraz *.gitkeep
# added by check-manifest
recursive-include invenio_config_tugraz *.csv

View File

@@ -1,43 +1,47 @@
..
Copyright (C) 2020 Mojib Wali.
Copyright (C) 2020-2021 Graz University of Technology.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
=======================
invenio-config-tugraz
invenio-config-iform
=======================
.. image:: https://github.com/tu-graz-library/invenio-config-tugraz/workflows/CI/badge.svg
:target: https://github.com/tu-graz-library/invenio-config-tugraz/actions
.. image:: https://github.com/Cian-H/invenio-config-iform/workflows/CI/badge.svg
:target: https://github.com/Cian-H/invenio-config-iform/actions
.. image:: https://img.shields.io/pypi/dm/invenio-config-tugraz.svg
:target: https://pypi.python.org/pypi/invenio-config-tugraz
.. image:: https://img.shields.io/pypi/dm/invenio-config-iform.svg
:target: https://pypi.python.org/pypi/invenio-config-iform
.. image:: https://img.shields.io/github/tag/mb-wali/invenio-config-tugraz.svg
:target: https://github.com/mb-wali/invenio-config-tugraz/releases
.. image:: https://img.shields.io/github/tag/Cian-H/invenio-config-iform.svg
:target: https://github.com/Cian-H/invenio-config-iform/releases
.. image:: https://img.shields.io/github/license/mb-wali/invenio-config-tugraz.svg
:target: https://github.com/mb-wali/invenio-config-tugraz/blob/master/LICENSE
.. image:: https://img.shields.io/github/license/Cian-H/invenio-config-iform.svg
:target: https://github.com/Cian-H/invenio-config-iform/blob/master/LICENSE
.. image:: https://readthedocs.org/projects/invenio-config-tugraz/badge/?version=latest
:target: https://invenio-config-tugraz.readthedocs.io/en/latest/?badge=latest
.. image:: https://img.shields.io/coveralls/mb-wali/invenio-config-tugraz.svg
:target: https://coveralls.io/r/mb-wali/invenio-config-tugraz
.. image:: https://readthedocs.org/projects/invenio-config-iform/badge/?version=latest
:target: https://invenio-config-iform.readthedocs.io/en/latest/?badge=latest
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
.. image:: https://img.shields.io/coveralls/mb-wali/invenio-config-iform.svg
:target: https://coveralls.io/r/mb-wali/invenio-config-iform
invenio module that adds tugraz configs.
.. image:: https://img.shields.io/badge/code%20style-Ruff-D7FF64.svg
:target: https://github.com/astral-sh/ruff
Override configs from diffrent invenio modules to meet TU Graz requirement:
invenio module that adds I-Form configs.
Override configs from invenio modules with I-Form configurations:
* Invenio-App
* Invenio-Mail
* Invenio-shibboleth
* Invenio-accounts
* Flask-security
* Defined routes for I-Form
Further documentation is available on
https://invenio-config-tugraz.readthedocs.io/
https://invenio-config-iform.readthedocs.io/
Forked from https://github.com/tu-graz-library/invenio-config-tugraz

View File

@@ -2,7 +2,7 @@
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
@@ -13,9 +13,8 @@ encoding = utf-8
# Extraction from Jinja2 templates
[jinja2: **/templates/**.html]
[jinja2: **/templates/**.*]
encoding = utf-8
extensions = jinja2.ext.autoescape, jinja2.ext.with_
# Extraction from JavaScript files

103
devenv.lock Normal file
View File

@@ -0,0 +1,103 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1746707904,
"owner": "cachix",
"repo": "devenv",
"rev": "fada79d97f2066c444766d039b0a62affd3e3cab",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1746537231,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "fa466640195d38ec97cf0493d6d6882bc4d14969",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1745934659,
"owner": "cachix",
"repo": "devenv-nixpkgs",
"rev": "fbc071e5c11e23fba50037de37268e3d8a1858eb",
"type": "github"
},
"original": {
"owner": "cachix",
"ref": "rolling",
"repo": "devenv-nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": [
"git-hooks"
]
}
}
},
"root": "root",
"version": 7
}

19
devenv.nix Normal file
View File

@@ -0,0 +1,19 @@
{
pkgs,
lib,
config,
inputs,
...
}: {
packages = [
pkgs.git
pkgs.act
];
languages.python = {
enable = true;
uv = {
enable = true;
};
};
}

4
devenv.yaml Normal file
View File

@@ -0,0 +1,4 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling

View File

@@ -87,9 +87,9 @@ qthelp:
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/invenio-config-tugraz.qhcp"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/invenio-config-iform.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/invenio-config-tugraz.qhc"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/invenio-config-iform.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@@ -104,8 +104,8 @@ devhelp:
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/invenio-config-tugraz"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/invenio-config-tugraz"
@echo "# mkdir -p $$HOME/.local/share/devhelp/invenio-config-iform"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/invenio-config-iform"
@echo "# devhelp"
epub:

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
@@ -9,5 +9,5 @@
API Docs
========
.. automodule:: invenio_config_tugraz.ext
.. automodule:: invenio_config_iform.ext
:members:

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.

View File

@@ -2,13 +2,13 @@
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Sphinx configuration."""
import os
from invenio_config_iform import __version__
# import sphinx.environment
@@ -46,9 +46,9 @@ source_suffix = ".rst"
master_doc = "index"
# General information about the project.
project = u"invenio-config-tugraz"
copyright = u"2020, Mojib Wali"
author = u"Mojib Wali"
project = "invenio-config-iform"
copyright = "2022, TU Graz"
author = "TU Graz"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -56,26 +56,15 @@ author = u"Mojib Wali"
#
# The short X.Y version.
# Get the version string. Cannot be done with import!
g = {}
with open(
os.path.join(
os.path.dirname(__file__), "..", "invenio_config_tugraz", "version.py"
),
"rt",
) as fp:
exec(fp.read(), g)
version = g["__version__"]
# The full version, including alpha/beta/rc tags.
release = version
release = __version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = "en"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
@@ -119,15 +108,15 @@ todo_include_todos = False
html_theme = "alabaster"
html_theme_options = {
"description": "invenio module that adds tugraz configs.",
"description": "invenio module that adds iform configs.",
"github_user": "TU Graz",
"github_repo": "invenio-config-tugraz",
"github_repo": "invenio-config-iform",
"github_button": False,
"github_banner": True,
"show_powered_by": False,
"extra_nav_links": {
"invenio-config-tugraz@GitHub": "https://github.com/tu-graz-library/invenio-config-tugraz",
"invenio-config-tugraz@PyPI": "https://pypi.python.org/pypi/invenio-config-tugraz/",
"invenio-config-iform@Github": "https://github.com/Cian-H/invenio-config-iform",
"invenio-config-iform@PyPI": "https://pypi.python.org/pypi/invenio-config-iform/",
},
}
@@ -232,7 +221,7 @@ html_sidebars = {
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = "invenio-config-tugraz_namedoc"
htmlhelp_basename = "invenio-config-iform_namedoc"
# -- Options for LaTeX output ---------------------------------------------
@@ -253,9 +242,9 @@ latex_elements = {
latex_documents = [
(
master_doc,
"invenio-config-tugraz.tex",
u"invenio-config-tugraz Documentation",
u"Mojib Wali",
"invenio-config-iform.tex",
"invenio-config-iform Documentation",
"Mojib Wali",
"manual",
),
]
@@ -288,8 +277,8 @@ latex_documents = [
man_pages = [
(
master_doc,
"invenio-config-tugraz",
u"invenio-config-tugraz Documentation",
"invenio-config-iform",
"invenio-config-iform Documentation",
[author],
1,
)
@@ -307,11 +296,11 @@ man_pages = [
texinfo_documents = [
(
master_doc,
"invenio-config-tugraz",
u"invenio-config-tugraz Documentation",
"invenio-config-iform",
"invenio-config-iform Documentation",
author,
"invenio-config-tugraz",
"invenio module that adds tugraz configs.",
"invenio-config-iform",
"invenio module that adds iform configs.",
"Miscellaneous",
),
]
@@ -332,6 +321,8 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
"python": ("https://docs.python.org/", None),
"flask": ("https://flask.palletsprojects.com/", None),
"werkzeug": ("https://werkzeug.palletsprojects.com/", None),
# TODO: Configure external documentation references, eg:
# 'Flask-Admin': ('https://flask-admin.readthedocs.io/en/latest/', None),
}

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
@@ -9,5 +9,5 @@
Configuration
=============
.. automodule:: invenio_config_tugraz.config
.. automodule:: invenio_config_iform.config
:members:

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
@@ -12,7 +12,7 @@ User's Guide
------------
This part of the documentation will show you how to get started in using
invenio-config-tugraz.
invenio-config-iform.
.. toctree::
:maxdepth: 2

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.

View File

@@ -127,9 +127,9 @@ if "%1" == "qthelp" (
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\invenio-config-tugraz.qhcp
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\invenio-config-iform.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\invenio-config-tugraz.ghc
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\invenio-config-iform.ghc
goto end
)

View File

@@ -1,7 +1,7 @@
..
Copyright (C) 2020 Mojib Wali.
invenio-config-tugraz is free software; you can redistribute it and/or
invenio-config-iform is free software; you can redistribute it and/or
modify it under the terms of the MIT License; see LICENSE file for more
details.
@@ -9,4 +9,4 @@
Usage
=====
.. automodule:: invenio_config_tugraz
.. automodule:: invenio_config_iform

View File

@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 I-Form Advanced Manufacturing Research Centre.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Metadata for this python module."""
__version__ = "2025.5.20.4"

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds I-Form configs."""
from .__about__ import __version__
from .ext import InvenioConfigIform
from .utils import get_identity_from_user_by_email
__all__ = (
"InvenioConfigIform",
"__version__",
"get_identity_from_user_by_email",
)

View File

@@ -0,0 +1,377 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds I-Form configs."""
from invenio_i18n import gettext as _
CONFIG_IFORM_SHIBBOLETH = False
"""Set True if SAML is configured"""
CONFIG_IFORM_SINGLE_IPS = []
"""Allows access to users whose IP address is listed.
INVENIO_CONFIG_IFORM_SINGLE_IPS =
["127.0.0.1", "127.0.0.2"]
"""
CONFIG_IFORM_IP_RANGES = []
"""Allows access to users whose range of IP address is listed.
INVENIO_CONFIG_IFORM_IP_RANGES =
[["127.0.0.2", "127.0.0.99"], ["127.0.1.3", "127.0.1.5"]]
"""
CONFIG_IFORM_IP_NETWORK = ""
"""Allows access to users who are in the IP network."""
CONFIG_IFORM_ROUTES = {
"guide": "/guide",
"terms": "/terms",
"gdpr": "/gdpr",
}
"""Defined routes for TUG."""
# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
APP_DEFAULT_SECURE_HEADERS = {
"content_security_policy": {
"default-src": [
"'self'",
"data:",
"'unsafe-inline'",
"blob:",
"ub-support.tugraz.at", # zammad contact form
],
},
"content_security_policy_report_only": False,
"content_security_policy_report_uri": None,
"force_file_save": False,
"force_https": True,
"force_https_permanent": False,
"frame_options": "sameorigin",
"frame_options_allow_from": None,
"session_cookie_http_only": True,
"session_cookie_secure": True,
"strict_transport_security": True,
"strict_transport_security_include_subdomains": True,
"strict_transport_security_max_age": 31556926, # One year in seconds
"strict_transport_security_preload": False,
}
# Invenio-I18N
# ============
# See https://invenio-i18n.readthedocs.io/en/latest/configuration.html
BABEL_DEFAULT_LOCALE = "en"
# Default time zone
BABEL_DEFAULT_TIMEZONE = "Europe/Vienna"
# Other supported languages (do not include BABEL_DEFAULT_LOCALE in list).
I18N_LANGUAGES = [("de", _("German"))]
# Invenio-Mail
# ===========
# See https://invenio-mail.readthedocs.io/en/latest/configuration.html
MAIL_SERVER = "localhost"
"""Domain ip where mail server is running."""
SECURITY_EMAIL_SENDER = "info@invenio-test.tugraz.at"
"""Email address used as sender of account registration emails."""
"""Domain name should match the domain used in web server."""
SECURITY_EMAIL_SUBJECT_REGISTER = _("Welcome to TU Graz Repository!")
"""Email subject for account registration emails."""
MAIL_SUPPRESS_SEND = True
"""Enable email sending by default.
Set this to False when sending actual emails.
"""
# CORS - Cross-origin resource sharing
# ===========
# Uncomment to enable the CORS
# CORS_RESOURCES = '*'
# CORS_SEND_WILDCARD = True
# CORS_EXPOSE_HEADERS = [
# 'ETag',
# 'Link',
# 'X-RateLimit-Limit',
# 'X-RateLimit-Remaining',
# 'X-RateLimit-Reset',
# 'Content-Type',
# ]
# REST_ENABLE_CORS = True
# Invenio-userprofiles
# ===========
# See https://invenio-userprofiles.readthedocs.io/en/latest/configuration.html
USERPROFILES_EXTEND_SECURITY_FORMS = True
"""Set True in order to register user_profile.
This also forces user to add username and fullname
when register.
"""
USERPROFILES_EMAIL_ENABLED = True
"""Exclude the user email in the profile form."""
USERPROFILES_READ_ONLY = True
"""Allow users to change profile info (name, email, etc...)."""
# Invenio-saml
# ===========
# See https://invenio-saml.readthedocs.io/en/latest/configuration.html
SSO_SAML_IDPS = {}
"""Configuration of IDPS. Actual values can be find in to invenio.cfg file"""
SSO_SAML_DEFAULT_BLUEPRINT_PREFIX = "/shibboleth"
"""Base URL for the extensions endpoint."""
SSO_SAML_DEFAULT_METADATA_ROUTE = "/metadata/<idp>"
"""URL route for the metadata request."""
"""This is also SP entityID https://domain/shibboleth/metadata/<idp>"""
SSO_SAML_DEFAULT_SSO_ROUTE = "/login/<idp>"
"""URL route for the SP login."""
SSO_SAML_DEFAULT_ACS_ROUTE = "/authorized/<idp>"
"""URL route to handle the IdP login request."""
SSO_SAML_DEFAULT_SLO_ROUTE = "/slo/<idp>"
"""URL route for the SP logout."""
SSO_SAML_DEFAULT_SLS_ROUTE = "/sls/<idp>"
"""URL route to handle the IdP logout request."""
# Invenio-accounts
# ===========
# See https://invenio-accounts.readthedocs.io/en/latest/configuration.html
ACCOUNTS_LOCAL_LOGIN_ENABLED = True
"""Allow local login."""
SECURITY_CHANGEABLE = False
"""Allow password change by users."""
SECURITY_RECOVERABLE = False
"""Allow password recovery by users."""
SECURITY_REGISTERABLE = True
""""Allow users to register.
With this variable set to "False" users will not be
able to register, or to navigate to /sigup page.
"""
SECURITY_CONFIRMABLE = False
"""Allow user to confirm their email address.
Instead user will get a welcome email.
"""
SECURITY_LOGIN_WITHOUT_CONFIRMATION = False
"""Require users to confirm email before being able to login."""
# Flask-Security
# =============
# See https://pythonhosted.org/Flask-Security/configuration.html
SECURITY_EMAIL_PLAINTEXT = True
"""Render email content as plaintext."""
SECURITY_EMAIL_HTML = False
"""Render email content as HTML."""
ACCOUNTS = True
"""Tells if the templates should use the accounts module.
If False, you won't be able to login via the web UI.
Instead if you have a overriden template somewhere in your config.py:
like this:
SECURITY_LOGIN_USER_TEMPLATE = 'invenio_theme_iform/accounts/login.html'
then you can remove this condition from header_login.htm:
{%- if config.ACCOUNTS %}
to render your overriden login.html
"""
# Accounts
# ========
# Actual values can be find in to invenio.cfg file
#: Recaptcha public key (change to enable).
RECAPTCHA_PUBLIC_KEY = None
#: Recaptcha private key (change to enable).
RECAPTCHA_PRIVATE_KEY = None
# invenio-records-permissions
# =======
# See:
# https://invenio-records-permissions.readthedocs.io/en/latest/configuration.html
# Uncomment these to enable overriding RDM permissions
# from .rdm_permissions import IformRDMRecordServiceConfig
# RDM_RECORDS_BIBLIOGRAPHIC_SERVICE_CONFIG = IformRDMRecordServiceConfig
"""Access control configuration for records."""
# invenio-rdm-records
# =======
# See:
# https://invenio-rdm-records.readthedocs.io/en/latest/configuration.html
#
RDM_RECORDS_USER_FIXTURE_PASSWORDS = {"info@tugraz.at": None}
"""Overrides for the user fixtures' passwords.
The password set for a user fixture in this dictionary overrides the
password set in the ``users.yaml`` file. This can be used to set custom
passwords for the fixture users (of course, this has to be configured
before the fixtures are installed, e.g. by setting up the services).
If ``None`` or an empty string is configured in this dictionary, then the
password from ``users.yaml`` will be used. If that is also absent, a password
will be generated randomly.
"""
DATACITE_FORMAT = "{prefix}/{id}"
"""Customize the generated DOI string."""
DATACITE_DATACENTER_SYMBOL = ""
""""The OAI-PMH server's metadata format oai_datacite
that allows you to harvest record from InvenioRDM in DataCite XML needs
to be configured with your DataCite data center symbol.
This is only required if you want your records to be harvestable in DataCite XML format.
"""
# Invenio-app-rdm
# =========================
# See https://github.com/inveniosoftware/invenio-app-rdm/blob/master/invenio_app_rdm/config.py
APP_RDM_DEPOSIT_FORM_DEFAULTS = {
"publisher": "Graz University of Technology",
}
"""Default values for new records in the deposit UI.
The keys denote the dot-separated path, where in the record's metadata
the values should be set (see invenio-records.dictutils).
If the value is callable, its return value will be used for the field
(e.g. lambda/function for dynamic calculation of values).
"""
APP_RDM_DEPOSIT_FORM_AUTOCOMPLETE_NAMES = "off"
"""Behavior for autocomplete names search field for creators/contributors.
Available options:
- ``search`` (default): Show search field and form always.
- ``search_only``: Only show search field. Form displayed after selection or
explicit "manual" entry.
- ``off``: Only show person form (no search field).
"""
APP_RDM_DEPOSIT_FORM_QUOTA = {
"maxFiles": 100,
# Easiest way to set this to a certain amount is to start from 1 Gb
# and go from there:
# 1 Gb: 10 ** 9
# 50 Gb: 10 ** 9 * 50
# 100 Mb: 10 ** 9 * 0.1
"maxStorage": 10**9 * 10,
}
"""Deposit file upload quota """
SQLALCHEMY_ECHO = False
"""Enable to see all SQL queries."""
SQLALCHEMY_ENGINE_OPTIONS = {
"pool_pre_ping": False,
"pool_recycle": 3600,
# set a more agressive timeout to ensure http requests don't wait for long
"pool_timeout": 10,
}
"""SQLAlchemy engine options.
This is used to configure for instance the database connection pool.
Specifically for connection pooling the following options below are relevant.
Note, that the connection pool settings have to be aligned with:
1. your database server's max allowed connections settings, and
2. your application deployment (number of processes/threads)
**Disconnect handling**
Note, it's possible that a connection you get from the connection pool is no
longer open. This happens if e.g. the database server was restarted or the
server has a timeout that closes the connection. In these case you'll see an
error similar to::
psycopg2.OperationalError: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The errors can be avoided by using the ``pool_pre_ping`` option, which will
ensure the connection is open first by issuing a ``SELECT 1``. The pre-ping
feature however, comes with a performance penalty, and thus it may be better
to first try adjusting the ``pool_recyle`` to ensure connections are closed and
reopened regularly.
... code-block:: python
SQLALCHEMY_ENGINE_OPTIONS = dict(
# enable the connection pool “pre-ping” feature that tests connections
# for liveness upon each checkout.
pool_pre_ping=True,
# the number of connections to allow in connection pool “overflow”,
# that is connections that can be opened above and beyond the
# pool_size setting
max_overflow=10,
# the number of connections to keep open inside the connection
pool_size=5,
# recycle connections after the given number of seconds has passed.
pool_recycle=3600,
# number of seconds to wait before giving up on getting a connection
# from the pool
pool_timeout=30,
)
See https://docs.sqlalchemy.org/en/latest/core/engines.html.
"""
# Redis (cache)
# ========
# Cache or Redis configurations
RATELIMIT_AUTHENTICATED_USER = "25000 per hour;1000 per minute"
"""Increase defaults for authenticated users."""
RATELIMIT_GUEST_USER = "5000 per hour;500 per minute"
"""Increase defaults for guest users."""
SESSION_COOKIE_SAMESITE = "Strict"
"""Sets cookie with the samesite flag to 'Strict' by default."""
# OAI-PMH
# =======
# See https://github.com/inveniosoftware/invenio-oaiserver/blob/master/invenio_oaiserver/config.py
OAISERVER_ID_PREFIX = "repository.tugraz.at"
"""The prefix that will be applied to the generated OAI-PMH ids."""
OAISERVER_ADMIN_EMAILS = [
"oai@repository.tugraz.at",
]
"""The e-mail addresses of administrators of the repository.
It **must** include one or more instances.
"""

View File

@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Custom fields."""
from invenio_records_resources.services.custom_fields import BooleanCF
ip_network = BooleanCF(name="ip_network")
single_ip = BooleanCF(name="single_ip")

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds I-Form configs."""
from flask import Flask
from . import config
from .custom_fields import ip_network, single_ip
class InvenioConfigIform:
"""invenio-config-iform extension."""
def __init__(self, app: Flask = None) -> None:
"""Extension initialization."""
if app:
self.init_app(app)
def init_app(self, app: Flask) -> None:
"""Flask application initialization."""
self.init_config(app)
self.add_custom_fields(app)
app.extensions["invenio-config-iform"] = self
def init_config(self, app: Flask) -> None:
"""Initialize configuration."""
for k in dir(config):
if k.startswith("INVENIO_CONFIG_IFORM_"):
app.config.setdefault(k, getattr(config, k))
def add_custom_fields(self, app: Flask) -> None:
"""Add custom fields."""
app.config.setdefault("RDM_CUSTOM_FIELDS", [])
app.config["RDM_CUSTOM_FIELDS"].append(ip_network)
app.config["RDM_CUSTOM_FIELDS"].append(single_ip)
def finalize_app(app: Flask) -> None:
"""Finalize app."""
rank_blueprint_higher(app)
def rank_blueprint_higher(app: Flask) -> None:
"""Rank this module's blueprint higher than blueprint of security module.
Needed in order to overwrite email templates.
Since the blueprints are in a dict and the order of insertion is
retained, popping and reinserting all items (except ours), ensures
our blueprint will be in front.
"""
bps = app.blueprints
for blueprint_name in list(bps.keys()):
if blueprint_name != "invenio_config_iform":
bps.update({blueprint_name: bps.pop(blueprint_name)})

View File

@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Permission-policies and roles, based on `flask-principal`."""
from .policies import IformRDMRecordPermissionPolicy
__all__ = ("IformRDMRecordPermissionPolicy",)

View File

@@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
r"""Permission generators for permission policies.
invenio's permissions build on
`flask-principal <https://pythonhosted.org/Flask-Principal>`_ .
In `flask-principal`, an action's `Need`s are checked
against current user's `Need`s to determine permissions.
For example, the action of deleting a record is only
permitted to users with `Need(method='role', value='admin')`.
Not all `Need`s can be known before the app is running.
For example, permissions for reading a record depend on whether
the record is public/private, so the set of `Need`s necessary
for reading a record must be computed dynamically at runtime.
This is the use case for
invenio's :py:class:`~invenio_records_permissions.generators.Generator`:
it generates `Need`s necessary for an action at runtime.
A `Generator` object defines 3 methods in addition to its constructor:
- ``needs(self, **kwargs)``: returns `Need`s, one of which a provider is
required to have to be allowed
- ``excludes(self, **kwargs)``: returns a list of `Need`s disallowing any
provider of a single one
- ``query_filter(self, **kwargs)``: returns a query filter to enable retrieval
of records
The ``needs`` and ``excludes`` methods specify access conditions from
the point-of-view of the object-of-concern; whereas, the ``query_filter``
method specifies those from the actor's point-of-view in search scenarios.
.. Note::
Exclusion has priority over inclusion. If a `Need` is returned by both
``needs`` and ``excludes``, providers of that `Need` will be **excluded**.
"""
from ipaddress import ip_address, ip_network
from typing import Any
from flask import current_app, request
from flask_principal import Need
from invenio_access.permissions import any_user
from invenio_records_permissions.generators import Generator
from invenio_search.engine import dsl
from .roles import iform_authenticated_user
class RecordSingleIP(Generator):
"""Allowed any user with accessing with the IP."""
def needs(self, record: dict | None = None, **__: dict) -> list[Need]:
"""Set of Needs granting permission. Enabling Needs."""
if record is None:
return []
# if record has singleip, and the ip of the user matches the allowed ip
if record.get("custom_fields", {}).get("single_ip", False) and self.check_permission():
return [any_user]
# non of the above - return empty
return []
def excludes(self, **kwargs: dict) -> list[Need]:
"""Set of Needs denying permission. Preventing Needs.
If ANY of the Needs are matched, permission is revoked.
.. note::
``_load_permissions()`` method from `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ adds by default the
``superuser_access`` Need (if tied to a User or Role) for us.
It also expands ActionNeeds into the Users/Roles that
provide them.
If the same Need is returned by `needs` and `excludes`, then that
Need provider is disallowed.
"""
try:
if kwargs["record"]["custom_fields"]["single_ip"] and not self.check_permission():
return [any_user]
except KeyError:
return []
else:
return []
def query_filter(self, *_: dict, **__: dict) -> Any: # noqa: ANN401
"""Filter for singleip records."""
if not self.check_permission():
# If user ip is not on the list, and If the record contains 'singleip' will not be seen
return ~dsl.Q("match", **{"custom_fields.single_ip": True})
# Lists all records
return dsl.Q("match_all")
def check_permission(self) -> bool:
"""Check for User IP address in config variable.
If the user ip is in the configured list return True.
"""
try:
user_ip = request.remote_addr
except RuntimeError:
return False
single_ips = current_app.config["CONFIG_IFORM_SINGLE_IPS"]
return user_ip in single_ips
class AllowedFromIPNetwork(Generator):
"""Allowed from ip range."""
def needs(self, record: dict | None = None, **__: dict) -> list[Need]:
"""Set of Needs granting permission. Enabling Needs."""
if record is None:
return []
# if the record has set the ip_range allowance and is in the range
if record.get("custom_fields", {}).get("ip_network", False) and self.check_permission():
return [any_user]
# non of the above - return empty
return []
def excludes(self, **kwargs: dict) -> Need:
"""Set of Needs denying permission. Preventing Needs.
If ANY of the Needs are matched, permission is revoked.
.. note::
``_load_permissions()`` method from `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ adds by default the
``superuser_access`` Need (if tied to a User or Role) for us.
It also expands ActionNeeds into the Users/Roles that
provide them.
If the same Need is returned by `needs` and `excludes`, then that
Need provider is disallowed.
"""
try:
if kwargs["record"]["custom_fields"]["ip_network"] and not self.check_permission():
return [any_user]
except KeyError:
return []
else:
return []
def query_filter(self, *_: dict, **__: dict) -> Any: # noqa: ANN401
"""Filter for ip range records."""
if not self.check_permission():
return ~dsl.Q("match", **{"custom_fields.ip_network": True})
return dsl.Q("match_all")
def check_permission(self) -> bool:
"""Check for User IP address in the configured network."""
try:
user_ip = request.remote_addr
except RuntimeError:
return False
network = current_app.config["CONFIG_IFORM_IP_NETWORK"]
try:
return ip_address(user_ip) in ip_network(network)
except ValueError:
return False
class IformAuthenticatedUser(Generator):
"""Generates the `iform_authenticated_user` role-need."""
def needs(self, **__: dict) -> list[Need]:
"""Generate needs to be checked against current user identity."""
return [iform_authenticated_user]

View File

@@ -0,0 +1,276 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
# Copyright (C) 2025 I-Form Advanced Manufacturing Research Centre.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""I-Form permission-policy for RDMRecordService.
To use, set config-variable `RDM_PERMISSION_POLICY` to `IformRDMRecordPermissionPolicy`.
Policies list **what actions** can be done **by whom**
over an implied category of objects (typically records). A Policy is
instantiated on a per action basis and is a descendant of `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ in
`invenio-access <https://invenio-access.readthedocs.io>`_ .
Generators are used to provide the "by whom" part and the implied category of
object.
Actions are class variables of the form: ``can_<action>`` and the
corresponding (dis-)allowed identities are a list of Generator instances.
One can define any action as long as it follows that pattern and
is verified at the moment it is undertaken.
"""
from invenio_administration.generators import Administration
from invenio_communities.generators import CommunityCurators
from invenio_rdm_records.services.generators import (
AccessGrant,
CommunityInclusionReviewers,
IfAtLeastOneCommunity,
IfDeleted,
IfExternalDOIRecord,
IfFileIsLocal,
IfNewRecord,
IfOneCommunity,
IfRecordDeleted,
IfRestricted,
RecordCommunitiesAction,
RecordOwners,
ResourceAccessToken,
SecretLinks,
SubmissionReviewer,
)
from invenio_records_permissions.generators import AnyUser, Disable, IfConfig, SystemProcess
from invenio_records_permissions.policies.records import RecordPermissionPolicy
from invenio_users_resources.services.permissions import UserManager
from .generators import AllowedFromIPNetwork, IformAuthenticatedUser, RecordSingleIP
class IformRDMRecordPermissionPolicy(RecordPermissionPolicy):
"""Overwrite authenticatedness to mean `iform_authenticated` rather than *signed up*."""
NEED_LABEL_TO_ACTION = {
"bucket-update": "update_files",
"bucket-read": "read_files",
"object-read": "read_files",
}
#
# General permission-groups, to be used below
#
can_manage = [
RecordOwners(),
RecordCommunitiesAction("curate"),
AccessGrant("manage"),
SystemProcess(),
]
can_manage_internal = [SystemProcess()]
can_curate = can_manage + [AccessGrant("edit"), SecretLinks("edit")]
can_review = can_curate + [SubmissionReviewer()]
can_preview = can_curate + [
AccessGrant("preview"),
SecretLinks("preview"),
SubmissionReviewer(),
UserManager,
]
can_view = can_preview + [
AccessGrant("view"),
SecretLinks("view"),
SubmissionReviewer(),
CommunityInclusionReviewers(),
RecordCommunitiesAction("view"),
AllowedFromIPNetwork(),
RecordSingleIP(),
]
can_iform_authenticated = [IformAuthenticatedUser(), SystemProcess()]
can_authenticated = can_iform_authenticated
can_all = [
AnyUser(),
SystemProcess(),
AllowedFromIPNetwork(),
RecordSingleIP(),
]
#
# Miscellaneous
#
# Allow for querying of statistics
# - This is currently disabled because it's not needed and could potentially
# open up surface for denial of service attacks
can_query_stats = [Disable()]
#
# Records - reading and creating
#
can_search = can_all
can_search_revisions = [Administration()]
can_read = [IfRestricted("record", then_=can_view, else_=can_all)]
can_read_deleted = [
IfRecordDeleted(then_=[UserManager, SystemProcess()], else_=can_read),
]
can_read_deleted_files = can_read_deleted
can_media_read_deleted_files = can_read_deleted_files
can_read_files = [
IfRestricted("files", then_=can_view, else_=can_all),
ResourceAccessToken("read"),
]
can_get_content_files = [
IfFileIsLocal(then_=can_read_files, else_=[SystemProcess()]),
]
can_create = can_iform_authenticated
#
# Drafts
#
can_search_drafts = can_iform_authenticated
can_read_draft = can_preview
can_draft_read_files = can_preview + [ResourceAccessToken("read")]
can_update_draft = can_review
can_draft_create_files = can_review
can_draft_set_content_files = [
IfFileIsLocal(then_=can_review, else_=[SystemProcess()]),
]
can_draft_get_content_files = [
IfFileIsLocal(then_=can_draft_read_files, else_=[SystemProcess()]),
]
can_draft_commit_files = [IfFileIsLocal(then_=can_review, else_=[SystemProcess()])]
can_draft_update_files = can_review
can_draft_delete_files = can_review
can_manage_files = [
IfConfig(
"RDM_ALLOW_METADATA_ONLY_RECORDS",
then_=[IfNewRecord(then_=can_iform_authenticated, else_=can_review)],
else_=[],
),
]
can_manage_record_access = [
IfConfig(
"RDM_ALLOW_RESTRICTED_RECORDS",
then_=[IfNewRecord(then_=can_iform_authenticated, else_=can_review)],
else_=[],
),
]
#
# PIDs
#
can_pid_create = can_review
can_pid_register = can_review
can_pid_update = can_review
can_pid_discard = can_review
can_pid_delete = can_review
can_pid_manage = [SystemProcess()]
#
# Actions
#
can_edit = [IfDeleted(then_=[Disable()], else_=can_curate)]
can_delete_draft = can_curate
can_new_version = [
IfConfig(
"RDM_ALLOW_EXTERNAL_DOI_VERSIONING",
then_=can_curate,
else_=[IfExternalDOIRecord(then_=[Disable()], else_=can_curate)],
),
]
can_publish = [
IfConfig(
"RDM_COMMUNITY_REQUIRED_TO_PUBLISH",
then_=[
IfAtLeastOneCommunity(
then_=can_review,
else_=[Administration(), SystemProcess()],
),
],
else_=can_review,
),
]
can_lift_embargo = can_manage
#
# Record communities
#
can_add_community = can_manage
can_remove_community_ = [RecordOwners(), CommunityCurators(), SystemProcess()]
can_remove_community = [
IfConfig(
"RDM_COMMUNITY_REQUIRED_TO_PUBLISH",
then_=[
IfOneCommunity(
then_=[Administration(), SystemProcess()],
else_=can_remove_community_,
),
],
else_=can_remove_community_,
),
]
can_remove_record = [CommunityCurators(), Administration(), SystemProcess()]
can_bulk_add = [SystemProcess()]
#
# Media files - draft
#
can_draft_media_create_files = can_review
can_draft_media_read_files = can_review
can_draft_media_set_content_files = [
IfFileIsLocal(then_=can_review, else_=[SystemProcess()]),
]
can_draft_media_get_content_files = [
IfFileIsLocal(then_=can_preview, else_=[SystemProcess()]),
]
can_draft_media_commit_files = [
IfFileIsLocal(then_=can_preview, else_=[SystemProcess()]),
]
can_draft_media_delete_files = can_review
can_draft_media_update_files = can_review
#
# Media files - record
#
can_media_read_files = [
IfRestricted("record", then_=can_view, else_=can_all),
ResourceAccessToken("read"),
]
can_media_get_content_files = [
IfFileIsLocal(then_=can_read, else_=[SystemProcess()]),
]
can_media_create_files = [Disable()]
can_media_set_content_files = [Disable()]
can_media_commit_files = [Disable()]
can_media_update_files = [Disable()]
can_media_delete_files = [Disable()]
#
# Record deletetion
#
can_delete = [Administration(), SystemProcess()]
can_delete_files = [SystemProcess()]
can_purge = [SystemProcess()]
#
# Quotas for records/users
#
can_manage_quota = [UserManager, SystemProcess()]
#
# Disabled
#
# - Records/files are updated/deleted via drafts so we don't support
# using below actions.
can_update = [Disable()]
can_create_files = [Disable()]
can_set_content_files = [Disable()]
can_commit_files = [Disable()]
can_update_files = [Disable()]
# Used to hide at the moment the `parent.is_verified` field. It should be set to
# correct permissions based on which the field will be exposed only to moderators
can_moderate = [SystemProcess()]

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""`RoleNeed`s for permission policies.
To use these roles, add them to the database via:
`$ invenio roles create iform_authenticated --description "..."`
then add roles to users via:
`$ invenio roles add user@email.com iform_authenticated`
"""
from flask_principal import RoleNeed
# using `flask_principal.RoleNeed`` instead of `invenio_access.SystemRoleNeed`,
# because these roles are assigned by an admin rather than automatically by the system
iform_authenticated_user = RoleNeed("iform_authenticated")

View File

@@ -0,0 +1,2 @@
access_right,access_right_name,icon,notes
open, Open Access, lock open
1 access_right,access_right_name,icon,notes
2 open, Open Access, lock open

View File

@@ -0,0 +1,18 @@
{{ _('Dear user,') }}
{{ _('Welcome to the Repository of TU Graz!') }}
{{ _('To help you get started, here are some useful links:') }}
- {{ _('Guidelines:')}} {{ _('Repository Guide')}} ({{ _('how to upload files')}}) ({{ config.SITE_UI_URL }}{{ url_for('invenio_config_iform.guide') }})
- {{ _('Search Guide')}} ({{ config.SITE_UI_URL }}{{url_for('invenio_app_rdm.help_search')}})
- {{ _('Terms And Conditions') }} ({{ config.SITE_UI_URL }}{{ url_for('invenio_config_iform.terms') }})
- {{ _('Data Protection Rights')}} ({{ config.SITE_UI_URL }}{{ url_for('invenio_config_iform.gdpr') }})
{% if security.confirmable %}
{{ _('You can confirm your email through the link below:') }}
{{ confirmation_link }}">
{% endif %}
{{ _('If you require any assistance please do not hesitate to contact us at repository-support@tugraz.at.') }}
{{ _('Best regards,') }}
{{ _('TU Graz Repository Team') }}

View File

@@ -0,0 +1,82 @@
# German translations for invenio-config-iform.
# Copyright (C) 2021 Graz University of Technology
# This file is distributed under the same license as the
# invenio-config-iform project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
#
msgid ""
msgstr ""
"Project-Id-Version: invenio-config-iform 0.5.5\n"
"Report-Msgid-Bugs-To: mojib.wali@tugraz.at\n"
"POT-Creation-Date: 2021-04-27 15:30+0200\n"
"PO-Revision-Date: 2021-04-22 11:57+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.0\n"
#: invenio_config_iform/config.py:87
msgid "Welcome to TU Graz Repository!"
msgstr "Willkommen im TU Graz Repository!"
#: invenio_config_iform/templates/security/email/welcome.txt:1
msgid "Dear user,"
msgstr "Lieber Nutzer,"
#: invenio_config_iform/templates/security/email/welcome.txt:3
msgid "Welcome to the Repository of TU Graz!"
msgstr "Willkommen im TU Graz Repository!"
#: invenio_config_iform/templates/security/email/welcome.txt:5
msgid "To help you get started, here are some useful links:"
msgstr ""
"Um Ihnen den Einstieg zu erleichtern, finden Sie hier einige nützliche "
"Links:"
#: invenio_config_iform/templates/security/email/welcome.txt:7
msgid "Guidelines:"
msgstr "Leitfaden:"
#: invenio_config_iform/templates/security/email/welcome.txt:7
msgid "Repository Guide"
msgstr "Handbuch"
#: invenio_config_iform/templates/security/email/welcome.txt:7
msgid "how to upload files"
msgstr "wie man Dateien hochlädt"
#: invenio_config_iform/templates/security/email/welcome.txt:8
msgid "Search Guide"
msgstr "Suchanleitung"
#: invenio_config_iform/templates/security/email/welcome.txt:9
msgid "Terms And Conditions"
msgstr "Nutzungsbedingungen"
#: invenio_config_iform/templates/security/email/welcome.txt:10
msgid "Data Protection Rights"
msgstr "Datenschutzerklärung"
#: invenio_config_iform/templates/security/email/welcome.txt:13
msgid "You can confirm your email through the link below:"
msgstr "Sie können Ihre E-Mail über den folgenden Link bestätigen:"
#: invenio_config_iform/templates/security/email/welcome.txt:16
msgid ""
"If you require any assistance please do not hesitate to contact us at "
"repository-support@tugraz.at."
msgstr ""
"Wenn Sie Hilfe benötigen, zögern Sie bitte nicht, uns unter repository-"
"support@tugraz.at zu kontaktieren."
#: invenio_config_iform/templates/security/email/welcome.txt:18
msgid "Best regards,"
msgstr "Mit freundlichen Grüßen,"
#: invenio_config_iform/templates/security/email/welcome.txt:19
msgid "TU Graz Repository Team"
msgstr "TU Graz Repository Team"

View File

@@ -0,0 +1,77 @@
# Translations template for invenio-config-iform.
# Copyright (C) 2021 Graz University of Technology
# This file is distributed under the same license as the
# invenio-config-iform project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: invenio-config-iform 0.5.5\n"
"Report-Msgid-Bugs-To: mojib.wali@tugraz.at\n"
"POT-Creation-Date: 2021-04-27 15:30+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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.9.0\n"
#: invenio_config_iform/config.py:87
msgid "Welcome to TU Graz Repository!"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:1
msgid "Dear user,"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:3
msgid "Welcome to the Repository of TU Graz!"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:5
msgid "To help you get started, here are some useful links:"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:7
msgid "Guidelines:"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:7
msgid "Repository Guide"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:7
msgid "how to upload files"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:8
msgid "Search Guide"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:9
msgid "Terms And Conditions"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:10
msgid "Data Protection Rights"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:13
msgid "You can confirm your email through the link below:"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:16
msgid ""
"If you require any assistance please do not hesitate to contact us at "
"repository-support@tugraz.at."
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:18
msgid "Best regards,"
msgstr ""
#: invenio_config_iform/templates/security/email/welcome.txt:19
msgid "TU Graz Repository Team"
msgstr ""

View File

@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2022-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Utils file."""
import warnings
from flask_principal import Identity
from invenio_access import any_user
from invenio_access.utils import get_identity
from invenio_accounts import current_accounts
def get_identity_from_user_by_email(email: str | None = None) -> Identity:
"""Get the user specified via email or ID."""
warnings.warn("deprecated", DeprecationWarning, stacklevel=2)
if email is None:
msg = "the email has to be set to get a identity"
raise ValueError(msg)
user = current_accounts.datastore.get_user(email)
if user is None:
msg = f"user with {email} not found"
raise LookupError(msg)
identity = get_identity(user)
# TODO: this is a temporary solution. this should be done with data from the db
identity.provides.add(any_user)
return identity
def iform_account_setup_extension(user, account_info) -> None: # noqa: ANN001, ARG001
"""Add iform_authenticated role to user after SAML-login was acknowledged.
To use, have `acs_handler_factory` call invenio_saml's `default_account_setup` first,
then this function second.
.. code-block:: python
# invenio.cfg
from invenio_saml.handlers import default_account_setup, acs_handler_factory
def iform_account_setup(user, account_info):
# links external `account_info` with our database's `user` for future logins
default_account_setup(user, account_info)
iform_account_setup_extension(user, account_info)
SSO_SAML_IDPS = {
"my-iform-idp": {
...
"acs_handler": acs_handler_factory(
"my-iform-idp", account_setup=iform_account_setup
)
}
}
For this to work, the role iform_authenticated must have been created
(e.g. via `invenio roles create iform_authenticated`).
"""
user_email = account_info["user"]["email"]
# NOTE: `datastore.commit`ing will be done by acs_handler that calls this func
# NOTE: this is a No-Op when user_email already has role iform_authenticated
current_accounts.datastore.add_role_to_user(user_email, "iform_authenticated")

View File

@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Invenio module for I-Form config."""
from flask import Blueprint, Flask, redirect, url_for
from invenio_i18n import get_locale
from werkzeug.wrappers import Response as BaseResponse
def ui_blueprint(app: Flask) -> Blueprint:
"""Blueprint for the routes and resources provided by invenio-config-iform."""
routes = app.config.get("CONFIG_IFORM_ROUTES")
blueprint = Blueprint(
"invenio_config_iform",
__name__,
template_folder="templates",
static_folder="static",
)
blueprint.add_url_rule(routes["guide"], view_func=guide)
blueprint.add_url_rule(routes["terms"], view_func=terms)
blueprint.add_url_rule(routes["gdpr"], view_func=gdpr)
return blueprint
def guide() -> BaseResponse:
"""I-Form_Repository_Guide."""
locale = get_locale()
return redirect(
url_for(
"static",
filename=f"documents/I-Form_Repository_Guide_02.1_{locale}.pdf",
_external=True,
),
)
def terms() -> BaseResponse:
"""Terms_And_Conditions."""
locale = get_locale()
return redirect(
url_for(
"static",
filename=f"documents/I-Form_Repository_Terms_And_Conditions_{locale}.pdf",
_external=True,
),
)
def gdpr() -> BaseResponse:
"""General_Data_Protection_Rights."""
locale = get_locale()
return redirect(
url_for(
"static",
filename=f"documents/I-Form_Repository_General_Data_Protection_Rights_{locale}.pdf",
_external=True,
),
)

View File

@@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds tugraz configs."""
from .ext import InvenioConfigTugraz
from .generators import RecordIp
from .version import __version__
__all__ = ("__version__", "InvenioConfigTugraz", "RecordIp")

View File

@@ -1,88 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Graz University of Technology.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""
Records permission policies.
Default policies for records:
.. code-block:: python
# Read access given to everyone.
can_search = [AnyUser()]
# Create action given to no one (Not even superusers) bc Deposits should
# be used.
can_create = [Disable()]
# Read access given to everyone if public record/files and owners always.
can_read = [AnyUserIfPublic(), RecordOwners()]
# Update access given to record owners.
can_update = [RecordOwners()]
# Delete access given to admins only.
can_delete = [Admin()]
# Associated files permissions (which are really bucket permissions)
can_read_files = [AnyUserIfPublic(), RecordOwners()]
can_update_files = [RecordOwners()]
How to override default policies for records.
Using Custom Generator for a policy:
.. code-block:: python
from invenio_rdm_records.permissions import RDMRecordPermissionPolicy
from invenio_config_tugraz.generators import RecordIp
class TUGRAZPermissionPolicy(RDMRecordPermissionPolicy):
# Delete access given to RecordIp only.
can_delete = [RecordIp()]
RECORDS_PERMISSIONS_RECORD_POLICY = TUGRAZPermissionPolicy
Permissions for Invenio records.
"""
from invenio_records_permissions.generators import (
Admin,
AnyUser,
AnyUserIfPublic,
RecordOwners,
)
from invenio_records_permissions.policies.base import BasePermissionPolicy
from .generators import RecordIp
class TUGRAZPermissionPolicy(BasePermissionPolicy):
"""Access control configuration for records.
This overrides the /api/records endpoint.
"""
# Read access to API given to everyone.
can_search = [AnyUser(), RecordIp()]
# Read access given to everyone if public record/files and owners always.
can_read = [AnyUserIfPublic(), RecordOwners(), RecordIp()]
# Create action given to no one (Not even superusers) bc Deposits should
# be used.
can_create = [AnyUser()]
# Update access given to record owners.
can_update = [RecordOwners()]
# Delete access given to admins only.
can_delete = [Admin()]
# Associated files permissions (which are really bucket permissions)
can_read_files = [AnyUserIfPublic(), RecordOwners()]
can_update_files = [RecordOwners()]

View File

@@ -1,223 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Graz University of Technology.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds tugraz configs."""
from os.path import abspath, dirname, join
from flask_babelex import gettext as _
INVENIO_CONFIG_TUGRAZ_SHIBBOLETH = True
"""Set True if SAML is configured"""
INVENIO_CONFIG_TUGRAZ_SINGLE_IP = []
"""Allows access to users whose IP address is listed.
INVENIO_CONFIG_TUGRAZ_SINGLE_IP =
["127.0.0.1", "127.0.0.2"]
"""
INVENIO_CONFIG_TUGRAZ_IP_RANGES = []
"""Allows access to users whose range of IP address is listed.
INVENIO_CONFIG_TUGRAZ_IP_RANGES =
[["127.0.0.2", "127.0.0.99"], ["127.0.1.3", "127.0.1.5"]]
"""
# Invenio-App
# ===========
# See https://invenio-app.readthedocs.io/en/latest/configuration.html
APP_ALLOWED_HOSTS = [
"0.0.0.0",
"localhost",
"127.0.0.1",
"invenio-dev01.tugraz.at",
"invenio-test.tugraz.at",
"repository.tugraz.at"
]
"""Allowed Hosts"""
APP_DEFAULT_SECURE_HEADERS = {
"content_security_policy": {
"default-src": [
"'self'",
"fonts.googleapis.com",
"*.gstatic.com",
"data:",
"'unsafe-inline'",
"'unsafe-eval'",
"blob:",
],
},
"content_security_policy_report_only": False,
"content_security_policy_report_uri": None,
"force_file_save": False,
"force_https": True,
"force_https_permanent": False,
"frame_options": "sameorigin",
"frame_options_allow_from": None,
"session_cookie_http_only": True,
"session_cookie_secure": True,
"strict_transport_security": True,
"strict_transport_security_include_subdomains": True,
"strict_transport_security_max_age": 31556926, # One year in seconds
"strict_transport_security_preload": False,
}
# Invenio-Mail
# ===========
# See https://invenio-mail.readthedocs.io/en/latest/configuration.html
MAIL_SERVER = "localhost"
"""Domain ip where mail server is running."""
SECURITY_EMAIL_SENDER = "info@invenio-test.tugraz.at"
"""Email address used as sender of account registration emails."""
"""Domain name should match the domain used in web server."""
SECURITY_EMAIL_SUBJECT_REGISTER = _("Welcome to RDM!")
"""Email subject for account registration emails."""
MAIL_SUPPRESS_SEND = True
"""Enable email sending by default.
Set this to False when sending actual emails.
"""
# CORS - Cross-origin resource sharing
# ===========
# Uncomment to enable the CORS
# CORS_RESOURCES = '*'
# CORS_SEND_WILDCARD = True
# CORS_EXPOSE_HEADERS = [
# 'ETag',
# 'Link',
# 'X-RateLimit-Limit',
# 'X-RateLimit-Remaining',
# 'X-RateLimit-Reset',
# 'Content-Type',
# ]
# REST_ENABLE_CORS = True
# Invenio-userprofiles
# ===========
# See https://invenio-userprofiles.readthedocs.io/en/latest/configuration.html
USERPROFILES_EXTEND_SECURITY_FORMS = False
"""Set True in order to register user_profile.
This also forces user to add username and fullname
when register.
"""
USERPROFILES_EMAIL_ENABLED = False
"""Exclude the user email in the profile form."""
# Invenio-shibboleth
# ===========
# See https://invenio-shibboleth.readthedocs.io/en/latest/configuration.html
SSO_SAML_IDPS = {}
"""Configuration of IDPS. Actual values can be find in to invenio.cfg file"""
SSO_SAML_DEFAULT_BLUEPRINT_PREFIX = "/shibboleth"
"""Base URL for the extensions endpoint."""
SSO_SAML_DEFAULT_METADATA_ROUTE = "/metadata/<idp>"
"""URL route for the metadata request."""
"""This is also SP entityID https://domain/shibboleth/metadata/<idp>"""
SSO_SAML_DEFAULT_SSO_ROUTE = "/login/<idp>"
"""URL route for the SP login."""
SSO_SAML_DEFAULT_ACS_ROUTE = "/authorized/<idp>"
"""URL route to handle the IdP login request."""
SSO_SAML_DEFAULT_SLO_ROUTE = "/slo/<idp>"
"""URL route for the SP logout."""
SSO_SAML_DEFAULT_SLS_ROUTE = "/sls/<idp>"
"""URL route to handle the IdP logout request."""
# Invenio-accounts
# ===========
# See https://invenio-accounts.readthedocs.io/en/latest/configuration.html
SECURITY_CHANGEABLE = False
"""Allow password change by users."""
SECURITY_RECOVERABLE = False
"""Allow password recovery by users."""
SECURITY_REGISTERABLE = True
""""Allow users to register.
With this variable set to "False" users will not be
able to register, or to navigate to /sigup page.
"""
SECURITY_CONFIRMABLE = False
"""Allow user to confirm their email address.
Instead user will get a welcome email.
"""
ACCOUNTS = True
"""Tells if the templates should use the accounts module.
If False, you won't be able to login via the web UI.
Instead if you have a overriden template somewhere in your config.py:
like this:
SECURITY_LOGIN_USER_TEMPLATE = 'invenio_theme_tugraz/accounts/login.html'
then you can remove this condition from header_login.htm:
{%- if config.ACCOUNTS %}
to render your overriden login.html
"""
# Accounts
# ========
# Actual values can be find in to invenio.cfg file
#: Recaptcha public key (change to enable).
RECAPTCHA_PUBLIC_KEY = None
#: Recaptcha private key (change to enable).
RECAPTCHA_PRIVATE_KEY = None
# invenio-records-permissions
# =======
# See:
# https://invenio-records-permissions.readthedocs.io/en/latest/configuration.html
#
# Uncomment these to enable overriding Base permissions - (NOT RECOMMANDED)
# RECORDS_PERMISSIONS_RECORD_POLICY = (
# 'invenio_config_tugraz.base_permissions.TUGRAZPermissionPolicy'
# )
#
# Uncomment these to enable overriding RDM permissions
# RDM_RECORDS_BIBLIOGRAPHIC_SERVICE_CONFIG = (
# 'invenio_config_tugraz.rdm_permissions.TUGRAZBibliographicRecordServiceConfig'
# )
"""Access control configuration for records."""
# invenio-rdm-records
# =======
# See:
# https://invenio-rdm-records.readthedocs.io/en/latest/configuration.html
#
# Custom Access Right
RDM_RECORDS_CUSTOM_VOCABULARIES = {
'access_right': {
'path': join(
dirname(abspath(__file__)),
'restrictions', 'access_right', 'access_right.csv'
)
}
}

View File

@@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds tugraz configs."""
from . import config
class InvenioConfigTugraz(object):
"""invenio-config-tugraz extension."""
def __init__(self, app=None):
"""Extension initialization."""
if app:
self.init_app(app)
def init_app(self, app):
"""Flask application initialization."""
self.init_config(app)
app.extensions["invenio-config-tugraz"] = self
def init_config(self, app):
"""Initialize configuration."""
for k in dir(config):
if k.startswith("INVENIO_CONFIG_TUGRAZ_"):
app.config.setdefault(k, getattr(config, k))

View File

@@ -1,240 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
r"""Permission generators and policies for Invenio records.
Invenio-records-permissions provides a means to fully customize access control
for Invenio records. It does so by defining and providing three layers of
permission constructs that build on each other:
Generators and Policies. You can extend or override them for maximum
control. Thankfully we provide default ones that cover most cases.
Invenio-records-permissions conveniently structures (and relies on)
functionalities from
`invenio-access <https://invenio-access.readthedocs.io>`_ and
`flask-principal <https://pythonhosted.org/Flask-Principal>`_ .
Generators
----------
Generators are the lowest level of abstraction provided by
invenio-records-permissions. A
:py:class:`~invenio_records_permissions.generators.Generator` represents
identities via
`Needs <https://invenio-access.readthedocs.io/en/latest/api.html#needs>`_ that
are allowed or disallowed to act on a kind of object. A Generator does not
specify the action, but it does specify who is allowed and the kind of object
of concern (typically records). Generators *generate* required and forbidden
Needs at the object-of-concern level and *generate* query filters
at the search-for-objects-of-concern level.
A Generator object defines 3 methods in addition to its constructor:
- ``needs(self, **kwargs)``: returns Needs, one of which a provider is
required to have to be allowed
- ``excludes(self, **kwargs)``: returns a list of Needs disallowing any
provider of a single one
- ``query_filter(self, **kwargs)``: returns a query filter to enable retrieval
of records
The ``needs`` and ``excludes`` methods specify access conditions from
the point-of-view of the object-of-concern; whereas, the ``query_filter``
method specifies those from the actor's point-of-view in search scenarios.
A simple example of a Generator is the provided
:py:class:`~invenio_records_permissions.generators.RecordOwners` Generator:
.. code-block:: python
from flask_principal import UserNeed
class RecordOwners(Generator):
'''Allows record owners.'''
def needs(self, record=None, **kwargs):
'''Enabling Needs.'''
return [UserNeed(owner) for owner in record.get('owners', [])]
def query_filter(self, record=None, **kwargs):
'''Filters for current identity as owner.'''
# NOTE: implementation subject to change until permissions metadata
# settled
provides = g.identity.provides
for need in provides:
if need.method == 'id':
return Q('term', owners=need.value)
return []
``RecordOwners`` allows any identity providing a `UserNeed
<https://pythonhosted.org/Flask-Principal/#flask_principal.UserNeed>`_
of value found in the ``owners`` metadata of a record. The
``query_filter(self, **kwargs)``
method outputs a query that returns all owned records of the current user.
Not included in the above, because it doesn't apply to ``RecordOwners``, is
the ``excludes(self, **kwargs)`` method.
.. Note::
Exclusion has priority over inclusion. If a Need is returned by both
``needs`` and ``excludes``, providers of that Need will be **excluded**.
If implementation of Generators seems daunting, fear not! A collection of
them has already been implemented in
:py:mod:`~invenio_records_permissions.generators`
and they cover most cases you may have.
To fully understand how they work, we have to show where Generators are used.
That is in the Policies.
Policies
--------
Classes inheriting from
:py:class:`~invenio_records_permissions.policies.base.BasePermissionPolicy` are
referred to as Policies. They list **what actions** can be done **by whom**
over an implied category of objects (typically records). A Policy is
instantiated on a per action basis and is a descendant of `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ in
`invenio-access <https://invenio-access.readthedocs.io>`_ .
Generators are used to provide the "by whom" part and the implied category of
object.
Here is an example of a custom record Policy:
.. code-block:: python
from invenio_records_permissions.generators import AnyUser, RecordOwners, \
SuperUser
from invenio_records_permissions.policies.base import BasePermissionPolicy
class ExampleRecordPermissionPolicy(BasePermissionPolicy):
can_create = [AnyUser()]
can_search = [AnyUser()]
can_read = [AnyUser()]
can_update = [RecordOwners()]
can_foo_bar = [SuperUser()]
The actions are class variables of the form: ``can_<action>`` and the
corresponding (dis-)allowed identities are a list of Generator instances.
One can define any action as long as it follows that pattern and
is verified at the moment it is undertaken.
In the example above, any user can create, list and read records, but only
a record's owner can edit it and only super users can perform the "foo_bar"
action.
We recommend you extend the provided
:py:class:`invenio_records_permissions.policies.records.RecordPermissionPolicy`
to customize record permissions for your instance.
This way you benefit from sane defaults.
After you have defined your own Policy, set it in your configuration:
.. code-block:: python
RECORDS_PERMISSIONS_RECORD_POLICY = (
'module.to.ExampleRecordPermissionPolicy'
)
The succinct encoding of the permissions for your instance gives you
- one central location where your permissions are defined
- exact control
- great flexibility by defining your own actions, generators and policies
"""
from elasticsearch_dsl.query import Q
from flask import current_app, request
from invenio_access.permissions import any_user, authenticated_user, superuser_access
from invenio_records_permissions.generators import Generator
class RecordIp(Generator):
"""Allowed any user with accessing with the IP."""
def needs(self, record=None, **kwargs):
"""Enabling Needs, Set of Needs granting permission."""
if record is None:
return []
# check if singleip is in the records restriction
is_single_ip = record.get("access", {}).get("access_right") == "singleip"
# check if the user ip is on list
visible = self.check_permission()
if not is_single_ip:
# if record does not have singleip - return any_user
return [any_user]
# if record has singleip, then check the ip of user - if ip user is on list - return any_user
elif visible:
return [any_user]
else:
# non of the above - return empty
return []
def excludes(self, **kwargs):
"""Preventing Needs, Set of Needs denying permission.
If ANY of the Needs are matched, permission is revoked.
.. note::
``_load_permissions()`` method from `Permission
<https://invenio-access.readthedocs.io/en/latest/api.html
#invenio_access.permissions.Permission>`_ adds by default the
``superuser_access`` Need (if tied to a User or Role) for us.
It also expands ActionNeeds into the Users/Roles that
provide them.
If the same Need is returned by `needs` and `excludes`, then that
Need provider is disallowed.
"""
return []
def query_filter(self, *args, **kwargs):
"""Filters for singleip records."""
# check if the user ip is on list
visible = self.check_permission()
if not visible:
# If user ip is not on the list, and If the record contains 'singleip' will not be seen
return ~Q("match", **{"access.access_right": "singleip"})
# Lists all records
return Q("match_all")
def check_permission(self):
"""Check for User IP address in config variable."""
# Get user IP
user_ip = request.remote_addr
# Checks if the user IP is among single IPs
if user_ip in current_app.config["INVENIO_CONFIG_TUGRAZ_SINGLE_IP"]:
return True
return False
class AuthenticatedUser(Generator):
"""Allows authenticated users."""
def __init__(self):
"""Constructor."""
super(AuthenticatedUser, self).__init__()
def needs(self, **kwargs):
"""Enabling Needs."""
return [authenticated_user]
def query_filter(self, **kwargs):
"""Filters for current identity as super user."""
# TODO: Implement with new permissions metadata
return []

View File

@@ -1,111 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Graz University of Technology.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""
Records permission policies.
Default policies for records:
.. code-block:: python
# Read access given to everyone.
can_search = [AnyUser()]
# Create action given to no one (Not even superusers) bc Deposits should
# be used.
can_create = [Disable()]
# Read access given to everyone if public record/files and owners always.
can_read = [AnyUserIfPublic(), RecordOwners()]
# Update access given to record owners.
can_update = [RecordOwners()]
# Delete access given to admins only.
can_delete = [Admin()]
# Associated files permissions (which are really bucket permissions)
can_read_files = [AnyUserIfPublic(), RecordOwners()]
can_update_files = [RecordOwners()]
How to override default policies for rdm-records.
Using Custom Generator for a policy:
.. code-block:: python
from invenio_rdm_records.services import (
BibliographicRecordServiceConfig,
RDMRecordPermissionPolicy,
)
from invenio_config_tugraz.generators import RecordIp
class TUGRAZPermissionPolicy(RDMRecordPermissionPolicy):
# Create access given to SuperUser only.
can_create = [SuperUser()]
RDM_RECORDS_BIBLIOGRAPHIC_SERVICE_CONFIG = TUGRAZBibliographicRecordServiceConfig
Permissions for Invenio (RDM) Records.
"""
from invenio_rdm_records.services import (
BibliographicRecordServiceConfig,
RDMRecordPermissionPolicy,
)
from invenio_records_permissions.generators import (
Admin,
AnyUser,
RecordOwners,
SuperUser,
)
from .generators import AuthenticatedUser, RecordIp
class TUGRAZPermissionPolicy(RDMRecordPermissionPolicy):
"""Access control configuration for rdm records.
This overrides the origin:
https://github.com/inveniosoftware/invenio-rdm-records/blob/master/invenio_rdm_records/services/permissions.py.
"""
# Read access given to:
# TODO:
# AnyUserIfPublic : grant access if record is public
# RecordIp: grant access for single_ip
# RecordOwners: owner of records, enable once the deposit is allowed only for loged-in users.
# CURRENT:
# RecordIp: grant access for single_ip
can_read = [RecordIp()] # RecordOwners()
# Search access given to:
# AnyUser : grant access anyUser
# RecordIp: grant access for single_ip
can_search = [AnyUser(), RecordIp()]
# Update access given to record owners.
can_update = [RecordOwners()]
# Delete access given to admins only.
can_delete = [Admin()]
# Create action given to AuthenticatedUser
# UI - if user is loged in
# API - if user has Access token (Bearer API-TOKEN)
can_create = [AuthenticatedUser()]
# Associated files permissions (which are really bucket permissions)
# can_read_files = [AnyUserIfPublic(), RecordOwners()]
# can_update_files = [RecordOwners()]
class TUGRAZBibliographicRecordServiceConfig(BibliographicRecordServiceConfig):
"""Overriding BibliographicRecordServiceConfig."""
permission_policy_cls = TUGRAZPermissionPolicy

View File

@@ -1 +0,0 @@
MIICjjCCAfegAwIBAgIBADANBgkqhkiG9w0BAQ0FADBkMQswCQYDVQQGEwJhdDENMAsGA1UECAwER3JhejEPMA0GA1UECgwGVFVHUkFaMRAwDgYDVQQDDAdpbnZlbmlvMSMwIQYJKoZIhvcNAQkBFhRtb2ppYi53YWxpQHR1Z3Jhei5hdDAeFw0yMDAxMTAyMDIwMTlaFw0yMTAxMDkyMDIwMTlaMGQxCzAJBgNVBAYTAmF0MQ0wCwYDVQQIDARHcmF6MQ8wDQYDVQQKDAZUVUdSQVoxEDAOBgNVBAMMB2ludmVuaW8xIzAhBgkqhkiG9w0BCQEWFG1vamliLndhbGlAdHVncmF6LmF0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5ZrPhRhyDyLTe93rpgqN9MMfnCsg+2QBW4EOuQnMXJzF1dqrFEsexot1FRW83IjqbY+680PmGABQtxUpS4Kinr/pLYbPhQ2WPQRad7mtOn/dD40VVwfG0GfcLrnKe5F4QLfNjervjl8jH/AKPCYwwfSeuw1LNoRjy1uDwkp9cRQIDAQABo1AwTjAdBgNVHQ4EFgQUPv2+wS1RuagCOed7w1FzouBmpP4wHwYDVR0jBBgwFoAUPv2+wS1RuagCOed7w1FzouBmpP4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOBgQA4qvU7gbgE/MoljUW68qMPs8z8Q2Ngttp6F1KOMNO9rgrYWAJh4u6BMt11mlBgBlLLJzG67wXpBr0l78IcOXun4w955te0VRp7aZ0b1uOPt0aUoDOXuBAhZURLZfbsogpWiE6bdB8N0nHTwk2WG2PPIC5Z99UdDivcP5ZeSPAkUw==

View File

@@ -1 +0,0 @@
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIHxNp8P2PsV8CAggAMBQGCCqGSIb3DQMHBAjOyik6fsEC3gSCAoC4tFsYAl4GexyXESiRKpOQzHQNFtQtwDEevT1IKgsafSNjOMJZLKrnoejNoxEQUPPPXgGEd83Fmp2cSHm+YVksH06zcsA+RKf5ab6t0bsgcyljGzkHEDQtMRPcaXNlVMbU9VEDOX26MgmlU/pd+GGfE99IbEFc6qN1e7qOnmKSw93Q3o05ubO3wEI76JhOioGGXB3pEn8f4XLDwck0thzYD6H2vdF+kyIdM8w1BgyLdeP0aDkfG1V3rLGhE8246rwVUzRSZv6BCNBZFk7YO1d7j0+BDxnbHFS631zdCgMcd/XS8u6acc3IYr/bQLH4a1y0X3Z+8ks8arEgUtXqYx9wMlp5lajlsr9JDIU5OnuZ2XY+4sqDQsTZPjBpxK8oMjvJNNatnTf+18htkTdovpInlP7xpEjp1L7H74iKY25UsAZ9e+gqHZwILnk418mQ1E4JYU6JRUZspJSFfqwn9FL6DnvhzPIhtzwhr3eL4f4RXWxxe2xCzvWg+GaWuMfZdj77SV4pMOi7vb3HlYY6luShVlYKdSaw+jf6XVy4ZMTWT5wcE1mc3tAJqF18Mi8amOetpZhz16ISOKnO0rKrfmxteNPQn2AB8QquGGn050PTW4m8zFXDBiyg2xvcRLAW/8ych3k+pkEZi4tVCkLcHM56J/XUEKMCxiSok+vbzxfVf1D2vYFFS7Lw1nP5RnLKFdn8XdHQ+lu2diod18wYBQP4eoU+XjjP2zjlpULiWHt7PpCERqGg7H2Z2amIL5rTeqQuyXczw1/xG/VBNn9qe3DXFodvoV6OZb3efNT/eJgOyaPLi2FmB7Kpdp4JIdJgLnaBCwNBXkpGSwb732O/cug8

View File

@@ -1,22 +0,0 @@
{
"strict": true,
"debug": true,
"idp": {
"entityId": "https://sso.tugraz.at/idp/shibboleth",
"singleLogoutService": {
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
"url": "https://sso.tugraz.at/slo/Logout"
},
"singleSignOnService": {
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
"url": "https://sso.tugraz.at/idp/profile/SAML2/Redirect/SSO"
},
"x509cert": "MIIDHzCCAgegAwIBAgIUG6ra0BvXswfyErcCDmzw3AV+uI0wDQYJKoZIhvcNAQEFBQAwGDEWMBQGA1UEAxMNc3NvLnR1Z3Jhei5hdDAeFw0xMDAzMjkxNzEzMTZaFw0zMDAzMjkxODEzMTZaMBgxFjAUBgNVBAMTDXNzby50dWdyYXouYXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCEyQxHIM1zxbBnXn60Ksg7B7HcPLPcN7bXLrLPOFXtkZxm0YkHY5Rxignm7wHD7C81U09DFS2eT8qRCcVtVz+kuwdgS54fC/alg9oLxXk4CgKjhtZZ2ECLdTHfUXOA5uOLlpoN1LY6VpIjSYe3UEX3HxfhXx/fPeE8VInGCKnml8Too22G30htB/EU44A2yqrR3LUngJIaq //N0QbeMYitNh02o6xB5+bp6k6noM7DH6S9phe0kCEibaiLaCf7k9LpNnAz9bPtQVth0gdJqoUry/iK1QBTFTEXvvJynFEp0+5Wz/XFmEcFhsaK8OcHd0R9FfpX5Z2fewA2Q0SLKz+bAgMBAAGjYTBfMD4GA1UdEQQ3MDWCDXNzby50dWdyYXouYXSGJGh0dHBzOi8vc3NvLnR1Z3Jhei5hdC9pZHAvc2hpYmJvbGV0aDAdBgNVHQ4EFgQUXd76PcSiXR6wFna5qQi+S0W/9Y0wDQYJKoZIhvcNAQEFBQADggEBACgkQqxBtYY1OcuoAUP/P+ukJW7XyofK89qs2dkGClx7s0hR/1zImWgljgfguLJOSfC/CWE1wfNK9bTi4Fu9809PmOoaCxkNmniFRAyaOiBoUz5XIpJniW7wBo+YBpBlXZXi5PmU2DOsfZxo7fs4se32dHO1WqgJodqkK2Wa4HDiigh42trZ9i3uS73uHSSCeIJYQNj84BMJ+ifgj3Zi/TgLS+IX7Ayy2bkDzIzIRnj7ULQ/MgfacGXQXJPHyp+w+YvydQalPAWc43+5DkNacN34K8cE3XjHq1kx/BgYOtQ7M2Xa1oApLzPoHO4D2kaf6FCgGR8Mx7GVAz0aQVxfB8I="
}
}

View File

@@ -1,26 +0,0 @@
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://sso.tugraz.at/idp/shibboleth">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIDHzCCAgegAwIBAgIUG6ra0BvXswfyErcCDmzw3AV+uI0wDQYJKoZIhvcNAQEFBQAwGDEWMBQGA1UEAxMNc3NvLnR1Z3Jhei5hdDAeFw0xMDAzMjkxNzEzMTZaFw0zMDAzMjkxODEzMTZaMBgxFjAUBgNVBAMTDXNzby50dWdyYXouYXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCEyQxHIM1zxbBnXn60Ksg7B7HcPLPcN7bXLrLPOFXtkZxm0YkHY5Rxignm7wHD7C81U09DFS2eT8qRCcVtVz+kuwdgS54fC/alg9oLxXk4CgKjhtZZ2ECLdTHfUXOA5uOLlpoN1LY6VpIjSYe3UEX3HxfhXx/fPeE8VInGCKnml8Too22G30htB/EU44A2yqrR3LUngJIaq//N0QbeMYitNh02o6xB5+bp6k6noM7DH6S9phe0kCEibaiLaCf7k9LpNnAz9bPtQVth0gdJqoUry/iK1QBTFTEXvvJynFEp0+5Wz/XFmEcFhsaK8OcHd0R9FfpX5Z2fewA2Q0SLKz+bAgMBAAGjYTBfMD4GA1UdEQQ3MDWCDXNzby50dWdyYXouYXSGJGh0dHBzOi8vc3NvLnR1Z3Jhei5hdC9pZHAvc2hpYmJvbGV0aDAdBgNVHQ4EFgQUXd76PcSiXR6wFna5qQi+S0W/9Y0wDQYJKoZIhvcNAQEFBQADggEBACgkQqxBtYY1OcuoAUP/P+ukJW7XyofK89qs2dkGClx7s0hR/1zImWgljgfguLJOSfC/CWE1wfNK9bTi4Fu9809PmOoaCxkNmniFRAyaOiBoUz5XIpJniW7wBo+YBpBlXZXi5PmU2DOsfZxo7fs4se32dHO1WqgJodqkK2Wa4HDiigh42trZ9i3uS73uHSSCeIJYQNj84BMJ+ifgj3Zi/TgLS+IX7Ayy2bkDzIzIRnj7ULQ/MgfacGXQXJPHyp+w+YvydQalPAWc43+5DkNacN34K8cE3XjHq1kx/BgYOtQ7M2Xa1oApLzPoHO4D2kaf6FCgGR8Mx7GVAz0aQVxfB8I=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIHxNp8P2PsV8CAggAMBQGCCqGSIb3DQMHBAjOyik6fsEC3gSCAoC4tFsYAl4GexyXESiRKpOQzHQNFtQtwDEevT1IKgsafSNjOMJZLKrnoejNoxEQUPPPXgGEd83Fmp2cSHm+YVksH06zcsA+RKf5ab6t0bsgcyljGzkHEDQtMRPcaXNlVMbU9VEDOX26MgmlU/pd+GGfE99IbEFc6qN1e7qOnmKSw93Q3o05ubO3wEI76JhOioGGXB3pEn8f4XLDwck0thzYD6H2vdF+kyIdM8w1BgyLdeP0aDkfG1V3rLGhE8246rwVUzRSZv6BCNBZFk7YO1d7j0+BDxnbHFS631zdCgMcd/XS8u6acc3IYr/bQLH4a1y0X3Z+8ks8arEgUtXqYx9wMlp5lajlsr9JDIU5OnuZ2XY+4sqDQsTZPjBpxK8oMjvJNNatnTf+18htkTdovpInlP7xpEjp1L7H74iKY25UsAZ9e+gqHZwILnk418mQ1E4JYU6JRUZspJSFfqwn9FL6DnvhzPIhtzwhr3eL4f4RXWxxe2xCzvWg+GaWuMfZdj77SV4pMOi7vb3HlYY6luShVlYKdSaw+jf6XVy4ZMTWT5wcE1mc3tAJqF18Mi8amOetpZhz16ISOKnO0rKrfmxteNPQn2AB8QquGGn050PTW4m8zFXDBiyg2xvcRLAW/8ych3k+pkEZi4tVCkLcHM56J/XUEKMCxiSok+vbzxfVf1D2vYFFS7Lw1nP5RnLKFdn8XdHQ+lu2diod18wYBQP4eoU+XjjP2zjlpULiWHt7PpCERqGg7H2Z2amIL5rTeqQuyXczw1/xG/VBNn9qe3DXFodvoV6OZb3efNT/eJgOyaPLi2FmB7Kpdp4JIdJgLnaBCwNBXkpGSwb732O/cug8</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.tugraz.at/slo/Logout"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sso.tugraz.at/idp/profile/SAML2/Redirect/SSO"/>
</md:IDPSSODescriptor>
<md:ContactPerson contactType="technical">
<md:GivenName>Administrator</md:GivenName>
<md:EmailAddress>admin@example.org</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>

View File

@@ -1 +0,0 @@
MIICjjCCAfegAwIBAgIBADANBgkqhkiG9w0BAQ0FADBkMQswCQYDVQQGEwJhdDENMAsGA1UECAwER3JhejEPMA0GA1UECgwGVFVHUkFaMRAwDgYDVQQDDAdpbnZlbmlvMSMwIQYJKoZIhvcNAQkBFhRtb2ppYi53YWxpQHR1Z3Jhei5hdDAeFw0yMDAxMTAyMDIwMTlaFw0yMTAxMDkyMDIwMTlaMGQxCzAJBgNVBAYTAmF0MQ0wCwYDVQQIDARHcmF6MQ8wDQYDVQQKDAZUVUdSQVoxEDAOBgNVBAMMB2ludmVuaW8xIzAhBgkqhkiG9w0BCQEWFG1vamliLndhbGlAdHVncmF6LmF0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5ZrPhRhyDyLTe93rpgqN9MMfnCsg+2QBW4EOuQnMXJzF1dqrFEsexot1FRW83IjqbY+680PmGABQtxUpS4Kinr/pLYbPhQ2WPQRad7mtOn/dD40VVwfG0GfcLrnKe5F4QLfNjervjl8jH/AKPCYwwfSeuw1LNoRjy1uDwkp9cRQIDAQABo1AwTjAdBgNVHQ4EFgQUPv2+wS1RuagCOed7w1FzouBmpP4wHwYDVR0jBBgwFoAUPv2+wS1RuagCOed7w1FzouBmpP4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOBgQA4qvU7gbgE/MoljUW68qMPs8z8Q2Ngttp6F1KOMNO9rgrYWAJh4u6BMt11mlBgBlLLJzG67wXpBr0l78IcOXun4w955te0VRp7aZ0b1uOPt0aUoDOXuBAhZURLZfbsogpWiE6bdB8N0nHTwk2WG2PPIC5Z99UdDivcP5ZeSPAkUw==

View File

@@ -1,17 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIHxNp8P2PsV8CAggA
MBQGCCqGSIb3DQMHBAjOyik6fsEC3gSCAoC4tFsYAl4GexyXESiRKpOQzHQNFtQt
wDEevT1IKgsafSNjOMJZLKrnoejNoxEQUPPPXgGEd83Fmp2cSHm+YVksH06zcsA+
RKf5ab6t0bsgcyljGzkHEDQtMRPcaXNlVMbU9VEDOX26MgmlU/pd+GGfE99IbEFc
6qN1e7qOnmKSw93Q3o05ubO3wEI76JhOioGGXB3pEn8f4XLDwck0thzYD6H2vdF+
kyIdM8w1BgyLdeP0aDkfG1V3rLGhE8246rwVUzRSZv6BCNBZFk7YO1d7j0+BDxnb
HFS631zdCgMcd/XS8u6acc3IYr/bQLH4a1y0X3Z+8ks8arEgUtXqYx9wMlp5lajl
sr9JDIU5OnuZ2XY+4sqDQsTZPjBpxK8oMjvJNNatnTf+18htkTdovpInlP7xpEjp
1L7H74iKY25UsAZ9e+gqHZwILnk418mQ1E4JYU6JRUZspJSFfqwn9FL6DnvhzPIh
tzwhr3eL4f4RXWxxe2xCzvWg+GaWuMfZdj77SV4pMOi7vb3HlYY6luShVlYKdSaw
+jf6XVy4ZMTWT5wcE1mc3tAJqF18Mi8amOetpZhz16ISOKnO0rKrfmxteNPQn2AB
8QquGGn050PTW4m8zFXDBiyg2xvcRLAW/8ych3k+pkEZi4tVCkLcHM56J/XUEKMC
xiSok+vbzxfVf1D2vYFFS7Lw1nP5RnLKFdn8XdHQ+lu2diod18wYBQP4eoU+XjjP
2zjlpULiWHt7PpCERqGg7H2Z2amIL5rTeqQuyXczw1/xG/VBNn9qe3DXFodvoV6O
Zb3efNT/eJgOyaPLi2FmB7Kpdp4JIdJgLnaBCwNBXkpGSwb732O/cug8
-----END RSA PRIVATE KEY-----

View File

@@ -1,20 +0,0 @@
{
"strict": true,
"debug": true,
"idp": {
"entityId": "https://app.onelogin.com/saml/metadata/01661574-91ed-4735-a3b9-f4ddebb2cbb8",
"singleLogoutService": {
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
"url": "https://tugraz-dev.onelogin.com/trust/saml2/http-redirect/slo/1070112"
},
"singleSignOnService": {
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
"url": "https://tugraz-dev.onelogin.com/trust/saml2/http-post/sso/01661574-91ed-4735-a3b9-f4ddebb2cbb8"
},
"x509cert": "MIID2DCCAsCgAwIBAgIUWRGl84DFd+GbLYt0BmwyI+FCKVIwDQYJKoZIhvcNAQEFBQAwRDEPMA0GA1UECgwGVFVHUkFaMRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxGjAYBgNVBAMMEU9uZUxvZ2luIEFjY291bnQgMB4XDTIwMDEyODEwNDI1M1oXDTI1MDEyODEwNDI1M1owRDEPMA0GA1UECgwGVFVHUkFaMRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxGjAYBgNVBAMMEU9uZUxvZ2luIEFjY291bnQgMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAve5a++I/VHC22fMk5v8GwCvdIyiziOwGjq0XXyjTg9TyhHJZbfDXa7S0NjK7dK4+d3iaB3MvCpnr+7H2J2Cohracgy2BQz9Z4BqsjDat016zkAPoID9R6osliqocw1jESnyL59OJWftAiA4rFmQs6v/b56vgre8EP6qKbykq6mWvepGyBbfjRsYbFoIDmnW8kJoZtLMDQfTBvEF2veHDt9EbsWP+hyedMYTWCfsbTHhFKNrhRKr3m3k+w6Zsca2zp3A8xiFv0fcl6PglEwEZz2Iwb0ySifaf4ZLDVjSekpCLf29doBJYUeE5TUP8oHfATOcWW+m5D3MXVcMUax+AFwIDAQABo4HBMIG+MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFK4GHoSfnMQKb8RjP2HrGzJ4ICiDMH8GA1UdIwR4MHaAFK4GHoSfnMQKb8RjP2HrGzJ4ICiDoUikRjBEMQ8wDQYDVQQKDAZUVUdSQVoxFTATBgNVBAsMDE9uZUxvZ2luIElkUDEaMBgGA1UEAwwRT25lTG9naW4gQWNjb3VudCCCFFkRpfOAxXfhmy2LdAZsMiPhQilSMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQUFAAOCAQEAUg7UHFju0QA7ubcSLBuvEMUQL9jxtzDi0ndSi8qqtLJSjBalcfll0X/gI+sAMGMd0MW7P3abOVVfGBSlZN01KCPC2WHKRwzyO3sOCatkPrn2SYthQWHD/W7psyFgoDt5lQNijLyZdpvZbRIotxcWpoaTcBzaArd/0MNe1VaGlLK5GeqtbwL+dQD+O3mtSUfF918qeiOHEwI7nfPo7vjUyRT8Ov1loqP5+A0/R1CyL0Dh/tVdIkOHx6EjrIXsb/K6xXPknYZqPApPkZq514ZCEPhAILFU+5R/cQMZMZEacCdKuQ9XMkR8bqnh8xu620SCYiSVPXtVW4bpXKs0nJazBQ=="
}
}

View File

@@ -1,26 +0,0 @@
<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://app.onelogin.com/saml/metadata/01661574-91ed-4735-a3b9-f4ddebb2cbb8">
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIID2DCCAsCgAwIBAgIUWRGl84DFd+GbLYt0BmwyI+FCKVIwDQYJKoZIhvcNAQEFBQAwRDEPMA0GA1UECgwGVFVHUkFaMRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxGjAYBgNVBAMMEU9uZUxvZ2luIEFjY291bnQgMB4XDTIwMDEyODEwNDI1M1oXDTI1MDEyODEwNDI1M1owRDEPMA0GA1UECgwGVFVHUkFaMRUwEwYDVQQLDAxPbmVMb2dpbiBJZFAxGjAYBgNVBAMMEU9uZUxvZ2luIEFjY291bnQgMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAve5a++I/VHC22fMk5v8GwCvdIyiziOwGjq0XXyjTg9TyhHJZbfDXa7S0NjK7dK4+d3iaB3MvCpnr+7H2J2Cohracgy2BQz9Z4BqsjDat016zkAPoID9R6osliqocw1jESnyL59OJWftAiA4rFmQs6v/b56vgre8EP6qKbykq6mWvepGyBbfjRsYbFoIDmnW8kJoZtLMDQfTBvEF2veHDt9EbsWP+hyedMYTWCfsbTHhFKNrhRKr3m3k+w6Zsca2zp3A8xiFv0fcl6PglEwEZz2Iwb0ySifaf4ZLDVjSekpCLf29doBJYUeE5TUP8oHfATOcWW+m5D3MXVcMUax+AFwIDAQABo4HBMIG+MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFK4GHoSfnMQKb8RjP2HrGzJ4ICiDMH8GA1UdIwR4MHaAFK4GHoSfnMQKb8RjP2HrGzJ4ICiDoUikRjBEMQ8wDQYDVQQKDAZUVUdSQVoxFTATBgNVBAsMDE9uZUxvZ2luIElkUDEaMBgGA1UEAwwRT25lTG9naW4gQWNjb3VudCCCFFkRpfOAxXfhmy2LdAZsMiPhQilSMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQUFAAOCAQEAUg7UHFju0QA7ubcSLBuvEMUQL9jxtzDi0ndSi8qqtLJSjBalcfll0X/gI+sAMGMd0MW7P3abOVVfGBSlZN01KCPC2WHKRwzyO3sOCatkPrn2SYthQWHD/W7psyFgoDt5lQNijLyZdpvZbRIotxcWpoaTcBzaArd/0MNe1VaGlLK5GeqtbwL+dQD+O3mtSUfF918qeiOHEwI7nfPo7vjUyRT8Ov1loqP5+A0/R1CyL0Dh/tVdIkOHx6EjrIXsb/K6xXPknYZqPApPkZq514ZCEPhAILFU+5R/cQMZMZEacCdKuQ9XMkR8bqnh8xu620SCYiSVPXtVW4bpXKs0nJazBQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIHxNp8P2PsV8CAggAMBQGCCqGSIb3DQMHBAjOyik6fsEC3gSCAoC4tFsYAl4GexyXESiRKpOQzHQNFtQtwDEevT1IKgsafSNjOMJZLKrnoejNoxEQUPPPXgGEd83Fmp2cSHm+YVksH06zcsA+RKf5ab6t0bsgcyljGzkHEDQtMRPcaXNlVMbU9VEDOX26MgmlU/pd+GGfE99IbEFc6qN1e7qOnmKSw93Q3o05ubO3wEI76JhOioGGXB3pEn8f4XLDwck0thzYD6H2vdF+kyIdM8w1BgyLdeP0aDkfG1V3rLGhE8246rwVUzRSZv6BCNBZFk7YO1d7j0+BDxnbHFS631zdCgMcd/XS8u6acc3IYr/bQLH4a1y0X3Z+8ks8arEgUtXqYx9wMlp5lajlsr9JDIU5OnuZ2XY+4sqDQsTZPjBpxK8oMjvJNNatnTf+18htkTdovpInlP7xpEjp1L7H74iKY25UsAZ9e+gqHZwILnk418mQ1E4JYU6JRUZspJSFfqwn9FL6DnvhzPIhtzwhr3eL4f4RXWxxe2xCzvWg+GaWuMfZdj77SV4pMOi7vb3HlYY6luShVlYKdSaw+jf6XVy4ZMTWT5wcE1mc3tAJqF18Mi8amOetpZhz16ISOKnO0rKrfmxteNPQn2AB8QquGGn050PTW4m8zFXDBiyg2xvcRLAW/8ych3k+pkEZi4tVCkLcHM56J/XUEKMCxiSok+vbzxfVf1D2vYFFS7Lw1nP5RnLKFdn8XdHQ+lu2diod18wYBQP4eoU+XjjP2zjlpULiWHt7PpCERqGg7H2Z2amIL5rTeqQuyXczw1/xG/VBNn9qe3DXFodvoV6OZb3efNT/eJgOyaPLi2FmB7Kpdp4JIdJgLnaBCwNBXkpGSwb732O/cug8</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://tugraz-dev.onelogin.com/trust/saml2/http-redirect/slo/1070112"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://tugraz-dev.onelogin.com/trust/saml2/http-post/sso/01661574-91ed-4735-a3b9-f4ddebb2cbb8"/>
</md:IDPSSODescriptor>
<md:ContactPerson contactType="technical">
<md:GivenName>Administrator</md:GivenName>
<md:EmailAddress>admin@example.org</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>

View File

@@ -1,25 +0,0 @@
# German translations for invenio-config-tugraz.
# Copyright (C) 2020 Mojib Wali
# This file is distributed under the same license as the
# invenio-config-tugraz project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: invenio-config-tugraz 0.1.5\n"
"Report-Msgid-Bugs-To: mojib.wali@tugraz.at\n"
"POT-Creation-Date: 2020-10-06 09:28+0200\n"
"PO-Revision-Date: 2020-10-06 09:28+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: de\n"
"Language-Team: de <LL@li.org>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.8.0\n"
#: invenio_config_tugraz/config.py:80
msgid "Welcome to RDM!"
msgstr ""

View File

@@ -1,24 +0,0 @@
# Translations template for invenio-config-tugraz.
# Copyright (C) 2020 Mojib Wali
# This file is distributed under the same license as the
# invenio-config-tugraz project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: invenio-config-tugraz 0.1.5\n"
"Report-Msgid-Bugs-To: mojib.wali@tugraz.at\n"
"POT-Creation-Date: 2020-10-06 09:28+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"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.8.0\n"
#: invenio_config_tugraz/config.py:80
msgid "Welcome to RDM!"
msgstr ""

View File

@@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Version information for invenio-config-tugraz.
This file is imported by ``invenio_config_tugraz.__init__``,
and parsed by ``setup.py``.
"""
__version__ = "0.4.0"

150
pyproject.toml Normal file
View File

@@ -0,0 +1,150 @@
[project]
name = "invenio-config-iform"
dynamic = ["version"]
description = "Invenio module that adds I-Form configs."
readme = { file = "README.rst", content-type = "text/x-rst" }
license = "MIT"
authors = [
{ name = "I-Form Advanced Research Manufacturing Research Centre", email = "cian.hughes@dcu.ie" },
]
keywords = ["invenio", "config", "I-Form"]
classifiers = [
"Environment :: Web Environment",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Development Status :: 3 - Alpha",
]
requires-python = ">=3.10,<3.14"
dependencies = [
"invenio-cache>=1.1.1",
"invenio-i18n>=2.0.0",
"invenio-rdm-records>=4.0.0",
]
[project.urls]
Homepage = "https://github.com/Cian-H/invenio-config-iform"
Issues = "https://github.com/Cian-H/invenio-config-iform/issues"
[project.scripts]
test-docs = "scripts.test_docs:main"
test-code = "pytest:console_main"
test = "scripts.test:main"
[project.entry-points."invenio_base.apps"]
invenio_config_iform = "invenio_config_iform:InvenioConfigIform"
[project.entry-points."invenio_base.blueprints"]
invenio_config_iform = "invenio_config_iform.views:ui_blueprint"
[project.entry-points."invenio_i18n.translations"]
messages = "invenio_config_iform"
[project.entry-points."invenio_config.module"]
invenio_config_iform = "invenio_config_iform.config"
[project.entry-points."invenio_base.finalize_app"]
invenio_config_iform = "invenio_config_iform.ext:finalize_app"
[dependency-groups]
dev = [
"hatch>=1.14.1",
"pre-commit>=4.2.0",
"pydocstyle>=6.3.0",
"ruff>=0.11.7",
]
tests = [
"invenio-app>=1.5.0",
"invenio-search[opensearch2]>=2.1.0",
"pytest-invenio>=2.1.0",
"pytest-ruff>=0.4.1",
"ruff>=0.5.3",
"Sphinx>=4.5.0",
]
[build-system]
requires = ["hatchling", "hatch-calver"]
build-backend = "hatchling.build"
[tool.hatch.version]
scheme = "calver"
path = "invenio_config_iform/__about__.py"
[tool.hatch.build]
include = ["invenio_config_iform"]
exclude = [".venv", "tests/*", "*/tests/*", "*.rst", "run-tests.sh"]
# Testing configuration
[tool.pytest]
addopts = "--ruff --ruff-format --pydocstyle --doctest-glob=\"*.rst\" --doctest-modules --cov=invenio_config_iform --cov-report=term-missing tests invenio_config_iform"
testpaths = ["tests", "invenio_config_iform"]
live_server_scope = "module"
[tool.pytest.ini_options]
addopts = "--ruff --ruff-format --pydocstyle --doctest-glob=\"*.rst\" --doctest-modules --cov=invenio_config_iform --cov-report=term-missing tests invenio_config_iform"
testpaths = ["tests", "invenio_config_iform"]
live_server_scope = "module"
# Code style tools configuration
[tool.ruff]
line-length = 100
target-version = "py313"
exclude = ["docs"]
[tool.ruff.lint]
select = ["ALL"]
ignore = [
"D203",
"D211",
"D212",
"D213",
"E501",
"ERA001",
"FA102",
"FIX002",
"INP001",
"RUF005",
"RUF012",
"S101",
"TD002",
"TD003",
"UP009",
]
[tool.ruff.lint.isort]
force-sort-within-sections = true
lines-after-imports = -1
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
line-ending = "auto"
[tool.pydocstyle]
add_ignore = ["D401"]
# Babel configuration
[tool.babel.compile_catalog]
directory = "invenio_config_iform/translations/"
use-fuzzy = true
[tool.babel.extract_messages]
copyright_holder = "I-Form Advanced Research Manufacturing Research Centre"
msgid_bugs_address = "cian.hughes@dcu.ie"
mapping-file = "babel.ini"
output-file = "invenio_config_iform/translations/messages.pot"
add-comments = "NOTE"
[tool.babel.init_catalog]
input-file = "invenio_config_iform/translations/messages.pot"
output-dir = "invenio_config_iform/translations/"
[tool.babel.update_catalog]
input-file = "invenio_config_iform/translations/messages.pot"
output-dir = "invenio_config_iform/translations/"

View File

@@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
[pytest]
addopts = --isort --pydocstyle --pycodestyle --doctest-glob="*.rst" --doctest-modules --cov=invenio_config_tugraz --cov-report=term-missing tests invenio_config_tugraz
testpaths = tests invenio_config_tugraz
live_server_scope = module

View File

@@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
#
# TODO: Add development versions of some important dependencies here to get a
# warning when there are breaking upstream changes, e.g.:
#
# -e git+git://github.com/mitsuhiko/werkzeug.git#egg=Werkzeug
# -e git+git://github.com/mitsuhiko/jinja2.git#egg=Jinja2

View File

@@ -1,33 +0,0 @@
#!/usr/bin/env bash
# -*- coding: utf-8 -*-
#
# Copyright (C) 2019-2020 CERN.
# Copyright (C) 2019-2020 Northwestern University.
# Copyright (C) 2020 Graz University of Technology.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
# Quit on errors
set -o errexit
# Quit on unbound symbols
set -o nounset
# Always bring down docker services
function cleanup() {
eval "$(docker-services-cli down --env)"
}
trap cleanup EXIT
python -m check_manifest --ignore ".*-requirements.txt"
python -m sphinx.cmd.build -qnNW docs docs/_build/html
eval "$(docker-services-cli up --db ${DB:-postgresql} --search ${SEARCH:-elasticsearch} --cache ${CACHE:-redis} --env)"
python -m pytest
tests_exit_code=$?
python -m sphinx.cmd.build -qnNW -b doctest docs docs/_build/doctest
exit "$tests_exit_code"

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python
"""A Script for checking that the version number has been incremented between pushes."""
from pathlib import Path
import re
import shutil
import subprocess
import sys
import tomllib
ALLOWED_EXECUTABLES: list[str] = [
"git",
"uv",
]
def validate_command(command: str) -> list[str]:
"""Validate and guard command calls.
Args:
command (str): the command to be validated.
Returns:
str: the validated command
Raises:
FileNotFoundError: if the command was not found
"""
cmd: list[str] = command.split().copy()
if cmd[0] not in ALLOWED_EXECUTABLES:
msg = f"Command {cmd} is not allowed!"
raise PermissionError(msg)
call = shutil.which(cmd[0])
if not call:
msg = f"Command {call} not found!"
raise FileNotFoundError(msg)
cmd[0] = call
if cmd[0] == "uv" and cmd[1] == "run":
cmd = [cmd[0], cmd[1], *validate_command("".join(cmd[2:]))]
return cmd
def run_command(command: str) -> str:
"""Run a command and get its output as a string.
Args:
command (str): The command to run.
Returns:
The output returned on stdout.
"""
cmd = validate_command(command)
return subprocess.run( # noqa: S603
cmd,
capture_output=True,
text=True,
check=True,
).stdout.strip()
def get_version_file_from_pyproject() -> str:
"""Get the path to the version file from the pyproject file.
Returns:
str: the path to the project version file
Raises:
FileNotFoundError: the pyproject file is not found
KeyError: the pyproject file does not reference a version file
"""
try:
with Path("pyproject.toml").open("rb") as f:
return tomllib.load(f)["tool"]["hatch"]["version"]["path"]
except FileNotFoundError as e:
msg = "Project has no pyproject.toml file!"
raise FileNotFoundError(msg) from e
except KeyError as e:
msg = "Attribute `tool.hatch.version.path` not found in pyproject.toml"
raise KeyError(msg) from e
def get_remote_version(remote: str, branch: str, version_file: str) -> str:
"""Get the version from the repository remote.
Args:
remote (str): The remote to fetch the version string from.
branch (str): The branch to fetch the version string from.
version_file (str): The file to fetch the version string from.
Returns:
str: The version string.
Raises:
AttributeError: NO `__version__` attribute was found in `version_file`.
"""
remote_file = f"{remote}/{branch}:{version_file}"
match = re.search(
r"__version__\s*=\s*['\"]([^'\"]+)['\"]",
run_command(f"git show {remote_file}"),
)
if match:
return match.group(1)
msg = f"No `__version__` attribute found in {remote_file}"
raise AttributeError(msg)
def main() -> None:
"""Entrypoint for this script."""
version_file = get_version_file_from_pyproject()
branch = run_command("git rev-parse --abbrev-ref HEAD")
remote = sys.argv[1] if len(sys.argv) > 1 else "origin"
current_version = run_command("uv run hatch version")
remote_version = get_remote_version(remote, branch, version_file)
assert current_version != remote_version, (
"Version has not been incremented! Please update the version before pushing."
)
if __name__ == "__main__":
main()

19
scripts/test.py Normal file
View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 I-Form Advanced Manufacturing Research Centre.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Run all tests for this module consecutively."""
import pytest
from . import test_docs
def main() -> None:
"""Run tests for this module."""
test_docs.main()
pytest.console_main()

16
scripts/test_docs.py Normal file
View File

@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2025 I-Form Advanced Manufacturing Research Centre.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""A script for testing sphinx documentation building."""
from sphinx.cmd.build import main as build_docs
def main() -> None:
"""Attempt to build documentation."""
build_docs(["-nN", "docs", "docs/_build/html"])

View File

@@ -1,56 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
[aliases]
test = pytest
[build_sphinx]
source-dir = docs/
build-dir = docs/_build
all_files = 1
[bdist_wheel]
universal = 1
[pydocstyle]
add_ignore = D401
[compile_catalog]
directory = invenio_config_tugraz/translations/
[extract_messages]
copyright_holder = Mojib Wali
msgid_bugs_address = mojib.wali@tugraz.at
mapping-file = babel.ini
output-file = invenio_config_tugraz/translations/messages.pot
add-comments = NOTE
[init_catalog]
input-file = invenio_config_tugraz/translations/messages.pot
output-dir = invenio_config_tugraz/translations/
[update_catalog]
input-file = invenio_config_tugraz/translations/messages.pot
output-dir = invenio_config_tugraz/translations/
[flake8]
max-line-length = 88
extend-ignore = E203
select = C,E,F,W,B,B950
ignore = E501
[isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88
[pycodestyle]
ignore = E203,E501

100
setup.py
View File

@@ -1,100 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""invenio module that adds tugraz configs."""
import os
from setuptools import find_packages, setup
readme = open("README.rst").read()
history = open("CHANGES.rst").read()
tests_require = [
"pytest-invenio>=1.4.0",
"SQLAlchemy-Utils>=0.33.1,<0.36",
"invenio-rdm-records~=0.20.8",
"invenio-search[elasticsearch7]>=1.4.0",
"psycopg2-binary>=2.8.6",
]
extras_require = {
"docs": [
"Sphinx>=3",
],
"tests": tests_require,
}
extras_require["all"] = []
for reqs in extras_require.values():
extras_require["all"].extend(reqs)
setup_requires = [
"Babel>=1.3",
"pytest-runner>=3.0.0,<5",
]
install_requires = [
"Flask-BabelEx>=0.9.4",
"elasticsearch_dsl>=7.2.1",
"sqlalchemy-continuum>=1.3.11",
]
packages = find_packages()
# Get the version string. Cannot be done with import!
g = {}
with open(os.path.join("invenio_config_tugraz", "version.py"), "rt") as fp:
exec(fp.read(), g)
version = g["__version__"]
setup(
name="invenio-config-tugraz",
version=version,
description=__doc__,
long_description=readme + "\n\n" + history,
keywords="invenio, config, Tu Graz",
license="MIT",
author="Mojib Wali",
author_email="mb_wali@hotmail.com",
url="https://github.com/tu-graz-library/invenio-config-tugraz",
packages=packages,
zip_safe=False,
include_package_data=True,
platforms="any",
entry_points={
"invenio_base.apps": [
"invenio_config_tugraz = invenio_config_tugraz:InvenioConfigTugraz",
],
"invenio_i18n.translations": [
"messages = invenio_config_tugraz",
],
"invenio_config.module": [
"invenio_config_tugraz = invenio_config_tugraz.config",
],
},
extras_require=extras_require,
install_requires=install_requires,
setup_requires=setup_requires,
tests_require=tests_require,
classifiers=[
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
"Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Development Status :: 3 - Alpha",
],
)

View File

@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
@@ -12,152 +13,20 @@ See https://pytest-invenio.readthedocs.io/ for documentation on which test
fixtures are available.
"""
import os
import shutil
import tempfile
import pytest
from flask import Flask
from flask_babelex import Babel
from invenio_db import InvenioDB, db
from sqlalchemy_utils.functions import create_database, database_exists, drop_database
import pytest
from invenio_config_tugraz import InvenioConfigTugraz
from invenio_config_iform import InvenioConfigIform
@pytest.fixture(scope="module")
def celery_config():
"""Override pytest-invenio fixture.
def create_app(instance_path: str) -> Flask:
"""Application factory fixture."""
TODO: Remove this fixture if you add Celery support.
"""
return {}
def factory(**config: str) -> Flask:
app = Flask("testapp", instance_path=instance_path)
app.config.update(**config)
InvenioConfigIform(app)
return app
@pytest.fixture()
def create_app(request):
"""Basic Flask application."""
instance_path = tempfile.mkdtemp()
app = Flask("testapp")
DB = os.getenv("SQLALCHEMY_DATABASE_URI", "sqlite://")
app.config.update(
INVENIO_CONFIG_TUGRAZ_SINGLE_IP=["127.0.0.1", "127.0.0.2"],
INVENIO_CONFIG_TUGRAZ_IP_RANGES=[
["127.0.0.2", "127.0.0.99"],
["127.0.1.3", "127.0.1.5"],
],
SQLALCHEMY_DATABASE_URI=DB,
SQLALCHEMY_TRACK_MODIFICATIONS=False,
)
Babel(app)
InvenioConfigTugraz(app)
InvenioDB(app)
with app.app_context():
db_url = str(db.engine.url)
if db_url != "sqlite://" and not database_exists(db_url):
create_database(db_url)
db.create_all()
def teardown():
with app.app_context():
db_url = str(db.engine.url)
db.session.close()
if db_url != "sqlite://":
drop_database(db_url)
shutil.rmtree(instance_path)
request.addfinalizer(teardown)
app.test_request_context().push()
return app
@pytest.fixture(scope='function')
def open_record():
"""Open record data as dict coming from the external world."""
return {
"access": {
"metadata": False,
"files": False,
"owned_by": [1],
"access_right": "open"
},
"metadata": {
"publication_date": "2020-06-01",
"resource_type": {
"type": "image",
"subtype": "image-photo"
},
# Technically not required
"creators": [{
"name": "Troy Brown",
"type": "personal"
}, {
"name": "Phillip Lester",
"type": "personal",
"identifiers": {"orcid": "0000-0002-1825-0097"},
"affiliations": [{
"name": "Carter-Morris",
"identifiers": {"ror": "03yrm5c26"}
}]
}, {
"name": "Steven Williamson",
"type": "personal",
"identifiers": {"orcid": "0000-0002-1825-0097"},
"affiliations": [{
"name": "Ritter and Sons",
"identifiers": {"ror": "03yrm5c26"}
}, {
"name": "Montgomery, Bush and Madden",
"identifiers": {"ror": "03yrm5c26"}
}]
}],
"title": "A Romans story"
}
}
@pytest.fixture(scope='function')
def singleip_record():
"""Single Ip record data as dict coming from the external world."""
return {
"access": {
"metadata": False,
"files": False,
"owned_by": [1],
"access_right": "singleip"
},
"metadata": {
"publication_date": "2020-06-01",
"resource_type": {
"type": "image",
"subtype": "image-photo"
},
# Technically not required
"creators": [{
"name": "Troy Brown",
"type": "personal"
}, {
"name": "Phillip Lester",
"type": "personal",
"identifiers": {"orcid": "0000-0002-1825-0097"},
"affiliations": [{
"name": "Carter-Morris",
"identifiers": {"ror": "03yrm5c26"}
}]
}, {
"name": "Steven Williamson",
"type": "personal",
"identifiers": {"orcid": "0000-0002-1825-0097"},
"affiliations": [{
"name": "Ritter and Sons",
"identifiers": {"ror": "03yrm5c26"}
}, {
"name": "Montgomery, Bush and Madden",
"identifiers": {"ror": "03yrm5c26"}
}]
}],
"title": "A Romans story"
}
}
return factory

View File

@@ -1,38 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Test Generators."""
from invenio_access.permissions import any_user, authenticated_user
from invenio_config_tugraz.generators import AuthenticatedUser, RecordIp
def test_recordip(create_app, open_record, singleip_record):
"""Test Generator RecordIp."""
generator = RecordIp()
open_record = open_record
singleiprec = singleip_record
assert generator.needs(record=None) == []
assert generator.needs(record=open_record) == [any_user]
assert generator.needs(record=singleiprec) == []
assert generator.excludes(record=open_record) == []
assert generator.excludes(record=open_record) == []
assert generator.query_filter().to_dict() == {'bool': {'must_not': [{'match': {'access.access_right': 'singleip'}}]}}
def test_authenticateduser():
"""Test Generator AuthenticatedUser."""
generator = AuthenticatedUser()
assert generator.needs() == [authenticated_user]
assert generator.excludes() == []
assert generator.query_filter() == []

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020-2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Module tests."""
from flask import Flask
from invenio_config_iform import InvenioConfigIform
def test_version() -> None:
"""Test version import."""
from invenio_config_iform import __version__
assert __version__
def test_init() -> None:
"""Test extension initialization."""
app = Flask("testapp")
ext = InvenioConfigIform(app)
assert "invenio-config-iform" in app.extensions
app = Flask("testapp")
ext = InvenioConfigIform()
assert "invenio-config-iform" not in app.extensions
ext.init_app(app)
assert "invenio-config-iform" in app.extensions

View File

@@ -1,33 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2020 Mojib Wali.
#
# invenio-config-tugraz is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Module tests."""
from flask import Flask
from invenio_config_tugraz import InvenioConfigTugraz
def test_version():
"""Test version import."""
from invenio_config_tugraz import __version__
assert __version__
def test_init():
"""Test extension initialization."""
app = Flask("testapp")
ext = InvenioConfigTugraz(app)
assert "invenio-config-tugraz" in app.extensions
app = Flask("testapp")
ext = InvenioConfigTugraz()
assert "invenio-config-tugraz" not in app.extensions
ext.init_app(app)
assert "invenio-config-tugraz" in app.extensions

88
tests/test_policies.py Normal file
View File

@@ -0,0 +1,88 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2024 Graz University of Technology.
#
# invenio-config-iform is free software; you can redistribute it and/or
# modify it under the terms of the MIT License; see LICENSE file for more
# details.
"""Tests for permissions-policy."""
from invenio_rdm_records.services.permissions import RDMRecordPermissionPolicy
from invenio_config_iform.permissions.policies import IformRDMRecordPermissionPolicy
ALLOWED_DIFFERENCES = {
"can_all",
"can_authenticated",
"can_create",
"can_iform_authenticated",
"can_search",
"can_search_drafts",
"can_view",
}
def test_policies_synced() -> None:
"""Make sure our permission-policy stays synced with invenio's."""
iform_cans = {
name: getattr(IformRDMRecordPermissionPolicy, name)
for name in dir(IformRDMRecordPermissionPolicy)
if name.startswith("can_")
}
rdm_cans = {
name: getattr(RDMRecordPermissionPolicy, name)
for name in dir(RDMRecordPermissionPolicy)
if name.startswith("can_")
}
# check whether same set of `can_<action>`s`
if extras := set(iform_cans) - set(rdm_cans) - ALLOWED_DIFFERENCES:
msg = f"""
I-Form's permission-policy has additional fields over invenio-rdm's:{extras}
if this is intentional, add to ALLOWED_DIFFERENCES in test-file
otherwise remove extraneous fields from IformRDMRecordPermissionPolicy
"""
raise KeyError(msg)
if missing := set(rdm_cans) - set(iform_cans):
msg = f"""
invenio-rdm's permission-policy has fields unhandled by I-Form's: {missing}
if this is intentional, add to ALLOWED_DIFFERENCES
otherwise set the corresponding fields in IformRDMRecordPermissionPolicy
"""
raise KeyError(msg)
# check whether same permission-generators used for same `can_<action>`
for can_name in rdm_cans.keys() & iform_cans.keys():
if can_name in ALLOWED_DIFFERENCES:
continue
iform_can = iform_cans[can_name]
rdm_can = rdm_cans[can_name]
# permission-Generators don't implement equality checks for their instances
# we can however compare which types (classes) of Generators are used...
if {type(gen) for gen in iform_can} != {type(gen) for gen in rdm_can}:
msg = f"""
permission-policy for `{can_name}` differs between I-Form and invenio-rdm
if this is intentional, add to ALLOWED_DIFFERENCES in test-file
otherwise fix IformRDMRecordPermissionPolicy
"""
raise ValueError(msg)
# check whether same `NEED_LABEL_TO_ACTION`
iform_label_to_action = IformRDMRecordPermissionPolicy.NEED_LABEL_TO_ACTION
rdm_label_to_action = RDMRecordPermissionPolicy.NEED_LABEL_TO_ACTION
for label in iform_label_to_action.keys() & rdm_label_to_action.keys():
if label in ALLOWED_DIFFERENCES:
continue
if iform_label_to_action.get(label) != rdm_label_to_action.get(label):
msg = f"""
invenio-rdm's NEED_LABEL_TO_ACTION differs from I-Form's in {label}
if this is intentional, add to ALLOWED_DIFFERENCES in test-file
otherwise fix IformRDMRecordPermissionPolicy.NEED_LABEL_TO_ACTION
"""
raise ValueError(msg)

5356
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff