Finished schema creation
Added Navbar functionality Added header
This commit is contained in:
@@ -2,6 +2,7 @@ import os
|
||||
from flask import Flask
|
||||
from .extensions import db, migrate, bcrypt, bootstrap, jwt
|
||||
from .models.user import User, Tenant
|
||||
from .models.document import Document, DocumentLanguage, DocumentVersion
|
||||
|
||||
|
||||
def create_app(config_file=None):
|
||||
|
||||
@@ -1,37 +1,38 @@
|
||||
from ..extensions import db
|
||||
from .user import User, Tenant
|
||||
|
||||
|
||||
class Document(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(100), nullable=False)
|
||||
tenant_id = db.Column(db.Integer, db.ForeignKey('tenant.id'), nullable=False)
|
||||
tenant_id = db.Column(db.Integer, db.ForeignKey(Tenant.id), nullable=False)
|
||||
valid_from = db.Column(db.DateTime, nullable=True)
|
||||
valid_to = db.Column(db.DateTime, nullable=True)
|
||||
|
||||
# Versioning Information
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False)
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now(), onupdate=db.func.now())
|
||||
updated_by = db.Column(db.Integer, db.ForeignKey('user.id'))
|
||||
updated_by = db.Column(db.Integer, db.ForeignKey(User.id))
|
||||
|
||||
|
||||
class DocumentLanguage(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
document_id = db.Column(db.Integer, db.ForeignKey('document.id'), nullable=False)
|
||||
document_id = db.Column(db.Integer, db.ForeignKey(Document.id), nullable=False)
|
||||
language = db.Column(db.String(2), nullable=False)
|
||||
|
||||
# Versioning Information
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
||||
created_by = db.Column(db.Integer, db.ForeignKey(User.id), nullable=False)
|
||||
|
||||
|
||||
class DocumentVersion(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
doc_lang_id = db.Column(db.Integer, db.ForeignKey('document_language.id'), nullable=False)
|
||||
doc_lang_id = db.Column(db.Integer, db.ForeignKey(DocumentLanguage.id), nullable=False)
|
||||
url = db.Column(db.String(200), nullable=True)
|
||||
embeddings = db.Column(db.PickleType, nullable=True)
|
||||
|
||||
# Versioning Information
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.now())
|
||||
created_by = db.Column(db.Integer, db.ForeignKey('user.id'))
|
||||
created_by = db.Column(db.Integer, db.ForeignKey(User.id))
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
|
||||
<body class="presentation-page bg-gray-200">
|
||||
{% include 'navbar.html' %}
|
||||
{% with messages = get_flashed_messages()%}
|
||||
{% include 'header.html' %}
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages%}
|
||||
{% for message in messages%}
|
||||
<p>{{message}}</p>
|
||||
|
||||
13
eveai_app/templates/header.html
Normal file
13
eveai_app/templates/header.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<header class="header-2">
|
||||
<div class="page-header min-vh-75" style="background-image: url({{url_for('static', filename='/assets/img/EveAI_bg1.jpg')}})" loading="lazy">
|
||||
<span class="mask bg-gradient-primary opacity-4"></span>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-7 text-center mx-auto">
|
||||
<h1 class="text-white pt-3 mt-n5">EveAI Virtual Assistant</h1>
|
||||
<p class="lead text-white mt-3 px-5">Enhance Customer Interaction with AI</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -1,59 +1,46 @@
|
||||
<!-- Navbar Light -->
|
||||
<nav
|
||||
class="navbar navbar-expand-lg navbar-light bg-white z-index-3 py-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="" rel="tooltip" title="Generated by Kobe & Pieter @ Flow IT" data-placement="bottom" target="_blank">
|
||||
EveAI
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navigation" aria-controls="navigation" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navigation">
|
||||
<ul class="navbar-nav navbar-nav-hover mx-auto">
|
||||
<li class="nav-item px-3">
|
||||
<a class="nav-link">
|
||||
User Mgmt
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<li>
|
||||
<a class="dropdown-item" href="/user/tenant">
|
||||
Tenant Registration
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="/user/user">
|
||||
User Registration
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li class="nav-item px-3">
|
||||
<a class="nav-link">
|
||||
Document Mgmt
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item px-3">
|
||||
<a class="nav-link">
|
||||
Interaction Mgmt
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item px-3">
|
||||
<a class="nav-link ">
|
||||
Login
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<button class="btn bg-gradient-primary mb-0">Buy Now</button>
|
||||
</ul>
|
||||
<div class="navbar navbar-expand-lg navbar-light bg-white z-index-3 py-3">
|
||||
<div class="container position-sticky z-index-sticky top-0">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<nav class="navbar navbar-expand-lg blur border-radius-xl top-0 z-index-fixed shadow position-absolute my-3 py-2 start-0 end-0 mx-4">
|
||||
<div class="container-fluid px-0">
|
||||
<a class="navbar-brand font-weight-bolder ms-sm-3 d-none d-md-block" href="https://www.flow-it.net" rel="tooltip" title="Idee Generated & Implemented by Flow IT" data-placement="bottom">
|
||||
EveAI
|
||||
</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse w-100 pt-3 pb-2 py-lg-0" id="navigation">
|
||||
<ul class="navbar-nav navbar-nav-hover mx-auto">
|
||||
<li class="nav-item dropdown dropdown-hover mx-2">
|
||||
<a role="button" class="nav-link ps-2 d-flex cursor-pointer align-items-center" id="dropdownMenuUser" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="material-icons opacity-6 me-2 text-md">contacts</i>
|
||||
User Mgmt
|
||||
<img src="{{url_for('static', filename='/assets/img/down-arrow-dark.svg')}}" alt="down-arrow" class="arrow ms-2 d-lg-block d-none">
|
||||
<img src="{{url_for('static', filename='/assets/img/down-arrow-dark.svg')}}" alt="down-arrow" class="arrow ms-1 d-lg-none d-block ms-auto">
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-animation ms-n3 dropdown-md p-3 border-radius-xl mt-0 mt-lg-3" aria-labelledby="dropdownMenuPages">
|
||||
<div class="d-none d-lg-flex">
|
||||
<ul class="list-group w-100">
|
||||
<li class="nav-item dropdown dropdown-hover dropdown-subitem list-group-item border-0 p-0">
|
||||
<a class="dropdown-item ps-3 border-radius-md mb-1" href="/user/tenant">
|
||||
<span>Tenant Registration</span>
|
||||
</a>
|
||||
<a class="dropdown-item ps-3 border-radius-md mb-1" href="/user/user">
|
||||
<span>User Registration</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- End Navbar -->
|
||||
|
||||
|
||||
</div>
|
||||
89
eveai_app/utils/database.py
Normal file
89
eveai_app/utils/database.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""Database related functions"""
|
||||
from os import popen
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.schema import CreateSchema
|
||||
from sqlalchemy.exc import InternalError
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from flask_migrate import heads
|
||||
|
||||
from ..extensions import db, migrate
|
||||
|
||||
|
||||
class Database:
|
||||
"""used for managing tenant databases related operations"""
|
||||
|
||||
def __init__(self, tenant: str) -> None:
|
||||
self.schema = str(tenant)
|
||||
|
||||
def get_engine(self):
|
||||
"""create new schema engine"""
|
||||
return db.engine.execution_options(
|
||||
schema_translate_map={None: self.schema}
|
||||
)
|
||||
|
||||
def get_session(self):
|
||||
"""To get session of tenant/public database schema for quick use
|
||||
|
||||
returns:
|
||||
session: session of tenant/public database schema
|
||||
"""
|
||||
return scoped_session(
|
||||
sessionmaker(bind=self.get_engine(), expire_on_commit=True)
|
||||
)
|
||||
|
||||
def create_schema(self):
|
||||
"""create new database schema, mostly used on tenant creation"""
|
||||
try:
|
||||
db.session.execute(CreateSchema(self.schema))
|
||||
db.session.commit()
|
||||
except InternalError:
|
||||
db.session.rollback()
|
||||
db.session.close()
|
||||
|
||||
def create_tables(self):
|
||||
"""create tables in for schema"""
|
||||
db.metadata.create_all(self.get_engine())
|
||||
|
||||
def switch_schema(self):
|
||||
"""switch between tenant/public database schema"""
|
||||
db.session.execute(text(f'set search_path to "{self.schema}"'))
|
||||
db.session.commit()
|
||||
|
||||
def migrate_tenant_schema(self):
|
||||
"""migrate tenant database schema for new tenant"""
|
||||
# Get the current revision for a database.
|
||||
# NOTE: using popen may have a minor performance impact on the application
|
||||
# you can store it in a different table in public schema and use it from there
|
||||
# may be a faster approach
|
||||
# last_revision = heads(directory="migrations/tenant", verbose=True, resolve_dependencies=False)
|
||||
last_revision = popen(".venv/bin/flask db heads -d migrations/tenant").read()
|
||||
print("LAST REVISION")
|
||||
print(last_revision)
|
||||
last_revision = last_revision.splitlines()[-1].split(" ")[0]
|
||||
|
||||
# creating revision table in tenant schema
|
||||
session = self.get_session()
|
||||
session.execute(
|
||||
text(
|
||||
f'CREATE TABLE "{self.schema}".alembic_version (version_num '
|
||||
"VARCHAR(32) NOT NULL)"
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
# Insert last revision to alembic_version table
|
||||
session.execute(
|
||||
text(
|
||||
f'INSERT INTO "{self.schema}".alembic_version (version_num) '
|
||||
"VALUES (:version)"
|
||||
),
|
||||
{"version": last_revision},
|
||||
)
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
def create_tenant_schema(self):
|
||||
"""create tenant used for creating new schema and its tables"""
|
||||
self.create_schema()
|
||||
self.create_tables()
|
||||
self.migrate_tenant_schema()
|
||||
@@ -4,6 +4,7 @@ from flask import request, redirect, url_for, flash, render_template, Blueprint
|
||||
from ..models.user import User, Tenant
|
||||
from ..extensions import db, bcrypt
|
||||
from .user_forms import TenantForm, UserForm
|
||||
from ..utils.database import Database
|
||||
|
||||
user_bp = Blueprint('user_bp', __name__, url_prefix='/user')
|
||||
|
||||
@@ -31,9 +32,9 @@ def tenant():
|
||||
monthly = request.form.get('allowed_monthly_interactions')
|
||||
|
||||
if lic_start != '':
|
||||
new_tenant.license_start_date = dt.strptime(lic_start, '%d-%m-%Y')
|
||||
new_tenant.license_start_date = dt.strptime(lic_start, '%Y-%m-%d')
|
||||
if lic_end != '':
|
||||
new_tenant.license_end_date = dt.strptime(lic_end, '%d-%m-%Y')
|
||||
new_tenant.license_end_date = dt.strptime(lic_end, '%Y-%m-%d')
|
||||
if monthly != '':
|
||||
new_tenant.allowed_monthly_interactions = int(monthly)
|
||||
|
||||
@@ -43,13 +44,17 @@ def tenant():
|
||||
new_tenant.updated_at = timestamp
|
||||
|
||||
# Add the new tenant to the database and commit the changes
|
||||
|
||||
try:
|
||||
db.session.add(new_tenant)
|
||||
db.session.commit()
|
||||
except Exception as e:
|
||||
error = e.args
|
||||
|
||||
# Create schema for new tenant
|
||||
if error is None:
|
||||
print(new_tenant.id)
|
||||
Database(new_tenant.id).create_tenant_schema()
|
||||
|
||||
flash(error) if error else flash('Tenant added successfully.')
|
||||
|
||||
form = TenantForm()
|
||||
@@ -81,7 +86,8 @@ def user():
|
||||
password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
|
||||
|
||||
# Create new user if there is no error
|
||||
new_user = User(user_name=username, email=email, password=password_hash, first_name=first_name, last_name=last_name)
|
||||
new_user = User(user_name=username, email=email, password=password_hash, first_name=first_name,
|
||||
last_name=last_name)
|
||||
|
||||
# Handle optional attributes
|
||||
new_user.is_active = bool(request.form.get('is_active'))
|
||||
|
||||
Reference in New Issue
Block a user