mirror of
https://github.com/Cian-H/invenio-config-iform.git
synced 2025-12-23 05:21:57 +00:00
Compare commits
121 Commits
v0.5.8
...
2025.5.20.
| Author | SHA1 | Date | |
|---|---|---|---|
| 529fe17d24 | |||
| 0fd2466b49 | |||
| 8f5c1e36a5 | |||
| 1992a4cee0 | |||
| 40ed1aa4f9 | |||
| 51f11bd910 | |||
| f4c8cbea03 | |||
| 56f7739ae4 | |||
| f2bcb03cd0 | |||
| 9646985e7c | |||
| b514df9d48 | |||
| e1d975dc98 | |||
| d4f6efe5a2 | |||
| 9b7aa9a217 | |||
| a0da4cf05f | |||
| 84595fa54f | |||
| 2cf44242fa | |||
| 899b391e29 | |||
| 610ea83652 | |||
| 28aa1eb9a3 | |||
| 98f37fc6d7 | |||
| 7c938751e6 | |||
| 7bd474a247 | |||
| 8582c8ce23 | |||
| 3ba2169591 | |||
| 3e566699c6 | |||
| 811bf6514d | |||
| 668ae1e34c | |||
| 60085e90ab | |||
| cb836a1d6d | |||
| 5fea611ab4 | |||
| e8df1e4541 | |||
| 069bb11033 | |||
| cd35917894 | |||
| 302ff471fd | |||
| e2e6a32c08 | |||
| 32f0c0af61 | |||
| d26e8cae6f | |||
| f537f0e383 | |||
| 3e82144fd3 | |||
| b925eaa678 | |||
| 5b2eb94994 | |||
| 7c7a281a5f | |||
| 8e3b48ab52 | |||
|
|
8746d704a1 | ||
|
|
a7b474bb78 | ||
| 969b16fe4a | |||
| d452fca79e | |||
| 2069f0826d | |||
| 98893598f8 | |||
| 4e20d6a5fe | |||
| 58a7e2f3a8 | |||
| 5665b01979 | |||
| b6cbd03f9c | |||
|
|
04ca3f5661 | ||
|
|
5d84b08e26 | ||
|
|
5e4fcca0ed | ||
|
|
c934a4952b | ||
|
|
c91d056a56 | ||
|
|
583a67d0cf | ||
|
|
760363b4a5 | ||
|
|
52fb93cc43 | ||
|
|
41db3186df | ||
|
|
20bdff0b79 | ||
|
|
99705d7a25 | ||
|
|
d4df756ebf | ||
|
|
a10dccba22 | ||
|
|
8b84077e83 | ||
|
|
08d745d367 | ||
|
|
bf62abff3f | ||
|
|
40a47ed36d | ||
|
|
129b331603 | ||
|
|
328abd1306 | ||
|
|
7ce124cdb9 | ||
|
|
75d78cf09a | ||
|
|
2e5fbcb4f9 | ||
|
|
4c4279965a | ||
|
|
0ee0df4ee1 | ||
|
|
8df08c09bf | ||
|
|
3a508ac3f0 | ||
|
|
087cafa3ae | ||
|
|
14e9e0557a | ||
|
|
8669f5dcda | ||
|
|
62256b346f | ||
|
|
4a8b02ec4a | ||
|
|
8a592e3fdf | ||
|
|
42d5e2db05 | ||
|
|
3db870784b | ||
|
|
73bc8b4575 | ||
|
|
7fd5a7df3f | ||
|
|
79fe24511a | ||
|
|
5b7a1718fc | ||
|
|
9192107e99 | ||
|
|
c43c36ece3 | ||
|
|
3acbaf65ef | ||
|
|
408bdc47b1 | ||
|
|
6c6138b682 | ||
|
|
cc2c462057 | ||
|
|
3f2cf9f800 | ||
|
|
db0c7a4e21 | ||
|
|
91464bbd7c | ||
|
|
d7fe2926c7 | ||
|
|
d5fcf60cf7 | ||
|
|
772b21c93a | ||
|
|
c39221378f | ||
|
|
a42f86fcdf | ||
|
|
0dd0db04e2 | ||
|
|
b02ce8a755 | ||
|
|
41dcb8f437 | ||
|
|
35854691bd | ||
|
|
f2e18b95c3 | ||
|
|
16c10593d6 | ||
|
|
dbd870d106 | ||
|
|
f02e992acd | ||
|
|
a7abb0bc5e | ||
|
|
7ca398efdd | ||
|
|
b33c7e09c3 | ||
|
|
0c775851d8 | ||
|
|
89f6aee814 | ||
|
|
44e5857143 | ||
|
|
460de9fc35 |
@@ -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
5
.envrc
Normal file
@@ -0,0 +1,5 @@
|
||||
export DIRENV_WARN_TIMEOUT=20s
|
||||
|
||||
eval "$(devenv direnvrc)"
|
||||
|
||||
use devenv
|
||||
1
.git-blame-ignore-revs
Normal file
1
.git-blame-ignore-revs
Normal file
@@ -0,0 +1 @@
|
||||
766b2cafae4dc74393b103389e6978eca5a9cfd2
|
||||
26
.github/workflows/publish.yml
vendored
Normal file
26
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
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: Set up uv
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
python-version: "${{ matrix.python-version }}"
|
||||
enable-cache: true
|
||||
cache-dependency-glob: |
|
||||
pyproject.toml
|
||||
- name: Build package
|
||||
run: uv build
|
||||
- name: Publish to PyPI
|
||||
run: uv publish --token ${{ secrets.PYPI_API_TOKEN }}
|
||||
26
.github/workflows/pypi-publish.yml
vendored
26
.github/workflows/pypi-publish.yml
vendored
@@ -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
20
.github/workflows/tagging.yml
vendored
Normal 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__
|
||||
129
.github/workflows/tests.yml
vendored
129
.github/workflows/tests.yml
vendored
@@ -1,87 +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, 3.9]
|
||||
requirements-level: [min, pypi]
|
||||
db-service: [postgresql12]
|
||||
search-service: [elasticsearch7]
|
||||
exclude:
|
||||
- python-version: 3.6
|
||||
requirements-level: pypi
|
||||
create-strategy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
- python-version: 3.7
|
||||
requirements-level: min
|
||||
outputs:
|
||||
matrix: ${{ steps.requirements.outputs.matrix }}
|
||||
|
||||
- python-version: 3.8
|
||||
requirements-level: min
|
||||
|
||||
- python-version: 3.9
|
||||
requirements-level: min
|
||||
|
||||
- db-service: postgresql12
|
||||
requirements-level: min
|
||||
|
||||
- search-service: elasticsearch7
|
||||
requirements-level: min
|
||||
|
||||
include:
|
||||
|
||||
- db-service: postgresql12
|
||||
DB_EXTRAS: "postgresql"
|
||||
|
||||
|
||||
- search-service: elasticsearch7
|
||||
SEARCH_EXTRAS: "elasticsearch7"
|
||||
|
||||
env:
|
||||
DB: ${{ matrix.db-service }}
|
||||
SEARCH: ${{ matrix.search-service }}
|
||||
EXTRAS: all,${{ matrix.DB_EXTRAS }},${{ matrix.SEARCH_EXTRAS }}
|
||||
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 "$EXTRAS" --level=${{ matrix.requirements-level }} setup.py > .${{ matrix.requirements-level }}-${{ matrix.python-version }}-requirements.txt
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
# 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
|
||||
|
||||
# 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 ".[$EXTRAS]"
|
||||
pip freeze
|
||||
docker --version
|
||||
docker-compose --version
|
||||
uv sync --group tests
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
./run-tests.sh
|
||||
uv run test
|
||||
|
||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -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
24
.pre-commit-config.yaml
Normal 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]
|
||||
33
.tx/config
33
.tx/config
@@ -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
|
||||
@@ -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
|
||||
|
||||
101
CHANGES.rst
101
CHANGES.rst
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
51
MANIFEST.in
51
MANIFEST.in
@@ -1,51 +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 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
|
||||
recursive-include invenio_config_tugraz *.txt
|
||||
recursive-include invenio_config_tugraz *.html
|
||||
|
||||
|
||||
# added by check-manifest
|
||||
recursive-include invenio_config_tugraz *.csv
|
||||
42
README.rst
42
README.rst
@@ -1,43 +1,47 @@
|
||||
..
|
||||
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/tu-graz-library/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/tu-graz-library/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://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/coveralls/mb-wali/invenio-config-tugraz.svg
|
||||
:target: https://coveralls.io/r/mb-wali/invenio-config-tugraz
|
||||
.. image:: https://img.shields.io/coveralls/mb-wali/invenio-config-iform.svg
|
||||
:target: https://coveralls.io/r/mb-wali/invenio-config-iform
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/psf/black
|
||||
.. image:: https://img.shields.io/badge/code%20style-Ruff-D7FF64.svg
|
||||
:target: https://github.com/astral-sh/ruff
|
||||
|
||||
invenio module that adds tugraz configs.
|
||||
invenio module that adds I-Form configs.
|
||||
|
||||
Override configs from diffrent invenio modules to meet TU Graz requirement:
|
||||
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
|
||||
|
||||
@@ -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,7 +15,6 @@ encoding = utf-8
|
||||
|
||||
[jinja2: **/templates/**.*]
|
||||
encoding = utf-8
|
||||
extensions = jinja2.ext.autoescape, jinja2.ext.with_
|
||||
|
||||
# Extraction from JavaScript files
|
||||
|
||||
|
||||
103
devenv.lock
Normal file
103
devenv.lock
Normal 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
19
devenv.nix
Normal 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
4
devenv.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
|
||||
inputs:
|
||||
nixpkgs:
|
||||
url: github:cachix/devenv-nixpkgs/rolling
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
55
docs/conf.py
55
docs/conf.py
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
11
invenio_config_iform/__about__.py
Normal file
11
invenio_config_iform/__about__.py
Normal 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.6"
|
||||
19
invenio_config_iform/__init__.py
Normal file
19
invenio_config_iform/__init__.py
Normal 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",
|
||||
)
|
||||
@@ -1,61 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2020-2021 Graz University of Technology.
|
||||
# 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.
|
||||
|
||||
"""invenio module that adds tugraz configs."""
|
||||
"""invenio module that adds I-Form configs."""
|
||||
|
||||
from os.path import abspath, dirname, join
|
||||
from invenio_i18n import gettext as _
|
||||
|
||||
from flask_babelex import gettext as _
|
||||
|
||||
INVENIO_CONFIG_TUGRAZ_SHIBBOLETH = False
|
||||
CONFIG_IFORM_SHIBBOLETH = False
|
||||
"""Set True if SAML is configured"""
|
||||
|
||||
INVENIO_CONFIG_TUGRAZ_SINGLE_IP = []
|
||||
CONFIG_IFORM_SINGLE_IPS = []
|
||||
"""Allows access to users whose IP address is listed.
|
||||
|
||||
INVENIO_CONFIG_TUGRAZ_SINGLE_IP =
|
||||
INVENIO_CONFIG_IFORM_SINGLE_IPS =
|
||||
["127.0.0.1", "127.0.0.2"]
|
||||
"""
|
||||
|
||||
INVENIO_CONFIG_TUGRAZ_IP_RANGES = []
|
||||
CONFIG_IFORM_IP_RANGES = []
|
||||
"""Allows access to users whose range of IP address is listed.
|
||||
|
||||
INVENIO_CONFIG_TUGRAZ_IP_RANGES =
|
||||
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_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:",
|
||||
"ub-support.tugraz.at", # zammad contact form
|
||||
"api.datacite.org/dois", # datacite
|
||||
"api.test.datacite.org/dois", # datacite test
|
||||
],
|
||||
},
|
||||
"content_security_policy_report_only": False,
|
||||
@@ -73,6 +67,15 @@ APP_DEFAULT_SECURE_HEADERS = {
|
||||
"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
|
||||
@@ -113,19 +116,22 @@ Set this to False when sending actual emails.
|
||||
# ===========
|
||||
# See https://invenio-userprofiles.readthedocs.io/en/latest/configuration.html
|
||||
|
||||
USERPROFILES_EXTEND_SECURITY_FORMS = False
|
||||
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 = False
|
||||
USERPROFILES_EMAIL_ENABLED = True
|
||||
"""Exclude the user email in the profile form."""
|
||||
|
||||
# Invenio-shibboleth
|
||||
USERPROFILES_READ_ONLY = True
|
||||
"""Allow users to change profile info (name, email, etc...)."""
|
||||
|
||||
# Invenio-saml
|
||||
# ===========
|
||||
# See https://invenio-shibboleth.readthedocs.io/en/latest/configuration.html
|
||||
# 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"""
|
||||
@@ -153,13 +159,16 @@ SSO_SAML_DEFAULT_SLS_ROUTE = "/sls/<idp>"
|
||||
# ===========
|
||||
# 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 = False
|
||||
SECURITY_REGISTERABLE = True
|
||||
""""Allow users to register.
|
||||
|
||||
With this variable set to "False" users will not be
|
||||
@@ -172,6 +181,9 @@ SECURITY_CONFIRMABLE = False
|
||||
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
|
||||
@@ -189,7 +201,7 @@ 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'
|
||||
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
|
||||
@@ -208,8 +220,8 @@ RECAPTCHA_PRIVATE_KEY = None
|
||||
# See:
|
||||
# https://invenio-records-permissions.readthedocs.io/en/latest/configuration.html
|
||||
# Uncomment these to enable overriding RDM permissions
|
||||
# from .rdm_permissions import TUGRAZRDMRecordServiceConfig
|
||||
# RDM_RECORDS_BIBLIOGRAPHIC_SERVICE_CONFIG = TUGRAZRDMRecordServiceConfig
|
||||
# from .rdm_permissions import IformRDMRecordServiceConfig
|
||||
# RDM_RECORDS_BIBLIOGRAPHIC_SERVICE_CONFIG = IformRDMRecordServiceConfig
|
||||
"""Access control configuration for records."""
|
||||
|
||||
# invenio-rdm-records
|
||||
@@ -228,20 +240,22 @@ password from ``users.yaml`` will be used. If that is also absent, a password
|
||||
will be generated randomly.
|
||||
"""
|
||||
|
||||
# Custom Access Right
|
||||
# RDM_RECORDS_CUSTOM_VOCABULARIES = {
|
||||
# 'access_right': {
|
||||
# 'path': join(
|
||||
# dirname(abspath(__file__)),
|
||||
# 'restrictions', 'access_right', 'access_right_limit.csv'
|
||||
# )
|
||||
# }
|
||||
# }
|
||||
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 = {}
|
||||
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
|
||||
@@ -250,6 +264,28 @@ 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."""
|
||||
|
||||
@@ -311,3 +347,31 @@ reopened regularly.
|
||||
|
||||
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.
|
||||
"""
|
||||
14
invenio_config_iform/custom_fields/__init__.py
Normal file
14
invenio_config_iform/custom_fields/__init__.py
Normal 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")
|
||||
61
invenio_config_iform/ext.py
Normal file
61
invenio_config_iform/ext.py
Normal 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)})
|
||||
13
invenio_config_iform/permissions/__init__.py
Normal file
13
invenio_config_iform/permissions/__init__.py
Normal 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",)
|
||||
195
invenio_config_iform/permissions/generators.py
Normal file
195
invenio_config_iform/permissions/generators.py
Normal 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]
|
||||
276
invenio_config_iform/permissions/policies.py
Normal file
276
invenio_config_iform/permissions/policies.py
Normal 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()]
|
||||
21
invenio_config_iform/permissions/roles.py
Normal file
21
invenio_config_iform/permissions/roles.py
Normal 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")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,10 +4,10 @@
|
||||
|
||||
{{ _('To help you get started, here are some useful links:') }}
|
||||
|
||||
- {{ _('Guidelines:')}} {{ _('Repository Guide')}} ({{ _('how to upload files')}}) (https://{{ config.SITE_HOSTNAME }}{{ url_for('invenio_theme_tugraz.guide') }})
|
||||
- {{ _('Search Guide')}} (https://{{ config.SITE_HOSTNAME }}{{url_for('invenio_app_rdm.help_search')}})
|
||||
- {{ _('Terms And Conditions') }} (https://{{ config.SITE_HOSTNAME }}{{ url_for('invenio_theme_tugraz.terms') }})
|
||||
- {{ _('Data Protection Rights')}} (https://{{ config.SITE_HOSTNAME }}{{ url_for('invenio_theme_tugraz.gdpr') }})
|
||||
- {{ _('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 }}">
|
||||
@@ -1,12 +1,12 @@
|
||||
# German translations for invenio-config-tugraz.
|
||||
# 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-tugraz project.
|
||||
# invenio-config-iform project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: invenio-config-tugraz 0.5.5\n"
|
||||
"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"
|
||||
@@ -19,53 +19,53 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.0\n"
|
||||
|
||||
#: invenio_config_tugraz/config.py:87
|
||||
#: invenio_config_iform/config.py:87
|
||||
msgid "Welcome to TU Graz Repository!"
|
||||
msgstr "Willkommen im TU Graz Repository!"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:1
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:1
|
||||
msgid "Dear user,"
|
||||
msgstr "Lieber Nutzer,"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:3
|
||||
#: 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_tugraz/templates/security/email/welcome.txt:5
|
||||
#: 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_tugraz/templates/security/email/welcome.txt:7
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:7
|
||||
msgid "Guidelines:"
|
||||
msgstr "Leitfaden:"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:7
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:7
|
||||
msgid "Repository Guide"
|
||||
msgstr "Handbuch"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:7
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:7
|
||||
msgid "how to upload files"
|
||||
msgstr "wie man Dateien hochlädt"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:8
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:8
|
||||
msgid "Search Guide"
|
||||
msgstr "Suchanleitung"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:9
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:9
|
||||
msgid "Terms And Conditions"
|
||||
msgstr "Nutzungsbedingungen"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:10
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:10
|
||||
msgid "Data Protection Rights"
|
||||
msgstr "Datenschutzerklärung"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:13
|
||||
#: 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_tugraz/templates/security/email/welcome.txt:16
|
||||
#: 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."
|
||||
@@ -73,11 +73,10 @@ msgstr ""
|
||||
"Wenn Sie Hilfe benötigen, zögern Sie bitte nicht, uns unter repository-"
|
||||
"support@tugraz.at zu kontaktieren."
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:18
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:18
|
||||
msgid "Best regards,"
|
||||
msgstr "Mit freundlichen Grüßen,"
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:19
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:19
|
||||
msgid "TU Graz Repository Team"
|
||||
msgstr "TU Graz Repository Team"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# Translations template for invenio-config-tugraz.
|
||||
# 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-tugraz project.
|
||||
# invenio-config-iform project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: invenio-config-tugraz 0.5.5\n"
|
||||
"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"
|
||||
@@ -18,61 +18,60 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.9.0\n"
|
||||
|
||||
#: invenio_config_tugraz/config.py:87
|
||||
#: invenio_config_iform/config.py:87
|
||||
msgid "Welcome to TU Graz Repository!"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:1
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:1
|
||||
msgid "Dear user,"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:3
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:3
|
||||
msgid "Welcome to the Repository of TU Graz!"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:5
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:5
|
||||
msgid "To help you get started, here are some useful links:"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:7
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:7
|
||||
msgid "Guidelines:"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:7
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:7
|
||||
msgid "Repository Guide"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:7
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:7
|
||||
msgid "how to upload files"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:8
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:8
|
||||
msgid "Search Guide"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:9
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:9
|
||||
msgid "Terms And Conditions"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:10
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:10
|
||||
msgid "Data Protection Rights"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:13
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:13
|
||||
msgid "You can confirm your email through the link below:"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:16
|
||||
#: 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_tugraz/templates/security/email/welcome.txt:18
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:18
|
||||
msgid "Best regards,"
|
||||
msgstr ""
|
||||
|
||||
#: invenio_config_tugraz/templates/security/email/welcome.txt:19
|
||||
#: invenio_config_iform/templates/security/email/welcome.txt:19
|
||||
msgid "TU Graz Repository Team"
|
||||
msgstr ""
|
||||
|
||||
73
invenio_config_iform/utils.py
Normal file
73
invenio_config_iform/utils.py
Normal 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")
|
||||
67
invenio_config_iform/views.py
Normal file
67
invenio_config_iform/views.py
Normal 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,
|
||||
),
|
||||
)
|
||||
@@ -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")
|
||||
@@ -1,88 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2020-2021 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()]
|
||||
@@ -1,32 +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 flask import Blueprint
|
||||
|
||||
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))
|
||||
@@ -1,223 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2020-2021 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.
|
||||
|
||||
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, 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
|
||||
@@ -1,86 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2020-2021 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 RDMRecordPermissionPolicy
|
||||
from invenio_rdm_records.services.config import RDMRecordServiceConfig
|
||||
from invenio_rdm_records.services.generators import IfDraft, IfRestricted, RecordOwners
|
||||
from invenio_records_permissions.generators import (
|
||||
Admin,
|
||||
AnyUser,
|
||||
AuthenticatedUser,
|
||||
Disable,
|
||||
SuperUser,
|
||||
SystemProcess,
|
||||
)
|
||||
|
||||
|
||||
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.
|
||||
Access control configuration for records.
|
||||
Note that even if the array is empty, the invenio_access Permission class
|
||||
always adds the ``superuser-access``, so admins will always be allowed.
|
||||
- Create action given to everyone for now.
|
||||
- Read access given to everyone if public record and given to owners
|
||||
always. (inherited)
|
||||
- Update access given to record owners. (inherited)
|
||||
- Delete access given to admins only. (inherited)
|
||||
"""
|
||||
|
||||
|
||||
class TUGRAZRDMRecordServiceConfig(RDMRecordServiceConfig):
|
||||
"""Overriding BibliographicRecordServiceConfig."""
|
||||
@@ -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.5.8"
|
||||
@@ -1,44 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2020-2021 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 for TUGRAZ config."""
|
||||
|
||||
from os import environ
|
||||
from typing import Dict
|
||||
|
||||
from elasticsearch_dsl.utils import AttrDict
|
||||
from flask import Blueprint, current_app
|
||||
|
||||
|
||||
def ui_blueprint(app):
|
||||
"""Blueprint for the routes and resources provided by invenio-config-tugraz."""
|
||||
blueprint = Blueprint(
|
||||
"invenio_config_tugraz",
|
||||
__name__,
|
||||
template_folder="templates",
|
||||
)
|
||||
|
||||
@blueprint.before_app_first_request
|
||||
def rank_higher():
|
||||
"""Rank this modules blueprint higher than blueprint of security module."""
|
||||
blueprints = current_app._blueprint_order
|
||||
our_index = None
|
||||
security_index = None
|
||||
|
||||
for index, bp in enumerate(blueprints):
|
||||
if bp.name == "security":
|
||||
security_index = index
|
||||
if bp.name == "invenio_config_tugraz":
|
||||
our_index = index
|
||||
|
||||
if (security_index is not None) and (our_index > security_index):
|
||||
temp = blueprints[security_index]
|
||||
blueprints[security_index] = blueprints[our_index]
|
||||
blueprints[our_index] = temp
|
||||
|
||||
return blueprint
|
||||
150
pyproject.toml
Normal file
150
pyproject.toml
Normal 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/"
|
||||
12
pytest.ini
12
pytest.ini
@@ -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
|
||||
@@ -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
|
||||
33
run-tests.sh
33
run-tests.sh
@@ -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"
|
||||
126
scripts/hooks/pre-push/check_version_increment.py
Executable file
126
scripts/hooks/pre-push/check_version_increment.py
Executable 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
19
scripts/test.py
Normal 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
16
scripts/test_docs.py
Normal 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"])
|
||||
56
setup.cfg
56
setup.cfg
@@ -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 = Graz University of Technology
|
||||
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
|
||||
115
setup.py
115
setup.py
@@ -1,115 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2020-2021 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."""
|
||||
|
||||
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",
|
||||
"invenio-app>=1.3.0,<2.0.0",
|
||||
]
|
||||
|
||||
# Should follow invenio-app-rdm
|
||||
invenio_search_version = ">=1.4.0,<1.5.0"
|
||||
invenio_db_version = ">=1.0.9,<1.1.0"
|
||||
|
||||
extras_require = {
|
||||
"elasticsearch7": [f"invenio-search[elasticsearch7]{invenio_search_version}"],
|
||||
"mysql": [f"invenio-db[mysql,versioning]{invenio_db_version}"],
|
||||
"postgresql": [f"invenio-db[postgresql,versioning]{invenio_db_version}"],
|
||||
"sqlite": [f"invenio-db[versioning]{invenio_db_version}"],
|
||||
"docs": [
|
||||
"Sphinx>=3",
|
||||
],
|
||||
"tests": tests_require,
|
||||
}
|
||||
|
||||
extras_require["all"] = []
|
||||
for name, reqs in extras_require.items():
|
||||
if name[0] == ":" or name in (
|
||||
"elasticsearch7",
|
||||
"mysql",
|
||||
"postgresql",
|
||||
"sqlite",
|
||||
):
|
||||
continue
|
||||
extras_require["all"].extend(reqs)
|
||||
|
||||
setup_requires = [
|
||||
"Babel>=1.3",
|
||||
"pytest-runner>=3.0.0,<5",
|
||||
]
|
||||
|
||||
install_requires = [
|
||||
"Flask-BabelEx>=0.9.4",
|
||||
# keep this in sync with invenioRDM release
|
||||
"invenio_app_rdm==3.0.0",
|
||||
]
|
||||
|
||||
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_base.blueprints": [
|
||||
"invenio_config_tugraz = invenio_config_tugraz.views:ui_blueprint",
|
||||
],
|
||||
"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",
|
||||
],
|
||||
)
|
||||
@@ -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.
|
||||
|
||||
TODO: Remove this fixture if you add Celery support.
|
||||
"""
|
||||
return {}
|
||||
|
||||
|
||||
@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()
|
||||
def create_app(instance_path: str) -> Flask:
|
||||
"""Application factory fixture."""
|
||||
|
||||
def factory(**config: str) -> Flask:
|
||||
app = Flask("testapp", instance_path=instance_path)
|
||||
app.config.update(**config)
|
||||
InvenioConfigIform(app)
|
||||
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
|
||||
|
||||
@@ -1,29 +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
|
||||
|
||||
from invenio_config_tugraz.generators import 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'}}]}}
|
||||
33
tests/test_invenio_config_iform.py
Normal file
33
tests/test_invenio_config_iform.py
Normal 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
|
||||
@@ -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
88
tests/test_policies.py
Normal 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)
|
||||
Reference in New Issue
Block a user