-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
162 lines (126 loc) · 5.11 KB
/
app.py
File metadata and controls
162 lines (126 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import os
from flask import Flask, render_template, redirect, request, make_response, url_for, jsonify, Response
from waitress import serve
import argparse as AP
import requests
import yaml
import hashlib
import logging
from pathlib import Path
from urllib.parse import urlparse
LOG_FILE = 'app.log'
IMPORTER_HOST = 'http://importer:5020'
FUSEKI_HOST = 'http://fuseki:3030'
logging.basicConfig(filename=LOG_FILE, level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__, template_folder='templates', static_folder='static', static_url_path='/assets')
app.secret_key = 'your_secret_key' # Replace with a strong secret key
users = []
def find_user(name):
'''Find a user by username in the users list'''
for user in users:
if user['username'] == name:
return user
return None
def pw_hash(pw_str):
'''Hash the password using MD5'''
return hashlib.md5(pw_str.encode()).hexdigest()
def get_page(page, title=""):
'''Render the home page'''
if 'username' in request.cookies:
return render_template(page, title=title)
else:
return redirect(url_for('login'))
@app.route('/')
@app.route('/collections')
def home():
return get_page('collections.html', "N4O-KG: Collections")
@app.route('/terminologies')
def terminologies():
return get_page('terminologies.html', "N4O-KG: Terminologies")
@app.route('/mappings')
def mappings():
return get_page('mappings.html', 'N4O-KG: Mappings')
@app.route('/login', methods=['GET', 'POST'])
def login():
'''Handle user login'''
if request.method == 'POST':
username = request.form['username']
user = find_user(username)
if user and user['password'] == pw_hash(request.form['password']):
response = make_response(redirect(url_for('home')))
response.set_cookie('username', username)
return response
else:
return render_template('login.html')
else:
return render_template('login.html')
@app.route('/logout')
def logout():
'''Handle user logout'''
response = make_response(redirect(url_for('login')))
response.delete_cookie('username')
return response
@app.route('/fuseki', methods=['post'])
def fuseki():
if data := request.json.get('data'):
res = requests.post(f'{FUSEKI_HOST}/n4o?query={data}')
return jsonify(res.text), res.status_code
@app.route('/importer/<path:subpath>', methods=["GET", "POST", "PUT", "DELETE"])
def importer(subpath):
'''Forwards requests to the importer service'''
res = requests.request(
method=request.method,
url=f'{IMPORTER_HOST}/{subpath}', # Forward to importer service
headers={k: v for k, v in request.headers if k.lower() != 'host'}, # Exclude 'host' header
data=request.get_data(),
cookies=request.cookies,
json=request.get_json(silent=True),
allow_redirects=False,
)
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
headers = [(k, v) for k, v in res.raw.headers.items() if k.lower() not in excluded_headers]
response = Response(res.content, res.status_code, headers)
return response
@app.route('/postCollectionData/<int:coll_index>', methods=['POST'])
def postCollectionData(coll_index):
'''Upload new collection data. Recent data will be deleted.'''
if coll_index > 0:
if file := request.files.get('file'):
add_mode = request.form.get('add_mode', 'false')
# Copy data to file, then call importer services receive and add/load
# logger.info(f'name = {file.filename} add-mode = {add_mode}')
buffer_name = f'collection_{coll_index}{Path(file.filename).suffix}'
file.save(f'./data/{buffer_name}')
service_url = f'{IMPORTER_HOST}/collection/{coll_index}'
res = requests.post(f'{service_url}/receive?from={buffer_name}')
if res.ok:
cmd_str = 'add' if add_mode == 'true' else 'load'
res = requests.post(f'{service_url}/{cmd_str}')
Path(f'./data/{buffer_name}').unlink(missing_ok=False)
return res.text, res.status_code
return jsonify(message='No data or collection index provided')
def read_yaml(fname):
'''Read a YAML file and return the data'''
if os.path.exists(fname):
with open(fname, 'r') as f:
return yaml.safe_load(f)
if __name__ == '__main__':
parser = AP.ArgumentParser()
parser.add_argument('-w', '--wsgi', action='store_true', help="Use WSGI server")
parser.add_argument('-p', '--port', type=int, default=5010, help="Server port")
parser.add_argument('-c', '--config', type=str, default="config.yaml", help="Config file")
args = parser.parse_args()
opts = {"port": args.port}
user_data = read_yaml('users.yaml')
if not user_data:
user_data = read_yaml('admin.yaml')
if user_data:
users = user_data['users']
else:
quit(stderr='No users found in users.yaml')
if args.wsgi:
opts['url_scheme'] = 'https'
serve(app, host="0.0.0.0", **opts)
else:
app.run(host="0.0.0.0", **opts)