Skip to content

Commit

Permalink
users: create user record on registration
Browse files Browse the repository at this point in the history
* Creates a user record when a new account is registered.
* Disables `invenio-userprofiles` module.
* Exposes and uses user record for displaying user information in templates.
* Gives role `user` by default when a new record is created.
* Removes `organisation` from required fields for users.
* Hides `applications` and `security` menu entries.
* Creates a new page for editing user data.
* Removes useless CSS rules
* Adds CSS rules for standalone editor.
* Customizes settings page.

Co-Authored-by: Sébastien Délèze <[email protected]>
  • Loading branch information
Sébastien Délèze committed Jun 18, 2020
1 parent d9b6761 commit 804ca2f
Show file tree
Hide file tree
Showing 22 changed files with 267 additions and 96 deletions.
2 changes: 1 addition & 1 deletion sonar/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def _(x):

# User profiles
# =============
USERPROFILES_EXTEND_SECURITY_FORMS = True
USERPROFILES = False

# Celery configuration
# ====================
Expand Down
9 changes: 8 additions & 1 deletion sonar/modules/ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
import jinja2
from flask_assets import Bundle, Environment
from flask_bootstrap import Bootstrap
from flask_security import user_registered
from flask_wiki import Wiki

from sonar.modules.permissions import has_admin_access, has_publisher_access, \
has_superuser_access
from sonar.modules.users.api import current_user_record
from sonar.modules.users.signals import user_registered_handler
from sonar.modules.utils import get_switch_aai_providers, get_view_code

from . import config
Expand All @@ -39,7 +42,8 @@ def utility_processor():
has_superuser_access=has_superuser_access,
ui_version=config.SONAR_APP_UI_VERSION,
aai_providers=get_switch_aai_providers,
view_code=get_view_code())
view_code=get_view_code(),
current_user_record=current_user_record)


class Sonar(object):
Expand Down Expand Up @@ -82,6 +86,9 @@ def init_app(self, app):

app.context_processor(utility_processor)

# Connect to signal sent when a user is created in Flask-Security.
user_registered.connect(user_registered_handler, weak=False)

def init_config(self, app):
"""Initialize configuration."""
for k in dir(config):
Expand Down
10 changes: 8 additions & 2 deletions sonar/modules/users/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,15 @@ def import_users(infile):
password = hash_password(password)
del user_data['password']

if not user_data.get('roles'):
user_data['roles'] = [UserRecord.ROLE_USER]

roles = user_data.get('roles', []).copy()
if not roles or not isinstance(roles, list):
roles = []

for role in roles:
if not datastore.find_role(role):
datastore.create_role(name=role)
datastore.commit()

