Correct functions for creating new users, confirming email, resetting password and forgot password.
This commit is contained in:
@@ -10,10 +10,11 @@ from flask_jwt_extended import JWTManager
|
||||
from flask_session import Session
|
||||
from flask_wtf import CSRFProtect
|
||||
|
||||
# from .utils.key_encryption import JosKMSClient
|
||||
from .utils.nginx_utils import prefixed_url_for
|
||||
from .utils.simple_encryption import SimpleEncryption
|
||||
from .utils.minio_utils import MinioClient
|
||||
|
||||
|
||||
# Create extensions
|
||||
db = SQLAlchemy()
|
||||
migrate = Migrate()
|
||||
|
||||
@@ -126,7 +126,7 @@ class User(db.Model, UserMixin):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_name = db.Column(db.String(80), unique=True, nullable=False)
|
||||
email = db.Column(db.String(255), unique=True, nullable=False)
|
||||
password = db.Column(db.String(255), nullable=False)
|
||||
password = db.Column(db.String(255), nullable=True)
|
||||
first_name = db.Column(db.String(80), nullable=False)
|
||||
last_name = db.Column(db.String(80), nullable=False)
|
||||
active = db.Column(db.Boolean)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from flask import current_app, render_template
|
||||
from flask_mailman import EmailMessage
|
||||
from itsdangerous import URLSafeTimedSerializer
|
||||
import socket
|
||||
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
|
||||
@@ -35,15 +36,66 @@ def generate_confirmation_token(email):
|
||||
|
||||
def send_confirmation_email(user):
|
||||
current_app.logger.debug(f'Sending confirmation email to {user.email}')
|
||||
|
||||
if not test_smtp_connection():
|
||||
raise Exception("Failed to connect to SMTP server")
|
||||
|
||||
token = generate_confirmation_token(user.email)
|
||||
confirm_url = prefixed_url_for('security_bp.confirm_email', token=token, _external=True)
|
||||
current_app.logger.debug(f'Confirmation URL: {confirm_url}')
|
||||
|
||||
html = render_template('email/activate.html', confirm_url=confirm_url)
|
||||
send_email(user.email, "Confirm your email", html)
|
||||
subject = "Please confirm your email"
|
||||
|
||||
try:
|
||||
send_email(user.email, "Confirm your email", html)
|
||||
current_app.logger.info(f'Confirmation email sent to {user.email}')
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Failed to send confirmation email to {user.email}. Error: {str(e)}')
|
||||
raise
|
||||
|
||||
|
||||
def send_reset_email(user):
|
||||
current_app.logger.debug(f'Sending reset email to {user.email}')
|
||||
token = generate_reset_token(user.email)
|
||||
reset_url = prefixed_url_for('security_bp.reset_password', token=token, _external=True)
|
||||
current_app.logger.debug(f'Reset URL: {reset_url}')
|
||||
|
||||
html = render_template('email/reset_password.html', reset_url=reset_url)
|
||||
send_email(user.email, "Reset Your Password", html)
|
||||
subject = "Reset Your Password"
|
||||
|
||||
try:
|
||||
send_email(user.email, "Reset Your Password", html)
|
||||
current_app.logger.info(f'Reset email sent to {user.email}')
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Failed to send reset email to {user.email}. Error: {str(e)}')
|
||||
raise
|
||||
|
||||
|
||||
def test_smtp_connection():
|
||||
try:
|
||||
current_app.logger.info(f"Attempting to resolve google.com...")
|
||||
google_ip = socket.gethostbyname('google.com')
|
||||
current_app.logger.info(f"Successfully resolved google.com to {google_ip}")
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Failed to resolve google.com: {str(e)}")
|
||||
|
||||
try:
|
||||
smtp_server = current_app.config['MAIL_SERVER']
|
||||
current_app.logger.info(f"Attempting to resolve {smtp_server}...")
|
||||
smtp_ip = socket.gethostbyname(smtp_server)
|
||||
current_app.logger.info(f"Successfully resolved {smtp_server} to {smtp_ip}")
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Failed to resolve {smtp_server}: {str(e)}")
|
||||
|
||||
try:
|
||||
smtp_server = current_app.config['MAIL_SERVER']
|
||||
smtp_port = current_app.config['MAIL_PORT']
|
||||
sock = socket.create_connection((smtp_server, smtp_port), timeout=10)
|
||||
sock.close()
|
||||
current_app.logger.info(f"Successfully connected to SMTP server {smtp_server}:{smtp_port}")
|
||||
return True
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Failed to connect to SMTP server: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from datetime import timedelta
|
||||
import redis
|
||||
|
||||
from common.utils.prompt_loader import load_prompt_templates
|
||||
from eveai_app.views.security_forms import ResetPasswordForm
|
||||
|
||||
basedir = path.abspath(path.dirname(__file__))
|
||||
|
||||
@@ -41,6 +42,11 @@ class Config(object):
|
||||
SECURITY_POST_LOGIN_VIEW = '/user/tenant_overview'
|
||||
SECURITY_RECOVERABLE = True
|
||||
SECURITY_EMAIL_SENDER = "eveai_super@flow-it.net"
|
||||
SECURITY_EMAIL_SUBJECT_PASSWORD_RESET = 'Reset Your Password'
|
||||
SECURITY_EMAIL_SUBJECT_PASSWORD_NOTICE = 'Your Password Has Been Reset'
|
||||
SECURITY_EMAIL_PLAINTEXT = False
|
||||
SECURITY_EMAIL_HTML = True
|
||||
SECURITY_RESET_PASSWORD_FORM = ResetPasswordForm
|
||||
|
||||
# Ensure Flask-Security-Too is handling CSRF tokens when behind a proxy
|
||||
SECURITY_CSRF_PROTECT_MECHANISMS = ['session']
|
||||
@@ -123,6 +129,15 @@ class Config(object):
|
||||
"LLM": {"name": "LLM", "description": "Algorithm using information integrated in the used LLM"}
|
||||
}
|
||||
|
||||
# flask-mailman settings
|
||||
MAIL_SERVER = environ.get('MAIL_SERVER')
|
||||
MAIL_PORT = int(environ.get('MAIL_PORT', 465))
|
||||
MAIL_USE_TLS = False
|
||||
MAIL_USE_SSL = True
|
||||
MAIL_USERNAME = environ.get('MAIL_USERNAME')
|
||||
MAIL_PASSWORD = environ.get('MAIL_PASSWORD')
|
||||
MAIL_DEFAULT_SENDER = ('eveAI Admin', MAIL_USERNAME)
|
||||
|
||||
|
||||
class DevConfig(Config):
|
||||
DEVELOPMENT = True
|
||||
@@ -138,15 +153,6 @@ class DevConfig(Config):
|
||||
SQLALCHEMY_DATABASE_URI = f'postgresql+pg8000://{DB_USER}:{DB_PASS}@{DB_HOST}:5432/{DB_NAME}'
|
||||
SQLALCHEMY_BINDS = {'public': SQLALCHEMY_DATABASE_URI}
|
||||
|
||||
# flask-mailman settings
|
||||
MAIL_SERVER = 'mail.flow-it.net'
|
||||
MAIL_PORT = 587
|
||||
MAIL_USE_TLS = True
|
||||
MAIL_USE_SSL = False
|
||||
MAIL_DEFAULT_SENDER = ('eveAI Admin', 'eveai_admin@flow-it.net')
|
||||
MAIL_USERNAME = environ.get('MAIL_USERNAME')
|
||||
MAIL_PASSWORD = environ.get('MAIL_PASSWORD')
|
||||
|
||||
# Define the nginx prefix used for the specific apps
|
||||
EVEAI_APP_LOCATION_PREFIX = '/admin'
|
||||
EVEAI_CHAT_LOCATION_PREFIX = '/chat'
|
||||
|
||||
@@ -19,7 +19,9 @@ x-common-variables: &common-variables
|
||||
SECRET_KEY: '97867c1491bea5ee6a8e8436eb11bf2ba6a69ff53ab1b17ecba450d0f2e572e1'
|
||||
SECURITY_PASSWORD_SALT: '228614859439123264035565568761433607235'
|
||||
MAIL_USERNAME: eveai_super@flow-it.net
|
||||
MAIL_PASSWORD: '$6xsWGbNtx$CFMQZqc*'
|
||||
MAIL_PASSWORD: '$$6xsWGbNtx$$CFMQZqc*'
|
||||
MAIL_SERVER: mail.flow-it.net
|
||||
MAIL_PORT: 465
|
||||
OPENAI_API_KEY: 'sk-proj-8R0jWzwjL7PeoPyMhJTZT3BlbkFJLb6HfRB2Hr9cEVFWEhU7'
|
||||
GROQ_API_KEY: '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'
|
||||
ANTHROPIC_API_KEY: 'sk-ant-api03-c2TmkzbReeGhXBO5JxNH6BJNylRDonc9GmZd0eRbrvyekec2'
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
x-common-variables: &common-variables
|
||||
DB_HOST: bswnz4.stackhero-network.com
|
||||
DB_USER: luke_skywalker
|
||||
DB_PASS: 2MK&1rHmWEydE2rFuJLq*ls%tdkPAk2
|
||||
DB_PASS: '2MK&1rHmWEydE2rFuJLq*ls%tdkPAk2'
|
||||
DB_NAME: eveai
|
||||
DB_PORT: '5945'
|
||||
FLASK_ENV: production
|
||||
@@ -20,6 +20,8 @@ x-common-variables: &common-variables
|
||||
SECURITY_PASSWORD_SALT: '166448071751628781809462050022558634074'
|
||||
MAIL_USERNAME: 'evie_admin@askeveai.com'
|
||||
MAIL_PASSWORD: 's5D%R#y^v!s&6Z^i0k&'
|
||||
MAIL_SERVER: mail.askeveai.com
|
||||
MAIL_PORT: 465
|
||||
REDIS_USER: eveai
|
||||
REDIS_PASS: 'jHliZwGD36sONgbm0fc6SOpzLbknqq4RNF8K'
|
||||
REDIS_URL: 8bciqc.stackhero-network.com
|
||||
|
||||
@@ -10,6 +10,7 @@ from common.extensions import (db, migrate, bootstrap, security, mail, login_man
|
||||
minio_client, simple_encryption)
|
||||
from common.models.user import User, Role, Tenant, TenantDomain
|
||||
import common.models.interaction
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
from config.logging_config import LOGGING
|
||||
from common.utils.security import set_tenant_session_data
|
||||
from .errors import register_error_handlers
|
||||
|
||||
13
eveai_app/templates/email/forgot_password.html
Normal file
13
eveai_app/templates/email/forgot_password.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reset Your Password</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hi,</p>
|
||||
<p>You requested a password reset for your EveAI account. Click the link below to reset your password:</p>
|
||||
<p><a href="{{ reset_url }}">Reset Password</a></p>
|
||||
<p>If you did not request a password reset, please ignore this email.</p>
|
||||
<p>Thanks,<br>The EveAI Team</p>
|
||||
</body>
|
||||
</html>
|
||||
13
eveai_app/templates/security/email/reset_instructions.html
Normal file
13
eveai_app/templates/security/email/reset_instructions.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reset Your Password</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hi,</p>
|
||||
<p>You requested a password reset for your EveAI account. Click the link below to reset your password:</p>
|
||||
<p><a href="{{ reset_link }}">Reset Password</a></p>
|
||||
<p>If you did not request a password reset, please ignore this email.</p>
|
||||
<p>Thanks,<br>The EveAI Team</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,10 +9,16 @@
|
||||
{% include "security/_messages.html" %}
|
||||
<form action="{{ url_for_security('forgot_password') }}" method="post" name="forgot_password_form">
|
||||
{{ forgot_password_form.hidden_tag() }}
|
||||
|
||||
<p>
|
||||
{{ forgot_password_form.email.label }}<br>
|
||||
{{ forgot_password_form.email(size=80) }}
|
||||
</p>
|
||||
<p>{{ forgot_password_form.submit() }}</p>
|
||||
|
||||
{{ render_form_errors(forgot_password_form) }}
|
||||
{{ render_field_with_errors(forgot_password_form.email) }}
|
||||
{{ render_field_errors(forgot_password_form.csrf_token) }}
|
||||
{{ render_field(forgot_password_form.submit) }}
|
||||
|
||||
</form>
|
||||
{% include "security/_menu.html" %}
|
||||
<!-- {% include "security/_menu.html" %}-->
|
||||
{% endblock content %}
|
||||
|
||||
@@ -14,10 +14,7 @@
|
||||
{{ login_user_form.password.label }}<br>
|
||||
{{ login_user_form.password(size=80) }}
|
||||
</p>
|
||||
{# <p>#}
|
||||
{# {{ login_user_form.remember_me }}#}
|
||||
{# {{ login_user_form.remember_me.label }}#}
|
||||
{# </p>#}
|
||||
|
||||
<p>{{ login_user_form.submit() }}</p>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{% extends "security/base.html" %}
|
||||
{% from "macros.html" import render_field %}
|
||||
|
||||
{% block title %} {{ _fsdomain('Reset password') }} {% endblock %}
|
||||
{% block content_title %} {{ _fsdomain('Reset password') }} {% endblock %}
|
||||
{% block title %} {{ _fsdomain('Reset AskEveAI password') }} {% endblock %}
|
||||
{% block content_title %} {{ _fsdomain('Reset AskEveAI password') }} {% endblock %}
|
||||
{% block content_description %}An email will be sent to you with instructions.{% endblock %}
|
||||
{% block content %}
|
||||
{# {% include "security/_messages.html" %}#}
|
||||
{# <form action="{{ url_for_security('reset_password', token=reset_password_token) }}" method="post" name="reset_password_form">#}
|
||||
{# <form action="{{ prefixed_url_for('security.reset_password', token=reset_password_token) }}" method="post" name="reset_password_form">#}
|
||||
<form action="" method="post">
|
||||
{{ reset_password_form.hidden_tag() }}
|
||||
{# {{ render_form_errors(reset_password_form) }}#}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<div class="form-group mt-3">
|
||||
<button type="submit" name="action" value="edit_user" class="btn btn-primary">Edit Selected User</button>
|
||||
<button type="submit" name="action" value="resend_confirmation_email" class="btn btn-secondary">Resend Confirmation Email</button>
|
||||
<button type="submit" name="action" value="send_password_reset_email" class="btn btn-secondary">Send Password Reset Email</button>
|
||||
<button type="submit" name="action" value="reset_uniquifier" class="btn btn-secondary">Reset Uniquifier</button>
|
||||
<!-- Additional buttons can be added here for other actions -->
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,10 @@ from flask import current_app
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, SubmitField, StringField
|
||||
from wtforms.validators import DataRequired, Length, Email, NumberRange, Optional, EqualTo
|
||||
from flask_security.forms import ForgotPasswordForm
|
||||
from flask_security.utils import send_mail, config_value
|
||||
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
|
||||
|
||||
class SetPasswordForm(FlaskForm):
|
||||
|
||||
@@ -164,3 +164,5 @@ def reset_password(token):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -154,30 +154,20 @@ def user():
|
||||
form.tenant_id.data = session.get('tenant').get('id') # It is only possible to create users for the session tenant
|
||||
if form.validate_on_submit():
|
||||
current_app.logger.info(f"Adding User for tenant {session['tenant']['id']} ")
|
||||
if form.password.data != form.confirm_password.data:
|
||||
flash('Passwords do not match.', 'danger')
|
||||
return render_template('user/user.html', form=form)
|
||||
|
||||
# Handle the required attributes
|
||||
hashed_password = hash_password(form.password.data)
|
||||
new_user = User(user_name=form.user_name.data,
|
||||
email=form.email.data,
|
||||
password=hashed_password,
|
||||
first_name=form.first_name.data,
|
||||
last_name=form.last_name.data,
|
||||
valid_to=form.valid_to.data,
|
||||
tenant_id=form.tenant_id.data
|
||||
tenant_id=form.tenant_id.data,
|
||||
fs_uniquifier=uuid.uuid4().hex,
|
||||
)
|
||||
|
||||
timestamp = dt.now(tz.utc)
|
||||
new_user.created_at = timestamp
|
||||
new_user.updated_at = timestamp
|
||||
|
||||
# Handle the relations
|
||||
tenant_id = request.form.get('tenant_id')
|
||||
# the_tenant = Tenant.query.get(tenant_id)
|
||||
# new_user.tenant = the_tenant
|
||||
|
||||
# Add roles
|
||||
for role_id in form.roles.data:
|
||||
the_role = Role.query.get(role_id)
|
||||
@@ -188,11 +178,17 @@ def user():
|
||||
try:
|
||||
db.session.add(new_user)
|
||||
db.session.commit()
|
||||
security.datastore.set_uniquifier()
|
||||
send_confirmation_email(new_user)
|
||||
current_app.logger.debug(f'User {new_user.id} with name {new_user.user_name} added to database'
|
||||
f'Confirmation email sent to {new_user.email}')
|
||||
flash('User added successfully and confirmation email sent.', 'success')
|
||||
# security.datastore.set_uniquifier(new_user)
|
||||
try:
|
||||
send_confirmation_email(new_user)
|
||||
current_app.logger.debug(f'User {new_user.id} with name {new_user.user_name} added to database'
|
||||
f'Confirmation email sent to {new_user.email}')
|
||||
flash('User added successfully and confirmation email sent.', 'success')
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Failed to send confirmation email to {new_user.email}. Error: {str(e)}')
|
||||
flash('User added successfully, but failed to send confirmation email. '
|
||||
'Please contact the administrator.', 'warning')
|
||||
|
||||
return redirect(prefixed_url_for('user_bp.view_users'))
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Failed to add user with name {new_user.user_name}. Error: {str(e)}')
|
||||
@@ -315,6 +311,9 @@ def handle_user_action():
|
||||
elif action == 'resend_confirmation_email':
|
||||
send_confirmation_email(user)
|
||||
flash(f'Confirmation email sent to {user.email}.', 'success')
|
||||
elif action == 'send_password_reset_email':
|
||||
send_reset_email(user)
|
||||
flash(f'Password reset email sent to {user.email}.', 'success')
|
||||
elif action == 'reset_uniquifier':
|
||||
reset_uniquifier(user)
|
||||
flash(f'Uniquifier reset for {user.user_name}.', 'success')
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,74 @@
|
||||
"""fs_uniquifier required / password not required for user
|
||||
|
||||
Revision ID: 229774547fed
|
||||
Revises: a39d2e378ccf
|
||||
Create Date: 2024-08-21 08:49:55.397338
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '229774547fed'
|
||||
down_revision = 'a39d2e378ccf'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('roles_users', schema=None) as batch_op:
|
||||
batch_op.drop_constraint('roles_users_user_id_fkey', type_='foreignkey')
|
||||
batch_op.drop_constraint('roles_users_role_id_fkey', type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'user', ['user_id'], ['id'], referent_schema='public', ondelete='CASCADE')
|
||||
batch_op.create_foreign_key(None, 'role', ['role_id'], ['id'], referent_schema='public', ondelete='CASCADE')
|
||||
|
||||
with op.batch_alter_table('tenant_domain', schema=None) as batch_op:
|
||||
batch_op.drop_constraint('tenant_domain_tenant_id_fkey', type_='foreignkey')
|
||||
batch_op.drop_constraint('tenant_domain_updated_by_fkey', type_='foreignkey')
|
||||
batch_op.drop_constraint('tenant_domain_created_by_fkey', type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'user', ['updated_by'], ['id'], referent_schema='public')
|
||||
batch_op.create_foreign_key(None, 'user', ['created_by'], ['id'], referent_schema='public')
|
||||
batch_op.create_foreign_key(None, 'tenant', ['tenant_id'], ['id'], referent_schema='public')
|
||||
|
||||
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||
batch_op.alter_column('password',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
nullable=True)
|
||||
batch_op.alter_column('fs_uniquifier',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
nullable=False)
|
||||
batch_op.drop_constraint('user_tenant_id_fkey', type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'tenant', ['tenant_id'], ['id'], referent_schema='public')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key('user_tenant_id_fkey', 'tenant', ['tenant_id'], ['id'])
|
||||
batch_op.alter_column('fs_uniquifier',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
nullable=True)
|
||||
batch_op.alter_column('password',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
nullable=False)
|
||||
|
||||
with op.batch_alter_table('tenant_domain', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key('tenant_domain_created_by_fkey', 'user', ['created_by'], ['id'])
|
||||
batch_op.create_foreign_key('tenant_domain_updated_by_fkey', 'user', ['updated_by'], ['id'])
|
||||
batch_op.create_foreign_key('tenant_domain_tenant_id_fkey', 'tenant', ['tenant_id'], ['id'])
|
||||
|
||||
with op.batch_alter_table('roles_users', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key('roles_users_role_id_fkey', 'role', ['role_id'], ['id'], ondelete='CASCADE')
|
||||
batch_op.create_foreign_key('roles_users_user_id_fkey', 'user', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Uniquifier not required when creating user
|
||||
|
||||
Revision ID: a39d2e378ccf
|
||||
Revises: 1716099b62f0
|
||||
Create Date: 2024-08-20 15:53:08.692690
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a39d2e378ccf'
|
||||
down_revision = '1716099b62f0'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('roles_users', schema=None) as batch_op:
|
||||
batch_op.drop_constraint('roles_users_role_id_fkey', type_='foreignkey')
|
||||
batch_op.drop_constraint('roles_users_user_id_fkey', type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'role', ['role_id'], ['id'], referent_schema='public', ondelete='CASCADE')
|
||||
batch_op.create_foreign_key(None, 'user', ['user_id'], ['id'], referent_schema='public', ondelete='CASCADE')
|
||||
|
||||
with op.batch_alter_table('tenant_domain', schema=None) as batch_op:
|
||||
batch_op.drop_constraint('tenant_domain_updated_by_fkey', type_='foreignkey')
|
||||
batch_op.drop_constraint('tenant_domain_created_by_fkey', type_='foreignkey')
|
||||
batch_op.drop_constraint('tenant_domain_tenant_id_fkey', type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'user', ['updated_by'], ['id'], referent_schema='public')
|
||||
batch_op.create_foreign_key(None, 'user', ['created_by'], ['id'], referent_schema='public')
|
||||
batch_op.create_foreign_key(None, 'tenant', ['tenant_id'], ['id'], referent_schema='public')
|
||||
|
||||
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||
batch_op.alter_column('fs_uniquifier',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
nullable=True)
|
||||
batch_op.drop_constraint('user_tenant_id_fkey', type_='foreignkey')
|
||||
batch_op.create_foreign_key(None, 'tenant', ['tenant_id'], ['id'], referent_schema='public')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
with op.batch_alter_table('user', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key('user_tenant_id_fkey', 'tenant', ['tenant_id'], ['id'])
|
||||
batch_op.alter_column('fs_uniquifier',
|
||||
existing_type=sa.VARCHAR(length=255),
|
||||
nullable=False)
|
||||
|
||||
with op.batch_alter_table('tenant_domain', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key('tenant_domain_tenant_id_fkey', 'tenant', ['tenant_id'], ['id'])
|
||||
batch_op.create_foreign_key('tenant_domain_created_by_fkey', 'user', ['created_by'], ['id'])
|
||||
batch_op.create_foreign_key('tenant_domain_updated_by_fkey', 'user', ['updated_by'], ['id'])
|
||||
|
||||
with op.batch_alter_table('roles_users', schema=None) as batch_op:
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.drop_constraint(None, type_='foreignkey')
|
||||
batch_op.create_foreign_key('roles_users_user_id_fkey', 'user', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
batch_op.create_foreign_key('roles_users_role_id_fkey', 'role', ['role_id'], ['id'], ondelete='CASCADE')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
@@ -53,6 +53,10 @@ http {
|
||||
index index.html index.htm;
|
||||
}
|
||||
|
||||
location /reset {
|
||||
rewrite ^/reset(.*)$ /admin/reset$1 permanent;
|
||||
}
|
||||
|
||||
location /static/ {
|
||||
alias /etc/nginx/static/;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user