-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
496 lines (416 loc) · 19.9 KB
/
app.py
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
from flask import Flask, render_template, request, jsonify
import psycopg2
app = Flask(__name__)
conn = psycopg2.connect(
host="host",
database="database",
user="user",
password="password"
)
# get a cursor from the database connection
conn.autocommit = True
conn.set_client_encoding('UTF8')
cur=conn.cursor()
# Index Page
@app.route('/')
def index():
try:
cur.execute("SELECT thesis_no, author_id,title, TYPE, year, language, num_pages FROM Theses")
result = cur.fetchall()
# Get column names from cursor description
column_names = [desc[0] for desc in cur.description]
# Convert result to dictionary format
result = [dict(zip(column_names, row)) for row in result]
return render_template('search_result.html', homepage=True, response=result)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
# add data page
@app.route('/add_data')
def add_data():
# get university names
cur.execute("SELECT university_id, name FROM Universities")
universities = cur.fetchall()
# get institute names
cur.execute("SELECT institute_id, name, university_id FROM institutes")
institutes = cur.fetchall()
# get person names
cur.execute("SELECT person_id, name FROM persons")
persons = cur.fetchall()
# get topic names
cur.execute("SELECT topic_id ,topic_name FROM subjecttopics")
topics = cur.fetchall()
return render_template('add_data.html', uni_list=universities, ins_list=institutes, person_list=persons, topic_list=topics)
# add person
@app.route('/add_person', methods=['POST'])
def add_person():
title = request.form.get('title')
name = request.form.get('name')
try:
cur.execute("INSERT INTO Persons(title, name) VALUES(%s, %s)", (title, name))
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Person added successfully")
# add university
@app.route('/add_university', methods=['POST'])
def add_university():
name = request.form.get('name')
try:
cur.execute("INSERT INTO Universities(name) VALUES(%s)", (name,))
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="University added successfully")
# add institute
@app.route('/add_institute', methods=['POST'])
def add_institute():
name = request.form.get('name')
uni_id = request.form.get('uni_id')
try:
cur.execute("INSERT INTO Institutes(name, university_id) VALUES(%s, %s)", (name, uni_id))
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Institute added successfully")
# add topic
@app.route('/add_topic', methods=['POST'])
def add_topic():
name = request.form.get('name')
# if topic already exists, return error
cur.execute("SELECT topic_name FROM SubjectTopics WHERE topic_name = %s", (name,))
if cur.fetchone():
return render_template('result.html', response="Topic already exists.", error=True)
try:
cur.execute("INSERT INTO SubjectTopics(topic_name) VALUES(%s)", (name,))
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Topic added successfully")
# add thesis
@app.route('/add_thesis', methods=['POST'])
def add_thesis():
'''
Add a thesis to the database.
if thesis and its related data are valid, add the thesis to the theses table, related data to the related tables.
if any error occurs, rollback the operation and return the error message.
'''
# Retrieve thesis details from the request
title = request.form.get('title')
abstract = request.form.get('abstract')
author = request.form.get('author')
year = request.form.get('year')
type = request.form.get('type')
uni = request.form.get('uni')
ins = request.form.get('ins')
num_pages = request.form.get('num_pages')
language = request.form.get('language')
supervisors = request.form.getlist('supervisors')
cosupervisors = request.form.getlist('cosupervisors')
topics = request.form.getlist('topics')
keywords = request.form.get('keywords')
# at least one supervisor is required
if not supervisors:
return render_template('result.html', response=( "At least one supervisor is required."), error=True)
if not topics:
return render_template('result.html', response=( "At least one topic is required."), error=True)
# Convert author, supervisors and cosupervisors to integer list
author_id = int(author)
supervisor_ids = [int(sup) for sup in supervisors]
cosupervisor_ids = [int(cosup) for cosup in cosupervisors]
# Create a union set of all persons
all_persons = set([author_id] + supervisor_ids + cosupervisor_ids)
cur.execute("SELECT person_id FROM Persons WHERE person_id = ANY(%s);", (list(all_persons),))
valid_persons = set([row[0] for row in cur.fetchall()])
if len(all_persons) > len(valid_persons):
return render_template('result.html', response=( "Some persons (author, supervisors, cosupervisors) are not found in the Persons table."), error=True)
topics_int = [int(topic) for topic in topics]
# Check topics in SubjectTopics table
cur.execute("SELECT topic_id FROM SubjectTopics WHERE topic_id = ANY(%s);", (topics_int,))
valid_topics = [row[0] for row in cur.fetchall()]
if len(valid_topics) != len(topics):
return render_template('result.html', response=( "Some topics are not found in the SubjectTopics table."), error=True)
# Each supervisor, cosupervisor and author must be different from each other
if len(set(supervisors).intersection(cosupervisors)) > 0 or author in supervisors or author in cosupervisors:
return render_template('result.html', response=("Author, supervisors, and cosupervisors must be different."), error=True)
# set submission date to current date
submission_date = "now()"
try:
# Add data to the Thesis table
cur.execute(
"""
INSERT INTO Theses(title, abstract, author_id, year, type, university_id, institute_id, num_pages, language, submission_date)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING thesis_no;
""",
(title, abstract, author, year, type, uni, ins, num_pages, language, submission_date)
)
thesis_no = cur.fetchone()[0]
try:
# Add data to the Supervisors table
for supervisor in supervisors:
cur.execute(
"INSERT INTO Supervisors (thesis_no, supervisor) VALUES (%s, %s);",
(thesis_no, supervisor)
)
# Add data to the CoSupervisors table
for cosupervisor in cosupervisors:
cur.execute(
"INSERT INTO CoSupervisors (thesis_no, cosupervisor) VALUES (%s, %s);",
(thesis_no, cosupervisor)
)
# Add data to the ThesisSubjectTopics table
for topic in topics_int:
cur.execute(
"INSERT INTO ThesisSubjectTopics (thesis_no, topic_id) VALUES (%s, %s);",
(thesis_no, topic)
)
# Add data to the Keywords table and ThesisKeywords table
for keyword in keywords.split(","):
keyword = keyword.strip() # Trim whitespace
if keyword: # Skip empty strings
cur.execute("INSERT INTO Keywords (keyword) VALUES (%s) ON CONFLICT (keyword) DO NOTHING RETURNING keyword_id;", (keyword,))
keyword_id = cur.fetchone()
if keyword_id:
cur.execute(
"INSERT INTO ThesisKeywords (thesis_no, keyword_id) VALUES (%s, %s);",
(thesis_no, keyword_id[0])
)
# Commit the operations and close the connection
conn.commit()
except psycopg2.errors.RaiseException as e:
# rollback the add thesis operation
conn.rollback()
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Thesis added successfully. Thesis No: "+str(thesis_no))
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
# search page
@app.route('/search', methods=['GET'])
def search2():
# get university names
cur.execute("SELECT university_id, name FROM Universities")
universities = cur.fetchall()
# query that gets institute names and its university name
cur.execute("SELECT institutes.institute_id, institutes.name, institutes.university_id, universities.name FROM institutes INNER JOIN universities ON institutes.university_id = universities.university_id")
institutes = cur.fetchall()
# get person names
cur.execute("SELECT person_id, title, name FROM persons")
persons = cur.fetchall()
# get topic names
cur.execute("SELECT topic_id ,topic_name FROM subjecttopics")
topics = cur.fetchall()
return render_template('search.html', uni_list=universities, ins_list=institutes, person_list=persons, topic_list=topics)
# get data from form, generate a query and return the result
@app.route('/search_thesis', methods=['POST'])
def search_thesis():
conditions=request.form.to_dict()
try:
query = generate_search_query(conditions)
except ValueError as e:
return render_template('result.html', response=(e), error=True)
try:
cur.execute(query)
result = cur.fetchall()
# Get column names from cursor description
column_names = [desc[0] for desc in cur.description]
# Convert result to dictionary format
result = [dict(zip(column_names, row)) for row in result]
return render_template('search_result.html', response=result)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
@app.route('/get_thesis/<string:id>', methods=['GET'])
def get_thesis(id):
try:
# Thesis details query
cur.execute('''SELECT
Theses.thesis_no,
Persons.title || ' ' || Persons.name AS author_name,
SupervisorPerson.NAME AS supervisor_name,
CoSupervisorPerson.NAME AS cosupervisor_name,
Theses.title,
Theses.abstract,
Universities.NAME AS university_name,
Institutes.NAME AS institute_name,
Theses.submission_date,
Theses.num_pages,
Theses.language,
Theses.year,
Theses.type
FROM
Theses
LEFT JOIN
Persons ON Theses.author_id = Persons.person_id
LEFT JOIN
Supervisors ON Theses.thesis_no = Supervisors.thesis_no
LEFT JOIN
Persons SupervisorPerson ON Supervisors.supervisor = SupervisorPerson.person_id
LEFT JOIN
CoSupervisors ON Theses.thesis_no = CoSupervisors.thesis_no
LEFT JOIN
Persons CoSupervisorPerson ON CoSupervisors.cosupervisor = CoSupervisorPerson.person_id
LEFT JOIN
Universities ON Theses.university_id = Universities.university_id
LEFT JOIN
Institutes ON Theses.institute_id = Institutes.institute_id
WHERE
Theses.thesis_no = %s;''', (id,))
thesis_details = cur.fetchall()
if not thesis_details:
return render_template('result.html', response="Thesis not found.", error=True)
thesis_details_dict = dict(zip([desc[0] for desc in cur.description], thesis_details[0]))
# Keywords query
cur.execute('''SELECT
Keywords.keyword
FROM
ThesisKeywords
LEFT JOIN
Keywords ON ThesisKeywords.keyword_id = Keywords.keyword_id
WHERE
ThesisKeywords.thesis_no = %s;''', (id,))
keywords = [item[0] for item in cur.fetchall()]
# Topics query
cur.execute('''SELECT
SubjectTopics.topic_name
FROM
ThesisSubjectTopics
LEFT JOIN
SubjectTopics ON ThesisSubjectTopics.topic_id = SubjectTopics.topic_id
WHERE
ThesisSubjectTopics.thesis_no = %s;''', (id,))
topics = [item[0] for item in cur.fetchall()]
result = {'thesis': thesis_details_dict, 'keywords': keywords, 'topics': topics}
return render_template('thesis.html', result=result)
except Exception as e:
return render_template('result.html', response=str(e), error=True)
@app.route('/edit')
def edit():
# get university names
cur.execute("SELECT university_id, name FROM Universities")
universities = cur.fetchall()
# query that gets institute names and its university name
cur.execute("SELECT institutes.institute_id, institutes.name, institutes.university_id, universities.name FROM institutes INNER JOIN universities ON institutes.university_id = universities.university_id")
institutes = cur.fetchall()
# get person names
cur.execute("SELECT person_id, title, name FROM persons")
persons = cur.fetchall()
# get topic names
cur.execute("SELECT topic_id ,topic_name FROM subjecttopics")
topics = cur.fetchall()
# get keywords
cur.execute("SELECT keyword_id, keyword FROM keywords")
return render_template('edit.html', uni_list=universities, ins_list=institutes, person_list=persons, topic_list=topics, keyword_list=cur.fetchall())
# Edit Person
@app.route('/edit_person/<int:id>', methods=['POST'])
def edit_person(id):
title = request.form.get('title')
name = request.form.get('name')
try:
cur.execute("UPDATE Persons SET title = %s, name = %s WHERE person_id = %s", (title, name, id))
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Person updated successfully")
# Edit Topic
@app.route('/edit_topic/<int:id>', methods=['POST'])
def edit_topic(id):
name = request.form.get('name')
try:
cur.execute("UPDATE SubjectTopics SET topic_name = %s WHERE topic_id = %s", (name, id))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Topic updated successfully")
# Edit University
@app.route('/edit_university/<int:id>', methods=['POST'])
def edit_university(id):
name = request.form.get('name')
try:
cur.execute("UPDATE Universities SET name = %s WHERE university_id = %s", (name, id))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="University updated successfully")
# Edit Institute
@app.route('/edit_institute/<int:id>', methods=['POST'])
def edit_institute(id):
name = request.form.get('name')
uni_id = request.form.get('university')
try:
cur.execute("UPDATE Institutes SET name = %s, university_id = %s WHERE institute_id = %s", (name, uni_id, id))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Institute updated successfully")
# Delete Person
@app.route('/delete_person/<int:id>', methods=['POST'])
def delete_person(id):
try:
cur.execute("DELETE FROM Persons WHERE person_id = %s", (id,))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Person deleted successfully")
# Delete Topic
@app.route('/delete_topic/<int:id>', methods=['POST'])
def delete_topic(id):
try:
cur.execute("DELETE FROM SubjectTopics WHERE topic_id = %s", (id,))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Topic deleted successfully")
# Delete University
@app.route('/delete_university/<int:id>', methods=['POST'])
def delete_university(id):
try:
cur.execute("DELETE FROM Universities WHERE university_id = %s", (id,))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="University deleted successfully")
# Delete Institute
@app.route('/delete_institute/<int:id>', methods=['POST'])
def delete_institute(id):
try:
cur.execute("DELETE FROM Institutes WHERE institute_id = %s", (id,))
except psycopg2.errors.ForeignKeyViolation as e:
return render_template('result.html', response=(e), error=True)
except psycopg2.errors.RaiseException as e:
return render_template('result.html', response=(e), error=True)
return render_template('result.html', response="Institute deleted successfully")
# Generate a SQL query based on the form data.
def generate_search_query(form_data):
if not form_data or all(not v for v in form_data.values()):
raise ValueError("At least one search parameter must be provided")
base_query = "SELECT DISTINCT Theses.thesis_no, Theses.author_id, Theses.title, Theses.TYPE, Theses.year, Theses.LANGUAGE, Theses.num_pages FROM Theses"
conditions = []
if form_data.get('uni'):
conditions.append(f"university_id = {form_data['uni']}")
if form_data.get('ins'):
conditions.append(f"institute_id = {form_data['ins']}")
if form_data.get('author'):
conditions.append(f"author_id = {form_data['author']}")
if form_data.get('title'):
conditions.append(f"title LIKE '%{form_data['title']}%'")
if form_data.get('abstract'):
conditions.append(f"abstract LIKE '%{form_data['abstract']}%'")
if form_data.get('type'):
conditions.append(f"TYPE = '{form_data['type']}'")
if form_data.get('language'):
conditions.append(f"LANGUAGE = '{form_data['language']}'")
if form_data.get('year'):
conditions.append(f"year = {form_data['year']}")
if form_data.get('topic'):
base_query += " INNER JOIN ThesisSubjectTopics ON Theses.thesis_no = ThesisSubjectTopics.thesis_no"
conditions.append(f"ThesisSubjectTopics.topic_id = {form_data['topic']}")
if form_data.get('keywords'):
base_query += " INNER JOIN ThesisKeywords ON Theses.thesis_no = ThesisKeywords.thesis_no"
keywords = form_data['keywords'].split(',')
keyword_conditions = [f"ThesisKeywords.keyword_id IN (SELECT keyword_id FROM Keywords WHERE keyword = '{keyword.strip()}')" for keyword in keywords]
conditions.append(f"({' OR '.join(keyword_conditions)})")
query = base_query
if conditions:
query += " WHERE " + " AND ".join(conditions)
return query
if __name__ == '__main__':
app.run(debug=True)