Skip to content

Commit 9b1a99f

Browse files
committed
initial commit
0 parents  commit 9b1a99f

24 files changed

+1293
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env

Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#FROM tiangolo/meinheld-gunicorn-flask:python3.8
2+
FROM tiangolo/uwsgi-nginx-flask:python3.8
3+
4+
COPY ./requirements.txt /tmp
5+
RUN pip install -r /tmp/requirements.txt
6+
COPY ./app /app
7+
8+

LICENSE

+674
Large diffs are not rendered by default.

Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
build:
2+
docker build . -t nherbaut/scpushack
3+
push:
4+
docker push nherbaut/scpushack
5+
run:
6+
docker run -d -p 8106:80 -e API_KEY=${API_KEY} --name "scpushack" nherbaut/scpushack
7+
sleep 2
8+
echo Go to localhost:8106 to visit the website
9+
stop:
10+
docker rm -f scpushack
11+
12+
13+

README.md

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Install
2+
3+
## Install docker and docker-compose if necessary:
4+
5+
```bash
6+
# docker-ce
7+
$ wget https://get.docker.com -O get.docker.sh sh ./get.docker.sh
8+
9+
# To run docker without sudo (remember to log out and back in for this to take effect!)
10+
$ sudo groupadd docker && sudo usermod -aG docker $USER
11+
12+
# docker compose
13+
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
14+
$ sudo chmod +x /usr/local/bin/docker-compose
15+
```
16+
17+
## Build all the services and create the database:
18+
19+
```bash
20+
$ docker-compose up
21+
22+
# Create the DB
23+
$ docker-compose exec web bash -c 'PGPASSWORD=$POSTGRES_PASSWORD createdb -U $POSTGRES_USER -h db $POSTGRES_USER'
24+
```
25+
26+
## Seed the database:
27+
28+
```python
29+
# /!\ Execute these commands inside the web container
30+
$ python
31+
>>> from app import db
32+
>>> db.create_all(); exit()
33+
# Set alembic revision to latest to avoid running all the previous migrations
34+
$ flask db stamp head
35+
```
36+
37+
## Start the project:
38+
39+
```
40+
docker-compose up
41+
```
42+
43+
---
44+
45+
# Code generation
46+
47+
We rely on [OpenAPIs code generation](http://openapis.org/) and sql reverse engineering to create back-end code for rest APIs and persistence.
48+
49+
**/!\ All these commands must be executed inside the web container /!\\**
50+
51+
## Python rest api
52+
53+
Generates the python-flask REST API layer from its [openapi specification](http://spec.openapis.org/oas/v3.0.2) in file api-definition.yml.
54+
55+
```bash
56+
make build-api
57+
```
58+
59+
## Python persistence models
60+
61+
Generates the persistence model objects from a live SQL connection specified in the Makefile.
62+
63+
```bash
64+
make build-model
65+
```
66+
67+
## Javascript client API
68+
69+
Generates the typescript-jquery client for the API.
70+
71+
```bash
72+
make build-api-client
73+
```
74+
75+
## Ruby client API
76+
77+
Generates the ruby client for the API.
78+
79+
```bash
80+
make build-api-client-ruby
81+
```
82+
83+
---
84+
85+
## Production
86+
87+
it should run as a WSGI app, behind https

app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
migrations/*

app/.idea/emns.iml

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/.idea/misc.xml

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/.idea/vcs.xml

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/.idea/workspace.xml

+272
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
migrations/*

app/app/.idea/.gitignore

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/.idea/app.iml

+19
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/.idea/inspectionProfiles/profiles_settings.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/.idea/misc.xml

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/.idea/vcs.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/app/__init__.py

Whitespace-only changes.

app/app/main.py

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from flask import Flask, render_template, request
2+
import requests
3+
import itertools
4+
import os
5+
import urllib
6+
app = Flask(__name__)
7+
8+
9+
@app.route('/')
10+
@app.route('/home')
11+
@app.route('/query', methods=["GET"])
12+
def hello_world():
13+
return render_template('index.html')
14+
15+
16+
17+
@app.route('/query', methods=["POST"])
18+
def query():
19+
query = request.form.get("query")
20+
21+
is_count = request.form.get("count")
22+
23+
p = f'https://api.elsevier.com/content/search/scopus?start=%d&count=%d&query=%s&apiKey={os.environ("API_KEY")}'
24+
count = int(requests.get(p % (0, 1, query.replace(" ", "+").replace("\\", "%%22"))).json()["search-results"][
25+
"opensearch:totalResults"])
26+
27+
print(f"fetching {count} results")
28+
if is_count:
29+
return render_template('index.html', query=query, count=count)
30+
else:
31+
refs = list(itertools.chain(*[aa["search-results"]["entry"] for aa in
32+
[requests.get(p % (i, 25, query.replace(" ", "+").replace("\\", "%%22"))).json() for i
33+
in
34+
range(0, min(1000,count), 25)]]))
35+
dois = [ r.get("prism:doi") for r in refs if "prism:doi" in r]
36+
return render_template('dois.html',dois=dois)
37+
38+
39+
if __name__ == '__main__':
40+
app.run()

app/app/templates/dois.html

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>dois</title>
6+
</head>
7+
<body>
8+
{% for d in dois %}
9+
@article{article{{loop.index}},
10+
doi = { {{d}} },
11+
}
12+
{% endfor %}
13+
</body>
14+
</html>

app/app/templates/index.html

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Scpus Hack</title>
6+
7+
<script>
8+
9+
function onLoaded(evt){
10+
11+
document.getElementById("querybox").value = window.localStorage.getItem("query");
12+
}
13+
14+
15+
function textAreaChange(){
16+
updateQueryStorage(document.getElementById("querybox").value);
17+
}
18+
19+
function updateQueryStorage(str){
20+
window.localStorage.setItem("query", str);
21+
}
22+
23+
24+
window.onload = onLoaded;
25+
26+
27+
</script>
28+
</head>
29+
<body>
30+
<h1>Scpus Hack: Get a list of DOIs that match your search queries</h1>
31+
<h2>How to</h2>
32+
<ol>
33+
<li>Type your query by following the <a
34+
href="http://schema.elsevier.com/dtds/document/bkapi/search/SCOPUSSearchTips.htm">doc</a> e.g. <i>TITLE-ABS-KEY(blockchain) AND TITLE-ABS-KEY(INDUSTRY 4.0) AND (TITLE-ABS-KEY(Security) OR TITLE-ABS-KEY(Privacy))</i></li>
35+
<li>Click "count results" to get the number of results</li>
36+
<li>Once you have a number, click Fetch to show the dois as bibtex</li>
37+
<li>save the content in a .bib file</li>
38+
<li>import it in mendeley Desktop</li>
39+
<li>Select all the (untitled) entries and right click > update details</li>
40+
<li>Wait for mendeley to populate each entry</li>
41+
<li>In mendeley, select all entires and export as a bib file</li>
42+
<li>Inport your results in <a href="parsif.al">parsif.al</a></li>
43+
</ol>
44+
45+
46+
<form action="query" method="POST">
47+
<p>Query:</p>
48+
<fieldset>
49+
50+
51+
52+
53+
{% if count %}
54+
<textarea id="querybox" name="query" readonly>{{ query }}</textarea>
55+
56+
57+
</fieldset>
58+
<input type="submit" value="Fetch {{ count }} results (up to 1000)">
59+
{% else %}
60+
<textarea id="querybox" name="query" onkeyup="textAreaChange()"></textarea>
61+
<input type="hidden" name="count" value="true">
62+
63+
</fieldset>
64+
<input type="submit" value="Count Results">
65+
{% endif %}
66+
67+
68+
69+
70+
</form>
71+
<form action="/home" method="GET">
72+
<input type="submit" value="Reset" />
73+
</form>
74+
75+
</body>
76+
77+
78+
</html>

app/uwsgi.ini

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[uwsgi]
2+
module = app.main
3+
callable = app
4+
buffer-size = 8192

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Flask==1.1.2
2+
requests==2.25.1

0 commit comments

Comments
 (0)