Clean up database constraints

This commit is contained in:
rubenwardy 2020-12-10 16:49:37 +00:00
parent 70ac8fa6ab
commit 8d8577a941
7 changed files with 78 additions and 25 deletions

@ -35,16 +35,17 @@ from .threads import *
class APIToken(db.Model): class APIToken(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
access_token = db.Column(db.String(34), unique=True) access_token = db.Column(db.String(34), unique=True, nullable=False)
name = db.Column(db.String(100), nullable=False) name = db.Column(db.String(100), nullable=False)
owner_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) owner_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
owner = db.relationship("User", back_populates="tokens", foreign_keys=[owner_id]) owner = db.relationship("User", foreign_keys=[owner_id], back_populates="tokens")
created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=True) package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=True)
package = db.relationship("Package", foreign_keys=[package_id]) package = db.relationship("Package", foreign_keys=[package_id], back_populates="tokens")
def canOperateOnPackage(self, package): def canOperateOnPackage(self, package):
if self.package and self.package != package: if self.package and self.package != package:
@ -80,7 +81,7 @@ class AuditLogEntry(db.Model):
created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
causer_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True) causer_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
causer = db.relationship("User", back_populates="", foreign_keys=[causer_id]) causer = db.relationship("User", foreign_keys=[causer_id], back_populates="audit_log_entries")
severity = db.Column(db.Enum(AuditSeverity), nullable=False) severity = db.Column(db.Enum(AuditSeverity), nullable=False)
@ -88,7 +89,7 @@ class AuditLogEntry(db.Model):
url = db.Column(db.String(200), nullable=True) url = db.Column(db.String(200), nullable=True)
package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=True) package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=True)
package = db.relationship("Package", foreign_keys=[package_id]) package = db.relationship("Package", foreign_keys=[package_id], back_populates="audit_log_entries")
description = db.Column(db.Text, nullable=True, default=None) description = db.Column(db.Text, nullable=True, default=None)
@ -104,15 +105,15 @@ class AuditLogEntry(db.Model):
self.description = description self.description = description
REPO_BLACKLIST = [".zip", "mediafire.com", "dropbox.com", "weebly.com", REPO_BLACKLIST = [".zip", "mediafire.com", "dropbox.com", "weebly.com",
"minetest.net", "dropboxusercontent.com", "4shared.com", "minetest.net", "dropboxusercontent.com", "4shared.com",
"digitalaudioconcepts.com", "hg.intevation.org", "www.wtfpl.net", "digitalaudioconcepts.com", "hg.intevation.org", "www.wtfpl.net",
"imageshack.com", "imgur.com"] "imageshack.com", "imgur.com"]
class ForumTopic(db.Model): class ForumTopic(db.Model):
topic_id = db.Column(db.Integer, primary_key=True, autoincrement=False) topic_id = db.Column(db.Integer, primary_key=True, autoincrement=False)
author_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) author_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
author = db.relationship("User") author = db.relationship("User")

