first commit

This commit is contained in:
Andrea Mannocci 2020-06-11 16:40:40 +02:00
commit 790940581e
10 changed files with 427 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
__pycache__
static/bower_components

0
README.md Normal file
View File

49
es_connector.py Normal file
View File

@ -0,0 +1,49 @@
from elasticsearch import Elasticsearch
from elasticsearch_dsl import *
import logging
log = logging.getLogger("ES connector")
log.setLevel(logging.INFO)
ES_HOST = "ip-90-147-167-25.ct1.garrservices.it"
class ESObject(object):
def __init__(self, id, pid, type, title, abstract, propagated_abstract):
self.id = id
self.pid = pid
self.type = type
self.title = title
self.abstract = abstract
self.propagated_abstract = propagated_abstract
class ESResponse(object):
def __init__(self, count=0, hits=[]):
self.count = count
self.hits = hits
class ESConnector(object):
def __init__(self):
self.index_host = ES_HOST
self.client = Elasticsearch(hosts=self.index_host, timeout=600000)
def query_after(self, query_string=None, start=0, i='propagation-after'):
s = Search(using=self.client, index=i)
if query_string is not None:
q = Q('query_string', query=query_string)
s = s.query(q)
s = s[start:start+10]
response = s.execute()
hits = []
for hit in response.hits:
hits.append(ESObject(hit.id,
hit.pid,
hit.type,
hit.title,
hit.abstract if 'abstract' in hit else '',
hit.propagated_abstract if 'propagated_abstract' in hit else ''))
return ESResponse(hits=hits, count=response.hits.total)

39
main.py Normal file
View File

@ -0,0 +1,39 @@
import logging
import os
import sys
from starlette.staticfiles import StaticFiles
from starlette.responses import FileResponse
from fastapi import FastAPI, Form
from es_connector import ESConnector
log = logging.getLogger("TPDL2020 webapp")
log.setLevel(logging.INFO)
log.info("TPDL2020 Webapp (re)started")
_CURDIR = os.path.dirname(os.path.abspath(__file__))
app = FastAPI()
app.mount('/static', StaticFiles(directory=os.path.join(_CURDIR, 'static' )))
es_connector = ESConnector()
@app.get('/')
def root():
return FileResponse(os.path.join(os.path.join(_CURDIR, 'static'),'index.html'))
# @app.get("/favicon.ico")
# def favicon():
# return FileResponse(os.path.join(os.path.join(_CURDIR, 'static' ),'favicon.ico'))
@app.get('/api/query/')
def query_get(q='*', s:int=0, i=None):
try:
log.info("Executing query={q} start={s}".format(q=q, s=s))
result = es_connector.query_after(q, s, i)
return result
except Exception as e:
log.error(e)

0
requirements.txt Normal file
View File

24
static/bower.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "static",
"authors": [
"Andrea Mannocci <andrea.mannocci@isti.cnr.it>"
],
"description": "",
"main": "",
"license": "MIT",
"homepage": "https://andremann.github.io",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"jquery": "^3.5.1",
"vue": "^2.6.11",
"bootstrap": "^4.5.0",
"axios": "^0.19.2"
}
}

106
static/css/cover.css Normal file
View File

@ -0,0 +1,106 @@
/*
* Globals
*/
/* Links */
a,
a:focus,
a:hover {
color: #fff;
}
/* Custom default button */
.btn-secondary,
.btn-secondary:hover,
.btn-secondary:focus {
color: #333;
text-shadow: none; /* Prevent inheritance from `body` */
background-color: #fff;
border: .05rem solid #fff;
}
/*
* Base structure
*/
html,
body {
height: 100%;
background-color: #333;
}
body {
display: -ms-flexbox;
display: flex;
color: #fff;
text-shadow: 0 .05rem .1rem rgba(0, 0, 0, .5);
box-shadow: inset 0 0 5rem rgba(0, 0, 0, .5);
}
.cover-container {
max-width: 42em;
}
/*
* Header
*/
.masthead {
margin-bottom: 2rem;
}
.masthead-brand {
margin-bottom: 0;
}
.nav-masthead .nav-link {
padding: .25rem 0;
font-weight: 700;
color: rgba(255, 255, 255, .5);
background-color: transparent;
border-bottom: .25rem solid transparent;
}
.nav-masthead .nav-link:hover,
.nav-masthead .nav-link:focus {
border-bottom-color: rgba(255, 255, 255, .25);
}
.nav-masthead .nav-link + .nav-link {
margin-left: 1rem;
}
.nav-masthead .active {
color: #fff;
border-bottom-color: #fff;
}
@media (min-width: 48em) {
.masthead-brand {
float: left;
}
.nav-masthead {
float: right;
}
}
/*
* Cover
*/
.cover {
padding: 0 1.5rem;
}
.cover .btn-lg {
padding: .75rem 1.25rem;
font-weight: 700;
}
/*
* Footer
*/
.mastfoot {
color: rgba(255, 255, 255, .5);
}

