fixed migrations
This commit is contained in:
58
Dockerfile
58
Dockerfile
@@ -1,33 +1,57 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
postgresql-client \
|
||||
build-essential \
|
||||
libpq-dev \
|
||||
curl \
|
||||
netcat-traditional \
|
||||
&& 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.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy the rest of the application
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Create migrations directory if it doesn't exist
|
||||
RUN mkdir -p migrations/versions
|
||||
# Create necessary directories and set permissions
|
||||
RUN mkdir -p /app/uploads /app/static/uploads && \
|
||||
chown -R celery:celery /app
|
||||
|
||||
# Make entrypoint script executable
|
||||
RUN chmod +x entrypoint.sh
|
||||
# Create and set up startup script
|
||||
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
|
||||
ENV FLASK_APP=app.py
|
||||
ENV FLASK_ENV=production
|
||||
# Switch to non-root user
|
||||
USER celery
|
||||
|
||||
# Expose the port the app runs on
|
||||
EXPOSE 5000
|
||||
|
||||
# Use the entrypoint script
|
||||
ENTRYPOINT ["./entrypoint.sh"]
|
||||
# Set entrypoint
|
||||
ENTRYPOINT ["/app/start.sh"]
|
||||
BIN
__pycache__/app.cpython-311.pyc
Normal file
BIN
__pycache__/app.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/celery_worker.cpython-311.pyc
Normal file
BIN
__pycache__/celery_worker.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/extensions.cpython-311.pyc
Normal file
BIN
__pycache__/extensions.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/forms.cpython-311.pyc
Normal file
BIN
__pycache__/forms.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/models.cpython-311.pyc
Normal file
BIN
__pycache__/models.cpython-311.pyc
Normal file
Binary file not shown.
BIN
__pycache__/tasks.cpython-311.pyc
Normal file
BIN
__pycache__/tasks.cpython-311.pyc
Normal file
Binary file not shown.
16
app.py
16
app.py
@@ -3,7 +3,7 @@ from flask import Flask, send_from_directory, jsonify
|
||||
from flask_migrate import Migrate
|
||||
from dotenv import load_dotenv
|
||||
import os
|
||||
from models import User
|
||||
from models import User, SiteSettings
|
||||
from flask_wtf.csrf import generate_csrf
|
||||
from routes.room_files import room_files_bp
|
||||
from routes.user import user_bp
|
||||
@@ -45,7 +45,12 @@ def create_app():
|
||||
|
||||
@app.context_processor
|
||||
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
|
||||
@login_manager.user_loader
|
||||
@@ -111,7 +116,12 @@ def create_app():
|
||||
|
||||
# Create default email templates if they don't exist
|
||||
with app.app_context():
|
||||
create_default_templates()
|
||||
try:
|
||||
# Ensure database tables exist
|
||||
db.create_all()
|
||||
create_default_templates()
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not create default templates: {e}")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ version: '3.8'
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
command: gunicorn --bind 0.0.0.0:5000 app:app
|
||||
ports:
|
||||
- "10335:5000"
|
||||
environment:
|
||||
@@ -59,17 +60,18 @@ services:
|
||||
celery_worker:
|
||||
build: .
|
||||
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:
|
||||
- .:/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:
|
||||
- web
|
||||
- redis
|
||||
- db
|
||||
db:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "celery", "-A", "celery_worker.celery", "inspect", "ping"]
|
||||
|
||||
BIN
migrations/__pycache__/env.cpython-311.pyc
Normal file
BIN
migrations/__pycache__/env.cpython-311.pyc
Normal file
Binary file not shown.
@@ -7,6 +7,7 @@ Create Date: 2025-06-02 14:10:54.033943
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,18 +19,23 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('key_value_settings',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('key', sa.String(length=100), nullable=False),
|
||||
sa.Column('value', sa.Text(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('key')
|
||||
)
|
||||
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',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('key', sa.String(length=100), nullable=False),
|
||||
sa.Column('value', sa.Text(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('key')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('key_value_settings')
|
||||
# ### end Alembic commands ###
|
||||
# ### end Alembic commands ###
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-26 14:00:05.521776
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
Revision ID: 1c297825e3a9
|
||||
Revises:
|
||||
Create Date: 2025-05-23 08:39:40.494853
|
||||
Create Date: 2025-06-02 13:26:30.353000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -17,17 +18,24 @@ depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('user',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('username', sa.String(length=150), nullable=False),
|
||||
sa.Column('email', sa.String(length=150), nullable=False),
|
||||
sa.Column('password_hash', sa.String(length=128), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('email'),
|
||||
sa.UniqueConstraint('username')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
# 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',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('username', sa.String(length=150), nullable=False),
|
||||
sa.Column('email', sa.String(length=150), nullable=False),
|
||||
sa.Column('password_hash', sa.String(length=128), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('email'),
|
||||
sa.UniqueConstraint('username')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-06-02 09:04:39.972021
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('mails',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'mails' not in tables:
|
||||
op.create_table('mails',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('recipient', sa.String(length=150), nullable=False),
|
||||
sa.Column('subject', sa.String(length=200), nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 16:10:53.731035
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 21:44:58.832286
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,17 +19,22 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('room_member_permissions',
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('can_view', sa.Boolean(), nullable=False),
|
||||
sa.Column('can_upload', sa.Boolean(), nullable=False),
|
||||
sa.Column('can_delete', sa.Boolean(), nullable=False),
|
||||
sa.Column('can_share', sa.Boolean(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['room_id'], ['room.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('room_id', 'user_id')
|
||||
)
|
||||
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',
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('can_view', sa.Boolean(), nullable=False),
|
||||
sa.Column('can_upload', sa.Boolean(), nullable=False),
|
||||
sa.Column('can_delete', sa.Boolean(), nullable=False),
|
||||
sa.Column('can_share', sa.Boolean(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['room_id'], ['room.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('room_id', 'user_id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 21:27:17.497481
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,15 +19,24 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('room_members',
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['room_id'], ['room.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('room_id', 'user_id')
|
||||
)
|
||||
with op.batch_alter_table('room', schema=None) as batch_op:
|
||||
batch_op.drop_column('is_private')
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'room_members' not in tables:
|
||||
op.create_table('room_members',
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['room_id'], ['room.id'], ),
|
||||
sa.ForeignKeyConstraint(['user_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:
|
||||
batch_op.drop_column('is_private')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 21:25:27.880150
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,16 +19,21 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('room',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('created_by', sa.Integer(), nullable=False),
|
||||
sa.Column('is_private', sa.Boolean(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'room' not in tables:
|
||||
op.create_table('room',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('created_by', sa.Integer(), nullable=False),
|
||||
sa.Column('is_private', sa.Boolean(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['created_by'], ['user.id'], ),
|
||||
sa.PrimaryKeyConstraint('id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 09:24:23.926302
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,12 +19,21 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### 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:
|
||||
batch_op.add_column(sa.Column('phone', sa.String(length=20), nullable=True))
|
||||
batch_op.add_column(sa.Column('company', sa.String(length=100), nullable=True))
|
||||
batch_op.add_column(sa.Column('position', sa.String(length=100), nullable=True))
|
||||
batch_op.add_column(sa.Column('notes', sa.Text(), nullable=True))
|
||||
batch_op.add_column(sa.Column('is_active', sa.Boolean(), nullable=True))
|
||||
if 'phone' not in columns:
|
||||
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))
|
||||
if 'position' not in columns:
|
||||
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))
|
||||
if 'is_active' not in columns:
|
||||
batch_op.add_column(sa.Column('is_active', sa.Boolean(), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-06-02 08:25:48.241102
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -24,7 +25,12 @@ def upgrade():
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('template_variables',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'template_variables' not in tables:
|
||||
op.create_table('template_variables',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('notification_type', sa.VARCHAR(length=50), autoincrement=False, nullable=False),
|
||||
sa.Column('variable_name', sa.VARCHAR(length=50), autoincrement=False, nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-24 10:07:02.159730
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('room_file',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'room_file' not in tables:
|
||||
op.create_table('room_file',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-24 18:14:38.320999
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:05:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.sql import text
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-25 10:03:03.423064
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-26 10:42:17.287566
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:15:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.sql import text
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-25 21:16:39.683736
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('site_settings',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'site_settings' not in tables:
|
||||
op.create_table('site_settings',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('primary_color', sa.String(length=7), nullable=True),
|
||||
sa.Column('secondary_color', sa.String(length=7), nullable=True),
|
||||
@@ -31,7 +37,12 @@ def upgrade():
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('color_settings',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'color_settings' not in tables:
|
||||
op.create_table('color_settings',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('primary_color', sa.VARCHAR(length=7), autoincrement=False, nullable=True),
|
||||
sa.Column('secondary_color', sa.VARCHAR(length=7), autoincrement=False, nullable=True),
|
||||
|
||||
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.
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.
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.
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:00:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# Create conversation table first
|
||||
op.create_table('conversation',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'conversation' not in tables:
|
||||
op.create_table('conversation',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('description', sa.Text(), nullable=True),
|
||||
@@ -29,7 +35,12 @@ def upgrade():
|
||||
)
|
||||
|
||||
# Create conversation_members table
|
||||
op.create_table('conversation_members',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'conversation_members' not in tables:
|
||||
op.create_table('conversation_members',
|
||||
sa.Column('conversation_id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['conversation_id'], ['conversation.id'], ),
|
||||
@@ -38,7 +49,12 @@ def upgrade():
|
||||
)
|
||||
|
||||
# Create message table
|
||||
op.create_table('message',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'message' not in tables:
|
||||
op.create_table('message',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('content', sa.Text(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:45:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'add_deleted_by_to_room_file'
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:30:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'add_deleted_column_to_room_file'
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:00:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -17,7 +18,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('trashed_file',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'trashed_file' not in tables:
|
||||
op.create_table('trashed_file',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('room_id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-24 08:36:03.426879
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-26 11:14:05.629795
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-24 12:32:19.239241
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -8,6 +8,7 @@ Create Date: 2025-05-23 19:28:16.977187
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
from sqlalchemy import inspect
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'c21f243b3640'
|
||||
@@ -19,8 +20,13 @@ depends_on = None
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
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:
|
||||
batch_op.add_column(sa.Column('profile_picture', sa.String(length=255), nullable=True))
|
||||
if 'profile_picture' not in columns:
|
||||
batch_op.add_column(sa.Column('profile_picture', sa.String(length=255), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 16:00:09.905001
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,8 +19,13 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### 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:
|
||||
batch_op.add_column(sa.Column('last_name', sa.String(length=150), nullable=True))
|
||||
if 'last_name' not in columns:
|
||||
batch_op.add_column(sa.Column('last_name', sa.String(length=150), nullable=True))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-06-01 20:09:08.019884
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('email_templates',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'email_templates' not in tables:
|
||||
op.create_table('email_templates',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=100), nullable=False),
|
||||
sa.Column('subject', sa.String(length=200), nullable=False),
|
||||
@@ -54,7 +60,12 @@ def downgrade():
|
||||
type_=postgresql.JSONB(astext_type=sa.Text()),
|
||||
existing_nullable=True)
|
||||
|
||||
op.create_table('notification',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'notification' not in tables:
|
||||
op.create_table('notification',
|
||||
sa.Column('id', sa.INTEGER(), autoincrement=True, nullable=False),
|
||||
sa.Column('user_id', sa.INTEGER(), autoincrement=False, nullable=False),
|
||||
sa.Column('title', sa.VARCHAR(length=255), autoincrement=False, nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-25 21:08:37.158900
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('color_settings',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'color_settings' not in tables:
|
||||
op.create_table('color_settings',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('primary_color', sa.String(length=7), nullable=True),
|
||||
sa.Column('secondary_color', sa.String(length=7), nullable=True),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2024-03-19 10:00:00.000000
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -17,7 +18,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# Create user_starred_file table
|
||||
op.create_table('user_starred_file',
|
||||
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',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('user_id', sa.Integer(), nullable=False),
|
||||
sa.Column('file_id', sa.Integer(), nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 08:45:00.693155
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-23 08:55:10.537722
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -35,9 +36,17 @@ def upgrade():
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
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:
|
||||
batch_op.add_column(sa.Column('is_admin', sa.Boolean(), nullable=True))
|
||||
batch_op.add_column(sa.Column('created_at', sa.DateTime(), nullable=True))
|
||||
if 'is_admin' not in columns:
|
||||
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))
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-26 15:00:18.557702
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
@@ -18,7 +19,12 @@ depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('message_attachment',
|
||||
conn = op.get_bind()
|
||||
inspector = inspect(conn)
|
||||
tables = inspector.get_table_names()
|
||||
|
||||
if 'message_attachment' not in tables:
|
||||
op.create_table('message_attachment',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('message_id', sa.Integer(), nullable=False),
|
||||
sa.Column('name', sa.String(length=255), nullable=False),
|
||||
|
||||
@@ -7,6 +7,7 @@ Create Date: 2025-05-26 10:52:32.572951
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import inspect
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
|
||||
BIN
routes/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
routes/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/admin.cpython-311.pyc
Normal file
BIN
routes/__pycache__/admin.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/auth.cpython-311.pyc
Normal file
BIN
routes/__pycache__/auth.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/contacts.cpython-311.pyc
Normal file
BIN
routes/__pycache__/contacts.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/conversations.cpython-311.pyc
Normal file
BIN
routes/__pycache__/conversations.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/email_templates.cpython-311.pyc
Normal file
BIN
routes/__pycache__/email_templates.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/main.cpython-311.pyc
Normal file
BIN
routes/__pycache__/main.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/room_files.cpython-311.pyc
Normal file
BIN
routes/__pycache__/room_files.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/room_members.cpython-311.pyc
Normal file
BIN
routes/__pycache__/room_members.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/rooms.cpython-311.pyc
Normal file
BIN
routes/__pycache__/rooms.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/trash.cpython-311.pyc
Normal file
BIN
routes/__pycache__/trash.cpython-311.pyc
Normal file
Binary file not shown.
BIN
routes/__pycache__/user.cpython-311.pyc
Normal file
BIN
routes/__pycache__/user.cpython-311.pyc
Normal file
Binary file not shown.
@@ -7,13 +7,6 @@ from utils import log_event, create_notification, get_unread_count
|
||||
|
||||
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):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
@@ -24,6 +17,13 @@ def require_password_change(f):
|
||||
return decorated_function
|
||||
|
||||
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'])
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
|
||||
22
start.sh
Normal file
22
start.sh
Normal 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
71
update_migrations.py
Normal 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()
|
||||
BIN
utils/__pycache__/__init__.cpython-311.pyc
Normal file
BIN
utils/__pycache__/__init__.cpython-311.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/email_templates.cpython-311.pyc
Normal file
BIN
utils/__pycache__/email_templates.cpython-311.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/event_logger.cpython-311.pyc
Normal file
BIN
utils/__pycache__/event_logger.cpython-311.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/notification.cpython-311.pyc
Normal file
BIN
utils/__pycache__/notification.cpython-311.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/path_utils.cpython-311.pyc
Normal file
BIN
utils/__pycache__/path_utils.cpython-311.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/permissions.cpython-311.pyc
Normal file
BIN
utils/__pycache__/permissions.cpython-311.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/time_utils.cpython-311.pyc
Normal file
BIN
utils/__pycache__/time_utils.cpython-311.pyc
Normal file
Binary file not shown.
Reference in New Issue
Block a user