Skip to content

Commit

Permalink
add alert, update docs (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikkonie committed Jan 14, 2025
1 parent d5ecc0e commit 21d1dc5
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 67 deletions.
9 changes: 5 additions & 4 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ Added
- App setting ``user_modifiable`` validation (#1536)
- ``AppSettingAPI.get_all_by_scope()`` helper (#1534)
- ``removeroles`` management command (#1391, #1541)
- Site read only mode (#21)
- ``site_read_only`` site app setting (#21)
- ``is_site_writable()`` rule predicate (#21)
- ``PermissionTestMixin.set_site_read_only()`` helper (#21)
- Site read only mode (#24)
- ``site_read_only`` site app setting (#24)
- ``is_site_writable()`` rule predicate (#24)
- ``PermissionTestMixin.set_site_read_only()`` helper (#24)
- ``PROJECTROLES_READ_ONLY_MSG`` setting (#24)

Changed
-------
Expand Down
6 changes: 4 additions & 2 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -626,15 +626,17 @@ def set_logging(level=None):
)

# Optional projectroles settings
# Sidebar icon size. Minimum=18, maximum=42.
# Sidebar icon size (must be between 18-42)
PROJECTROLES_SIDEBAR_ICON_SIZE = env.int('PROJECTROLES_SIDEBAR_ICON_SIZE', 36)
# PROJECTROLES_SECRET_LENGTH = 32
# PROJECTROLES_HELP_HIGHLIGHT_DAYS = 7
# PROJECTROLES_SEARCH_PAGINATION = 5
# Support for viewing the site in "kiosk mode" (under work, experimental)
# Support for viewing the site in "kiosk mode" (experimental)
# PROJECTROLES_KIOSK_MODE = env.bool('PROJECTROLES_KIOSK_MODE', False)
# Scroll project navigation with page content if set False
# PROJECTROLES_BREADCRUMB_STICKY = True
# Custom message to be displayed if site read-only mode is enabled
PROJECTROLES_READ_ONLY_MSG = env.str('PROJECTROLES_READ_ONLY_MSG', None)

# Hide project apps from the UI (sidebar, dropdown menus and project details)
PROJECTROLES_HIDE_PROJECT_APPS = env.list(
Expand Down
5 changes: 2 additions & 3 deletions docs/source/app_projectroles_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,5 @@ name and/or description.
REST API
========

Several SODAR Core functionalities are also available via a HTTP REST API
starting in version 0.8. See :ref:`app_projectroles_api_rest` for instructions
on REST API usage.
Several SODAR Core functionalities are also available via a REST API. See
:ref:`app_projectroles_api_rest` for instructions on REST API usage.
10 changes: 5 additions & 5 deletions docs/source/dev_project_app.rst
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,11 @@ app if needed.

.. hint::

To support the site read-only mode introduced in SODAR Core v1.1, you should
ensure your data-modifying views respect it. Check for the read-only mode is
built-in to ``can_modify_project_data``, so if your view already uses that
predicate, no further steps are necessary. For non-project views,
``is_site_writable`` should be used. For more information, see
To support the site read-only mode introduced in SODAR Core v1.1, the rules
for your app's views need to be implemented accordingly. A check for the
read-only mode is built-in to ``can_modify_project_data``. If your view
already uses that predicate, no further steps are necessary. For non-project
views, ``is_site_writable`` should be used. For more information, see
:ref:`dev_resources_read_only`.


Expand Down
74 changes: 74 additions & 0 deletions docs/source/dev_resource.rst
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,80 @@ when creating multi-plugin apps:
This, again, ensures apps are correctly detected and highlighted in the UI.
.. _dev_resources_read_only:
Site Read-Only Mode
===================
A superuser can temporarily set the site to read-only mode. When this mode is
enabled, all data on the site is only accessible for reading. No project or user
data should be modifiable.
SODAR Core apps enforce this mode by prohibiting access to views and/or UI
elements which enable the user to modify data. Apps developed for a SODAR Core
based site must implement this within their rule and UI logic.
If your data modifying view is in a project app and uses the
``can_modify_project_data()`` rule predicate, checks for view access are already
done for that view. Example of this in a ``rules.py`` file:
.. code-block:: python
import rules
from projectroles import rules as pr_rules
rules.add_perm(
'your_project_app.update_data',
pr_rules.can_modify_project_data
& (
pr_rules.is_project_owner
| pr_rules.is_project_delegate
| pr_rules.is_project_contributor
),
)
For site apps, you can use the ``is_site_writable()`` predicate. Example:
.. code-block:: python
import rules
from projectroles import rules as pr_rules
rules.add_perm(
'your_site_app.update_data',
rules.is_authenticated & pr_rules.is_site_writable,
)
To check for the mode in your Python code, you should use the app settings API
as follows:
.. code-block:: python
from projectroles.app_settings import AppSettingAPI
app_settings = AppSettingAPI()
if app_settings.get('projectroles', 'site_read_only'):
pass # Add logic for read-only mode here
In templates, the same can be done using the ``get_app_setting()`` template tag.
Example:
.. code-block:: django
{% load projectroles_common_tags %}
{% get_app_setting 'projectroles' 'site_read_only' as site_read_only %}
{% if site_read_only %}
{# ... #}
{% endif %}
.. note::
It is assumed that in read-only mode, superusers are still able to access
data modifying views and operations. The rule settings also allow this.
Actions within management command should thus also be allowed in read-only
mode, as they are only accessible by administrators.
Management Command Logger
=========================
Expand Down
8 changes: 8 additions & 0 deletions docs/source/major_changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ Release Highlights
Breaking Changes
================

Site Read-Only Mode Implemented
-------------------------------

This release adds the site-wide read-only mode, which is intended to temporarily
prohibit modifying all data on the site. The rules, logic and/or UI of your
views may have to be changed to support this functionality. For more
information, see :ref:`dev_resources_read_only`.

AppSettingAPI Definition Getter Return Data
-------------------------------------------

Expand Down
65 changes: 40 additions & 25 deletions projectroles/templates/projectroles/_messages.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,54 @@
{% load projectroles_common_tags %}

{% get_site_app_messages request.user as site_app_messages %}
{% get_app_setting 'projectroles' 'site_read_only' as site_read_only %}

{% if messages or site_app_messages %}
{% if site_read_only or messages or site_app_messages %}
<div class="container-fluid sodar-alert-container">

{# Site app messages #}
{% for message in site_app_messages %}
{% if request.user.is_authenticated or not message.require_auth %}
<div class="alert alert-{{ message.color }} {% if message.dismissable %}alert-dismissable fade show{% endif %} sodar-alert-top sodar-alert-site-app">
{# Site read-only mode message #}
{% if site_read_only %}
{% get_django_setting 'PROJECTROLES_READ_ONLY_MSG' as read_only_msg %}
<div class="alert alert-danger sodar-alert-top sodar-alert-site-read-only">
<div class="sodar-alert-top-content">
{% comment %}
{% if message.dismissable %}
<a href="#" data-dismiss="alert" class="pull-right sodar-alert-close-link">
<i class="iconify text-muted" data-icon="mdi:close-thick"></i>
</a>
<i class="iconify" data-icon="mdi:cancel"></i>
{% if read_only_msg %}
{{ read_only_msg }}
{% else %}
This site is currently in read-only mode. Modifying data is not
permitted.
{% endif %}
{% endcomment %}
{{ message.content | safe }}
</div>
</div>
{% endif %}
{% endfor %}

{# Regular Django messages #}
{% for message in messages %}
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %} alert-dismissable fade show sodar-alert-top">
<div class="sodar-alert-top-content">
{{ message }}
<a href="#" data-dismiss="alert" class="pull-right sodar-alert-close-link">
<i class="iconify text-muted" data-icon="mdi:close-thick"></i>
</a>
</div>
</div>
{% endfor %}
{# Site app messages #}
{% for message in site_app_messages %}
{% if request.user.is_authenticated or not message.require_auth %}
<div class="alert alert-{{ message.color }} {% if message.dismissable %}alert-dismissable fade show{% endif %} sodar-alert-top sodar-alert-site-app">
<div class="sodar-alert-top-content">
{% comment %}
{% if message.dismissable %}
<a href="#" data-dismiss="alert" class="pull-right sodar-alert-close-link">
<i class="iconify text-muted" data-icon="mdi:close-thick"></i>
</a>
{% endif %}
{% endcomment %}
{{ message.content | safe }}
</div>
</div>
{% endif %}
{% endfor %}

{# Regular Django messages #}
{% for message in messages %}
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% endif %} alert-dismissable fade show sodar-alert-top">
<div class="sodar-alert-top-content">
{{ message }}
<a href="#" data-dismiss="alert" class="pull-right sodar-alert-close-link">
<i class="iconify text-muted" data-icon="mdi:close-thick"></i>
</a>
</div>
</div>
{% endfor %}
</div>
{% endif %}
3 changes: 0 additions & 3 deletions projectroles/templates/projectroles/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,8 @@
{% include 'projectroles/_footer.html' %}
{% endif %}
</footer>

</div> <!-- /sodar-app-container -->

</div> <!-- /sodar-content-right -->

{% endblock content %}

{% block javascript %}
Expand Down
25 changes: 0 additions & 25 deletions projectroles/templates/projectroles/base_site.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@
{% endif %}

{% block head_javascript %}

<!-- Critical Javascript includes -->
{# NOTE: The rest are included under the "javascript" block at the end #}

<!-- Iconify SVG icons -->
<script type="text/javascript" src="{% url 'config.js' %}"></script>
<script type="text/javascript" src="{% static 'projectroles/js/iconify.min.js' %}"></script>
Expand All @@ -46,17 +44,14 @@
<!--[if lt IE 9]>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<![endif]-->

<!-- JQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

<!-- Required by Bootstrap v4 -->
<!--<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<!-- Shepherd -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.4/js/tether.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/shepherd/1.8.1/js/shepherd.min.js"></script>

<!-- Clipboard helper -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js"></script>
{% endif %}
Expand All @@ -65,68 +60,52 @@
{% for js_inc in custom_js_includes %}
<script type="text/javascript" src="{{ js_inc }}"></script>
{% endfor %}

{% endblock head_javascript %}

{% block css %}

<!-- CSS includes -->

<!-- Fix for pull-right/pull-left bug when including imports -->
<style type="text/css">
.pull-right {
float: right;
}

.pull-left {
float: left;
}
</style>

{% if not disable_cdn_includes %}
<!-- Bootstrap 4 CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">

{% endif %}

{# Custom CSS includes #}
{% for css_inc in custom_css_includes %}
<link rel="stylesheet" type="text/css" href="{{ css_inc }}" />
{% endfor %}

<!-- Local CSS Includes -->

<!-- Shepherd theme -->
<link rel="stylesheet" type="text/css" href="{% static 'projectroles/css/shepherd-theme-sodar.css' %}" />

<!-- Projectroles custom CSS -->
<link rel="stylesheet" type="text/css" href="{% static 'projectroles/css/projectroles.css' %}" />

<!-- Project CSS -->
<link rel="stylesheet" type="text/css" href="{% static 'css/project.css' %}" />

{% endblock css %}

{% block head_extend %}
{# Extended head stuff from apps goes here #}
{% endblock head_extend %}
</head>

<body>

<div class="sodar-base-container" id="sodar-base-container">

<div class="sodar-top-container" id="sodar-top-container">
{# Projectroles site title bar #}
{% include 'projectroles/_site_titlebar.html' %}
</div> <!-- /sodar-top-container -->

<div class="sodar-content-container" id="sodar-content-container">
{% block content %}
<p>Use this document as a way to quick start any new project.</p>
{% endblock content %}
</div> <!-- /sodar-content-container -->

</div> <!-- /sodar-base-container -->

{# Custom template for Bootstrap4 modal #}
Expand All @@ -142,14 +121,10 @@
{% get_django_setting name='PROJECTROLES_BROWSER_WARNING' js=True as browser_warning %}
window.sodarBrowserWarning = {{ browser_warning }};
</script>

<!-- General project Javascript -->
<script type="text/javascript" src="{% static 'js/project.js' %}"></script>

<!-- App alerts Javascript -->
{% include 'projectroles/_appalerts_include.html' %}
{% endblock javascript %}

</body>

</html>
Loading

0 comments on commit 21d1dc5

Please sign in to comment.