@ -143,26 +143,31 @@ class PackagePropertyKey(enum.Enum):
else: else:
return str(value) return str(value)
provides = db.Table("provides", provides = db.Table("provides",
db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True), db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True),
db.Column("metapackage_id", db.Integer, db.ForeignKey("meta_package.id"), primary_key=True) db.Column("metapackage_id", db.Integer, db.ForeignKey("meta_package.id"), primary_key=True)
) )
Tags = db.Table("tags", Tags = db.Table("tags",
db.Column("tag_id", db.Integer, db.ForeignKey("tag.id"), primary_key=True), db.Column("tag_id", db.Integer, db.ForeignKey("tag.id"), primary_key=True),
db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True) db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True)
) )
ContentWarnings = db.Table("content_warnings", ContentWarnings = db.Table("content_warnings",
db.Column("content_warning_id", db.Integer, db.ForeignKey("content_warning.id"), primary_key=True), db.Column("content_warning_id", db.Integer, db.ForeignKey("content_warning.id"), primary_key=True),
db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True) db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True)
) )
maintainers = db.Table("maintainers", maintainers = db.Table("maintainers",
db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True), db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True),
db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True) db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True)
) )
class Dependency(db.Model): class Dependency(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -252,14 +257,14 @@ class Package(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
# Basic details # Basic details
author_id = db.Column(db.Integer, db.ForeignKey("user.id")) author_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
author = db.relationship("User", back_populates="packages", foreign_keys=[author_id]) author = db.relationship("User", back_populates="packages", foreign_keys=[author_id])
name = db.Column(db.Unicode(100), nullable=False) name = db.Column(db.Unicode(100), nullable=False)
title = db.Column(db.Unicode(100), nullable=False) title = db.Column(db.Unicode(100), nullable=False)
short_desc = db.Column(db.Unicode(200), nullable=False) short_desc = db.Column(db.Unicode(200), nullable=False)
desc = db.Column(db.UnicodeText, nullable=True) desc = db.Column(db.UnicodeText, nullable=True)
type = db.Column(db.Enum(PackageType)) type = db.Column(db.Enum(PackageType), nullable=False)
created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow) created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
approved_at = db.Column(db.DateTime, nullable=True, default=None) approved_at = db.Column(db.DateTime, nullable=True, default=None)
@ -273,7 +278,7 @@ class Package(db.Model):
media_license_id = db.Column(db.Integer, db.ForeignKey("license.id"), nullable=False, default=1) media_license_id = db.Column(db.Integer, db.ForeignKey("license.id"), nullable=False, default=1)
media_license = db.relationship("License", foreign_keys=[media_license_id]) media_license = db.relationship("License", foreign_keys=[media_license_id])
state = db.Column(db.Enum(PackageState), default=PackageState.WIP) state = db.Column(db.Enum(PackageState), nullable=False, default=PackageState.WIP)
@property @property
def approved(self): def approved(self):
@ -284,7 +289,7 @@ class Package(db.Model):
downloads = db.Column(db.Integer, nullable=False, default=0) downloads = db.Column(db.Integer, nullable=False, default=0)
review_thread_id = db.Column(db.Integer, db.ForeignKey("thread.id"), nullable=True, default=None) review_thread_id = db.Column(db.Integer, db.ForeignKey("thread.id"), nullable=True, default=None)
review_thread = db.relationship("Thread", foreign_keys=[review_thread_id], back_populates="is_review_thread") review_thread = db.relationship("Thread", uselist=False, foreign_keys=[review_thread_id], back_populates="is_review_thread")
# Downloads # Downloads
repo = db.Column(db.String(200), nullable=True) repo = db.Column(db.String(200), nullable=True)
@ -321,6 +326,9 @@ class Package(db.Model):
audit_log_entries = db.relationship("AuditLogEntry", foreign_keys="AuditLogEntry.package_id", back_populates="package", audit_log_entries = db.relationship("AuditLogEntry", foreign_keys="AuditLogEntry.package_id", back_populates="package",
order_by=db.desc("audit_log_entry_created_at"), lazy="dynamic") order_by=db.desc("audit_log_entry_created_at"), lazy="dynamic")
notifications = db.relationship("Notification", foreign_keys="Notification.package_id",
back_populates="package", cascade="all, delete, delete-orphan")
tokens = db.relationship("APIToken", foreign_keys="APIToken.package_id", back_populates="package", tokens = db.relationship("APIToken", foreign_keys="APIToken.package_id", back_populates="package",
lazy="dynamic", cascade="all, delete, delete-orphan") lazy="dynamic", cascade="all, delete, delete-orphan")
@ -625,7 +633,6 @@ class Package(db.Model):
return True return True
def getNextStates(self, user): def getNextStates(self, user):
states = [] states = []
@ -635,7 +642,6 @@ class Package(db.Model):
return states return states
def getScoreDict(self): def getScoreDict(self):
return { return {
"author": self.author.username, "author": self.author.username,
@ -872,7 +878,7 @@ class PackageRelease(db.Model):
class PackageScreenshot(db.Model): class PackageScreenshot(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
package_id = db.Column(db.Integer, db.ForeignKey("package.id")) package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=False)
package = db.relationship("Package", back_populates="screenshots", foreign_keys=[package_id]) package = db.relationship("Package", back_populates="screenshots", foreign_keys=[package_id])
order = db.Column(db.Integer, nullable=False, default=0) order = db.Column(db.Integer, nullable=False, default=0)

@ -22,11 +22,13 @@ from . import db
from .users import Permission, UserRank from .users import Permission, UserRank
from .packages import Package from .packages import Package
watchers = db.Table("watchers", watchers = db.Table("watchers",
db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True), db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True),
db.Column("thread_id", db.Integer, db.ForeignKey("thread.id"), primary_key=True) db.Column("thread_id", db.Integer, db.ForeignKey("thread.id"), primary_key=True)
) )
class Thread(db.Model): class Thread(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -89,6 +91,7 @@ class Thread(db.Model):
else: else:
raise Exception("Permission {} is not related to threads".format(perm.name)) raise Exception("Permission {} is not related to threads".format(perm.name))
class ThreadReply(db.Model): class ThreadReply(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -134,7 +137,7 @@ class PackageReview(db.Model):
recommends = db.Column(db.Boolean, nullable=False) recommends = db.Column(db.Boolean, nullable=False)
thread = db.relationship("Thread", uselist=False, back_populates="review", cascade="all, delete") thread = db.relationship("Thread", uselist=False, back_populates="review")
def asSign(self): def asSign(self):
return 1 if self.recommends else -1 return 1 if self.recommends else -1

@ -114,9 +114,11 @@ class Permission(enum.Enum):
return perm.check(user) return perm.check(user)
def display_name_default(context): def display_name_default(context):
return context.get_current_parameters()["username"] return context.get_current_parameters()["username"]
class User(db.Model, UserMixin): class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
@ -128,7 +130,7 @@ class User(db.Model, UserMixin):
def get_id(self): def get_id(self):
return self.username return self.username
rank = db.Column(db.Enum(UserRank)) rank = db.Column(db.Enum(UserRank), nullable=False)
# Account linking # Account linking
github_username = db.Column(db.String(50, collation="NOCASE"), nullable=True, unique=True) github_username = db.Column(db.String(50, collation="NOCASE"), nullable=True, unique=True)
@ -139,7 +141,7 @@ class User(db.Model, UserMixin):
# User email information # User email information
email = db.Column(db.String(255), nullable=True, unique=True) email = db.Column(db.String(255), nullable=True, unique=True)
email_confirmed_at = db.Column(db.DateTime()) email_confirmed_at = db.Column(db.DateTime(), nullable=True)
# User information # User information
profile_pic = db.Column(db.String(255), nullable=True, server_default=None) profile_pic = db.Column(db.String(255), nullable=True, server_default=None)
@ -265,9 +267,9 @@ class User(db.Model, UserMixin):
class UserEmailVerification(db.Model): class UserEmailVerification(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("user.id")) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
email = db.Column(db.String(100)) email = db.Column(db.String(100), nullable=False)
token = db.Column(db.String(32)) token = db.Column(db.String(32), nullable=True)
user = db.relationship("User", foreign_keys=[user_id]) user = db.relationship("User", foreign_keys=[user_id])
is_password_reset = db.Column(db.Boolean, nullable=False, default=False) is_password_reset = db.Column(db.Boolean, nullable=False, default=False)
@ -373,9 +375,9 @@ class Notification(db.Model):
url = db.Column(db.String(200), nullable=True) url = db.Column(db.String(200), nullable=True)
package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=True) package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=True)
package = db.relationship("Package", foreign_keys=[package_id]) package = db.relationship("Package", foreign_keys=[package_id], back_populates="notifications")
created_at = db.Column(db.DateTime, nullable=True, default=datetime.datetime.utcnow) created_at = db.Column(db.DateTime, nullable=False, default=datetime.datetime.utcnow)
def __init__(self, user, causer, type, title, url, package=None): def __init__(self, user, causer, type, title, url, package=None):
if len(title) > 100: if len(title) > 100:

@ -1,14 +1,14 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block title %} {% block title %}
Delete thread in {{ thread.title }} {{ _('Delete "%(title)s" by %(author)s', title=thread.title, author=thread.author.display_name) }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<form method="POST" action="" class="card box_grey"> <form method="POST" action="" class="card box_grey">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" /> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<h3 class="card-header">Delete {{ thread.title }} by {{ thread.author.display_name }}</h3> <h3 class="card-header">{{ self.title() }}</h3>
<div class="card-body"> <div class="card-body">
{{ thread.replies[0].comment | markdown }} {{ thread.replies[0].comment | markdown }}
</div> </div>

@ -0,0 +1,41 @@
"""empty message
Revision ID: a9c1c08bf956
Revises: 43dc7dbf64c8
Create Date: 2020-12-10 16:42:28.086146
"""
from alembic import op
# revision identifiers, used by Alembic.
revision = 'a9c1c08bf956'
down_revision = '43dc7dbf64c8'
branch_labels = None
def upgrade():
op.alter_column('api_token', 'access_token', nullable=False)
op.alter_column('package', 'author_id', nullable=False)
op.execute("""UPDATE package SET "state"='WIP' WHERE "state" IS NULL""")
op.alter_column('package', 'state', nullable=False)
op.alter_column('package_screenshot', 'package_id', nullable=False)
op.alter_column('user', 'rank', nullable=False)
op.alter_column('user_email_verification', 'user_id', nullable=False)
op.alter_column('user_email_verification', 'email', nullable=False)
op.alter_column('user_email_verification', 'token', nullable=False)
op.execute("UPDATE notification SET created_at=NOW() WHERE created_at IS NULL")
op.alter_column('notification', 'created_at', nullable=False)
def downgrade():
op.alter_column('api_token', 'access_token', nullable=True)
op.alter_column('package', 'author_id', nullable=True)
op.alter_column('package', 'state', nullable=True)
op.alter_column('package_screenshot', 'package_id', nullable=True)
op.alter_column('user', 'rank', nullable=True)
op.alter_column('user_email_verification', 'user_id', nullable=True)
op.alter_column('user_email_verification', 'email', nullable=True)
op.alter_column('user_email_verification', 'token', nullable=True)
op.alter_column('notification', 'created_at', nullable=True)
depends_on = None

@ -2,7 +2,7 @@
# Create a database migration, and copy it back to the host. # Create a database migration, and copy it back to the host.
docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py flask db migrate" docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py flask db revision"
docker exec -u root contentdb_app_1 sh -c "cp /home/cdb/migrations/versions/* /source/migrations/versions/" docker exec -u root contentdb_app_1 sh -c "cp /home/cdb/migrations/versions/* /source/migrations/versions/"
USER=$(whoami) USER=$(whoami)