registration email added
Some checks failed
Gitea Docker Redeploy / Redploy-App-on-self-via-SSH (push) Failing after 17s
Some checks failed
Gitea Docker Redeploy / Redploy-App-on-self-via-SSH (push) Failing after 17s
This commit is contained in:
parent
e9c1d1815f
commit
83ea3a7a64
@ -21,6 +21,10 @@ jobs:
|
|||||||
git pull
|
git pull
|
||||||
echo "============ Git pull finished! ========="
|
echo "============ Git pull finished! ========="
|
||||||
echo '${{ vars.ENV }}' > .env
|
echo '${{ vars.ENV }}' > .env
|
||||||
|
echo '\n' >> .env
|
||||||
|
echo '${{ secrets.CB_EMAIL_SMTP }}\n' >> .env
|
||||||
|
echo '${{ secrets.CB_EMAIL_ADDR }}\n' >> .env
|
||||||
|
echo '${{ secrets.CB_EMAIL_PWD }}\n' >> .env
|
||||||
echo "============ Env creation finished! ========="
|
echo "============ Env creation finished! ========="
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ from flask import Flask, send_from_directory, send_file, Response, request, json
|
|||||||
from flask_openapi3 import Info, Tag, OpenAPI, Server #FileStorage
|
from flask_openapi3 import Info, Tag, OpenAPI, Server #FileStorage
|
||||||
from flask_socketio import SocketIO, join_room, leave_room, rooms, send
|
from flask_socketio import SocketIO, join_room, leave_room, rooms, send
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -133,6 +132,9 @@ def uses_jwt(logger=None, required=True):
|
|||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
|
|
||||||
|
app_name = "Creative Bots"
|
||||||
|
|
||||||
|
|
||||||
# JWT Bearer Sample
|
# JWT Bearer Sample
|
||||||
jwt = {
|
jwt = {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
@ -144,7 +146,7 @@ def create_app():
|
|||||||
|
|
||||||
|
|
||||||
info = Info(
|
info = Info(
|
||||||
title="CreativeBots-API",
|
title=app_name + " API",
|
||||||
version=__version__,
|
version=__version__,
|
||||||
summary="The REST-API to manage bots, users and more!",
|
summary="The REST-API to manage bots, users and more!",
|
||||||
description=""
|
description=""
|
||||||
@ -192,13 +194,10 @@ def create_app():
|
|||||||
|
|
||||||
@socket.on('client message')
|
@socket.on('client message')
|
||||||
def handle_message(message):
|
def handle_message(message):
|
||||||
|
|
||||||
SocketMessage.model_validate(message)
|
SocketMessage.model_validate(message)
|
||||||
|
|
||||||
logger.info("Starting stream")
|
logger.info("Starting stream")
|
||||||
|
|
||||||
|
|
||||||
#try:
|
|
||||||
room = message["room"]
|
room = message["room"]
|
||||||
question = message["question"]
|
question = message["question"]
|
||||||
system_prompt = message["system_prompt"]
|
system_prompt = message["system_prompt"]
|
||||||
@ -305,12 +304,20 @@ def create_app():
|
|||||||
|
|
||||||
case [user]:
|
case [user]:
|
||||||
if user["password_hash"] == hash_password(form.password + form.email):
|
if user["password_hash"] == hash_password(form.password + form.email):
|
||||||
token = pyjwt.encode({"email": form.email}, jwt_secret, algorithm="HS256")
|
if not user["isEmailVerified"]:
|
||||||
#logger.info(token)
|
msg = "E-Mail unverified!"
|
||||||
return jsonify({
|
logger.error(msg)
|
||||||
'status': 'success',
|
return jsonify({
|
||||||
'jwt': token
|
'status': 'error',
|
||||||
})
|
'message': msg
|
||||||
|
}), 400
|
||||||
|
else:
|
||||||
|
token = pyjwt.encode({"email": form.email}, jwt_secret, algorithm="HS256")
|
||||||
|
#logger.info(token)
|
||||||
|
return jsonify({
|
||||||
|
'status': 'success',
|
||||||
|
'jwt': token
|
||||||
|
})
|
||||||
else:
|
else:
|
||||||
msg = "Invalid password!"
|
msg = "Invalid password!"
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
@ -341,12 +348,15 @@ def create_app():
|
|||||||
|
|
||||||
|
|
||||||
if User.get(id=form.email, ignore=404) is not None:
|
if User.get(id=form.email, ignore=404) is not None:
|
||||||
|
msg = "User with that e-mail address already exists!"
|
||||||
|
logger.error(msg)
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
"message": "User with that e-mail address already exists!"
|
"message": msg
|
||||||
})
|
})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
logger.info("Try creating user...!")
|
||||||
user = User(meta={'id': form.email})
|
user = User(meta={'id': form.email})
|
||||||
user.creation_date = datetime.now()
|
user.creation_date = datetime.now()
|
||||||
user.email = form.email
|
user.email = form.email
|
||||||
@ -354,21 +364,23 @@ def create_app():
|
|||||||
user.role = "User"
|
user.role = "User"
|
||||||
user.isEmailVerified = False
|
user.isEmailVerified = False
|
||||||
user.save()
|
user.save()
|
||||||
|
logger.info("User created!")
|
||||||
|
|
||||||
msg = """
|
msg = f"""
|
||||||
<h1>Verify E-Mail</h1>
|
<h1>Verify E-Mail</h1>
|
||||||
|
|
||||||
Hi!
|
|
||||||
|
|
||||||
Please click on the following link to verify your e-mail:
|
Please click on the following link to verify your e-mail:
|
||||||
|
|
||||||
|
<a href="http://127.0.0.1:5000/verify?id={user.password_hash}">Click here!</a>
|
||||||
<a href="http://127.0.0.1:5000/">Click here!</a>
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
send_mail(user.email, "User registration @ Creative Bots", "Creative Bots", msg)
|
send_mail(
|
||||||
|
target_mail=user.email,
|
||||||
|
subject="User registration @ " + app_name,
|
||||||
|
msg=msg
|
||||||
|
)
|
||||||
|
logger.info("Mail send!")
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'success'
|
'status': 'success'
|
||||||
})
|
})
|
||||||
@ -599,9 +611,6 @@ def create_app():
|
|||||||
"score_docs": xs
|
"score_docs": xs
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#-----------------Embedding----------------------
|
#-----------------Embedding----------------------
|
||||||
|
|
||||||
class TrainTextRequest(BaseModel):
|
class TrainTextRequest(BaseModel):
|
||||||
@ -659,15 +668,41 @@ def create_app():
|
|||||||
|
|
||||||
d = {}
|
d = {}
|
||||||
d["module_versions"] = get_module_versions()
|
d["module_versions"] = get_module_versions()
|
||||||
d["OLLAMA_NUM_PARALLEL"] = os.getenv("OLLAMA_NUM_PARALLEL")
|
#d["OLLAMA_NUM_PARALLEL"] = os.getenv("OLLAMA_NUM_PARALLEL")
|
||||||
d["OLLAMA_MAX_LOADED_MODELS"] = os.getenv("OLLAMA_MAX_LOADED_MODELS")
|
#d["OLLAMA_MAX_LOADED_MODELS"] = os.getenv("OLLAMA_MAX_LOADED_MODELS")
|
||||||
d["cpus"] = multiprocessing.cpu_count()
|
d["cpus"] = multiprocessing.cpu_count()
|
||||||
|
|
||||||
#return "CPUs: " + str(cpus) + "<br>" + json.dumps(get_module_versions(), indent=4).replace("\n", "<br>")
|
#return "CPUs: " + str(cpus) + "<br>" + json.dumps(get_module_versions(), indent=4).replace("\n", "<br>")
|
||||||
|
|
||||||
return json.dumps(d, indent=4).replace("\n", "<br>")
|
return json.dumps(d, indent=4).replace("\n", "<br>")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/verify", methods=['GET'])
|
||||||
|
def verify_email():
|
||||||
|
x = request.args.get('id')
|
||||||
|
s = User.search()
|
||||||
|
s = s.filter('term', isEmailVerified=False).query('match', password_hash=x)
|
||||||
|
results = s.execute()
|
||||||
|
|
||||||
|
# when you execute the search the results are wrapped in your document class (Post)
|
||||||
|
for user in results:
|
||||||
|
#print(post.meta.score, post.title)
|
||||||
|
if user.password_hash == x:
|
||||||
|
user.isEmailVerified = True
|
||||||
|
user.save()
|
||||||
|
return "E-Mail verified!"
|
||||||
|
|
||||||
|
|
||||||
|
return "Verrification Error!"
|
||||||
|
"""
|
||||||
|
match get_by_id(index="user", id_field_name="password_hash", id_value=x):
|
||||||
|
case [d]:
|
||||||
|
#user.isEmailVerified = True
|
||||||
|
#user.save()
|
||||||
|
return "E-Mail verified!"
|
||||||
|
|
||||||
|
case _:
|
||||||
|
return "Verrification Error!"
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@app.route('/<path:path>') #generische Route (auch Unterordner)
|
@app.route('/<path:path>') #generische Route (auch Unterordner)
|
||||||
|
@ -9,8 +9,7 @@ from elasticsearch.exceptions import ConnectionError
|
|||||||
|
|
||||||
|
|
||||||
def get_by_id(index: str, id_field_name: str, id_value: str):
|
def get_by_id(index: str, id_field_name: str, id_value: str):
|
||||||
client = connections.get_connection()
|
response = Search(using=connections.get_connection(), index=index).filter("term", **{id_field_name: id_value})[0:10000].execute()
|
||||||
response = Search(using=client, index=index).filter("term", **{id_field_name: id_value})[0:10000].execute()
|
|
||||||
return [hit.to_dict() for hit in response]
|
return [hit.to_dict() for hit in response]
|
||||||
|
|
||||||
|
|
||||||
@ -30,15 +29,13 @@ def update_by_id(index: str, id_field_name: str, id_value: str, values_to_set: D
|
|||||||
|
|
||||||
|
|
||||||
def delete_by_id(index: str, id_field_name: str, id_value: str):
|
def delete_by_id(index: str, id_field_name: str, id_value: str):
|
||||||
client = connections.get_connection()
|
s = Search(using=connections.get_connection(), index=index).filter("term", **{id_field_name: id_value})
|
||||||
s = Search(using=client, index=index).filter("term", **{id_field_name: id_value})
|
|
||||||
response = s.delete()
|
response = s.delete()
|
||||||
#if not response.success():
|
#if not response.success():
|
||||||
# raise Exception("Unable to delete id '%s' in index '%' !" % (index, id_value))
|
# raise Exception("Unable to delete id '%s' in index '%' !" % (index, id_value))
|
||||||
print(response, flush=True)
|
print(response, flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_datetime_interval(search: Search, start, end) -> Search:
|
def get_datetime_interval(search: Search, start, end) -> Search:
|
||||||
return search.filter("range", timest={"gte": start}).filter("range", timest={"lte": end})
|
return search.filter("range", timest={"gte": start}).filter("range", timest={"lte": end})
|
||||||
|
|
||||||
@ -57,21 +54,18 @@ def simplify_properties(d):
|
|||||||
|
|
||||||
|
|
||||||
def get_type_schema():
|
def get_type_schema():
|
||||||
client = connections.get_connection()
|
d = connections.get_connection().indices.get(index="*").body
|
||||||
d = client.indices.get(index="*").body
|
|
||||||
new_d = {}
|
new_d = {}
|
||||||
for index, d2 in d.items():
|
for index, d2 in d.items():
|
||||||
new_d[index] = simplify_properties(d2["mappings"])
|
new_d[index] = simplify_properties(d2["mappings"])
|
||||||
return new_d
|
return new_d
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def wait_for_elasticsearch():
|
def wait_for_elasticsearch():
|
||||||
i = 1
|
i = 1
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
client = connections.get_connection()
|
connections.get_connection().indices.get_alias(index="*")
|
||||||
client.indices.get_alias(index="*")
|
|
||||||
print("Elasticsearch found! Run Flask-app!", flush=True)
|
print("Elasticsearch found! Run Flask-app!", flush=True)
|
||||||
return
|
return
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
|
@ -1,14 +1,33 @@
|
|||||||
|
import os
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
from smtplib import *
|
from smtplib import *
|
||||||
from email.mime.text import MIMEText
|
from email.message import EmailMessage
|
||||||
|
|
||||||
def send_mail(target_mail, subject, sender_mail, msg):
|
env = Environment(loader=FileSystemLoader('templates'))
|
||||||
|
|
||||||
msg = MIMEText(msg)
|
# Credentials
|
||||||
|
username = os.getenv("EMAIL_ADDR")
|
||||||
|
password = os.getenv("EMAIL_PWD")
|
||||||
|
smtp_domain_and_port = os.getenv("EMAIL_SMTP")
|
||||||
|
|
||||||
|
assert username
|
||||||
|
assert password
|
||||||
|
|
||||||
|
def send_mail(target_mail, subject, msg, sender_mail=username):
|
||||||
|
html = env.get_template('html_mail.twig').render(
|
||||||
|
subject=subject,
|
||||||
|
msg=msg
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = EmailMessage()
|
||||||
msg['Subject'] = subject
|
msg['Subject'] = subject
|
||||||
msg['From'] = sender_mail
|
msg['From'] = sender_mail
|
||||||
msg['To'] = target_mail
|
msg['To'] = target_mail
|
||||||
|
msg.set_content(html, subtype='html')
|
||||||
|
|
||||||
smtp = SMTP('mailserver', port=10025)
|
domain, port = smtp_domain_and_port.split(":")
|
||||||
smtp.sendmail("Creative Bots", [target_mail], msg.as_string())
|
|
||||||
smtp.quit()
|
|
||||||
|
|
||||||
|
#with SMTP_SSL('smtp.gmx.de', port=465) as smtp:
|
||||||
|
with SMTP_SSL(domain, port=int(port)) as smtp:
|
||||||
|
smtp.login(username, password)
|
||||||
|
smtp.send_message(msg)
|
||||||
|
@ -4,7 +4,10 @@ from elasticsearch_dsl import Document, InnerDoc, Nested, Date, Integer, Keyword
|
|||||||
class User(Document):
|
class User(Document):
|
||||||
creation_date = Date()
|
creation_date = Date()
|
||||||
email = Keyword()
|
email = Keyword()
|
||||||
password_hash = Text(index=False)
|
#password_hash = Text(index=False)
|
||||||
|
password_hash = Keyword()
|
||||||
|
#password_hash = Text(index=True)
|
||||||
|
|
||||||
role = Keyword()
|
role = Keyword()
|
||||||
|
|
||||||
#salt = Text(index=False)
|
#salt = Text(index=False)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
All around managing users
|
All around managing users
|
||||||
"""
|
"""
|
||||||
import os, json, hashlib, traceback, logging
|
import os, json, hashlib, traceback, logging
|
||||||
|
from datetime import datetime, date
|
||||||
from elasticsearch import NotFoundError, Elasticsearch # for normal read/write without vectors
|
from elasticsearch import NotFoundError, Elasticsearch # for normal read/write without vectors
|
||||||
|
|
||||||
from lib.models import User
|
from lib.models import User
|
||||||
@ -15,7 +16,6 @@ assert elastic_url
|
|||||||
def hash_password(s: str) -> str:
|
def hash_password(s: str) -> str:
|
||||||
return hashlib.md5(s.encode('utf-8')).hexdigest()
|
return hashlib.md5(s.encode('utf-8')).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def create_user(email, password, role="user", verified=False):
|
def create_user(email, password, role="user", verified=False):
|
||||||
user = User(meta={'id': email}, email=email, password_hash=hash_password(password + email), role=role)
|
user = User(meta={'id': email}, email=email, password_hash=hash_password(password + email), role=role)
|
||||||
user.creation_date = datetime.now()
|
user.creation_date = datetime.now()
|
||||||
|
@ -260,7 +260,7 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-text">@
|
<span class="input-group-text">
|
||||||
<select name="bots" id="bot_select" class="form-select"></select>
|
<select name="bots" id="bot_select" class="form-select"></select>
|
||||||
</span>
|
</span>
|
||||||
<input class="form-control" list="questions" name="question" id="user_input" placeholder="What is...">
|
<input class="form-control" list="questions" name="question" id="user_input" placeholder="What is...">
|
||||||
@ -270,7 +270,7 @@
|
|||||||
<option value="Is a monad a burito?">
|
<option value="Is a monad a burito?">
|
||||||
<option value="Give the JSON of a graph linking Germanys 9 biggest cities">
|
<option value="Give the JSON of a graph linking Germanys 9 biggest cities">
|
||||||
</datalist>
|
</datalist>
|
||||||
<button id="submit_btn" class="btn btn-success" type="button">Send</button>
|
<button id="submit_btn" class="btn btn-success" type="button">❯</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<!-- Button to open the offcanvas sidebar -->
|
<!-- Button to open the offcanvas sidebar -->
|
||||||
@ -459,6 +459,8 @@
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
<footer>
|
<footer>
|
||||||
<div id="fun2" class="container-fluid p-3 bg-primary text-white mt-5">
|
<div id="fun2" class="container-fluid p-3 bg-primary text-white mt-5">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -482,6 +484,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
-->
|
||||||
|
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -684,6 +684,7 @@ window.onload = async ()=>{
|
|||||||
|
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
|
console.error(e);
|
||||||
console.error("Registration failed!");
|
console.error("Registration failed!");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@ webdriver_manager
|
|||||||
requests==2.32.3
|
requests==2.32.3
|
||||||
selenium==4.23.1
|
selenium==4.23.1
|
||||||
bs4
|
bs4
|
||||||
|
jinja2
|
||||||
|
|
||||||
elasticsearch==8.15.0
|
elasticsearch==8.15.0
|
||||||
elasticsearch-dsl==8.15.1
|
elasticsearch-dsl==8.15.1
|
||||||
|
41
backend/templates/html_mail.twig
Normal file
41
backend/templates/html_mail.twig
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{{ subject }}</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<!--
|
||||||
|
<link rel="stylesheet" type="text/css" hs-webfonts="true" href="https://fonts.googleapis.com/css?family=Lato|Lato:i,b,bi">
|
||||||
|
-->
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<style type="text/css">
|
||||||
|
h1{font-size:56px}
|
||||||
|
h2{font-size:28px;font-weight:900}
|
||||||
|
p{font-weight:100}
|
||||||
|
td{vertical-align:top}
|
||||||
|
#email{margin:auto;width:600px;background-color:#fff}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#F5F8FA" style="width: 100%; font-family:Lato, sans-serif; font-size:18px;">
|
||||||
|
<div id="email">
|
||||||
|
<table role="presentation" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td bgcolor="#00A4BD" align="center" style="color: white;">
|
||||||
|
<h1>{{ subject }}</h1>
|
||||||
|
</td>
|
||||||
|
</table>
|
||||||
|
<table role="presentation" border="0" cellpadding="0" cellspacing="10px" style="padding: 30px 30px 30px 60px;">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p>
|
||||||
|
{{ msg }}
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -19,6 +19,7 @@ services:
|
|||||||
minio:
|
minio:
|
||||||
container_name: ${APP_PREFIX}_minio
|
container_name: ${APP_PREFIX}_minio
|
||||||
image: minio/minio
|
image: minio/minio
|
||||||
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- "29000:9000"
|
- "29000:9000"
|
||||||
- "29001:9001"
|
- "29001:9001"
|
||||||
@ -37,7 +38,8 @@ services:
|
|||||||
image: neo4j
|
image: neo4j
|
||||||
#image: neo4j:3.5
|
#image: neo4j:3.5
|
||||||
#image: neo4j:4.1
|
#image: neo4j:4.1
|
||||||
restart: unless-stopped
|
#restart: unless-stopped
|
||||||
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 7474:7474
|
- 7474:7474
|
||||||
- 7687:7687
|
- 7687:7687
|
||||||
@ -104,12 +106,6 @@ services:
|
|||||||
- /dev/dri
|
- /dev/dri
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ollama-webui:
|
#ollama-webui:
|
||||||
# container_name: ${APP_PREFIX}_ollama-webui
|
# container_name: ${APP_PREFIX}_ollama-webui
|
||||||
# image: ghcr.io/ollama-webui/ollama-webui:main
|
# image: ghcr.io/ollama-webui/ollama-webui:main
|
||||||
|
@ -9,3 +9,9 @@ SECRET=23A344F670E
|
|||||||
|
|
||||||
#WARN INFO FATAL
|
#WARN INFO FATAL
|
||||||
LOG_LEVEL=WARN
|
LOG_LEVEL=WARN
|
||||||
|
|
||||||
|
#Admin E-Mail sender account
|
||||||
|
EMAIL_SMTP=smtp.mail.net:465
|
||||||
|
EMAIL_ADDR=user@mail.net
|
||||||
|
EMAIL_PWD=somepass
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user