From 4a353ec17ed4a3fa96b6be2aee488e876a3bdff9 Mon Sep 17 00:00:00 2001 From: Midgard Date: Wed, 25 May 2022 13:54:42 +0200 Subject: [PATCH] Create a slug for old orders in the migration --- .../versions/29ccbe077c57_add_slug.py | 28 +++++++++++++++++-- app/models/order.py | 10 ++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/app/migrations/versions/29ccbe077c57_add_slug.py b/app/migrations/versions/29ccbe077c57_add_slug.py index 6e527e9..4827845 100644 --- a/app/migrations/versions/29ccbe077c57_add_slug.py +++ b/app/migrations/versions/29ccbe077c57_add_slug.py @@ -12,12 +12,34 @@ down_revision = '55013fe95bea' from alembic import op import sqlalchemy as sa +from sqlalchemy.sql import text def upgrade(): - op.add_column('order', sa.Column('slug', sa.String(length=7), nullable=True)) - op.create_unique_constraint(None, 'order', ['slug']) + op.add_column('order', sa.Column( + 'slug', + sa.String(length=7), + nullable=False, + # Default: random alphanumerical string + server_default=text('SUBSTRING(MD5(RAND()) FROM 1 FOR 7)') + )) + op.create_unique_constraint('order_slug_unique', 'order', ['slug']) + + # Trigger to handle duplicates: generate new slug if slug already exists + op.execute(text( + """ + CREATE TRIGGER order_before_insert + BEFORE UPDATE ON `order` + FOR EACH ROW + BEGIN + WHILE (NEW.slug IS NULL OR (SELECT id FROM `order` WHERE slug = NEW.slug) IS NOT NULL) DO + SET NEW.slug = SUBSTRING(MD5(RAND()) FROM 1 FOR 7); + END WHILE; + END + """ + )) def downgrade(): - op.drop_constraint(None, 'order', type_='unique') + op.execute(text("DROP TRIGGER order_before_insert")) + op.drop_constraint('order_slug_unique', 'order', type_='unique') op.drop_column('order', 'slug') diff --git a/app/models/order.py b/app/models/order.py index c7b458e..6e1ff0b 100644 --- a/app/models/order.py +++ b/app/models/order.py @@ -2,7 +2,6 @@ import typing from collections import defaultdict from datetime import datetime -import secrets import string from hlds.definitions import location_definitions @@ -12,11 +11,6 @@ from .database import db from .user import User -def generate_slug(): - alphabet = string.ascii_letters + string.digits - return ''.join(secrets.choice(alphabet) for i in range(7)) - - class Order(db.Model): """Class used for configuring the Order model in the database""" id = db.Column(db.Integer, primary_key=True) @@ -26,7 +20,9 @@ class Order(db.Model): starttime = db.Column(db.DateTime) stoptime = db.Column(db.DateTime) public = db.Column(db.Boolean, default=True) - slug = db.Column(db.String(7), default=generate_slug, unique=True) + # The default value for `slug`, a random 7-character alphanumerical string, + # is created on the database side. See migrations/versions/29ccbe077c57_add_slug.py + slug = db.Column(db.String(7), unique=True) association = db.Column(db.String(120), nullable=False, server_default="") items = db.relationship("OrderItem", backref="order", lazy="dynamic")