7
static/css/starter.css Normal file
View File

@ -0,0 +1,7 @@
body {
padding-top: 5rem;
}
.starter-template {
padding: 3rem 1.5rem;
text-align: center;
}

143
static/index.html Normal file
View File

@ -0,0 +1,143 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="static/css/starter.css" rel="stylesheet">
<!-- <link href="static/css/cover.css" rel="stylesheet"> -->
<title>TPDL 2020 Companion WebApp</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" href="#">TPDL 2020 Paper #55 WebApp</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault"
aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">The paper</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="container" id="app">
<div class="row justify-content-center">
<div class="col-10">
<div class="input-group">
<input type="text" class="form-control" v-model="query" placeholder="Your query terms..."
aria-label="Your query terms..." aria-describedby="button-addon2">
<select class="form-control col-md-3" aria-describedby="button-addon2" v-model="index" v-on:change="switch_index">
<option v-bind:value="'propagation-after'">After propagation</option>
<option v-bind:value="'propagation-before'">Before propagation</option>
</select>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" id="button-addon2"
v-on:click="first_query">Search!</button>
</div>
</div>
<a href="#" v-on:click="run_example(1)">Example 1</a>
<a href="#" v-on:click="run_example(2)">Example 2</a>
<a href="#" v-on:click="run_example(3)">Example 3</a>
</div>
</div>
<div class="row justify-content-center" v-if="hits">
<div>
<strong>Query:</strong> {{query}} - Viewing records {{start}} to {{start+10}} - <strong>Hits:</strong> {{total}}
</div>
</div>
<div class="row justify-content-center" v-if="hits">
<div>
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
<li class="page-item" v-bind:class="{disabled: start < 10}" v-on:click="start >= 10 && previous_page()">
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
</li>
<li class="page-item" v-bind:class="{disabled: start+10 > total}"
v-on:click="start+10 <= total && next_page()">
<a class="page-link" href="#">Next</a>
</li>
</ul>
</nav>
</div>
<table class="table table-responsive">
<thead>
<tr>
<th scope="col"><span class="badge badge-primary">ID</span> &amp; <span
class="badge badge-warning">PIDs</span></th>
<th scope="col">Type</th>
<th scope="col">Metadata</th>
</tr>
</thead>
<tbody>
<tr v-for="hit in hits">
<td>
<div><span class="badge badge-primary">{{hit.id}}</span></div>
<div v-for="pid in hit.pid['_l_']"><span class="badge badge-warning">{{pid}}</span></div>
</td>
<td>
<div>
<span v-if="hit.type == 'publication'" class="badge badge-success">publication</span>
<span v-if="hit.type == 'dataset'" class="badge badge-danger">dataset</span>
</div>
</td>
<td>
<div><strong>Titles</strong></div>
<div v-for="title in hit.title['_l_']">→ {{title}}</div>
<div><strong>Abstracts</strong></div>
<div v-for="abstract in hit.abstract['_l_']">→ {{abstract}}</div>
<div v-if="index != 'propagation-before'"><strong>Propagated abstracts</strong></div>
<div v-for="propagated in hit.propagated_abstract['_l_']">→ {{propagated}}<br />
</td>
</tr>
</tbody>
</table>
</div>
</main>
<!-- Optional JavaScript -->
<script src="static/bower_components/vue/dist/vue.min.js"></script>
<script src="static/bower_components/axios/dist/axios.min.js"></script>
<script src="static/js/app.js"></script>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="static/bower_components/jquery/dist/jquery.slim.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
crossorigin="anonymous"></script>
<script src="static/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
</body>
</html>

56
static/js/app.js Normal file
View File

@ -0,0 +1,56 @@
var app = new Vue({
el: '#app',
data: {
query: null,
hits: null,
start: 0,
total: null,
index: 'propagation-after'
},
methods: {
switch_index: function () {
this.first_query()
},
run_query: function () {
if (this.query == null)
this.query = '*';
axios
.get('/api/query?q=' + this.query + '&s=' + this.start + '&i=' + this.index)
.then(response => { this.hits = response.data.hits, this.total = response.data.count });
},
first_query: function () {
this.start = 0;
this.run_query();
},
run_example: function (n) {
switch (n) {
case 1:
this.query = "\"60|725e95aad103035a194402a606c5826d\"";
this.run_query();
break;
case 2:
this.query = "\"PRIMAP-hist Socio-Eco dataset\"";
this.run_query();
break;
case 3:
this.query = "shc014";
this.run_query();
break;
}
},
previous_page: function () {
this.start = this.start - 10;
this.run_query();
},
next_page: function () {
this.start = this.start + 10;
this.run_query();
}
},
mounted() {
}
})