-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
584 lines (511 loc) · 22.6 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
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
"""
This file contains the main function
"""
from modules import (
Log, # Importing the Log class for logging
timedelta, # Importing the timedelta class for working with time differences
terminalASCII, # Importing the terminalASCII function for displaying ASCII art in the terminal
currentTimeStamp, # Importing the currentTimeStamp function for getting the current timestamp
)
# Get the start time of the app
startTime = currentTimeStamp()
# Print a line breaker and a ASCII art
Log.breaker()
print(terminalASCII())
# Print a line breaker and a message that the app is starting
Log.app("Starting...")
# Importing necessary modules and classes
from modules import (
Flask,
) # Importing Flask class for creating the Flask application instance
# Importing blueprints for different routes
from routes.post import postBlueprint # Importing the blueprint for post route
from routes.user import userBlueprint # Importing the blueprint for user route
from routes.index import (
indexBlueprint,
) # Importing the blueprint for index route
from routes.login import (
loginBlueprint,
) # Importing the blueprint for login route
from routes.about import (
aboutBlueprint,
) # Importing the blueprint for about route
from routes.signup import (
signUpBlueprint,
) # Importing the blueprint for signup route
from routes.logout import (
logoutBlueprint,
) # Importing the blueprint for logout route
from routes.search import (
searchBlueprint,
) # Importing the blueprint for search route
from db.similaritysearch import (
similaritySearchBlueprint,
) # Importing the blueprint for vector search route
# from routes.ai import (
# AIBlueprint,
# ) # Importing the blueprint for vector search route
from routes.category import (
categoryBlueprint,
) # Importing the blueprint for category route
from routes.editPost import (
editPostBlueprint,
) # Importing the blueprint for post editing route
from routes.searchBar import (
searchBarBlueprint,
) # Importing the blueprint for search bar route
from routes.dashboard import (
dashboardBlueprint,
) # Importing the blueprint for dashboard route
from routes.verifyUser import (
verifyUserBlueprint,
) # Importing the blueprint for user verification route
from routes.adminPanel import (
adminPanelBlueprint,
) # Importing the blueprint for admin panel route
from routes.createPost import (
createPostBlueprint,
) # Importing the blueprint for creating post route
from routes.setLanguage import (
setLanguageBlueprint,
) # Importing the blueprint for setting language route
from routes.privacyPolicy import (
privacyPolicyBlueprint,
) # Importing the blueprint for privacy policy route
from routes.passwordReset import (
passwordResetBlueprint,
) # Importing the blueprint for password reset route
from routes.changeUserName import (
changeUserNameBlueprint,
) # Importing the blueprint for changing username route
from routes.changePassword import (
changePasswordBlueprint,
) # Importing the blueprint for changing password route
from routes.changeLanguage import (
changeLanguageBlueprint,
) # Importing the blueprint for changing language route
from routes.adminPanelUsers import (
adminPanelUsersBlueprint,
) # Importing the blueprint for admin panel users route
from routes.adminPanelPosts import (
adminPanelPostsBlueprint,
) # Importing the blueprint for admin panel posts route
from routes.accountSettings import (
accountSettingsBlueprint,
) # Importing the blueprint for account settings route
from routes.returnPostBanner import (
returnPostBannerBlueprint,
) # Importing the blueprint for returning post banners
from routes.adminPanelComments import (
adminPanelCommentsBlueprint,
) # Importing the blueprint for admin panel comments route
from routes.changeProfilePicture import (
changeProfilePictureBlueprint,
) # Importing the blueprint for changing profile picture route
from flask_wtf.csrf import (
CSRFProtect,
CSRFError,
) # Importing CSRF protection for Flask forms
# Importing database related utilities
from utils.dbChecker import dbFolder, usersTable, postsTable, commentsTable
# Importing various configuration variables from the modules
from modules import (
LOG_IN, # Importing the log-in configuration
UI_NAME, # Importing the UI name configuration
APP_HOST, # Importing the application host configuration
APP_NAME, # Importing the application name configuration
APP_PORT, # Importing the application port configuration
SMTP_MAIL, # Importing the SMTP mail configuration
SMTP_PORT, # Importing the SMTP port configuration
DEBUG_MODE, # Importing the debug mode configuration
APP_VERSION, # Importing the application version configuration
SMTP_SERVER, # Importing the SMTP server configuration
REGISTRATION, # Importing the registration configuration
SMTP_PASSWORD, # Importing the SMTP password configuration
DEFAULT_ADMIN, # Importing the default admin configuration
LOG_FILE_ROOT, # Importing the log file root configuration
APP_ROOT_PATH, # Importing the application root path configuration
STATIC_FOLDER, # Importing the static folder configuration
CUSTOM_LOGGER, # Importing the custom logger configuration
APP_SECRET_KEY, # Importing the application secret key configuration
RECAPTCHA_BADGE, # Flag for enabling/disabling reCAPTCHA for badge configuration
TEMPLATE_FOLDER, # Importing the template folder configuration
LOG_FOLDER_ROOT, # Importing the log folder root configuration
WERKZEUG_LOGGER, # Importing the werkzeug logger configuration
LOG_APP_FILE_ROOT, # Importing the app log file root configuration
SESSION_PERMANENT, # Importing the session permanence configuration
LOG_INFO_FILE_ROOT, # Importing the info log file root configuration
DEFAULT_ADMIN_POINT, # Importing the default admin point configuration
DEFAULT_ADMIN_EMAIL, # Importing the default admin email configuration
LOG_DANGER_FILE_ROOT, # Importing the danger log file root configuration
LOG_SUCCESS_FILE_ROOT, # Importing the success log file root configuration
LOG_WARNING_FILE_ROOT, # Importing the warning log file root configuration
DEFAULT_ADMIN_USERNAME, # Importing the default admin username configuration
DEFAULT_ADMIN_PASSWORD, # Importing the default admin password configuration
DEFAULT_ADMIN_PROFILE_PICTURE, # Importing the default admin profile picture configuration
)
# Importing reCAPTCHA configurations
from modules import (
RECAPTCHA, # Flag for enabling/disabling reCAPTCHA
RECAPTCHA_LOGIN, # Flag for enabling/disabling reCAPTCHA for login
RECAPTCHA_COMMENT, # Flag for enabling/disabling reCAPTCHA for comment
RECAPTCHA_SIGN_UP, # Flag for enabling/disabling reCAPTCHA for sign-up
RECAPTCHA_SITE_KEY, # Flag for enabling/disabling reCAPTCHA for site key
RECAPTCHA_POST_EDIT, # Flag for enabling/disabling reCAPTCHA for post edit
RECAPTCHA_SECRET_KEY, # Flag for enabling/disabling reCAPTCHA for secret key
RECAPTCHA_VERIFY_URL, # Flag for enabling/disabling reCAPTCHA for verify URL
RECAPTCHA_DELETE_USER, # Flag for enabling/disabling reCAPTCHA for delete user
RECAPTCHA_POST_DELETE, # Flag for enabling/disabling reCAPTCHA for post delete
RECAPTCHA_VERIFY_USER, # Flag for enabling/disabling reCAPTCHA for verify user
RECAPTCHA_POST_CREATE, # Flag for enabling/disabling reCAPTCHA for post create
RECAPTCHA_COMMENT_DELETE, # Flag for enabling/disabling reCAPTCHA for comment delete
RECAPTCHA_PASSWORD_RESET, # Flag for enabling/disabling reCAPTCHA for password reset
RECAPTCHA_PASSWORD_CHANGE, # Flag for enabling/disabling reCAPTCHA for password change
RECAPTCHA_USERNAME_CHANGE, # Flag for enabling/disabling reCAPTCHA for username change
RECAPTCHA_PROFILE_PICTURE_CHANGE, # Flag for enabling/disabling reCAPTCHA for profile picture change
)
from utils.errorHandlers.notFoundErrorHandler import (
notFoundErrorHandler,
) # This function handles 404 errors
from utils.errorHandlers.csrfErrorHandler import (
csrfErrorHandler,
) # This function handles CSRF errors
from utils.errorHandlers.unauthorizedErrorHandler import (
unauthorizedErrorHandler,
) # This function handles unauthorized access errors
from utils.afterRequest import (
afterRequestLogger,
) # This function handles loggins of every request
# Import the contextProcessor module that contains custom functions for the app
from modules import (
isLogin, # A function that checks LOG_IN constant
recaptchaBadge, # A function that checks RECAPTCHA_BADGE constant
isRegistration, # A function that checks REGISTRATION constant
browserLanguage, # A function that sets the app language based on the browser's preferred language
injectTranslations, # A function that injects translations into the context of the application
returnUserProfilePicture, # A function that returns the user's profile picture
)
from flask import Flask, render_template_string, request
import sqlite3
from peewee import Model, MySQLDatabase, TextField, SQL
from tidb_vector.peewee import VectorField
import google.generativeai as genai # Hypothetical import for Gemini API client
import threading
import time
# Import the necessary modules and functions
from modules import (
Log, # A class for logging messages
Blueprint, # A class for creating Flask blueprints
render_template, # A function for rendering Jinja templates
)
# Create a Flask app object with the app name, root path, static folder and template folder
app = Flask(
import_name=APP_NAME, # The name of the app
root_path=APP_ROOT_PATH, # The root path of the app
static_folder=STATIC_FOLDER, # The folder where the static files(*.js/*.css) are stored
template_folder=TEMPLATE_FOLDER, # The folder where the Jinja(*.html.jinja) templates are stored
)
# Set the secret key and the session permanent flag for the app
app.secret_key = APP_SECRET_KEY # The secret key for the app
app.config["SESSION_PERMANENT"] = (
SESSION_PERMANENT # A flag that determines if the session is permanent or not
)
# Create a CSRFProtect object for the app
csrf = CSRFProtect(app) # A CSRF protection mechanism for the app
# Init Gemini client
genai.configure(api_key='AIzaSyDDEdN89laTbTO8JEHJULde5fPm-h1GRGY')
embedding_model = 'models/embedding-001'
embedding_dimensions = 768
# Init TiDB connection
db = MySQLDatabase(
'test',
user='GLhAdq53EXzFzXf.root',
password='tbt7GsoxCY0cHvVs',
host='gateway01.eu-central-1.prod.aws.tidbcloud.com',
port=4000,
ssl_verify_cert=True,
ssl_verify_identity=True
)
# Define a model with a VectorField to store the embeddings
class DocModel(Model):
text = TextField()
embedding = VectorField(dimensions=embedding_dimensions)
class Meta:
database = db
table_name = "gemini_embedding_test"
def __str__(self):
return self.text
def fetch_titles():
"""Fetch titles from the local SQLite database."""
conn = sqlite3.connect('db/posts.db')
cursor = conn.cursor()
cursor.execute("SELECT title FROM posts")
titles = cursor.fetchall()
conn.close()
return [title[0] for title in titles]
def update_tidb():
"""Update TiDB with titles from the posts table."""
documents = fetch_titles()
# Fetch existing titles from TiDB to avoid duplication
existing_titles = set(doc.text for doc in DocModel.select(DocModel.text))
# Filter out titles that are already in TiDB
new_documents = [doc for doc in documents if doc not in existing_titles]
if new_documents:
# Insert only new documents and their embeddings into TiDB
embeddings = genai.embed_content(model=embedding_model, content=new_documents, task_type="retrieval_document")
data_source = [{"text": doc, "embedding": emb} for doc, emb in zip(new_documents, embeddings['embedding'])]
DocModel.insert_many(data_source).execute()
print(f"Inserted {len(new_documents)} new documents into TiDB.")
else:
print("No new documents to insert into TiDB.")
def background_updater():
"""Background thread function that updates TiDB every 10 seconds."""
while True:
update_tidb()
time.sleep(10) # Wait for 10 seconds before the next update
# Register the custom functions from the contextProcessor module as context processors for the app
# Context processors are functions that run before rendering a template and add variables to the template context
app.context_processor(
isLogin
) # A context processor that adds the isLogin variable to the template context
app.context_processor(
recaptchaBadge
) # A context processor that adds the recaptchaBadge variable to the template context
app.context_processor(
isRegistration
) # A context processor that adds the isRegistration variable to the template context
app.context_processor(
returnUserProfilePicture
) # A context processor that adds the getProfilePicture variable to the template context
app.context_processor(
injectTranslations
) # A context processor that adds the translations variable to the template context
app.before_request(
browserLanguage
) # A function that sets the app language based on the browser's preferred language
# Match WERKZEUG_LOGGER status
match WERKZEUG_LOGGER:
# If Werkzeug default logger is enabled
case True:
# Log that Werkzeug default logger is enabled
Log.app("Werkzeug default logger is enabled")
# If Werkzeug default logger is disabled
case False:
# Import getLogger from logging module
from logging import getLogger
# Log that Werkzeug default logger is disabled
Log.app("Werkzeug default logger is disabled")
# Disable the Werkzeug default logger
getLogger("werkzeug").disabled = True
# Match CUSTOM_LOGGER status
match CUSTOM_LOGGER:
# If Custom logger is enabled
case True:
# Log that Custom logger is enabled
Log.app("Custom logger is enabled")
# If Custom logger is disabled
case False:
# Log that Custom logger is disabled
Log.app("Custom logger is disabled")
# Log app settings
Log.app(f"Debug mode: {DEBUG_MODE}")
Log.app(f"Name: {APP_NAME}")
Log.app(f"Version: {APP_VERSION}")
Log.app(f"Host: {APP_HOST}")
Log.app(f"Port: {APP_PORT}")
Log.app(f"Secret key: {APP_SECRET_KEY}")
Log.app(f"Session permanent: {SESSION_PERMANENT}")
Log.app(f"Root path: {APP_ROOT_PATH}")
Log.app(f"Log folder root: {LOG_FOLDER_ROOT}")
Log.app(f"Log file root: {LOG_FILE_ROOT}")
Log.app(f"Log app file root: {LOG_APP_FILE_ROOT}")
Log.app(f"Log danger file root: {LOG_DANGER_FILE_ROOT}")
Log.app(f"Log success file root: {LOG_SUCCESS_FILE_ROOT}")
Log.app(f"Log info file root: {LOG_INFO_FILE_ROOT}")
Log.app(f"Log warning file root: {LOG_WARNING_FILE_ROOT}")
Log.app(f"Log in: {LOG_IN}")
Log.app(f"Registration: {REGISTRATION}")
# Log the UI name, template folder and the static folder
Log.app(f"UI: {UI_NAME}")
Log.app(f"Template folder: {TEMPLATE_FOLDER}")
Log.app(f"Static folder: {STATIC_FOLDER}")
# Log the SMTP server settings
Log.app(f"SMTP server: {SMTP_SERVER}")
Log.app(f"SMTP port: {SMTP_PORT}")
Log.app(f"SMTP mail: {SMTP_MAIL}")
Log.app(f"SMTP password: {SMTP_PASSWORD}")
# Check if recaptcha is enabled
match RECAPTCHA:
case True:
# Check if the recaptcha site key and secret key are valid
match RECAPTCHA_SITE_KEY == "" or RECAPTCHA_SECRET_KEY == "":
case True:
# Log a warning message that the recaptcha keys are invalid and may cause the app to crash
Log.danger(
f"reCAPTCHA keys is unvalid this may cause the application to crash",
)
Log.danger(
f"Please check your recaptcha keys or set recaptcha to false from true in 'constants.py'",
)
case False:
# Log a success message that recaptcha is on and print the recaptcha keys, url and badge status
Log.app("reCAPTCHA is on")
Log.app(f"reCAPTCHA recaptcha site key: {RECAPTCHA_SITE_KEY}")
Log.app(f"reCAPTCHA secret key: {RECAPTCHA_SECRET_KEY}")
Log.app(f"reCAPTCHA verify url: {RECAPTCHA_VERIFY_URL}")
Log.app(f"reCAPTCHA badge: {RECAPTCHA_BADGE}")
# Log the recaptcha settings for different actions
Log.app(f"reCAPTCHA login: {RECAPTCHA_LOGIN}")
Log.app(f"reCAPTCHA sign up: {RECAPTCHA_SIGN_UP }")
Log.app(f"reCAPTCHA post create: {RECAPTCHA_POST_CREATE}")
Log.app(f"reCAPTCHA post edit: {RECAPTCHA_POST_EDIT }")
Log.app(f"reCAPTCHA post delete: {RECAPTCHA_POST_DELETE}")
Log.app(f"reCAPTCHA comment: {RECAPTCHA_COMMENT}")
Log.app(f"reCAPTCHA comment delete: {RECAPTCHA_COMMENT_DELETE}")
Log.app(f"reCAPTCHA password reset: {RECAPTCHA_PASSWORD_RESET}")
Log.app(f"reCAPTCHA password change: {RECAPTCHA_PASSWORD_CHANGE}")
Log.app(f"reCAPTCHA username change: {RECAPTCHA_USERNAME_CHANGE}")
Log.app(f"reCAPTCHA verify user: {RECAPTCHA_VERIFY_USER}")
Log.app(f"reCAPTCHA delete user: {RECAPTCHA_DELETE_USER}")
Log.app(
f"reCAPTCHA user profile picture change: {RECAPTCHA_PROFILE_PICTURE_CHANGE}",
)
Log.app(
f"reCAPTCHA profile picture change: {RECAPTCHA_PROFILE_PICTURE_CHANGE}",
)
case False:
# Log a warning message that recaptcha is off
Log.app(f"reCAPTCHA is off")
# Check if default admin is enabled
match DEFAULT_ADMIN:
case True:
# Log a success message that admin is on and print the default admin settings
Log.app(f"Default admin is on")
Log.app(f"Default admin username: {DEFAULT_ADMIN_USERNAME}")
Log.app(f"Default admin email: {DEFAULT_ADMIN_EMAIL}")
Log.app(f"Default admin password: {DEFAULT_ADMIN_PASSWORD}")
Log.app(f"Default admin point: {DEFAULT_ADMIN_POINT}")
Log.app(f"Default admin profile picture: {DEFAULT_ADMIN_PROFILE_PICTURE}")
case False:
# Log a danger message that admin is off
Log.app(f"Default admin is off")
# Call the dbFolder, usersTable, postsTable and commentsTable functions to check the database status
dbFolder()
usersTable()
postsTable()
commentsTable()
# Use the app.errorhandler decorator to register error handler functions for app
@app.errorhandler(404)
def notFound(e):
# Call the notFoundErrorHandler function and return its result
return notFoundErrorHandler(e)
@app.route("/ai")
def ai():
return render_template('ai.html')
# Use the app.errorhandler decorator to register error handler functions for app
@app.errorhandler(401)
def unauthorized(e):
# Call the unauthorizedErrorHandler function and return its result
return unauthorizedErrorHandler(e)
# Use the app.errorhandler decorator to register error handler functions for app
@app.errorhandler(CSRFError)
def csrfError(e):
# Call the csrfErrorHandler function and return its result
return csrfErrorHandler(e)
# Use the app.after_request decorator to handle every request
@app.after_request
def afterRequest(response):
# Call the afterRequestLogger function and return its result
return afterRequestLogger(response)
# Registering blueprints for different routes with the Flask application instance
app.register_blueprint(
postBlueprint
) # Registering the blueprint for handling post routes
app.register_blueprint(
userBlueprint
) # Registering the blueprint for handling user routes
app.register_blueprint(indexBlueprint) # Registering the blueprint for the index route
app.register_blueprint(aboutBlueprint) # Registering the blueprint for the about route
app.register_blueprint(loginBlueprint) # Registering the blueprint for the login route
app.register_blueprint(
signUpBlueprint
) # Registering the blueprint for the sign-up route
app.register_blueprint(
logoutBlueprint
) # Registering the blueprint for the logout route
app.register_blueprint(
searchBlueprint
) # Registering the blueprint for the search route
app.register_blueprint(
categoryBlueprint
) # Registering the blueprint for the category route
app.register_blueprint(
editPostBlueprint
) # Registering the blueprint for the edit post route
app.register_blueprint(
dashboardBlueprint
) # Registering the blueprint for the dashboard route
app.register_blueprint(
searchBarBlueprint
)
# Registering the blueprint for the search bar route
app.register_blueprint(
similaritySearchBlueprint
)
# Registering the blueprint for the similarity search route
# Registering the blueprint for the ai bar route
# app.register_blueprint(
# AIBlueprint
# )
# Registering the blueprint for the ai route
app.register_blueprint(
adminPanelBlueprint
) # Registering the blueprint for the admin panel route
app.register_blueprint(
createPostBlueprint
) # Registering the blueprint for the create post route
app.register_blueprint(
verifyUserBlueprint
) # Registering the blueprint for the verify user route
app.register_blueprint(
setLanguageBlueprint
) # Registering the blueprint for the set language route
app.register_blueprint(
privacyPolicyBlueprint
) # Registering the blueprint for the privacy policy route
app.register_blueprint(
passwordResetBlueprint
) # Registering the blueprint for the password reset route
app.register_blueprint(
changeUserNameBlueprint
) # Registering the blueprint for the change username route
app.register_blueprint(
changePasswordBlueprint
) # Registering the blueprint for the change password route
app.register_blueprint(
changeLanguageBlueprint
) # Registering the blueprint for the change language route
app.register_blueprint(
adminPanelUsersBlueprint
) # Registering the blueprint for the admin panel users route
app.register_blueprint(
adminPanelPostsBlueprint
) # Registering the blueprint for the admin panel posts route
app.register_blueprint(
accountSettingsBlueprint
) # Registering the blueprint for the account settings route
app.register_blueprint(
returnPostBannerBlueprint
) # Registering the blueprint for the return post banner route
app.register_blueprint(
adminPanelCommentsBlueprint
) # Registering the blueprint for the admin panel comments route
app.register_blueprint(
changeProfilePictureBlueprint
) # Registering the blueprint for the change profile picture route
if __name__ == '__main__':
# Start the background updater thread
updater_thread = threading.Thread(target=background_updater)
updater_thread.daemon = True # Daemonize thread to exit when the main program exits
updater_thread.start()
app.run(debug=True)