import datetime
import os
from flask import current_app, url_for
from flask_security import SQLAlchemyUserDatastore, UserMixin, RoleMixin
from flask_security.utils import verify_password
from flask_sqlalchemy import SQLAlchemy
from slugify import slugify
from sqlalchemy import event, UniqueConstraint, PrimaryKeyConstraint, and_
from sqlalchemy.ext.hybrid import Comparator, hybrid_property
from sqlalchemy.sql import func
from sqlalchemy_searchable import make_searchable
from sqlalchemy_utils.types.choice import ChoiceType
from sqlalchemy_utils.types.url import URLType
from little_boxes.key import Key as LittleBoxesKey
from activitypub.utils import ap_url
from activitypub.vars import DEFAULT_CTX
from sqlalchemy.dialects.postgresql import UUID, JSONB
from sqlalchemy import text as sa_text
from little_boxes import activitypub as ap
from urllib.parse import urlparse
from authlib.integrations.sqla_oauth2 import OAuth2ClientMixin, OAuth2AuthorizationCodeMixin, OAuth2TokenMixin
import time
import uuid
from utils.defaults import Reel2bitsDefaults
db = SQLAlchemy()
make_searchable(db.metadata)
# #### Base ####
class CaseInsensitiveComparator(Comparator):
def __eq__(self, other):
return func.lower(self.__clause_element__()) == func.lower(other)
class Config(db.Model):
__tablename__ = "config"
id = db.Column(db.Integer, primary_key=True)
app_name = db.Column(db.String(255), default=None)
app_description = db.Column(db.Text)
user_quota = db.Column(db.BigInteger, default=Reel2bitsDefaults.user_quotas_default)
announcement = db.Column(db.Text, nullable=True)
# #### User ####
roles_users = db.Table(
"roles_users",
db.Column("user_id", db.Integer(), db.ForeignKey("user.id")),
db.Column("role_id", db.Integer(), db.ForeignKey("role.id")),
)
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False, info={"label": "Name"})
description = db.Column(db.String(255), info={"label": "Description"})
__mapper_args__ = {"order_by": name}
class PasswordResetToken(db.Model):
__tablename__ = "password_reset_token"
id = db.Column(db.Integer, primary_key=True)
token = db.Column(db.String(255), unique=True, nullable=False)
created_at = db.Column(db.DateTime(timezone=False), default=datetime.datetime.utcnow)
updated_at = db.Column(
db.DateTime(timezone=False), default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow
)
expires_at = db.Column(db.DateTime(timezone=False), nullable=True)
used = db.Column(db.Boolean(), default=False)
user_id = db.Column(db.Integer(), db.ForeignKey("user.id"), nullable=True)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True, nullable=True, info={"label": "Email"})
name = db.Column(db.String(255), nullable=False, info={"label": "Username"})
password = db.Column(db.String(255), nullable=True, info={"label": "Password"})
active = db.Column(db.Boolean())
fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False)
confirmed_at = db.Column(db.DateTime())
created_at = db.Column(db.DateTime(timezone=False), default=datetime.datetime.utcnow)
updated_at = db.Column(
db.DateTime(timezone=False), default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow
)
display_name = db.Column(db.String(30), nullable=True, info={"label": "Display name"})
locale = db.Column(db.String(5), default="en")
timezone = db.Column(db.String(255), nullable=False, default="UTC") # Managed and fed by pytz
flake_id = db.Column(UUID(as_uuid=True), unique=False, nullable=True)
# should be removed since User.name is URL friendly
slug = db.Column(db.String(255), nullable=True)
# User default quota, database default is the one from the hardcoded value
# It is overriden when registering with the app config one, here it is only
# if there is no quota defined, and in cas of, to avoid issues.
# Both are in bytes
quota = db.Column(db.BigInteger(), default=Reel2bitsDefaults.user_quotas_default)
# This should be updated on each upload and deletes
quota_count = db.Column(db.BigInteger(), default=0)
avatar_filename = db.Colu