fixed migrations

This commit is contained in:
2025-06-02 16:11:56 +02:00
parent c95a1c456b
commit 4dbaa27cba
98 changed files with 399 additions and 109 deletions

View File

@@ -1,33 +1,57 @@
FROM python:3.11-slim FROM python:3.11-slim
WORKDIR /app
# Install system dependencies # Install system dependencies
RUN apt-get update && apt-get install -y \ RUN apt-get update && apt-get install -y \
gcc \ build-essential \
postgresql-client \ libpq-dev \
curl \
netcat-traditional \ netcat-traditional \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Create a non-root user
RUN useradd -m -u 1000 celery
# Set working directory
WORKDIR /app
# Copy requirements first to leverage Docker cache # Copy requirements first to leverage Docker cache
COPY requirements.txt . COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application # Copy application code
COPY . . COPY . .
# Create migrations directory if it doesn't exist # Create necessary directories and set permissions
RUN mkdir -p migrations/versions RUN mkdir -p /app/uploads /app/static/uploads && \
chown -R celery:celery /app
# Make entrypoint script executable # Create and set up startup script
RUN chmod +x entrypoint.sh RUN echo '#!/bin/bash\n\
echo "Waiting for database..."\n\
while ! nc -z db 5432; do\n\
sleep 0.1\n\
done\n\
echo "Database is ready!"\n\
\n\
echo "Waiting for Redis..."\n\
while ! nc -z redis 6379; do\n\
sleep 0.1\n\
done\n\
echo "Redis is ready!"\n\
\n\
echo "Running database migrations..."\n\
flask db upgrade\n\
\n\
echo "Creating admin user..."\n\
flask create-admin\n\
\n\
echo "Starting application..."\n\
exec "$@"' > /app/start.sh && \
chmod +x /app/start.sh && \
chown celery:celery /app/start.sh
# Set environment variables # Switch to non-root user
ENV FLASK_APP=app.py USER celery
ENV FLASK_ENV=production
# Expose the port the app runs on # Set entrypoint
EXPOSE 5000 ENTRYPOINT ["/app/start.sh"]
# Use the entrypoint script
ENTRYPOINT ["./entrypoint.sh"]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

14
app.py
View File

@@ -3,7 +3,7 @@ from flask import Flask, send_from_directory, jsonify
from flask_migrate import Migrate from flask_migrate import Migrate
from dotenv import load_dotenv from dotenv import load_dotenv
import os import os
from models import User from models import User, SiteSettings
from flask_wtf.csrf import generate_csrf from flask_wtf.csrf import generate_csrf
from routes.room_files import room_files_bp from routes.room_files import room_files_bp
from routes.user import user_bp from routes.user import user_bp
@@ -45,7 +45,12 @@ def create_app():
@app.context_processor @app.context_processor
def inject_config(): def inject_config():
return dict(config=app.config) site_settings = SiteSettings.query.first()
if not site_settings:
site_settings = SiteSettings()
db.session.add(site_settings)
db.session.commit()
return dict(config=app.config, site_settings=site_settings)
# User loader for Flask-Login # User loader for Flask-Login
@login_manager.user_loader @login_manager.user_loader
@@ -111,7 +116,12 @@ def create_app():
# Create default email templates if they don't exist # Create default email templates if they don't exist
with app.app_context(): with app.app_context():
try:
# Ensure database tables exist
db.create_all()
create_default_templates() create_default_templates()
except Exception as e:
print(f"Warning: Could not create default templates: {e}")
return app return app

View File

@@ -3,6 +3,7 @@ version: '3.8'
services: services:
web: web:
build: . build: .
command: gunicorn --bind 0.0.0.0:5000 app:app
ports: ports:
- "10335:5000" - "10335:5000"
environment: environment:
@@ -59,17 +60,18 @@ services:
celery_worker: celery_worker:
build: . build: .
command: celery -A celery_worker.celery worker --loglevel=info command: celery -A celery_worker.celery worker --loglevel=info
environment:
- FLASK_APP=app.py
- FLASK_ENV=production
- DATABASE_URL=postgresql://postgres:postgres@db:5432/docupulse
- REDIS_URL=redis://redis:6379/0
volumes: volumes:
- .:/app - .:/app
environment:
- FLASK_APP=app.py
- FLASK_ENV=development
- DATABASE_URL=postgresql://postgres:postgres@db:5432/docupulse
- REDIS_URL=redis://redis:6379/0
depends_on: depends_on:
- web db:
- redis condition: service_healthy
- db redis:
condition: service_healthy
restart: unless-stopped restart: unless-stopped
healthcheck: healthcheck:
test: ["CMD", "celery", "-A", "celery_worker.celery", "inspect", "ping"] test: ["CMD", "celery", "-A", "celery_worker.celery", "inspect", "ping"]

