mirror of
https://github.com/minetest/contentdb.git
synced 2024-12-22 14:02:24 +01:00
Add screenshot resolution checking
This commit is contained in:
parent
625e4cf9ee
commit
d08710684d
@ -27,6 +27,7 @@ from app.models import *
|
|||||||
from app.tasks.forumtasks import importTopicList, checkAllForumAccounts
|
from app.tasks.forumtasks import importTopicList, checkAllForumAccounts
|
||||||
from app.tasks.importtasks import importRepoScreenshot, checkZipRelease, check_for_updates
|
from app.tasks.importtasks import importRepoScreenshot, checkZipRelease, check_for_updates
|
||||||
from app.utils import addNotification, get_system_user
|
from app.utils import addNotification, get_system_user
|
||||||
|
from app.utils.image import get_image_size
|
||||||
|
|
||||||
actions = {}
|
actions = {}
|
||||||
|
|
||||||
@ -54,8 +55,7 @@ def check_releases():
|
|||||||
|
|
||||||
tasks = []
|
tasks = []
|
||||||
for release in releases:
|
for release in releases:
|
||||||
zippath = release.url.replace("/uploads/", app.config["UPLOAD_DIR"])
|
tasks.append(checkZipRelease.s(release.id, release.file_path))
|
||||||
tasks.append(checkZipRelease.s(release.id, zippath))
|
|
||||||
|
|
||||||
result = group(tasks).apply_async()
|
result = group(tasks).apply_async()
|
||||||
|
|
||||||
@ -71,8 +71,7 @@ def reimport_packages():
|
|||||||
for package in Package.query.filter(Package.state!=PackageState.DELETED).all():
|
for package in Package.query.filter(Package.state!=PackageState.DELETED).all():
|
||||||
release = package.releases.first()
|
release = package.releases.first()
|
||||||
if release:
|
if release:
|
||||||
zippath = release.url.replace("/uploads/", app.config["UPLOAD_DIR"])
|
tasks.append(checkZipRelease.s(release.id, release.file_path))
|
||||||
tasks.append(checkZipRelease.s(release.id, zippath))
|
|
||||||
|
|
||||||
result = group(tasks).apply_async()
|
result = group(tasks).apply_async()
|
||||||
|
|
||||||
@ -311,3 +310,16 @@ def remind_video_url():
|
|||||||
url_for('users.profile', username=user.username))
|
url_for('users.profile', username=user.username))
|
||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
|
@action("Update screenshot sizes")
|
||||||
|
def remind_video_url():
|
||||||
|
import sys
|
||||||
|
|
||||||
|
for screenshot in PackageScreenshot.query.all():
|
||||||
|
width, height = get_image_size(screenshot.file_path)
|
||||||
|
print(f"{screenshot.url}: {width}, {height}", file=sys.stderr)
|
||||||
|
screenshot.width = width
|
||||||
|
screenshot.height = height
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
from celery import uuid
|
from celery import uuid
|
||||||
from flask import *
|
from flask import *
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from sqlalchemy import or_
|
from sqlalchemy import or_, and_
|
||||||
|
|
||||||
from app.models import *
|
from app.models import *
|
||||||
from app.querybuilder import QueryBuilder
|
from app.querybuilder import QueryBuilder
|
||||||
@ -168,6 +168,11 @@ def view_user(username=None):
|
|||||||
Package.state == PackageState.CHANGES_NEEDED)) \
|
Package.state == PackageState.CHANGES_NEEDED)) \
|
||||||
.order_by(db.asc(Package.created_at)).all()
|
.order_by(db.asc(Package.created_at)).all()
|
||||||
|
|
||||||
|
packages_with_small_screenshots = user.maintained_packages \
|
||||||
|
.filter(Package.screenshots.any(and_(PackageScreenshot.width < PackageScreenshot.SOFT_MIN_SIZE[0],
|
||||||
|
PackageScreenshot.height < PackageScreenshot.SOFT_MIN_SIZE[1]))) \
|
||||||
|
.all()
|
||||||
|
|
||||||
outdated_packages = user.maintained_packages \
|
outdated_packages = user.maintained_packages \
|
||||||
.filter(Package.state != PackageState.DELETED,
|
.filter(Package.state != PackageState.DELETED,
|
||||||
Package.update_config.has(PackageUpdateConfig.outdated_at.isnot(None))) \
|
Package.update_config.has(PackageUpdateConfig.outdated_at.isnot(None))) \
|
||||||
@ -185,7 +190,9 @@ def view_user(username=None):
|
|||||||
|
|
||||||
return render_template("todo/user.html", current_tab="user", user=user,
|
return render_template("todo/user.html", current_tab="user", user=user,
|
||||||
unapproved_packages=unapproved_packages, outdated_packages=outdated_packages,
|
unapproved_packages=unapproved_packages, outdated_packages=outdated_packages,
|
||||||
needs_tags=needs_tags, topics_to_add=topics_to_add)
|
needs_tags=needs_tags, topics_to_add=topics_to_add,
|
||||||
|
packages_with_small_screenshots=packages_with_small_screenshots,
|
||||||
|
screenshot_min_size=PackageScreenshot.HARD_MIN_SIZE, screenshot_rec_size=PackageScreenshot.SOFT_MIN_SIZE)
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/users/<username>/update-configs/apply-all/", methods=["POST"])
|
@bp.route("/users/<username>/update-configs/apply-all/", methods=["POST"])
|
||||||
|
@ -67,7 +67,7 @@ is available.
|
|||||||
### Meta and packaging
|
### Meta and packaging
|
||||||
|
|
||||||
* MUST: `screenshot.png` is present and up-to-date, with a correct aspect ratio (3:2, at least 300x200).
|
* MUST: `screenshot.png` is present and up-to-date, with a correct aspect ratio (3:2, at least 300x200).
|
||||||
* MUST: Have a high resolution cover image on ContentDB (at least 1280x768 pixels).
|
* MUST: Have a high resolution cover image on ContentDB (at least 1280x720 pixels).
|
||||||
It may be shown cropped to 16:9 aspect ratio, or shorter.
|
It may be shown cropped to 16:9 aspect ratio, or shorter.
|
||||||
* MUST: mod.conf/game.conf/texture_pack.conf present with:
|
* MUST: mod.conf/game.conf/texture_pack.conf present with:
|
||||||
* name (if mod or game)
|
* name (if mod or game)
|
||||||
|
@ -6,6 +6,7 @@ from app.logic.LogicError import LogicError
|
|||||||
from app.logic.uploads import upload_file
|
from app.logic.uploads import upload_file
|
||||||
from app.models import User, Package, PackageScreenshot, Permission, NotificationType, db, AuditSeverity
|
from app.models import User, Package, PackageScreenshot, Permission, NotificationType, db, AuditSeverity
|
||||||
from app.utils import addNotification, addAuditLog
|
from app.utils import addNotification, addAuditLog
|
||||||
|
from app.utils.image import get_image_size
|
||||||
|
|
||||||
|
|
||||||
def do_create_screenshot(user: User, package: Package, title: str, file, reason: str = None):
|
def do_create_screenshot(user: User, package: Package, title: str, file, reason: str = None):
|
||||||
@ -27,6 +28,13 @@ def do_create_screenshot(user: User, package: Package, title: str, file, reason:
|
|||||||
ss.url = uploaded_url
|
ss.url = uploaded_url
|
||||||
ss.approved = package.checkPerm(user, Permission.APPROVE_SCREENSHOT)
|
ss.approved = package.checkPerm(user, Permission.APPROVE_SCREENSHOT)
|
||||||
ss.order = counter
|
ss.order = counter
|
||||||
|
ss.width, ss.height = get_image_size(uploaded_path)
|
||||||
|
|
||||||
|
if ss.is_too_small():
|
||||||
|
raise LogicError(429,
|
||||||
|
lazy_gettext("Screenshot is too small, it should be at least %(width)s by %(height)s pixels",
|
||||||
|
width=PackageScreenshot.HARD_MIN_SIZE[0], height=PackageScreenshot.HARD_MIN_SIZE[1]))
|
||||||
|
|
||||||
db.session.add(ss)
|
db.session.add(ss)
|
||||||
|
|
||||||
if reason is None:
|
if reason is None:
|
||||||
|
@ -26,6 +26,7 @@ from sqlalchemy_utils.types import TSVectorType
|
|||||||
|
|
||||||
from . import db
|
from . import db
|
||||||
from .users import Permission, UserRank, User
|
from .users import Permission, UserRank, User
|
||||||
|
from .. import app
|
||||||
|
|
||||||
|
|
||||||
class PackageQuery(BaseQuery, SearchQueryMixin):
|
class PackageQuery(BaseQuery, SearchQueryMixin):
|
||||||
@ -885,6 +886,10 @@ class PackageRelease(db.Model):
|
|||||||
# If the release is approved, then the task_id must be null and the url must be present
|
# If the release is approved, then the task_id must be null and the url must be present
|
||||||
CK_approval_valid = db.CheckConstraint("not approved OR (task_id IS NULL AND (url = '') IS NOT FALSE)")
|
CK_approval_valid = db.CheckConstraint("not approved OR (task_id IS NULL AND (url = '') IS NOT FALSE)")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_path(self):
|
||||||
|
return self.url.replace("/uploads/", app.config["UPLOAD_DIR"])
|
||||||
|
|
||||||
def getAsDictionary(self):
|
def getAsDictionary(self):
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
@ -986,6 +991,9 @@ class PackageRelease(db.Model):
|
|||||||
|
|
||||||
|
|
||||||
class PackageScreenshot(db.Model):
|
class PackageScreenshot(db.Model):
|
||||||
|
HARD_MIN_SIZE = (920, 517)
|
||||||
|
SOFT_MIN_SIZE = (1280, 720)
|
||||||
|
|
||||||
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"), nullable=False)
|
package_id = db.Column(db.Integer, db.ForeignKey("package.id"), nullable=False)
|
||||||
@ -997,6 +1005,22 @@ class PackageScreenshot(db.Model):
|
|||||||
approved = db.Column(db.Boolean, nullable=False, default=False)
|
approved = db.Column(db.Boolean, nullable=False, default=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)
|
||||||
|
|
||||||
|
width = db.Column(db.Integer, nullable=False)
|
||||||
|
height = db.Column(db.Integer, nullable=False)
|
||||||
|
|
||||||
|
def is_very_small(self):
|
||||||
|
return self.width < 720 or self.height < 405
|
||||||
|
|
||||||
|
def is_too_small(self):
|
||||||
|
return self.width < PackageScreenshot.HARD_MIN_SIZE[0] or self.height < PackageScreenshot.HARD_MIN_SIZE[1]
|
||||||
|
|
||||||
|
def is_low_res(self):
|
||||||
|
return self.width < PackageScreenshot.SOFT_MIN_SIZE[0] or self.height < PackageScreenshot.SOFT_MIN_SIZE[1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file_path(self):
|
||||||
|
return self.url.replace("/uploads/", app.config["UPLOAD_DIR"])
|
||||||
|
|
||||||
def getEditURL(self):
|
def getEditURL(self):
|
||||||
return url_for("packages.edit_screenshot",
|
return url_for("packages.edit_screenshot",
|
||||||
author=self.package.author.username,
|
author=self.package.author.username,
|
||||||
|
@ -27,6 +27,7 @@ from app.utils.git import clone_repo, get_latest_tag, get_latest_commit, get_tem
|
|||||||
from .minetestcheck import build_tree, MinetestCheckError, ContentType
|
from .minetestcheck import build_tree, MinetestCheckError, ContentType
|
||||||
from ..logic.LogicError import LogicError
|
from ..logic.LogicError import LogicError
|
||||||
from ..logic.packages import do_edit_package, ALIASES
|
from ..logic.packages import do_edit_package, ALIASES
|
||||||
|
from ..utils.image import get_image_size
|
||||||
|
|
||||||
|
|
||||||
@celery.task()
|
@celery.task()
|
||||||
@ -213,6 +214,10 @@ def importRepoScreenshot(id):
|
|||||||
ss.package = package
|
ss.package = package
|
||||||
ss.title = "screenshot.png"
|
ss.title = "screenshot.png"
|
||||||
ss.url = "/uploads/" + filename
|
ss.url = "/uploads/" + filename
|
||||||
|
ss.width, ss.height = get_image_size(destPath)
|
||||||
|
if ss.is_too_small():
|
||||||
|
return None
|
||||||
|
|
||||||
db.session.add(ss)
|
db.session.add(ss)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{{ _("Add a screenshot") }}</h1>
|
<h1>{{ _("Add a screenshot") }}</h1>
|
||||||
|
<p class="mb-4">
|
||||||
|
{{ _("The recommended resolution is 1920x1080, and screenshots must be at least %(width)dx%(height)d.",
|
||||||
|
width=920, height=517) }}
|
||||||
|
</p>
|
||||||
|
|
||||||
{% from "macros/forms.html" import render_field, render_submit_field %}
|
{% from "macros/forms.html" import render_field, render_submit_field %}
|
||||||
<form method="POST" action="" enctype="multipart/form-data">
|
<form method="POST" action="" enctype="multipart/form-data">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if package.checkPerm(current_user, "ADD_SCREENSHOTS") %}
|
{% if package.checkPerm(current_user, "ADD_SCREENSHOTS") %}
|
||||||
<a href="{{ package.getURL("packages.create_screenshot") }}" class="btn btn-primary float-right">
|
<a href="{{ package.getURL('packages.create_screenshot') }}" class="btn btn-primary float-right">
|
||||||
<i class="fas fa-plus mr-1"></i>
|
<i class="fas fa-plus mr-1"></i>
|
||||||
{{ _("Add Image") }}
|
{{ _("Add Image") }}
|
||||||
</a>
|
</a>
|
||||||
@ -26,16 +26,34 @@
|
|||||||
<i class="fas fa-bars"></i>
|
<i class="fas fa-bars"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<img class="img-fluid" style="max-height: 64px;"
|
<img class="img-fluid" style="max-height: 64px;" src="{{ ss.getThumbnailURL() }}" />
|
||||||
src="{{ ss.getThumbnailURL() }}" alt="{{ ss.title }}" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
{{ ss.title }}
|
{{ ss.title }}
|
||||||
{% if not ss.approved %}
|
|
||||||
<div class="text-muted">
|
<div class="mt-1 text-muted">
|
||||||
{{ _("Awaiting approval") }}
|
{{ ss.width }} x {{ ss.height }}
|
||||||
</div>
|
{% if ss.is_low_res() %}
|
||||||
{% endif %}
|
{% if ss.is_very_small() %}
|
||||||
|
<span class="badge badge-danger ml-3">
|
||||||
|
{{ _("Way too small") }}
|
||||||
|
</span>
|
||||||
|
{% elif ss.is_too_small() %}
|
||||||
|
<span class="badge badge-warning ml-3">
|
||||||
|
{{ _("Too small") }}
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge badge-secondary ml-3">
|
||||||
|
{{ _("Not HD") }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if not ss.approved %}
|
||||||
|
<span class="ml-3">
|
||||||
|
{{ _("Awaiting approval") }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form action="{{ ss.getDeleteURL() }}" method="POST" class="col-auto text-right" role="form">
|
<form action="{{ ss.getDeleteURL() }}" method="POST" class="col-auto text-right" role="form">
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2>{{ _("Unapproved Packages Needing Action") }}</h2>
|
<h2>{{ _("Unapproved Packages Needing Action") }}</h2>
|
||||||
<div class="list-group mt-3 mb-5">
|
<div class="list-group mt-3 mb-5">
|
||||||
{% for package in unapproved_packages %}
|
{% for package in unapproved_packages %}
|
||||||
@ -53,21 +54,75 @@
|
|||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h2>{{ _("Potentially Outdated Packages") }}</h2>
|
<h2>{{ _("Potentially Outdated Packages") }}</h2>
|
||||||
<p class="alert alert-info">
|
|
||||||
{{ _("New: Git Update Detection has been set up on all packages to send notifications.") }}<br />
|
|
||||||
{{ _("Consider changing the update settings to create releases automatically instead.") }}
|
|
||||||
</p>
|
|
||||||
<p>
|
<p>
|
||||||
{{ _("Instead of marking packages as outdated, you can automatically create releases when New Commits or New Tags are pushed to Git by clicking 'Update Settings'.") }}
|
{{ _("Instead of marking packages as outdated, you can automatically create releases when New Commits or New Tags are pushed to Git by clicking 'Update Settings'.") }}
|
||||||
{% if outdated_packages %}
|
{% if outdated_packages %}
|
||||||
{{ _("To remove a package from below, create a release or change the update settings.") }}
|
{{ _("To remove a package from below, create a release or change the update settings.") }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% from "macros/todo.html" import render_outdated_packages %}
|
{% from "macros/todo.html" import render_outdated_packages %}
|
||||||
{{ render_outdated_packages(outdated_packages, current_user) }}
|
{{ render_outdated_packages(outdated_packages, current_user) }}
|
||||||
|
|
||||||
|
|
||||||
<div class="mt-5"></div>
|
<div class="mt-5"></div>
|
||||||
|
<h2 id="small-screenshots">{{ _("Small Screenshots") }}</h2>
|
||||||
|
{% if packages_with_small_screenshots %}
|
||||||
|
<p>
|
||||||
|
{{ _("These packages have screenshots that are too small, and should be replaced.") }}
|
||||||
|
{{ _("Red and orange are screenshots below the limit, and grey screenshots are below the recommended resolution.") }}
|
||||||
|
{{ _("The recommended resolution is 1920x1080, and screenshots must be at least %(width)dx%(height)d.",
|
||||||
|
width=920, height=517) }}
|
||||||
|
|
||||||
|
<span class="badge badge-danger ml-3">
|
||||||
|
{{ _("Way too small") }}
|
||||||
|
</span>
|
||||||
|
<span class="badge badge-warning">
|
||||||
|
{{ _("Too small") }}
|
||||||
|
</span>
|
||||||
|
<span class="badge badge-secondary">
|
||||||
|
{{ _("Not HD") }}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<div class="list-group mt-3 mb-5">
|
||||||
|
{% for package in packages_with_small_screenshots %}
|
||||||
|
<a class="list-group-item list-group-item-action" href="{{ package.getURL('packages.screenshots') }}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3 text-muted" style="min-width: 200px;">
|
||||||
|
<img
|
||||||
|
class="img-fluid"
|
||||||
|
style="max-height: 22px; max-width: 22px;"
|
||||||
|
src="{{ package.getThumbnailOrPlaceholder() }}" />
|
||||||
|
|
||||||
|
<span class="pl-2">
|
||||||
|
{{ package.title }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm">
|
||||||
|
{% for ss in package.screenshots %}
|
||||||
|
{% if ss.is_low_res() %}
|
||||||
|
{% if ss.is_very_small() %}
|
||||||
|
{% set badge_color = "badge-danger" %}
|
||||||
|
{% elif ss.is_too_small() %}
|
||||||
|
{% set badge_color = "badge-warning" %}
|
||||||
|
{% else %}
|
||||||
|
{% set badge_color = "badge-secondary" %}
|
||||||
|
{% endif %}
|
||||||
|
<span class="badge {{ badge_color }} ml-2" title="{{ ss.title }}">
|
||||||
|
{{ ss.width }} x {{ ss.height }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-muted">{{ _("Nothing to do :)") }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<a class="btn btn-secondary float-right" href="{{ url_for('todo.tags', author=user.username) }}">
|
<a class="btn btn-secondary float-right" href="{{ url_for('todo.tags', author=user.username) }}">
|
||||||
{{_ ("See All") }}</a>
|
{{_ ("See All") }}</a>
|
||||||
<h2>{{ _("Packages Without Tags") }}</h2>
|
<h2>{{ _("Packages Without Tags") }}</h2>
|
||||||
|
24
app/utils/image.py
Normal file
24
app/utils/image.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# ContentDB
|
||||||
|
# Copyright (C) 2022 rubenwardy
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
from typing import Tuple
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
def get_image_size(path: str) -> Tuple[int,int]:
|
||||||
|
im = Image.open(path)
|
||||||
|
return im.size
|
26
migrations/versions/f6ef5f35abca_.py
Normal file
26
migrations/versions/f6ef5f35abca_.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: f6ef5f35abca
|
||||||
|
Revises: 011e42c52d21
|
||||||
|
Create Date: 2022-01-26 00:10:46.610784
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'f6ef5f35abca'
|
||||||
|
down_revision = '011e42c52d21'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('package_screenshot', sa.Column('height', sa.Integer(), nullable=False, server_default="0"))
|
||||||
|
op.add_column('package_screenshot', sa.Column('width', sa.Integer(), nullable=False, server_default="0"))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('package_screenshot', 'width')
|
||||||
|
op.drop_column('package_screenshot', 'height')
|
Loading…
Reference in New Issue
Block a user