summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scraper/client/actions.js11
-rw-r--r--scraper/client/app.js2
-rw-r--r--scraper/client/common/autocomplete.component.js49
-rw-r--r--scraper/client/paper/citationList.component.js96
-rw-r--r--scraper/client/paper/paper.citations.js55
-rw-r--r--scraper/client/paper/paper.css73
-rw-r--r--scraper/client/paper/paper.info.js4
-rw-r--r--scraper/client/paper/paper.random.js2
-rw-r--r--scraper/client/paper/paper.unknown.js48
-rw-r--r--scraper/client/paper/paper.verify.js286
-rw-r--r--scraper/client/store.js2
-rw-r--r--scraper/client/types.js7
-rw-r--r--scraper/s2-geocode-server.py30
-rw-r--r--scraper/util.py15
14 files changed, 519 insertions, 161 deletions
diff --git a/scraper/client/actions.js b/scraper/client/actions.js
index 6c4e16b2..1b5152ea 100644
--- a/scraper/client/actions.js
+++ b/scraper/client/actions.js
@@ -1,9 +1,10 @@
import { get, post } from './util'
import * as types from './types'
-export const api = (dispatch, method, tag, url, params) => {
+export const api = (dispatch, method, tag, url, params, after) => {
dispatch({ type: types.api.loading, tag })
return method(url, params).then(data => {
+ if (after) data = after(data)
dispatch({ type: types.api.loaded, tag, data })
return data
}).catch(err => {
@@ -32,6 +33,14 @@ export const postAddress = data => dispatch => {
api(dispatch, post, 'address', '/api/address/add', data)
}
+export const getVerifications = () => dispatch => (
+ api(dispatch, get, 'verifications', '/api/verifications', {})
+)
+
+export const getVerificationsDataset = dataset => dispatch => (
+ api(dispatch, get, 'verifications', '/api/verifications/' + dataset, {})
+)
+
export const getVerification = sha256 => dispatch => (
api(dispatch, get, 'verify', '/api/verify/' + sha256, {})
)
diff --git a/scraper/client/app.js b/scraper/client/app.js
index dc5c6fe6..b449d0d0 100644
--- a/scraper/client/app.js
+++ b/scraper/client/app.js
@@ -15,7 +15,7 @@ export default class App extends Component {
<div className='body'>
<Route path="/paper/:key/" component={Paper.Manager} />
<Switch>
- <Route exact path="/paper/:key/" component={Paper.Random} />
+ <Route exact path="/paper/:key/" component={Paper.Info} />
<Route exact path="/paper/:key/citations/" component={Paper.Citations} />
<Route exact path="/paper/:key/unknown/" component={Paper.UnknownCitations} />
<Route exact path="/paper/:key/info/" component={Paper.Info} />
diff --git a/scraper/client/common/autocomplete.component.js b/scraper/client/common/autocomplete.component.js
index e2908cd1..67dc78c9 100644
--- a/scraper/client/common/autocomplete.component.js
+++ b/scraper/client/common/autocomplete.component.js
@@ -49,6 +49,10 @@ class Autocomplete extends Component {
componentDidMount() {
// build index based on what's in the hierarchy
+ if (!this.props.institutions.loading) this.buildIndex()
+ }
+
+ buildIndex() {
const { entities, lookup } = this.props.institutions
let index = []
this.index = index
@@ -69,6 +73,9 @@ class Autocomplete extends Component {
}
componentDidUpdate(oldProps) {
+ if (oldProps.institutions.loading && !this.props.institutions.loading) {
+ this.buildIndex()
+ }
if (this.props.vetting !== oldProps.vetting) {
this.handleChange({ target: { value: this.props.vetting } })
} else if (this.props.value !== oldProps.value) {
@@ -77,30 +84,37 @@ class Autocomplete extends Component {
}
handleKeyDown(e) {
- let id
+ let name
+ console.log(e.keyCode)
switch (e.keyCode) {
case 27: // escape
e.preventDefault()
this.handleCancel()
break
- case 37: // left
case 38: // up
e.preventDefault()
this.setState({
selected: (this.state.matches.length + this.state.selected - 1) % this.state.matches.length
})
return false
- case 39: // right
case 40: // down
e.preventDefault()
this.setState({
selected: (this.state.selected + 1) % this.state.matches.length
})
return false
- case 13: // enter
- id = this.state.matches[this.state.selected]
+ case 13: // enter - select from the list
+ name = this.state.matches[this.state.selected]
e.preventDefault()
- this.handleSelect(id)
+ this.handleSelect(name, true)
+ return false
+ case 9: // tab - keep the unverified text
+ name = this.state.matches[this.state.selected]
+ if (name === this.state.q) {
+ this.handleSelect(this.state.q, true)
+ } else {
+ this.handleSelect(this.state.q, false)
+ }
return false
default:
break
@@ -121,7 +135,6 @@ class Autocomplete extends Component {
return
}
let seen = {}
- let matches = []
value.split(' ').forEach(word => {
const re = new RegExp(word)
this.index.forEach(([synonym, term]) => {
@@ -139,14 +152,14 @@ class Autocomplete extends Component {
}
}
})
- matches = Object.keys(seen)
- .map(term => [seen[term], term])
- .sort((a, b) => {
- return b[0] - a[0]
- })
- .slice(0, 100)
- .map(pair => pair[1])
})
+ let matches = Object.keys(seen)
+ .map(term => [seen[term], term])
+ .sort((a, b) => {
+ return b[0] - a[0]
+ })
+ .slice(0, 100)
+ .map(pair => pair[1])
this.setState({
q,
selected: 0,
@@ -154,9 +167,9 @@ class Autocomplete extends Component {
})
}
- handleSelect(name) {
- console.log('select', name)
- if (this.props.onSelect) this.props.onSelect(name)
+ handleSelect(name, valid) {
+ console.log('select', name, valid)
+ if (this.props.onSelect) this.props.onSelect(name, valid)
this.setState({ q: name, selected: 0, matches: [] })
}
@@ -173,7 +186,7 @@ class Autocomplete extends Component {
<div
key={i}
className={selected === i ? 'selected' : ''}
- onClick={() => this.handleSelect(match)}
+ onClick={() => this.handleSelect(match, true)}
onMouseEnter={() => this.setState({ selected: i })}
>
{label}
diff --git a/scraper/client/paper/citationList.component.js b/scraper/client/paper/citationList.component.js
new file mode 100644
index 00000000..09060375
--- /dev/null
+++ b/scraper/client/paper/citationList.component.js
@@ -0,0 +1,96 @@
+import React, { Component } from 'react'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+import { Link } from 'react-router-dom'
+
+import * as actions from '../actions'
+
+import { TableObject, Loader } from '../common'
+import { USES_DATASET } from '../types'
+
+class CitationList extends Component {
+ render() {
+ const { citations, title, api } = this.props
+ const { paperInfo, unknownCitations, verifications } = api
+ const { dataset } = paperInfo
+ if (!dataset || !citations || !verifications[dataset.key]) return <Loader />
+ let verifiedLookup = verifications[dataset.key] || {}
+ // console.log(verifications)
+
+ return (
+ <div className='citations'>
+ <h2>{title}</h2>
+ <ul>
+ {citations
+ .map(citation => [citation.title, verifiedLookup[citation.id] ? verifiedLookup[citation.id].uses_dataset : USES_DATASET.NO_DATA, citation])
+ .sort((a,b) => (b[1] - a[1] || (a[0].localeCompare(b[0]))))
+ .map((pair, i) => {
+ const [ title, uses_dataset, citation ] = pair
+ let cite = { ...citation }
+ cite.id = {
+ _raw: true,
+ value: <Link to={'/paper/' + dataset.key + '/verify/' + citation.id}>{citation.id}</Link>
+ }
+ cite.pdf = {
+ _raw: true,
+ value: (cite.pdf && cite.pdf.length)
+ ? cite.pdf.map((pdf, i) => <a key={'pdf_' + i} href={pdf} rel='noopener noreferrer' target="_blank">[pdf]</a>)
+ : "no pdf"
+ }
+ cite.s2 = {
+ _raw: true,
+ value: <a
+ href={'https://www.semanticscholar.org/paper/' + citation.id}
+ target="_blank"
+ rel="noopener noreferrer"
+ className={'pdfLink'}
+ >{'[semantic scholar]'}</a>
+ }
+ cite.addresses = {
+ _raw: true,
+ value: (cite.addresses || []).map((address, j) => (
+ <div key={j}>{address.name}{', '}<span className='type'>{address.type}</span></div>
+ ))
+ }
+ if (citation.id in verifiedLookup) {
+ const verification = verifiedLookup[citation.id]
+ cite.verified = {
+ _raw: true,
+ value: verification.uses_dataset === USES_DATASET.YES
+ ? <span className='verified'>uses dataset</span>
+ : verification.uses_dataset === USES_DATASET.NO
+ ? <span className='unverified'>{"doesn't use dataset"}</span>
+ : <span className='not_enough_info'>{"not enough information"}</span>
+ }
+ }
+ else {
+ cite.verified = {
+ _raw: true,
+ value: <span className='unknown'>unknown</span>
+ }
+ }
+ return (
+ <li key={i}>
+ <TableObject
+ summary
+ object={cite}
+ tag={cite.title}
+ order={['id', 'pdf', 's2', 'year', 'addresses', 'verified']}
+ />
+ </li>
+ )
+ })}
+ </ul>
+ </div>
+ )
+ }
+}
+
+const mapStateToProps = state => ({
+ api: state.api
+})
+const mapDispatchToProps = dispatch => ({
+ actions: bindActionCreators({ ...actions }, dispatch),
+})
+
+export default connect(mapStateToProps, mapDispatchToProps)(CitationList)
diff --git a/scraper/client/paper/paper.citations.js b/scraper/client/paper/paper.citations.js
index 41ddd55e..f0e9ea26 100644
--- a/scraper/client/paper/paper.citations.js
+++ b/scraper/client/paper/paper.citations.js
@@ -5,47 +5,28 @@ import { Link } from 'react-router-dom'
import * as actions from '../actions'
-import { TableObject } from '../common'
+import { Loader } from '../common'
+import { USES_DATASET } from '../types'
+
+import CitationList from './citationList.component'
class PaperCitations extends Component {
+ componentDidUpdate(prevProps) {
+ if (this.props.api.paperInfo.dataset !== prevProps.api.paperInfo.dataset) {
+ this.props.actions.getVerificationsDataset(this.props.api.paperInfo.dataset.key)
+ }
+ }
+
render() {
- const { dataset, citations } = this.props.api.paperInfo
- if (!dataset || !citations) return null
- console.log('rendering citations...')
- console.log(citations)
+ const { paperInfo, unknownCitations, verifications } = this.props.api
+ const { dataset, citations } = paperInfo
+ if (!dataset || !citations || !verifications[dataset.key]) return <Loader />
+
return (
- <div className='citations'>
- <h2>{dataset.name_full}: Citations</h2>
- <ul>
- {citations.map((citation, i) => {
- let cite = { ...citation }
- cite.id = {
- _raw: true,
- value: <Link to={'/paper/' + dataset.key + '/verify/' + citation.id}>{citation.id}</Link>
- }
- cite.pdf = {
- _raw: true,
- value: (cite.pdf && cite.pdf.length) ? <a href={cite.pdf[0]} rel='noopener noreferrer' target="_blank">[pdf]</a> : "no pdf"
- }
- cite.addresses = {
- _raw: true,
- value: cite.addresses.map((address, j) => (
- <div key={j}>{address.name}{', '}<span className='type'>{address.type}</span></div>
- ))
- }
- return (
- <li key={i}>
- <TableObject
- summary
- object={cite}
- tag={cite.title}
- order={['id', 'pdf', 'year', 'addresses']}
- />
- </li>
- )
- })}
- </ul>
- </div>
+ <CitationList
+ title={dataset.name_full + ': Citations'}
+ citations={citations.concat(unknownCitations.citations)}
+ />
)
}
}
diff --git a/scraper/client/paper/paper.css b/scraper/client/paper/paper.css
index 4815bd30..302eceb0 100644
--- a/scraper/client/paper/paper.css
+++ b/scraper/client/paper/paper.css
@@ -1,8 +1,20 @@
+.row {
+ display: flex;
+ flex-direction: row;
+ padding: 4px;
+}
+.rowHeading {
+ display: block;
+ width: 194px;
+}
.form, .paperInfo {
padding: 10px;
width: 100%;
}
+.citations {
+ padding:40px;
+}
.citations ul {
list-style-type: none;
margin: 0;
@@ -12,7 +24,13 @@
.citations li {
list-style-type: none;
margin: 0;
- padding-bottom: 40px;
+ padding-bottom: 20px;
+ border:1px solid #ccc;
+}
+.citations h3{
+ font-size:20px;
+ margin:10px 0 15px 0;
+ font-weight: bold;
}
.type {
@@ -26,6 +44,41 @@
cursor: pointer;
color: #11f;
}
+.verified {
+ font-weight: bold;
+ color: white;
+ font-weight: bold;
+ display: inline-block;
+ background: #00b200;
+ padding:4px;
+ font-size:12px;
+}
+.unverified {
+ color: white;
+ font-weight: bold;
+ display: inline-block;
+ background: #ff0000;
+ padding:4px;
+ font-size:12px;
+}
+.not_enough_info {
+ font-weight: bold;
+ color: white;
+ font-weight: bold;
+ display: inline-block;
+ background: #e0c200;
+ padding:4px;
+ font-size:12px;
+}
+.unknown {
+ font-weight: bold;
+ color: white;
+ font-weight: bold;
+ display: inline-block;
+ background: #999;
+ padding:4px;
+ font-size:12px;
+}
.param {
display: flex;
@@ -39,9 +92,16 @@ input.notes {
.param .btn {
margin-top: 5px;
}
-.vetting {
- width: 250px;
- margin-right: 10px;
+.row.disabled { opacity: 0.5; pointer-events: none;}
+
+.vettingRow label {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 0 10px 0 0;
+}
+.vettingRow input {
+ margin-right: 6px;
}
.param label {
display: block;
@@ -51,7 +111,11 @@ input.notes {
.param input[type=checkbox] {
margin: 6px 0;
}
+input[type=text] {
+ margin-bottom: 2px;
+}
textarea {
+ margin-bottom: 2px;
padding: 4px;
font-size: 14px;
}
@@ -68,6 +132,7 @@ iframe.pdfViewer {
header select {
margin-right: 10px;
width: 100px;
+ min-width: 200px;
}
header a {
color: white;
diff --git a/scraper/client/paper/paper.info.js b/scraper/client/paper/paper.info.js
index a8553c9b..35234617 100644
--- a/scraper/client/paper/paper.info.js
+++ b/scraper/client/paper/paper.info.js
@@ -9,7 +9,7 @@ import { TableObject } from '../common'
class PaperInfo extends Component {
render() {
const { paperInfo, unknownCitations } = this.props.api
- const { dataset, statistics, address } = paperInfo
+ const { dataset, address } = paperInfo
if (!dataset) return null
return (
<div className='paperInfo'>
@@ -21,7 +21,7 @@ class PaperInfo extends Component {
/>
<TableObject summary
tag="Statistics"
- object={statistics}
+ object={dataset}
order={['year_published', 'purpose_short',
'wild', 'indoor', 'outdoor', 'cyberspace',
'names', 'downloaded',
diff --git a/scraper/client/paper/paper.random.js b/scraper/client/paper/paper.random.js
index aab22172..c7476332 100644
--- a/scraper/client/paper/paper.random.js
+++ b/scraper/client/paper/paper.random.js
@@ -15,7 +15,7 @@ class PaperRandom extends Component {
const citation = choice(citations)
console.log(citation)
if (citation.id) {
- history.push('/paper/' + this.props.match.params.key + '/address/' + citation.id)
+ history.push('/paper/' + this.props.match.params.key + '/verify/' + citation.id)
}
}
diff --git a/scraper/client/paper/paper.unknown.js b/scraper/client/paper/paper.unknown.js
index 0cb7d2da..876ac144 100644
--- a/scraper/client/paper/paper.unknown.js
+++ b/scraper/client/paper/paper.unknown.js
@@ -5,40 +5,28 @@ import { Link } from 'react-router-dom'
import * as actions from '../actions'
-import { TableObject } from '../common'
+import { Loader } from '../common'
+import { USES_DATASET } from '../types'
+
+import CitationList from './citationList.component'
class PaperUnknown extends Component {
+ componentDidUpdate(prevProps) {
+ if (this.props.api.paperInfo.dataset !== prevProps.api.paperInfo.dataset) {
+ this.props.actions.getVerificationsDataset(this.props.api.paperInfo.dataset.key)
+ }
+ }
+
render() {
- const { dataset } = this.props.api.paperInfo
- const { citations } = this.props.api.unknownCitations
- if (!dataset || !citations) return null
- console.log('rendering unknown citations...')
+ const { paperInfo, unknownCitations, verifications } = this.props.api
+ const { dataset, citations } = paperInfo
+ if (!dataset || !citations || !verifications[dataset.key]) return <Loader />
+
return (
- <div className='citations'>
- <h2>{dataset.name_full}: Unknown Citations</h2>
- <ul>
- {citations.map((citation, i) => {
- let cite = { ...citation }
- cite.id = {
- _raw: true,
- value: <Link to={'/paper/' + dataset.key + '/address/' + citation.id}>{citation.id}</Link>
- }
- cite.pdf = {
- _raw: true,
- value: cite.pdf ? <a href={cite.pdf} rel='noopener noreferrer' target="_blank">[pdf]</a> : "no pdf"
- }
- return (
- <li key={i}>
- <TableObject
- summary
- object={cite}
- tag={cite.title}
- />
- </li>
- )
- })}
- </ul>
- </div>
+ <CitationList
+ title={dataset.name_full + ': Unknown Citations'}
+ citations={unknownCitations.citations}
+ />
)
}
}
diff --git a/scraper/client/paper/paper.verify.js b/scraper/client/paper/paper.verify.js
index 5f85a551..61faa24a 100644
--- a/scraper/client/paper/paper.verify.js
+++ b/scraper/client/paper/paper.verify.js
@@ -3,20 +3,28 @@ import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as actions from '../actions'
-
import { history } from '../store'
-
import { Loader, Autocomplete } from '../common'
+import { USES_DATASET } from '../types'
const initialState = {
citation: null,
- uses_dataset: false,
- doesnt_use_dataset: true,
- images_in_paper: false,
+ address: {},
+ uses_dataset: USES_DATASET.UNKNOWN,
+ images_in_paper: "FALSE",
+ used_as_model: "FALSE",
verified_by: localStorage.getItem('verify.username') || '',
reference: '',
notes: '',
+ location: '',
pdf_index: 0,
+ isUnknown: false,
+ institution_1: '',
+ institution_2: '',
+ institution_3: '',
+ validate_1: false,
+ validate_2: false,
+ validate_3: false,
}
class PaperVerify extends Component {
@@ -27,6 +35,7 @@ class PaperVerify extends Component {
componentDidMount() {
const { sha256 } = this.props.match.params
this.props.actions.getInstitutions()
+ this.props.actions.getAddress(sha256)
this.props.actions.getVerification(sha256)
const citationState = this.getCitationState(sha256)
console.log('DID MOUNT')
@@ -35,53 +44,67 @@ class PaperVerify extends Component {
componentDidUpdate(oldProps) {
const { sha256 } = this.props.match.params
- const { verify } = this.props.api
+ const { address, verify } = this.props.api
const { sha256: oldSha256 } = oldProps.match.params
- const { verify: oldVerify } = oldProps.api
+ const { verify: oldVerify, address: oldAddress } = oldProps.api
const oldPaper = oldVerify ? oldVerify.paper : null
const paper = verify ? verify.paper : null
+ let newState = {}
if (oldSha256 && sha256 !== oldSha256) {
console.log('update verification')
+ this.props.actions.getAddress(sha256)
this.props.actions.getVerification(sha256)
const citationState = this.getCitationState(sha256)
- this.setState({
+ newState = {
...initialState,
...citationState,
- })
+ ...address.paper,
+ }
+ this.setState(newState)
} else if (verify && !verify.loading && verify.paper && (!oldPaper || oldPaper !== verify.paper)) {
if (paper.error) {
console.log('USING PAPER VERIFICATION')
const citationState = this.getCitationState(sha256)
- this.setState({
+ newState = {
...initialState,
...citationState,
- })
+ ...address.paper,
+ }
+ this.setState(newState)
} else {
// console.log(paper)
console.log('GOT CUSTOM CITATION STATE', paper)
const citationState = this.getCitationState(sha256)
- this.setState({
+ newState = {
...citationState,
- uses_dataset: paper.uses_dataset === "TRUE",
- doesnt_use_dataset: paper.doesnt_use_dataset === "TRUE",
- images_in_paper: paper.images_in_paper === "TRUE",
+ ...address.paper,
+ uses_dataset: paper.uses_dataset,
+ images_in_paper: paper.images_in_paper,
verified_by: paper.verified_by,
reference: paper.reference,
notes: paper.notes,
- })
+ }
+ this.setState(newState)
}
} else if (oldProps.api.unknownCitations !== this.props.api.unknownCitations) {
+ console.log('loaded unknown citations')
const citationState = this.getCitationState(sha256)
- this.setState(citationState)
+ newState = citationState
+ this.setState(newState)
}
}
getCitationState(sha256) {
const { paperInfo, unknownCitations } = this.props.api
let citation = (unknownCitations.citations || []).find(f => f.id === sha256)
- if (!citation) {
+ if (citation) {
+ citation.isUnknown = true
+ } else {
citation = (paperInfo.citations || []).find(f => f.id === sha256)
+ if (citation) {
+ citation.isUnknown = false
+ }
}
// console.log(sha256, citation)
let state = { citation }
@@ -103,12 +126,19 @@ class PaperVerify extends Component {
title: this.state.citation.title,
dataset: this.props.api.paperInfo.dataset.key,
uses_dataset: this.state.uses_dataset,
- doesnt_use_dataset: this.state.doesnt_use_dataset,
images_in_paper: this.state.images_in_paper,
+ used_as_model: this.state.used_as_model,
verified_by: this.state.verified_by,
reference: this.state.reference,
notes: this.state.notes,
date: dateString,
+ isUnknown: this.state.citation.isUnknown,
+ institution_1: this.state.institution_1,
+ validate_1: this.state.validate_1,
+ institution_2: this.state.institution_2,
+ validate_2: this.state.validate_2,
+ institution_3: this.state.institution_3,
+ validate_3: this.state.validate_3,
})
this.next(false)
}
@@ -150,7 +180,7 @@ class PaperVerify extends Component {
}
render() {
- let { paperInfo } = this.props.api
+ const { paperInfo, unknownCitations } = this.props.api
if (paperInfo.loading) return <Loader />
// console.log(this.state)
const { citation } = this.state
@@ -169,6 +199,7 @@ class PaperVerify extends Component {
return (
<a
key={i}
+ href={pdf}
onClick={() => this.setState({ pdf_index: i })}
className={i === this.state.pdf_index ? 'selected pdfLink' : 'pdfLink'}
>
@@ -186,45 +217,117 @@ class PaperVerify extends Component {
</a>
</div>
- <div className='param'>
- <label>Uses the dataset?</label>
- <input
- className='vetting'
- type='radio'
- name='uses_dataset'
- checked={!!this.state.uses_dataset}
- onChange={e => this.setState({
- uses_dataset: e.target.checked,
- doesnt_use_dataset: !e.target.checked,
- })}
- />
+ {this.renderLocationForm()}
+
+ <div className='row vettingRow'>
+ <div className='rowHeading'>
+ {'Uses dataset'}
+ </div>
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='uses_dataset'
+ checked={String(this.state.uses_dataset) === USES_DATASET.YES}
+ onChange={e => this.setState({
+ uses_dataset: USES_DATASET.YES,
+ })}
+ />
+ <div>{"Yes"}</div>
+ </label>
+
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='uses_dataset'
+ checked={String(this.state.uses_dataset) === USES_DATASET.NO}
+ onChange={e => this.setState({
+ uses_dataset: USES_DATASET.NO,
+ })}
+ />
+ <div>{"No"}</div>
+ </label>
+
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='uses_dataset'
+ checked={String(this.state.uses_dataset) !== USES_DATASET.YES && String(this.state.uses_dataset) !== USES_DATASET.NO}
+ onChange={e => this.setState({
+ uses_dataset: USES_DATASET.UNKNOWN,
+ })}
+ />
+ <div>{"Not enough information"}</div>
+ </label>
</div>
- <div className='param'>
- <label>{"Doesn't use dataset"}</label>
- <input
- className='vetting'
- type='radio'
- name='uses_dataset'
- checked={!!this.state.doesnt_use_dataset}
- onChange={e => this.setState({
- uses_dataset: !e.target.checked,
- doesnt_use_dataset: e.target.checked
- })}
- />
+ <div
+ className={String(this.state.uses_dataset) === USES_DATASET.YES ? 'row vettingRow' : 'row vettingRow disabled'}
+ disabled={String(this.state.uses_dataset) === USES_DATASET.YES ? false : true}
+ >
+ <div className='rowHeading'>
+ {'Paper shows images'}
+ </div>
+
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='images_in_paper'
+ checked={this.state.images_in_paper === "TRUE"}
+ onChange={e => this.setState({
+ images_in_paper: "TRUE",
+ })}
+ />
+ <div>{"Yes"}</div>
+ </label>
+
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='images_in_paper'
+ checked={this.state.images_in_paper === "FALSE"}
+ onChange={e => this.setState({
+ images_in_paper: "FALSE",
+ })}
+ />
+ <div>{"No"}</div>
+ </label>
</div>
- <div className='param'>
- <label>{"Uses images from dataset"}</label>
- <input
- className='vetting'
- type='checkbox'
- name='images_in_paper'
- checked={!!this.state.images_in_paper}
- onChange={e => this.setState({
- images_in_paper: e.target.checked,
- })}
- />
+ <div className='row vettingRow'>
+ <div className='rowHeading'>
+ {'Used as model'}
+ </div>
+
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='used_as_model'
+ checked={this.state.used_as_model === "TRUE"}
+ onChange={e => this.setState({
+ used_as_model: "TRUE",
+ })}
+ />
+ <div>{"Yes"}</div>
+ </label>
+
+ <label>
+ <input
+ className='vetting'
+ type='radio'
+ name='used_as_model'
+ checked={this.state.used_as_model === "FALSE"}
+ onChange={e => this.setState({
+ used_as_model: "FALSE",
+ })}
+ />
+ <div>{"No"}</div>
+ </label>
</div>
<div className='param'>
@@ -244,10 +347,10 @@ class PaperVerify extends Component {
rows={3}
cols={50}
type='text'
- className='notes'
- value={this.state.notes}
- placeholder='Notes'
- onChange={e => this.setState({ notes: e.target.value })}
+ className='reference'
+ value={this.state.reference}
+ placeholder='Reference'
+ onChange={e => this.setState({ reference: e.target.value })}
/>
</div>
@@ -274,7 +377,7 @@ class PaperVerify extends Component {
<button
className='btn'
onClick={this.prev.bind(this)}
- >{'Prev >'}</button>
+ >{'< Prev'}</button>
<button
className='btn'
@@ -286,8 +389,71 @@ class PaperVerify extends Component {
</div>
)
}
+ renderLocationForm() {
+ if (!this.state.citation.isUnknown) return
+ return (
+ <div>
+ <div className='param'>
+ <label>Institution #1</label>
+ <Autocomplete
+ placeholder='Institution #1'
+ value={this.state.institution_1}
+ onSelect={(institution_1, validate_1) => {
+ this.setState({ institution_1, validate_1 })
+ }}
+ onCancel={value => {
+ this.setState({ institution_1: '', validate_1: false })
+ }}
+ />
+ </div>
+
+ <div className='param'>
+ <label>Institution #2</label>
+ <Autocomplete
+ placeholder='Institution #2'
+ value={this.state.institution_2}
+ onSelect={(institution_2, validate_2) => {
+ this.setState({ institution_2, validate_2 })
+ }}
+ onCancel={value => {
+ this.setState({ institution_2: '', validate_2: false })
+ }}
+ />
+ </div>
+
+ <div className='param'>
+ <label>Institution #3</label>
+ <Autocomplete
+ placeholder='Institution #3'
+ value={this.state.institution_3}
+ onSelect={(institution_3, validate_3) => {
+ this.setState({ institution_3, validate_3 })
+ }}
+ onCancel={value => {
+ this.setState({ institution_3: '', validate_3: false })
+ }}
+ />
+ </div>
+ </div>
+ )
+ }
}
+/*
+ <div className='param'>
+ <label>{"Verifiable"}</label>
+ <input
+ className='vetting'
+ type='checkbox'
+ name='verifiable'
+ checked={!!this.state.verifiable}
+ onChange={e => this.setState({
+ verifiable: e.target.checked,
+ })}
+ />
+ </div>
+*/
+
const mapStateToProps = state => ({
api: state.api,
})
diff --git a/scraper/client/store.js b/scraper/client/store.js
index 8649d472..b199ae29 100644
--- a/scraper/client/store.js
+++ b/scraper/client/store.js
@@ -13,6 +13,8 @@ const initialState = () => ({
address: {},
paperInfo: {},
unknownCitations: {},
+ verify: {},
+ verifications: {},
options: {}
})
diff --git a/scraper/client/types.js b/scraper/client/types.js
index 53c0cff0..e6b4142c 100644
--- a/scraper/client/types.js
+++ b/scraper/client/types.js
@@ -11,3 +11,10 @@ export const api = tagAsType('api', [
])
export const init = '@@INIT'
+
+export const USES_DATASET = {
+ YES: "1",
+ NO: "-1",
+ UNKNOWN: "0",
+ NO_DATA: "-2",
+}
diff --git a/scraper/s2-geocode-server.py b/scraper/s2-geocode-server.py
index 9d824443..3aeda881 100644
--- a/scraper/s2-geocode-server.py
+++ b/scraper/s2-geocode-server.py
@@ -13,9 +13,6 @@ load_dotenv()
from util import *
-locations_worksheet = fetch_worksheet('paper_locations')
-verifications_worksheet = fetch_worksheet('verifications')
-paper_lookup = fetch_google_lookup('citation_lookup')
addresses = AddressBook()
app = Flask(__name__, static_url_path="/reports", static_folder=os.path.abspath("reports"))
@@ -41,6 +38,7 @@ def list_locations():
@app.route('/api/papers', methods=['GET'])
def list_papers():
+ paper_lookup = fetch_google_lookup('citation_lookup')
return jsonify({
'papers': paper_lookup,
})
@@ -73,6 +71,7 @@ def add_address():
form = request.get_json()
print(form)
# id, title, institution_1, institution_2, institution_3, institution_4, notes
+ locations_worksheet = fetch_worksheet('paper_locations')
locations_worksheet.append_row([
form['paper_id'],
form['title'],
@@ -90,6 +89,23 @@ def add_address():
'status': 'ok'
})
+@app.route('/api/verifications', methods=['GET'])
+def list_verifications():
+ return jsonify({
+ 'verifications': fetch_google_lookup('verifications', item_key='paper_id'),
+ })
+
+@app.route('/api/verifications/<dataset>', methods=['GET'])
+def list_dataset_verifications(dataset):
+ rows = fetch_google_sheet_objects('verifications')
+ verifications = {}
+ for row in rows:
+ if row['dataset'] == dataset:
+ verifications[row['paper_id']] = row
+ return jsonify({
+ dataset: verifications,
+ })
+
@app.route('/api/verify/<sha256>', methods=['GET'])
def find_verification(sha256):
worksheet = fetch_worksheet('verifications')
@@ -114,12 +130,12 @@ def find_verification(sha256):
})
@app.route('/api/verify/add', methods=['POST'])
-def add_verifications():
+def add_verification():
form = request.get_json()
print(form)
- keys = verifications_worksheet.row_values(1)
- row = [ form[key] if key in form else '' for key in keys ]
- verifications_worksheet.append_row(row)
+ update_or_append_worksheet('verifications', form)
+ if form['isUnknown']:
+ update_or_append_worksheet('paper_locations', form)
return jsonify({
'status': 'ok'
})
diff --git a/scraper/util.py b/scraper/util.py
index 1ee2ad52..96ced430 100644
--- a/scraper/util.py
+++ b/scraper/util.py
@@ -452,6 +452,21 @@ def fetch_google_lookup(name, item_key='key'):
lookup[rec[item_key]] = rec
return lookup
+def update_or_append_worksheet(name, form):
+ worksheet = fetch_worksheet(name)
+ keys = worksheet.row_values(1)
+ row = [ form[key] if key in form else '' for key in keys ]
+ try:
+ cell = worksheet.find(form['paper_id'])
+ except:
+ cell = None
+
+ if cell:
+ for i, item in enumerate(row):
+ worksheet.update_cell(cell.row, i+1, item)
+ else:
+ worksheet.append_row(row)
+
def load_countries():
countries = read_json('countries.json')
lookup = {}