# Create account and activate it
datastore.create_user(email=email, password=password, roles=roles)
Expand Down
1 change: 0 additions & 1 deletion sonar/modules/users/jsonschemas/users/user-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@
"full_name",
"email",
"roles",
"organisation",
"$schema"
]
}
44 changes: 44 additions & 0 deletions sonar/modules/users/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
#
# Swiss Open Access Repository
# Copyright (C) 2019 RERO
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Signals for users."""

from sonar.modules.users.api import UserRecord, datastore


def user_registered_handler(app, user, confirm_token):
"""Called when a new user is registered.
:param app: App context.
:param user: User account.
"""
# Add a default role to user
role = datastore.find_role(UserRecord.ROLE_USER)
datastore.add_role_to_user(user, role)
datastore.commit()

# Create user record
user_record = UserRecord.get_user_by_email(user.email)
if not user_record:
user_record = UserRecord.create(
{
'full_name': user.email,
'email': user.email,
'roles': [UserRecord.ROLE_USER]
},
dbcommit=True)
user_record.reindex()
25 changes: 4 additions & 21 deletions sonar/theme/assets/scss/common/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,8 @@ img.logo {
@extend .text-light
}

// CSS code to allow `ng-csp="no-inline-css"`
[ng\:cloak],
[ng-cloak],
[data-ng-cloak],
[x-ng-cloak],
.ng-cloak,
.x-ng-cloak,
.ng-hide:not(.ng-hide-animate) {
display: none !important;
}

ng\:form {
display: block;
}

.ng-animate-shim {
visibility:hidden;
}

.ng-anchor {
position:absolute;
.standalone-editor {
legend, button.btn-outline-danger {
display: none;
}
}
36 changes: 36 additions & 0 deletions sonar/theme/templates/sonar/accounts/profile.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{# -*- coding: utf-8 -*-
Swiss Open Access Repository
Copyright (C) 2019 RERO

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
#}

{% extends 'sonar/page_settings.html' %}

{%- block settings_body scoped %}
<div class="standalone-editor">
<sonar-root></sonar-root>
</div>
{%- endblock settings_body %}

{%- block javascript %}
<script src="/static/sonar-ui/runtime.js?{{ ui_version }}"></script>
<script src="/static/sonar-ui/polyfills.js?{{ ui_version }}"></script>
<script src="/static/sonar-ui/main.js?{{ ui_version }}"></script>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
{%- endblock javascript %}
2 changes: 0 additions & 2 deletions sonar/theme/templates/sonar/accounts/signup.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ <h4 class="text-center mb-4">
<form action="{{ url_for_security('register') }}" method="POST" name="register_user_form">
{{ form_errors(form) }}
{{ form.hidden_tag() }}
{{ render_field(form.profile.full_name, errormsg=False) }}
{{ render_field(form.profile.username, errormsg=False) }}
{{ render_field(form.email, autofocus=True, errormsg=False) }}
{{ render_field(form.password, errormsg=False) }}
{%- if form.password_confirm %}
Expand Down
69 changes: 32 additions & 37 deletions sonar/theme/templates/sonar/page_settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,43 @@
{%- block body scoped %}
<div class="container">
<div class="row">
<div class="col-sm-3 col-md-3 col-pad-left-0">
{%- block settings_menu scoped %}
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading"><strong>{{ _('Settings') }}</strong></div>
<ul class="list-group">
{%- for item in current_menu.submenu('settings').children if item.visible %}
{%- block settings_menu_item scoped %}
<a href="{{ item.url }}" class="list-group-item{% if item.active %} active{% endif %}">
{{ item.text|safe }}
</a>
<div class="col-sm-3 col-md-3 col-pad-left-0">
{%- block settings_menu scoped %}
<ul class="list-group">
{%- for item in current_menu.submenu('settings').children if item.visible %}
{%- block settings_menu_item scoped %}
<a href="{{ item.url }}" class="list-group-item{% if item.active %} active{% endif %}">
{{ item.text|safe }}
</a>
{%- endblock %}
{%- endfor %}
</ul>
{%- endblock %}
</div>
<div class="col-sm-9 col-md-9 col-pad-right-0">
{%- block settings_content scoped %}
<div class="panel-group panel-bot-margin">
<div class="panel panel-default">
<div class="panel-heading">
{%- block settings_content_title scoped %}
{%- if panel_icon %}
{%- block settings_content_title_icon scoped %}
<i class="{{panel_icon}}"></i>
{%- endblock %}
{%- endif %}
<strong>{{ panel_title|default("") }}</strong>
{%- endblock %}
{%- endfor %}
</ul>
</div>
</div>
{%- endblock %}
</div>
<div class="col-sm-9 col-md-9 col-pad-right-0">
{%- block settings_content scoped %}
<div class="panel-group panel-bot-margin">
<div class="panel panel-default">
<div class="panel-heading">
{%- block settings_content_title scoped %}
{%- if panel_icon %}
{%- block settings_content_title_icon scoped %}
<i class="{{panel_icon}}"></i>
{%- endblock %}
{%- endif %}
<strong>{{ panel_title|default("") }}</strong>
{%- endblock %}
</div>
{%- block settings_body scoped %}
<div class="panel-body">
{%- block settings_form scoped %}
{%- endblock settings_form %}
</div>
{%- endblock settings_body %}
{%- block settings_body scoped %}
<div class="panel-body">
{%- block settings_form scoped %}
{%- endblock settings_form %}
</div>
{%- endblock settings_body %}
</div>
{%- endblock %}
</div>
{%- endblock %}
</div>
</div>
</div>
{%- endblock %}
6 changes: 2 additions & 4 deletions sonar/theme/templates/sonar/partial/dropdown_user.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@
#}

<div class="dropdown-menu dropdown-menu-right" aria-labelledby="{{dropdownId}}">
<h6 class="dropdown-header">{{current_user.email}}</h6>
{%- if config.USERPROFILES %}
<a class="dropdown-item" href="{{ url_for('invenio_userprofiles.profile')}}">
<h6 class="dropdown-header">{{current_user_record.email}}</h6>
<a class="dropdown-item" href="{{ url_for('sonar.profile')}}">
{{_('Profile')}}
</a>
{% endif %}
{% if has_superuser_access() %}
<a class="dropdown-item" href="{{ url_for('admin.index')}}">
{{_('Super administration')}}
Expand Down
2 changes: 1 addition & 1 deletion sonar/theme/templates/sonar/partial/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
<a class="nav-link text-uppercase" href="#" id="{{ dropdownId }}" role="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<i class="fa fa-user mr-2"></i>
{{ current_user.profile.full_name if current_user.profile.full_name else current_user.email }}
{{ current_user_record.full_name }}
</a>
{% include 'sonar/partial/dropdown_user.html' %}
{% endwith %}
Expand Down
37 changes: 34 additions & 3 deletions sonar/theme/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@

import re

from flask import Blueprint, abort, current_app, jsonify, render_template, \
request
from flask_login import current_user
from flask import Blueprint, abort, current_app, jsonify, redirect, \
render_template, request, url_for
from flask_babelex import lazy_gettext as _
from flask_breadcrumbs import register_breadcrumb
from flask_login import current_user, login_required
from flask_menu import current_menu, register_menu
from invenio_jsonschemas import current_jsonschemas
from invenio_jsonschemas.errors import JSONSchemaNotFound

Expand All @@ -46,6 +49,34 @@
static_folder='static')


@blueprint.before_app_request
def init_view():
"""Do some stuff before rendering any view."""
current_menu.submenu('settings').submenu('security').hide()
current_menu.submenu('settings').submenu('applications').hide()


@blueprint.route('/users/profile')
@blueprint.route('/users/profile/<pid>')
@login_required
@register_menu(blueprint, 'settings.profile',
_('%(icon)s Profile', icon='<i class="fa fa-user fa-fw"></i>'))
@register_breadcrumb(blueprint, 'breadcrumbs.profile', _('Profile'))
def profile(pid=None):
"""Logged user profile edition page.
:param pid: Logged user PID.
"""
if pid and pid != current_user_record['pid']:
abort(403)

if not pid:
return redirect(
url_for('sonar.profile', pid=current_user_record['pid']))

return render_template('sonar/accounts/profile.html')


@blueprint.route('/error')
def error():
"""Error to generate exception for test purposes."""
Expand Down
12 changes: 8 additions & 4 deletions sonar/translations/de/LC_MESSAGES/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: sonar 0.4.0\n"
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: 2020-06-05 10:30+0200\n"
"POT-Creation-Date: 2020-06-05 10:32+0200\n"
"PO-Revision-Date: 2020-05-13 05:58+0000\n"
"Last-Translator: Nicolas Prongué <[email protected]>, 2020\n"
"Language: de\n"
Expand All @@ -20,6 +20,10 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.8.0\n"

#, python-format
msgid "%(icon)s Profile"
msgstr ""

msgid "Abstract"
msgstr ""

Expand Down Expand Up @@ -514,9 +518,6 @@ msgstr ""
msgid "Series to which belongs the resource."
msgstr ""

msgid "Settings"
msgstr ""

msgid "Sign Up"
msgstr ""

Expand Down Expand Up @@ -2747,3 +2748,6 @@ msgstr ""
msgid "vol."
msgstr ""

#~ msgid "Settings"
#~ msgstr ""

Loading

0 comments on commit 804ca2f

Please sign in to comment.