# -*- coding: utf-8 -*-
#
# This file is part of HEPData.
# Copyright (C) 2016 CERN.
#
# HEPData is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# HEPData 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with HEPData; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.
from datetime import datetime
import json
import logging
from flask_login import login_required, current_user
from invenio_accounts.models import Role
from invenio_db import db
from sqlalchemy import func
from flask import Blueprint, jsonify, url_for, redirect, request, abort, render_template
from hepdata.ext.opensearch.admin_view.api import AdminIndexer
from hepdata.modules.dashboard.api import get_dashboard_current_user
from hepdata.modules.email.api import send_coordinator_request_mail, send_coordinator_approved_email, \
send_cookie_email, send_reserve_email
from hepdata.modules.permissions.api import get_records_participated_in_by_user, get_approved_coordinators, \
get_pending_request
from hepdata.modules.permissions.models import SubmissionParticipant, CoordinatorRequest
from hepdata.modules.records.utils.common import get_record_by_id
from hepdata.modules.submission.api import get_latest_hepsubmission
from hepdata.modules.submission.models import HEPSubmission
from hepdata.utils.users import get_user_from_id, user_is_admin
logging.basicConfig()
log = logging.getLogger(__name__)
blueprint = Blueprint('hep_permissions', __name__, url_prefix="/permissions",
template_folder='templates')
[docs]
@blueprint.route(
'/manage/<int:recid>/<string:action>/<string:status_action>/<int:participant_id>')
@login_required
def manage_participant_status(recid, action, status_action,
participant_id):
"""
Can promote or demote a participant to/from primary reviewer/uploader, or
remove the participant from the record.
:param recid: record id that the user will be promoted or demoted for
:param action: upload or review
:param status_action: demote, promote or remove
:param participant_id: id of user from the SubmissionParticipant table.
:return:
"""
try:
participant = SubmissionParticipant.query.filter_by(
id=participant_id).one()
if status_action == 'remove':
db.session.delete(participant)
else:
status = 'reserve'
if status_action == 'promote':
status = 'primary'
participant.status = status
db.session.add(participant)
db.session.commit()
record = get_record_by_id(recid)
# now send the email telling the user of their new status!
hepsubmission = get_latest_hepsubmission(publication_recid=recid)
if status_action == 'promote':
send_cookie_email(participant, record, version=hepsubmission.version)
elif status_action == 'demote':
send_reserve_email(participant, record)
admin_idx = AdminIndexer()
admin_idx.index_submission(hepsubmission)
return json.dumps({"success": True, "recid": recid})
except Exception as e:
error_str = f"Unable to {status_action} participant id {participant_id} for record {recid}"
log.error(f"{error_str}: {str(e)}")
return json.dumps(
{"success": False, "recid": recid, "message": f"{error_str}. Please refresh the page and try again."})
[docs]
@blueprint.route('/manage/person/add/<int:recid>', methods=['POST'])
@login_required
def add_participant(recid):
"""
Adds a participant to a record.
:param recid:
:return:
"""
try:
submission_record = get_latest_hepsubmission(publication_recid=recid)
full_name = request.form['name']
email = request.form['email']
participant_type = request.form['type']
new_record = SubmissionParticipant(publication_recid=recid,
full_name=full_name,
email=email, role=participant_type)
db.session.add(new_record)
db.session.commit()
admin_idx = AdminIndexer()
admin_idx.index_submission(submission_record)
return json.dumps(
{"success": True, "recid": recid,
"message": "{0} {1} added.".format(full_name, participant_type)})
except Exception as e:
return json.dumps(
{"success": False, "recid": recid,
"message": 'Unable to add participant.'})
[docs]
@blueprint.route('/manage/coordinator/', methods=['POST'])
@login_required
def change_coordinator_for_submission():
"""
Changes the coordinator for a record to that defined by a user id.
Accepts a data object containing {'recid': record id to be acted upon,
'coordinator': id of user who will now be the coordinator}.
:return: dict
"""
recid = request.form['recid']
coordinator_id = request.form['coordinator']
submission_records = HEPSubmission.query.filter_by(publication_recid=recid).all()
admin_idx = AdminIndexer()
for submission_record in submission_records:
submission_record.coordinator = coordinator_id
db.session.add(submission_record)
admin_idx.index_submission(submission_record)
db.session.commit()
return jsonify({'success': True})
[docs]
@blueprint.route('/request/coordinator/', methods=['POST'])
@login_required
def request_coordinator_privileges():
"""
Submits a request for coordinator privileges.
:return:
"""
_user_id = int(current_user.get_id())
message = request.form['message']
experiment = request.form['experiment']
existing_requests = get_pending_request()
if len(existing_requests) > 0:
return jsonify({'message': 'Pending coordinator requests already exist for this user.',
'status': 'error'})
try:
coordinator_request = CoordinatorRequest(user=_user_id, message=str(message), collaboration=experiment)
db.session.add(coordinator_request)
db.session.commit()
send_coordinator_request_mail(coordinator_request)
except Exception as e:
db.session.rollback()
return jsonify({"status": "error", "message": e.__str__()})
return jsonify({'message': 'Request sent successfully.', 'status': 'ok'})
[docs]
@blueprint.route('/coordinator/response/<int:request_id>/<string:decision>', methods=['POST', 'GET'])
@login_required
def respond_coordinator_privileges(request_id, decision):
"""
Handles a request for coordinator privileges.
:return:
"""
if user_is_admin(current_user):
coordinator_request = CoordinatorRequest.query.filter_by(
id=request_id).one()
if coordinator_request:
coordinator_request.in_queue = False
if decision == 'approve':
coordinator_request.approved = True
coordinator_role = Role.query.filter_by(name='coordinator').one()
if coordinator_role:
user = get_user_from_id(coordinator_request.user)
if user:
user.roles.append(coordinator_role)
db.session.add(user)
send_coordinator_approved_email(coordinator_request)
else:
return render_template('hepdata_records/error_page.html',
recid=None,
message="Unable to find a user with id {0} in the system.".format(
coordinator_request.user),
errors={})
else:
return render_template('hepdata_records/error_page.html', recid=None,
message="Unable to find the role coordinator in the system.",
errors={})
db.session.add(coordinator_request)
db.session.commit()
return redirect(url_for('hep_dashboard.dashboard'))
return render_template('hepdata_records/error_page.html', recid=None,
message="No request found with that ID.",
errors={})
abort(403)
[docs]
@blueprint.route('/assign/<cookie>')
@login_required
def assign_role(cookie):
try:
participant_record = SubmissionParticipant.query.filter(
func.lower(SubmissionParticipant.email) == func.lower(current_user.email),
SubmissionParticipant.invitation_cookie == cookie).first()
participant_record.user_account = current_user.get_id()
participant_record.action_date = datetime.utcnow()
db.session.add(participant_record)
db.session.commit()
return redirect('/record/{0}'.format(participant_record.publication_recid))
except:
abort(403)
[docs]
def check_is_sandbox_record(recid):
try:
submission = HEPSubmission.query.filter_by(publication_recid=recid).first()
return submission.overall_status.startswith('sandbox')
except Exception as e:
return False
[docs]
@blueprint.route('/list')
@login_required
def get_permissions_list():
"""
Gets all permissions given for a user.
:return:
"""
user = get_dashboard_current_user(current_user)
return jsonify(get_records_participated_in_by_user(user))
[docs]
@blueprint.route('/coordinators')
def get_coordinators():
"""
Returns a list of coordinators and their experiments in the system.
:return:
"""
coordinators = get_approved_coordinators()
return render_template('hepdata_permissions/coordinator_list.html',
coordinators=coordinators)