Commit 559ad23b authored by Markus Scheidgen's avatar Markus Scheidgen
Browse files

Added PID resolve. Fixes #212

parent 8f5308d2
Pipeline #54985 passed with stages
in 33 minutes and 10 seconds
......@@ -28,6 +28,7 @@ import packageJson from '../../package.json'
import { Cookies, withCookies } from 'react-cookie'
import Markdown from './Markdown'
import {help as uploadHelp, default as Uploads} from './uploads/Uploads'
import ResolvePID from './entry/ResolvePID';
export class VersionMismatch extends Error {
constructor(msg) {
......@@ -49,6 +50,7 @@ const toolbarThemes = {
'/': genTheme,
'/search': repoTheme,
'/uploads': repoTheme,
'/entry': repoTheme,
'/metainfo': archiveTheme
}
......@@ -388,9 +390,9 @@ export default class App extends React.Component {
path: '/search',
render: props => <SearchPage {...props} />
},
'searchEntry': {
path: '/search/:uploadId/:calcId',
key: (props) => `searchEntry/${props.match.params.uploadId}/${props.match.params.uploadId}`,
'entry': {
path: '/entry/id/:uploadId/:calcId',
key: (props) => `entry/${props.match.params.uploadId}/${props.match.params.uploadId}`,
render: props => {
const { match, ...rest } = props
if (match && match.params.uploadId && match.params.calcId) {
......@@ -400,24 +402,24 @@ export default class App extends React.Component {
}
}
},
'uploads': {
exact: true,
singleton: true,
path: '/uploads',
render: props => <Uploads {...props} />
},
'uploadedEntry': {
path: '/uploads/:uploadId/:calcId',
key: (props) => `uploadedEntry/${props.match.params.uploadId}/${props.match.params.uploadId}`,
'entry_pid': {
path: '/entry/pid/:pid',
key: (props) => `entry/pid/${props.match.params.pid}`,
render: props => {
const { match, ...rest } = props
if (match && match.params.uploadId && match.params.calcId) {
return (<Calc {...rest} uploadId={match.params.uploadId} calcId={match.params.calcId} />)
if (match && match.params.pid) {
return (<ResolvePID {...rest} pid={match.params.pid} />)
} else {
return ''
}
}
},
'uploads': {
exact: true,
singleton: true,
path: '/uploads',
render: props => <Uploads {...props} />
},
'metainfo': {
exact: true,
path: '/metainfo',
......
......@@ -171,6 +171,7 @@ class Api {
this.onStartLoading = () => null
this.onFinishLoading = () => null
this.isLoggedIn = true && user
user = user || {}
this.auth_headers = {
'X-Token': user.token
......@@ -290,6 +291,15 @@ class Api {
.finally(this.onFinishLoading)
}
async resolvePid(pid) {
this.onStartLoading()
return this.swaggerPromise
.then(client => client.apis.repo.resolve_pid({pid: pid}))
.catch(handleApiError)
.then(response => response.body)
.finally(this.onFinishLoading)
}
async search(search) {
this.onStartLoading()
return this.swaggerPromise
......
import React from 'react'
import PropTypes from 'prop-types'
import { withStyles, Typography } from '@material-ui/core'
import { compose } from 'recompose'
import { withApi } from '../api'
import { withRouter } from 'react-router'
class ResovlePID extends React.Component {
static styles = theme => ({
root: {
padding: theme.spacing.unit * 3
}
})
static propTypes = {
classes: PropTypes.object.isRequired,
pid: PropTypes.string.isRequired,
api: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
raiseError: PropTypes.func.isRequired
}
state = {
doesNotExist: false
}
componentDidMount() {
const { pid, api, history } = this.props
api.resolvePid(pid).then(entry => {
history.push(`/entry/id/${entry.upload_id}/${entry.calc_id}`)
}).catch(error => {
this.setState({calcData: null})
if (error.name === 'DoesNotExist') {
this.setState({doesNotExist: true})
} else {
this.props.raiseError(error)
}
})
}
render() {
const { classes, api } = this.props
const { doesNotExist } = this.state
let message = 'loading ...'
if (doesNotExist) {
if (api.isLoggedIn) {
message = `
This URL points to an entry that either does not exist, or that you are not
authorized to see.`
} else {
message = `
This URL points to an entry that either does not exist, or that is not
publically visibile. Please login; you might be authorized to view it.`
}
}
return (
<Typography className={classes.root}>{message}</Typography>
)
}
}
export default compose(withRouter, withApi(false), withStyles(ResovlePID.styles))(ResovlePID)
......@@ -63,7 +63,7 @@ class SearchResultListUnstyled extends React.Component {
}
handleClickCalc(calc) {
this.props.history.push(`/search/${calc.upload_id}/${calc.calc_id}`)
this.props.history.push(`/entry/id/${calc.upload_id}/${calc.calc_id}`)
}
handleChangePage = (event, page) => {
......
......@@ -390,7 +390,7 @@ class Upload extends React.Component {
const processed = tasks_status === 'FAILURE' || tasks_status === 'SUCCESS'
const row = (
<TableRow key={index} hover={processed}
onClick={() => this.props.history.push(`/uploads/${upload_id}/${calc_id}`)}
onClick={() => this.props.history.push(`/entry/id/${upload_id}/${calc_id}`)}
className={processed ? classes.clickableRow : null} >
<TableCell>
......
......@@ -24,7 +24,7 @@ from elasticsearch_dsl import Q
from elasticsearch.exceptions import NotFoundError
import datetime
from nomad import search
from nomad import search, utils
from .app import api, rfc3339DateTime
from .auth import login_if_available
......@@ -87,6 +87,11 @@ repo_calcs_model = api.model('RepoCalculations', {
})
repo_calc_id_model = api.model('RepoCalculationId', {
'upload_id': fields.String(), 'calc_id': fields.String()
})
def add_common_parameters(request_parser):
request_parser.add_argument(
'owner', type=str,
......@@ -353,3 +358,26 @@ class RepoQuantityResource(Resource):
import traceback
traceback.print_exc()
abort(400, 'Given quantity does not exist: %s' % str(e))
@ns.route('/pid/<int:pid>')
class RepoPidResource(Resource):
@api.doc('resolve_pid')
@api.response(404, 'Entry with PID does not exist')
@api.marshal_with(repo_calc_id_model, skip_none=True, code=200, description='Entry resolved')
@login_if_available
def get(self, pid: int):
q = _create_owner_query()
results = search.entry_search(q, page=1, per_page=1, search_parameters=dict(pid=pid))
total = results['pagination']['total']
if total == 1:
return dict(
upload_id=results['results'][0]['upload_id'],
calc_id=results['results'][0]['calc_id'])
elif total == 0:
abort(404, 'Entry with PID %d does not exist' % pid)
else:
utils.get_logger(__name__).error('Two entries for the same pid', pid=pid)
return dict(
upload_id=results['results'][0]['upload_id'],
calc_id=results['results'][0]['calc_id'])
......@@ -656,18 +656,20 @@ class TestRepo():
search.Entry.from_calc_with_metadata(calc_with_metadata).save(refresh=True)
calc_with_metadata.update(
calc_id='2', uploader=other_test_user.to_popo(), published=True, with_embargo=False,
upload_time=today - datetime.timedelta(days=5))
calc_id='2', uploader=other_test_user.to_popo(), published=True,
with_embargo=False, pid=2, upload_time=today - datetime.timedelta(days=5))
calc_with_metadata.update(
atoms=['Fe'], comment='this is a specific word', formula='AAA', basis_set='zzz')
search.Entry.from_calc_with_metadata(calc_with_metadata).save(refresh=True)
calc_with_metadata.update(
calc_id='3', uploader=other_test_user.to_popo(), published=False, with_embargo=False)
calc_id='3', uploader=other_test_user.to_popo(), published=False,
with_embargo=False, pid=3)
search.Entry.from_calc_with_metadata(calc_with_metadata).save(refresh=True)
calc_with_metadata.update(
calc_id='4', uploader=other_test_user.to_popo(), published=True, with_embargo=True)
calc_id='4', uploader=other_test_user.to_popo(), published=True,
with_embargo=True, pid=4)
search.Entry.from_calc_with_metadata(calc_with_metadata).save(refresh=True)
def assert_search(self, rv: Any, number_of_calcs: int) -> dict:
......@@ -935,6 +937,21 @@ class TestRepo():
assert after != quantity['after']
after = quantity['after']
@pytest.mark.parametrize('pid, with_login, success', [
(2, True, True), (2, False, True),
(3, True, True), (3, False, False),
(4, True, True), (4, False, False)])
def test_resolve_pid(
self, client, example_elastic_calcs, other_test_user_auth, pid, with_login,
success, no_warn):
rv = client.get(
'/repo/pid/%d' % pid,
headers=other_test_user_auth if with_login else {})
assert rv.status_code == 200 if success else 404
if success:
assert json.loads(rv.data)['calc_id'] == '%d' % pid
assert json.loads(rv.data)['upload_id'] == '0'
class TestRaw(UploadFilesBasedTests):
......
Supports Markdown
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