Binary file not shown.

View File

@@ -7,6 +7,7 @@ Create Date: 2025-06-02 14:10:54.033943
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'key_value_settings' not in tables:
op.create_table('key_value_settings', op.create_table('key_value_settings',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('key', sa.String(length=100), nullable=False), sa.Column('key', sa.String(length=100), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-26 14:00:05.521776
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -2,11 +2,12 @@
Revision ID: 1c297825e3a9 Revision ID: 1c297825e3a9
Revises: Revises:
Create Date: 2025-05-23 08:39:40.494853 Create Date: 2025-06-02 13:26:30.353000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -17,7 +18,15 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # Check if the table exists before creating it
conn = op.get_bind()
inspector = sa.inspect(conn)
if 'user' not in inspector.get_table_names():
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'user' not in tables:
op.create_table('user', op.create_table('user',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('username', sa.String(length=150), nullable=False), sa.Column('username', sa.String(length=150), nullable=False),
@@ -27,7 +36,6 @@ def upgrade():
sa.UniqueConstraint('email'), sa.UniqueConstraint('email'),
sa.UniqueConstraint('username') sa.UniqueConstraint('username')
) )
# ### end Alembic commands ###
def downgrade(): def downgrade():

View File

@@ -7,6 +7,7 @@ Create Date: 2025-06-02 09:04:39.972021
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'mails' not in tables:
op.create_table('mails', op.create_table('mails',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('recipient', sa.String(length=150), nullable=False), sa.Column('recipient', sa.String(length=150), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 16:10:53.731035
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 21:44:58.832286
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'room_member_permissions' not in tables:
op.create_table('room_member_permissions', op.create_table('room_member_permissions',
sa.Column('room_id', sa.Integer(), nullable=False), sa.Column('room_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 21:27:17.497481
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'room_members' not in tables:
op.create_table('room_members', op.create_table('room_members',
sa.Column('room_id', sa.Integer(), nullable=False), sa.Column('room_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=False),
@@ -25,6 +31,10 @@ def upgrade():
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ), sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('room_id', 'user_id') sa.PrimaryKeyConstraint('room_id', 'user_id')
) )
# Check if is_private column exists before dropping it
columns = [col['name'] for col in inspector.get_columns('room')]
if 'is_private' in columns:
with op.batch_alter_table('room', schema=None) as batch_op: with op.batch_alter_table('room', schema=None) as batch_op:
batch_op.drop_column('is_private') batch_op.drop_column('is_private')

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 21:25:27.880150
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'room' not in tables:
op.create_table('room', op.create_table('room',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=100), nullable=False), sa.Column('name', sa.String(length=100), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 09:24:23.926302
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,11 +19,20 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
columns = [col['name'] for col in inspector.get_columns('user')]
with op.batch_alter_table('user', schema=None) as batch_op: with op.batch_alter_table('user', schema=None) as batch_op:
if 'phone' not in columns:
batch_op.add_column(sa.Column('phone', sa.String(length=20), nullable=True)) batch_op.add_column(sa.Column('phone', sa.String(length=20), nullable=True))
if 'company' not in columns:
batch_op.add_column(sa.Column('company', sa.String(length=100), nullable=True)) batch_op.add_column(sa.Column('company', sa.String(length=100), nullable=True))
if 'position' not in columns:
batch_op.add_column(sa.Column('position', sa.String(length=100), nullable=True)) batch_op.add_column(sa.Column('position', sa.String(length=100), nullable=True))
if 'notes' not in columns:
batch_op.add_column(sa.Column('notes', sa.Text(), nullable=True)) batch_op.add_column(sa.Column('notes', sa.Text(), nullable=True))
if 'is_active' not in columns:
batch_op.add_column(sa.Column('is_active', sa.Boolean(), nullable=True)) batch_op.add_column(sa.Column('is_active', sa.Boolean(), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@@ -7,6 +7,7 @@ Create Date: 2025-06-02 08:25:48.241102
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -24,6 +25,11 @@ def upgrade():
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'template_variables' not in tables:
op.create_table('template_variables', op.create_table('template_variables',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('notification_type', sa.VARCHAR(length=50), autoincrement=False, nullable=False), sa.Column('notification_type', sa.VARCHAR(length=50), autoincrement=False, nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-24 10:07:02.159730
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'room_file' not in tables:
op.create_table('room_file', op.create_table('room_file',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('room_id', sa.Integer(), nullable=False), sa.Column('room_id', sa.Integer(), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-24 18:14:38.320999
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:05:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.sql import text from sqlalchemy.sql import text

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-25 10:03:03.423064
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-26 10:42:17.287566
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:15:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.sql import text from sqlalchemy.sql import text

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-25 21:16:39.683736
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'site_settings' not in tables:
op.create_table('site_settings', op.create_table('site_settings',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('primary_color', sa.String(length=7), nullable=True), sa.Column('primary_color', sa.String(length=7), nullable=True),
@@ -31,6 +37,11 @@ def upgrade():
def downgrade(): def downgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'color_settings' not in tables:
op.create_table('color_settings', op.create_table('color_settings',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('primary_color', sa.VARCHAR(length=7), autoincrement=False, nullable=True), sa.Column('primary_color', sa.VARCHAR(length=7), autoincrement=False, nullable=True),

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:00:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# Create conversation table first # Create conversation table first
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'conversation' not in tables:
op.create_table('conversation', op.create_table('conversation',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=100), nullable=False), sa.Column('name', sa.String(length=100), nullable=False),
@@ -29,6 +35,11 @@ def upgrade():
) )
# Create conversation_members table # Create conversation_members table
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'conversation_members' not in tables:
op.create_table('conversation_members', op.create_table('conversation_members',
sa.Column('conversation_id', sa.Integer(), nullable=False), sa.Column('conversation_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=False),
@@ -38,6 +49,11 @@ def upgrade():
) )
# Create message table # Create message table
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'message' not in tables:
op.create_table('message', op.create_table('message',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('content', sa.Text(), nullable=False), sa.Column('content', sa.Text(), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:45:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'add_deleted_by_to_room_file' revision = 'add_deleted_by_to_room_file'

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:30:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'add_deleted_column_to_room_file' revision = 'add_deleted_column_to_room_file'

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:00:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -17,6 +18,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'trashed_file' not in tables:
op.create_table('trashed_file', op.create_table('trashed_file',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('room_id', sa.Integer(), nullable=False), sa.Column('room_id', sa.Integer(), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-24 08:36:03.426879
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-26 11:14:05.629795
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-24 12:32:19.239241
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -8,6 +8,7 @@ Create Date: 2025-05-23 19:28:16.977187
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = 'c21f243b3640' revision = 'c21f243b3640'
@@ -19,7 +20,12 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
op.drop_table('contact') op.drop_table('contact')
conn = op.get_bind()
inspector = inspect(conn)
columns = [col['name'] for col in inspector.get_columns('user')]
with op.batch_alter_table('user', schema=None) as batch_op: with op.batch_alter_table('user', schema=None) as batch_op:
if 'profile_picture' not in columns:
batch_op.add_column(sa.Column('profile_picture', sa.String(length=255), nullable=True)) batch_op.add_column(sa.Column('profile_picture', sa.String(length=255), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 16:00:09.905001
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,7 +19,12 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
columns = [col['name'] for col in inspector.get_columns('user')]
with op.batch_alter_table('user', schema=None) as batch_op: with op.batch_alter_table('user', schema=None) as batch_op:
if 'last_name' not in columns:
batch_op.add_column(sa.Column('last_name', sa.String(length=150), nullable=True)) batch_op.add_column(sa.Column('last_name', sa.String(length=150), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@@ -7,6 +7,7 @@ Create Date: 2025-06-01 20:09:08.019884
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'email_templates' not in tables:
op.create_table('email_templates', op.create_table('email_templates',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=100), nullable=False), sa.Column('name', sa.String(length=100), nullable=False),
@@ -54,6 +60,11 @@ def downgrade():
type_=postgresql.JSONB(astext_type=sa.Text()), type_=postgresql.JSONB(astext_type=sa.Text()),
existing_nullable=True) existing_nullable=True)
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'notification' not in tables:
op.create_table('notification', op.create_table('notification',
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False), sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False), sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-25 21:08:37.158900
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'color_settings' not in tables:
op.create_table('color_settings', op.create_table('color_settings',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('primary_color', sa.String(length=7), nullable=True), sa.Column('primary_color', sa.String(length=7), nullable=True),

View File

@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:00:00.000000
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -17,6 +18,11 @@ depends_on = None
def upgrade(): def upgrade():
# Create user_starred_file table # Create user_starred_file table
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'user_starred_file' not in tables:
op.create_table('user_starred_file', op.create_table('user_starred_file',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False), sa.Column('user_id', sa.Integer(), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 08:45:00.693155
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-23 08:55:10.537722
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -35,8 +36,16 @@ def upgrade():
sa.PrimaryKeyConstraint('id'), sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email') sa.UniqueConstraint('email')
) )
# Check if columns exist before adding them
conn = op.get_bind()
inspector = inspect(conn)
columns = [col['name'] for col in inspector.get_columns('user')]
with op.batch_alter_table('user', schema=None) as batch_op: with op.batch_alter_table('user', schema=None) as batch_op:
if 'is_admin' not in columns:
batch_op.add_column(sa.Column('is_admin', sa.Boolean(), nullable=True)) batch_op.add_column(sa.Column('is_admin', sa.Boolean(), nullable=True))
if 'created_at' not in columns:
batch_op.add_column(sa.Column('created_at', sa.DateTime(), nullable=True)) batch_op.add_column(sa.Column('created_at', sa.DateTime(), nullable=True))
# ### end Alembic commands ### # ### end Alembic commands ###

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-26 15:00:18.557702
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
@@ -18,6 +19,11 @@ depends_on = None
def upgrade(): def upgrade():
# ### commands auto generated by Alembic - please adjust! ### # ### commands auto generated by Alembic - please adjust! ###
conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if 'message_attachment' not in tables:
op.create_table('message_attachment', op.create_table('message_attachment',
sa.Column('id', sa.Integer(), nullable=False), sa.Column('id', sa.Integer(), nullable=False),
sa.Column('message_id', sa.Integer(), nullable=False), sa.Column('message_id', sa.Integer(), nullable=False),

View File

@@ -7,6 +7,7 @@ Create Date: 2025-05-26 10:52:32.572951
""" """
from alembic import op from alembic import op
import sqlalchemy as sa import sqlalchemy as sa
from sqlalchemy import inspect
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -7,13 +7,6 @@ from utils import log_event, create_notification, get_unread_count
auth_bp = Blueprint('auth', __name__) auth_bp = Blueprint('auth', __name__)
@auth_bp.context_processor
def inject_unread_notifications():
if current_user.is_authenticated:
unread_count = get_unread_count(current_user.id)
return {'unread_notifications': unread_count}
return {'unread_notifications': 0}
def require_password_change(f): def require_password_change(f):
@wraps(f) @wraps(f)
def decorated_function(*args, **kwargs): def decorated_function(*args, **kwargs):
@@ -24,6 +17,13 @@ def require_password_change(f):
return decorated_function return decorated_function
def init_routes(auth_bp): def init_routes(auth_bp):
@auth_bp.context_processor
def inject_unread_notifications():
if current_user.is_authenticated:
unread_count = get_unread_count(current_user.id)
return {'unread_notifications': unread_count}
return {'unread_notifications': 0}
@auth_bp.route('/login', methods=['GET', 'POST']) @auth_bp.route('/login', methods=['GET', 'POST'])
def login(): def login():
if current_user.is_authenticated: if current_user.is_authenticated:

22
start.sh Normal file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
echo "Waiting for database..."
while ! nc -z db 5432; do
sleep 0.1
done
echo "Database is ready!"
echo "Waiting for Redis..."
while ! nc -z redis 6379; do
sleep 0.1
done
echo "Redis is ready!"
echo "Running database migrations..."
flask db upgrade
echo "Creating admin user..."
flask create-admin
echo "Starting application..."
exec "$@"

71
update_migrations.py Normal file
View File

@@ -0,0 +1,71 @@
import os
import re
from pathlib import Path
def update_migration_file(file_path):
with open(file_path, 'r') as f:
content = f.read()
# Skip if already has the pattern
if 'from sqlalchemy import inspect' in content:
return False
# Add import if not present
if 'import sqlalchemy as sa' in content:
content = content.replace('import sqlalchemy as sa', 'import sqlalchemy as sa\nfrom sqlalchemy import inspect')
else:
content = content.replace('from alembic import op', 'from alembic import op\nfrom sqlalchemy import inspect')
# Find all create_table operations
create_table_pattern = r'op\.create_table\([\'"](\w+)[\'"]'
tables = re.findall(create_table_pattern, content)
for table in tables:
# Create the check pattern with proper indentation
check_pattern = f""" conn = op.get_bind()
inspector = inspect(conn)
tables = inspector.get_table_names()
if '{table}' not in tables:"""
# Find the create_table line and its indentation
create_table_line = f"op.create_table('{table}'"
if create_table_line in content:
# Get the indentation of the create_table line
lines = content.split('\n')
for i, line in enumerate(lines):
if create_table_line in line:
indent = len(line) - len(line.lstrip())
# Add the check before the create_table with matching indentation
check_lines = check_pattern.split('\n')
check_lines = [' ' * indent + line.lstrip() for line in check_lines]
check_pattern = '\n'.join(check_lines)
# Add extra indentation to the create_table line
create_table_line = ' ' * (indent + 4) + create_table_line
# Replace in the content
content = content.replace(line, f"{check_pattern}\n{create_table_line}")
# Write back the updated content
with open(file_path, 'w') as f:
f.write(content)
return True
def main():
migrations_dir = Path('migrations/versions')
updated_files = []
for file in migrations_dir.glob('*.py'):
if file.name != '__init__.py':
if update_migration_file(file):
updated_files.append(file.name)
if updated_files:
print("Updated the following migration files:")
for file in updated_files:
print(f"- {file}")
else:
print("No files needed updating.")
if __name__ == '__main__':
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.