diff --git a/README.md b/README.md index fe81cff..c2716c6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ list app install 1. clone repo 2. create subfolder "instance" to store database file -3. for an initial instance: run python3 initialze_data.py, with the python from the virtual-env +3. for an initial instance, run `.venv/bin/python initialize_data.py` 4. add the below config to your apache2 enabled site ## Secrets and configuration diff --git a/initialize_data.py b/initialize_data.py index ec60469..f1ceb7b 100644 --- a/initialize_data.py +++ b/initialize_data.py @@ -1,47 +1,103 @@ -from lapp import create_app import sqlalchemy as sa -from models import db, User, ListOfItems, Shared, Item, Group + +from lapp import create_app +from models import Group, Item, ListOfItems, Shared, User, db from secrets_config import load_secrets -if __name__ == "__main__": + +def has_rows(model): + primary_key = next(iter(model.__table__.primary_key.columns)) + return db.session.scalar(sa.select(primary_key).limit(1)) is not None + + +def initialize(app): + initial_data = load_secrets(app.instance_path)["initial_data"] + + with app.app_context(): + with db.session.begin(): + if has_rows(User): + return False + + partially_populated = [ + model.__tablename__ + for model in (Group, ListOfItems, Item, Shared) + if has_rows(model) + ] + if partially_populated: + tables = ", ".join(partially_populated) + raise RuntimeError( + "Refusing to initialize a partially populated database. " + f"These tables contain data while user is empty: {tables}" + ) + + admin_group = Group(secret=initial_data["admin_group"]) + user_group = Group(secret=initial_data["user_group"]) + db.session.add_all([admin_group, user_group]) + db.session.flush() + + admin = User( + name="admin", + group_id=admin_group.id, + is_admin=True, + is_approved=True, + is_private=True, + ) + admin.set_password(initial_data["admin_password"]) + + user = User( + name="ignace", + group_id=user_group.id, + is_admin=False, + is_approved=True, + ) + user.set_password(initial_data["user_password"]) + db.session.add_all([admin, user]) + db.session.flush() + + groceries = ListOfItems( + owner_user_id=user.id, + name="Supermarkt", + is_active=True, + ) + chores = ListOfItems( + owner_user_id=user.id, + name="Klusjes", + is_active=True, + ) + db.session.add_all([groceries, chores]) + db.session.flush() + + db.session.add_all([ + Item(listofitems_id=groceries.id, label="Stokbrood"), + Item( + listofitems_id=groceries.id, + label="Speltbroodje", + category="Brood", + ), + Item( + listofitems_id=groceries.id, + label="Boter", + category="Zuivel", + unit="x", + quantity=1, + ), + Item( + listofitems_id=groceries.id, + label="Notenbroodjes", + is_checked=True, + ), + ]) + + return True + + +def main(): app = create_app() - app.app_context().push() - query = sa.select(User) - users = db.session.scalars(query).all() - if len(users) == 0: - initial_data = load_secrets(app.instance_path)["initial_data"] - admin_group_secret = initial_data["admin_group"] - user_group_secret = initial_data["user_group"] - admin_password = initial_data["admin_password"] - user_password = initial_data["user_password"] - - g = Group(secret=admin_group_secret) - db.session.add(g) - g = Group(secret=user_group_secret) - db.session.add(g) - admin = User(name="admin", group_id=1, is_admin=True, is_approved=True, is_private=True) - admin.set_password(admin_password) - db.session.add(admin) - user1 = User(name="ignace", group_id=2, is_admin=False, is_approved=True) - user1.set_password(user_password) - db.session.add(user1) - db.session.commit() - + if initialize(app): print("Created initial credentials from instance/secrets.yaml") + else: + print("Database already contains users; no initial data was added") - lol1 = ListOfItems(owner_user_id = user1.id, name="Supermarkt", is_active=True) - db.session.add(lol1) - lol2 = ListOfItems(owner_user_id = user1.id, name="Klusjes", is_active=True) - db.session.add(lol2) - db.session.commit() - - item1 = Item(listofitems_id=lol1.id, label="Stokbrood") - item2 = Item(listofitems_id=lol1.id, label="Speltbroodje", category="Brood") - item3 = Item(listofitems_id=lol1.id, label="Boter", category="Zuivel", unit='x', quantity=1) - item4 = Item(listofitems_id=lol1.id, label="Notenbroodjes", is_checked=True) - db.session.add(item1) - db.session.add(item2) - db.session.add(item3) - db.session.add(item4) - db.session.commit() +if __name__ == "__main__": + main() diff --git a/models.py b/models.py index 94f69df..33df469 100644 --- a/models.py +++ b/models.py @@ -8,7 +8,7 @@ db = SQLAlchemy() # Create the extension object class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) - updated_at = db.Column(db.TIMESTAMP, default=datetime.now(), onupdate=datetime.now(), nullable=False) + updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) group_id = db.Column(db.Integer, default=0, nullable=False) name = db.Column(db.String(40), unique=True, nullable=False) password_hash = db.Column(db.String(256)) @@ -78,7 +78,7 @@ class ListOfItems(db.Model): ) id = db.Column(db.Integer, primary_key=True) - updated_at = db.Column(db.TIMESTAMP, default=datetime.now(), onupdate=datetime.now(), nullable=False) + updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) owner_user_id = db.Column(db.Integer, nullable=False) name = db.Column(db.String(40), nullable=False) is_active = db.Column(db.Boolean, default=False) @@ -109,7 +109,7 @@ class ListOfItems(db.Model): class Item(db.Model): id = db.Column(db.Integer, primary_key=True) - updated_at = db.Column(db.TIMESTAMP, default=datetime.now(), onupdate=datetime.now(), nullable=False) + updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) listofitems_id = db.Column(db.Integer, nullable=False) label = db.Column(db.String(40), nullable=False) quantity = db.Column(db.Integer, default=0) @@ -132,5 +132,5 @@ class Shared(db.Model): class Group(db.Model): id = db.Column(db.Integer, primary_key=True) - updated_at = db.Column(db.TIMESTAMP, default=datetime.now(), onupdate=datetime.now(), nullable=False) + updated_at = db.Column(db.TIMESTAMP, default=datetime.now, onupdate=datetime.now, nullable=False) secret = db.Column(db.String(128))