Commit fb0c0801 authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Added new report endpoint for user error reporting. This endpoint requires...

Added new report endpoint for user error reporting. This endpoint requires proper authentication through keycloak. Added additional checks to phonon data.
parent aabbf939
Pipeline #79279 failed with stages
in 41 minutes and 37 seconds
Subproject commit 134d89fc0a25ea367c454d299c8603af893b3b66
Subproject commit 15cb97c9cf61fd59309a50f6700b99733fc6a659
......@@ -17,6 +17,7 @@ The encyclopedia API of the nomad@FAIRDI APIs.
"""
import re
import math
import json
import numpy as np
from flask_restplus import Resource, abort, fields, marshal
......@@ -24,12 +25,12 @@ from flask import request
from elasticsearch_dsl import Search, Q, A
from elasticsearch_dsl.utils import AttrDict
from nomad import config, files
from nomad import config, files, infrastructure
from nomad.units import ureg
from nomad.atomutils import get_hill_decomposition
from nomad.datamodel.datamodel import EntryArchive
from .api import api
from .common import enable_gzip
from .auth import authenticate
ns = api.namespace("encyclopedia", description="Access encyclopedia metadata.")
re_formula = re.compile(r"([A-Z][a-z]?)(\d*)")
......@@ -791,7 +792,6 @@ calculations_result = api.model("calculations_result", {
@ns.route("/materials/<string:material_id>/calculations")
class EncCalculationsResource(Resource):
@enable_gzip()
@api.response(404, "Suggestion not found")
@api.response(400, "Bad request")
@api.response(200, "Metadata send", fields.Raw)
......@@ -1133,7 +1133,6 @@ calculation_property_result = api.model("calculation_property_result", {
@ns.route("/materials/<string:material_id>/calculations/<string:calc_id>")
class EncCalculationResource(Resource):
@enable_gzip()
@api.response(404, "Material or calculation not found")
@api.response(400, "Bad request")
@api.response(200, "Metadata send", fields.Raw)
......@@ -1283,6 +1282,63 @@ class EncCalculationResource(Resource):
return result, 200
report_query = api.model("report_query", {
"server": fields.String,
"username": fields.String,
"email": fields.String,
"first_name": fields.String,
"last_name": fields.String,
"category": fields.String,
"subcategory": fields.String(allow_null=True),
"representatives": fields.Raw(Raw=True),
"message": fields.String,
})
@ns.route("/materials/<string:material_id>/reports")
class ReportsResource(Resource):
@api.response(500, "Error sending report")
@api.response(400, "Bad request")
@api.response(204, "Report succesfully sent", fields.Raw)
@api.expect(calculation_property_query, validate=False)
@api.marshal_with(calculation_property_result, skip_none=True)
@api.doc("enc_calculation")
@authenticate(required=True)
def post(self, material_id):
# Get query parameters as json
try:
query = marshal(request.get_json(), report_query)
except Exception as e:
abort(400, message=str(e))
# Send the report as an email
query["material_id"] = material_id
representatives = query["representatives"]
if representatives is not None:
representatives = "\n" + "\n".join([" {}: {}".format(key, value) for key, value in representatives.items()])
query["representatives"] = representatives
mail = (
"Server: {server}\n\n"
"Username: {username}\n"
"First name: {first_name}\n"
"Last name: {last_name}\n"
"Email: {email}\n\n"
"Material id: {material_id}\n"
"Category: {category}\n"
"Subcategory: {subcategory}\n"
"Representative calculations: {representatives}\n\n"
"Message: {message}"
).format(**query)
try:
infrastructure.send_mail(
name="webmaster", email="lauri.himanen@gmail.com", message=mail, subject='Encyclopedia error report')
except Exception as e:
abort(500, message="Error sending error report email.")
print(mail)
return "", 204
def read_archive(upload_id: str, calc_id: str) -> EntryArchive:
"""Used to read data from the archive.
......
......@@ -453,7 +453,6 @@ def send_mail(name: str, email: str, message: str, subject: str):
msg = MIMEText(message)
msg['Subject'] = subject
msg['From'] = 'The nomad team <%s>' % config.mail.from_address
msg['To'] = name
to_addrs = [email]
......
......@@ -207,6 +207,7 @@ class EncyclopediaNormalizer(Normalizer):
"""
sec_enc = self.backend.entry_archive.section_metadata.m_create(EncyclopediaMetadata)
status_enums = EncyclopediaMetadata.status.type
calc_enums = Calculation.calculation_type.type
# Do nothing if section_run is not present
if self.section_run is None:
......@@ -261,7 +262,6 @@ class EncyclopediaNormalizer(Normalizer):
"unsupported method type for encyclopedia",
enc_status=status_enums.unsupported_method_type,
)
calc_enums = Calculation.calculation_type.type
if calc_type != calc_enums.phonon_calculation:
return
......@@ -292,7 +292,7 @@ class EncyclopediaNormalizer(Normalizer):
if functional_type is None:
sec_enc.status = status_enums.unsupported_method_type
self.logger.info(
"unsupported functinoal type for encyclopedia",
"unsupported functional type for encyclopedia",
enc_status=status_enums.unsupported_method_type,
)
return
......
......@@ -444,7 +444,7 @@ class Calc(Proc):
# Get encyclopedia method information directly from the referenced calculation.
ref_enc_method = ref_archive.section_metadata.encyclopedia.method
if ref_enc_method is None or len(ref_enc_method) == 0:
if ref_enc_method is None or len(ref_enc_method) == 0 or ref_enc_method.functional_type is None:
raise ValueError("No method information available in referenced calculation.")
backend.entry_archive.section_metadata.encyclopedia.method = ref_enc_method
......@@ -455,6 +455,7 @@ class Calc(Proc):
self._entry_metadata.dft.xc_functional = ref_archive.section_metadata.dft.xc_functional
self._entry_metadata.dft.basis_set = ref_archive.section_metadata.dft.basis_set
self._entry_metadata.dft.update_group_hash()
self._entry_metadata.encyclopedia.status = EncyclopediaMetadata.status.type.success
except Exception as e:
logger.error("Could not retrieve method information for phonon calculation.", exception=e)
if self._entry_metadata.encyclopedia is None:
......
......@@ -520,9 +520,9 @@ def test_phonon(phonon: EntryArchive):
dos = prop.phonon_dos
thermo_props = prop.thermodynamical_properties
assert calc_type == Calculation.calculation_type.type.phonon_calculation
assert status == EncyclopediaMetadata.status.type.success
# TODO: Check method information
# The method information is filled after the whole upload has been processed.
assert status == EncyclopediaMetadata.status.type.unsupported_method_type
# Check dos
assert dos is not None
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment