From 8d8577a941b86ae4ce3327125ed9013bbf77fefd Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Thu, 10 Dec 2020 16:49:37 +0000 Subject: [PATCH] Clean up database constraints --- app/models/__init__.py | 15 +++++---- app/models/packages.py | 20 ++++++++---- app/models/threads.py | 5 ++- app/models/users.py | 16 +++++---- app/templates/threads/delete_thread.html | 4 +-- migrations/versions/a9c1c08bf956_.py | 41 ++++++++++++++++++++++++ utils/create_migration.sh | 2 +- 7 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 migrations/versions/a9c1c08bf956_.py diff --git a/app/models/__init__.py b/app/models/__init__.py index d9e3f60..6ca0ac2 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -35,16 +35,17 @@ from .threads import * class APIToken(db.Model): 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) + 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) 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): 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) 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) @@ -88,7 +89,7 @@ class AuditLogEntry(db.Model): url = db.Column(db.String(200), 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) @@ -104,15 +105,15 @@ class AuditLogEntry(db.Model): self.description = description - - REPO_BLACKLIST = [".zip", "mediafire.com", "dropbox.com", "weebly.com", "minetest.net", "dropboxusercontent.com", "4shared.com", "digitalaudioconcepts.com", "hg.intevation.org", "www.wtfpl.net", "imageshack.com", "imgur.com"] + class ForumTopic(db.Model): topic_id = db.Column(db.Integer, primary_key=True, autoincrement=False) + author_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) author = db.relationship("User") diff --git a/app/models/packages.py b/app/models/packages.py index 838f229..894951a 100644 --- a/app/models/packages.py +++ b/app/models/packages.py @@ -143,26 +143,31 @@ class PackagePropertyKey(enum.Enum): else: return str(value) + provides = db.Table("provides", 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) ) + Tags = db.Table("tags", 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) ) + ContentWarnings = db.Table("content_warnings", 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) ) + maintainers = db.Table("maintainers", 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) ) + class Dependency(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -252,14 +257,14 @@ class Package(db.Model): id = db.Column(db.Integer, primary_key=True) # 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]) name = db.Column(db.Unicode(100), nullable=False) title = db.Column(db.Unicode(100), nullable=False) short_desc = db.Column(db.Unicode(200), nullable=False) 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) 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 = 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 def approved(self): @@ -284,7 +289,7 @@ class Package(db.Model): 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 = 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 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", 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", lazy="dynamic", cascade="all, delete, delete-orphan") @@ -625,7 +633,6 @@ class Package(db.Model): return True - def getNextStates(self, user): states = [] @@ -635,7 +642,6 @@ class Package(db.Model): return states - def getScoreDict(self): return { "author": self.author.username, @@ -872,7 +878,7 @@ class PackageRelease(db.Model): class PackageScreenshot(db.Model): 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]) order = db.Column(db.Integer, nullable=False, default=0) diff --git a/app/models/threads.py b/app/models/threads.py index 502f541..88608b2 100644 --- a/app/models/threads.py +++ b/app/models/threads.py @@ -22,11 +22,13 @@ from . import db from .users import Permission, UserRank from .packages import Package + watchers = db.Table("watchers", 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) ) + class Thread(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -89,6 +91,7 @@ class Thread(db.Model): else: raise Exception("Permission {} is not related to threads".format(perm.name)) + class ThreadReply(db.Model): id = db.Column(db.Integer, primary_key=True) @@ -134,7 +137,7 @@ class PackageReview(db.Model): 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): return 1 if self.recommends else -1 diff --git a/app/models/users.py b/app/models/users.py index 96cd976..e53d918 100644 --- a/app/models/users.py +++ b/app/models/users.py @@ -114,9 +114,11 @@ class Permission(enum.Enum): return perm.check(user) + def display_name_default(context): return context.get_current_parameters()["username"] + class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) @@ -128,7 +130,7 @@ class User(db.Model, UserMixin): def get_id(self): return self.username - rank = db.Column(db.Enum(UserRank)) + rank = db.Column(db.Enum(UserRank), nullable=False) # Account linking 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 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 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): id = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.Integer, db.ForeignKey("user.id")) - email = db.Column(db.String(100)) - token = db.Column(db.String(32)) + user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) + email = db.Column(db.String(100), nullable=False) + token = db.Column(db.String(32), nullable=True) user = db.relationship("User", foreign_keys=[user_id]) 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) 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): if len(title) > 100: diff --git a/app/templates/threads/delete_thread.html b/app/templates/threads/delete_thread.html index 7da540a..cc2068f 100644 --- a/app/templates/threads/delete_thread.html +++ b/app/templates/threads/delete_thread.html @@ -1,14 +1,14 @@ {% extends "base.html" %} {% block title %} - Delete thread in {{ thread.title }} + {{ _('Delete "%(title)s" by %(author)s', title=thread.title, author=thread.author.display_name) }} {% endblock %} {% block content %}
-

Delete {{ thread.title }} by {{ thread.author.display_name }}

+

{{ self.title() }}

{{ thread.replies[0].comment | markdown }}
diff --git a/migrations/versions/a9c1c08bf956_.py b/migrations/versions/a9c1c08bf956_.py new file mode 100644 index 0000000..cbe052d --- /dev/null +++ b/migrations/versions/a9c1c08bf956_.py @@ -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 diff --git a/utils/create_migration.sh b/utils/create_migration.sh index 4c73937..59aaea0 100755 --- a/utils/create_migration.sh +++ b/utils/create_migration.sh @@ -2,7 +2,7 @@ # 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/" USER=$(whoami)