Skip to content

Commit

Permalink
organisations: access records with specific URL
Browse files Browse the repository at this point in the history
* Adds a property `isShared` in organisation to allow access to records by a specific URL.
* Adds a property `isDedicated` in organisation to allow organisation to have a specific theme and logo.
* Adds a specific route to document details instead of built-in invenio view.
* Adds a method to get current view code in templates.
* Renames `ir` query parameter to `view` for consistency.
* Stores current organisation record in Flask globals.
* Adds a header containing current organisation information in templates.
* Checks if organisation is flagged as dedicated for including custom logo and styles.
* Closes #216.

Co-Authored-by: Sébastien Délèze <sebastien.deleze@rero.ch>
  • Loading branch information
Sébastien Délèze committed Jun 17, 2020
1 parent 5af14d6 commit d9b6761
Show file tree
Hide file tree
Showing 22 changed files with 325 additions and 151 deletions.
5 changes: 0 additions & 5 deletions sonar/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,6 @@ def _(x):
SECURITY_REGISTER_USER_TEMPLATE = 'sonar/accounts/signup.html'

RECORDS_UI_ENDPOINTS = {
'document': {
'pid_type': 'doc',
'route': '/organisation/<ir>/documents/<pid_value>',
'view_imp': 'sonar.modules.documents.views:detail'
},
'doc_previewer': {
'pid_type': 'doc',
'route': '/documents/<pid_value>/preview/<filename>',
Expand Down
4 changes: 3 additions & 1 deletion sonar/modules/documents/dojson/rerodoc/overdo.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ def create_organisation(organisation_key):
organisation = OrganisationRecord.create(
{
'code': organisation_key,
'name': organisation_key
'name': organisation_key,
'isShared': False,
'isDedicated': False
},
dbcommit=True)
organisation.reindex()
Expand Down
2 changes: 1 addition & 1 deletion sonar/modules/documents/templates/documents/record.html
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ <h5 class="text-secondary">{{ _(record.organisation.name) }}</h5>
{% endif %}

<!-- PERMANENT LINK -->
{% set link = url_for('invenio_records_ui.document', pid_value=record.pid, ir=g.ir|default('sonar'), _external=True) %}
{% set link = url_for('documents.detail', pid_value=record.pid, view=view_code, _external=True) %}
{{ dl(_('Permalink'), '<a href="' + link + '">' + link + '</a>') }}
</dl>
</div>
Expand Down
64 changes: 43 additions & 21 deletions sonar/modules/documents/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
import re
from datetime import datetime

from flask import Blueprint, current_app, g, render_template, request
from flask import Blueprint, abort, current_app, g, render_template, request
from flask_babelex import gettext as _

from sonar.modules.documents.api import DocumentRecord
from sonar.modules.organisations.api import OrganisationRecord
from sonar.modules.utils import change_filename_extension

from .utils import publication_statement_text, series_format_text
Expand All @@ -33,7 +35,7 @@
__name__,
template_folder='templates',
static_folder='static',
url_prefix='/organisation/<ir>')
url_prefix='/organisation/<view>')
"""Blueprint used for loading templates and static assets
The sole purpose of this blueprint is to ensure that Invenio can find the
Expand All @@ -43,33 +45,50 @@


@blueprint.url_defaults
def add_ir(endpoint, values):
"""Add default ir parameter."""
values.setdefault('ir', 'sonar')
def default_view_code(endpoint, values):
"""Add default view code."""
values.setdefault('view',
current_app.config.get('SONAR_APP_DEFAULT_ORGANISATION'))


@blueprint.url_value_preprocessor
def pull_ir(endpoint, values):
"""Add ir parameter to global variables."""
g.ir = values.pop('ir')
def store_organisation(endpoint, values):
"""Add organisation record to global variables."""
view = values.pop('view',
current_app.config.get('SONAR_APP_DEFAULT_ORGANISATION'))

if view != current_app.config.get('SONAR_APP_DEFAULT_ORGANISATION'):
organisation = OrganisationRecord.get_record_by_pid(view)

if not organisation or not organisation['isShared']:
raise Exception('Organisation\'s view is not accessible')

g.organisation = organisation.dumps()


@blueprint.route('/')
def index():
"""IR (and SONAR) home view."""
"""Homepage."""
return render_template('sonar/frontpage.html')


@blueprint.route('/search/<resource_type>')
def search(resource_type=None):
"""IR search results."""
@blueprint.route('/search/documents')
def search():
"""Search results page."""
return render_template('sonar/search.html')


def detail(pid, record, template=None, **kwargs):
"""Search details."""
g.ir = kwargs.get('ir')
return render_template('documents/record.html', pid=pid, record=record)
@blueprint.route('/documents/<pid_value>')
def detail(pid_value):
"""Document detail page."""
record = DocumentRecord.get_record_by_pid(pid_value)

if not record:
abort(404)

return render_template('documents/record.html',
pid=pid_value,
record=record)


@blueprint.app_template_filter()
Expand Down Expand Up @@ -301,7 +320,7 @@ def is_restricted_by_scope(file):
'SONAR_APP_INTERNAL_IPS')

# File is restricted by organisation
organisation = get_current_organisation()
organisation = get_current_organisation_code()

# We are in global organisation, so restriction is active
if organisation == current_app.config.get(
Expand Down Expand Up @@ -389,13 +408,16 @@ def get_preferred_languages(force_language=None):
return list(dict.fromkeys(preferred_languages))


def get_current_organisation():
def get_current_organisation_code():
"""Return current organisation by globals or query parameter."""
# Organisation is present in query parameters, useful for API calls.
organisation = request.args.get('view')
if organisation:
return organisation

if g.get('ir'):
return g.ir
# Organisation stored in globals
if g.get('organisation', {}).get('code'):
return g.organisation['code']

return None
# Default organisation
return current_app.config.get('SONAR_APP_DEFAULT_ORGANISATION')
5 changes: 3 additions & 2 deletions sonar/modules/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

from sonar.modules.permissions import has_admin_access, has_publisher_access, \
has_superuser_access
from sonar.modules.utils import get_switch_aai_providers
from sonar.modules.utils import get_switch_aai_providers, get_view_code

from . import config

Expand All @@ -38,7 +38,8 @@ def utility_processor():
has_admin_access=has_admin_access,
has_superuser_access=has_superuser_access,
ui_version=config.SONAR_APP_UI_VERSION,
aai_providers=get_switch_aai_providers)
aai_providers=get_switch_aai_providers,
view_code=get_view_code())


class Sonar(object):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,28 @@
"title": "Name",
"type": "string",
"minLength": 1
},
"isShared": {
"title": "Is shared",
"description": "Organisation records can be accessed by a specific URL.",
"type": "boolean",
"default": false
},
"isDedicated": {
"title": "Is dedicated",
"description": "Organisation has a specific theme for his view.",
"type": "boolean",
"default": false,
"form": {
"hideExpression": "!field.model.isShared"
}
}
},
"propertiesOrder": [
"code",
"name"
"name",
"isShared",
"isDedicated"
],
"required": [
"pid",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
"code": {
"type": "keyword"
},
"name": {
"type": "text"
"isShared": {
"type": "boolean"
},
"isDedicated": {
"type": "boolean"
},
"_created": {
"type": "date"
Expand Down
2 changes: 2 additions & 0 deletions sonar/modules/organisations/marshmallow/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ class OrganisationMetadataSchemaV1(StrictKeysMixin):
pid = PersistentIdentifier()
code = SanitizedUnicode(required=True)
name = SanitizedUnicode(required=True)
isShared = fields.Boolean()
isDedicated = fields.Boolean()
# When loading, if $schema is not provided, it's retrieved by
# Record.schema property.
schema = GenFunction(load_only=True,
Expand Down
13 changes: 12 additions & 1 deletion sonar/modules/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import re

from flask import current_app
from flask import current_app, g
from invenio_i18n.ext import current_i18n
from invenio_mail.api import TemplatedMessage
from wand.color import Color
Expand Down Expand Up @@ -118,3 +118,14 @@ def remove_trailing_punctuation(data,
def get_current_language():
"""Return the current selected locale."""
return current_i18n.locale.language


def get_view_code():
"""Return view code corresponding to organisation.
:returns: View code as string.
"""
if g.get('organisation'):
return g.organisation['code']

return current_app.config.get('SONAR_APP_DEFAULT_ORGANISATION')
6 changes: 3 additions & 3 deletions sonar/theme/assets/scss/common/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@
background-color: #15334D;
}

.bg-ir {
background-color: $bg-ir;
.bg-organisation {
background-color: $bg-organisation;
}

img.logo {
width: 100%;
max-height: 90px;
}

.text-ir {
.text-organisation {
@extend .text-light
}

Expand Down
2 changes: 1 addition & 1 deletion sonar/theme/assets/scss/common/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ $fa-font-path: "~font-awesome/fonts";
$primary: #205078 !default;
$secondary: rgb(246, 130, 17) !default;

$bg-ir: $primary !default;
$bg-organisation: $primary !default;

$font-family-base: 'Roboto', sans-serif;
11 changes: 6 additions & 5 deletions sonar/theme/templates/sonar/frontpage.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@
{%- extends config.BASE_TEMPLATE %}

{% block header %}
<div class="bg-ir p-4">
<div class="bg-organisation p-4">
<div class="container">
<div class="row justify-content-center">
<div class="col-8 col-xs-6 col-lg-4 py-3 py-sm-5">
<a href="{{ url_for('documents.index', ir=g.ir|default('sonar')) }}">
<a href="{{ url_for('documents.index', view=view_code) }}">
{%- if config.THEME_LOGO %}
<img src="{{ url_for('static', filename='images/' ~ g.ir|default('sonar') ~ '-logo.svg')}}" alt="{{_(config.THEME_SITENAME)}}" class="logo"/>
{% set logo_code = view_code if g.get('organisation', {}).get('isDedicated') else config.SONAR_APP_DEFAULT_ORGANISATION %}
<img src="{{ url_for('static', filename='images/' ~ logo_code ~ '-logo.svg')}}" alt="{{_(config.THEME_SITENAME)}}" class="logo"/>
{%- else %}
{{_(config.THEME_SITENAME)}}
{%- endif %}
Expand All @@ -35,14 +36,14 @@
</div>
<div class="row justify-content-center">
<div class="col-sm-12 col-lg-8 text-right my-4">
<form class="justify-content-end" action="{{ url_for('documents.search', ir=g.ir|default('sonar'), resource_type='documents') }}" role="search">
<form class="justify-content-end" action="{{ url_for('documents.search', view=view_code) }}" role="search">
<div class="row">
<div class="col-12 col-sm-11">
<input class="form-control form-control-lg mr-2" type="search" placeholder="{{_('Search publications, authors, projects, ...')}}" aria-label="Search" name="q">
</div>
<div class="col-2 col-sm-1 d-none d-sm-block">
<button class="btn btn-link btn-lg" type="submit">
<i class="fa fa-search fa-lg text-ir"></i>
<i class="fa fa-search fa-lg text-organisation"></i>
</button>
</div>
</div>
Expand Down
6 changes: 5 additions & 1 deletion sonar/theme/templates/sonar/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@
{%- endblock head_links %}

{%- block css %}
{{ webpack[g.ir|default('sonar') ~ '-theme.css'] }}
{% if g.get('organisation', {}).get('isDedicated') %}
{{ webpack[view_code ~ '-theme.css'] }}
{% else %}
{{ webpack['sonar-theme.css'] }}
{% endif %}
{# assets "invenio_theme_css" %}<link href="{{ ASSET_URL }}" rel="stylesheet">{% endassets #}
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
Expand Down
Loading

0 comments on commit d9b6761

Please sign in to comment.