diff --git a/.replit b/.replit index 50ad76d0..30438301 100644 --- a/.replit +++ b/.replit @@ -1,11 +1,16 @@ -entrypoint = "wsgi.py" -modules = ["python-3.10:v18-20230807-322e88b"] + +modules = ["python-3.10", "nix"] hidden = [".pythonlibs"] +run = "flask run --host=0.0.0.0 --port=8080 --reload" [nix] -channel = "stable-23_05" +channel = "stable-24_05" [deployment] -run = ["python3", "wsgi.py"] -deploymentTarget = "cloudrun" \ No newline at end of file +run = ["sh", "-c", "flask run --host=0.0.0.0 --port=8080 --reload"] +deploymentTarget = "cloudrun" + +[[ports]] +localPort = 8080 +externalPort = 80 diff --git a/app.py b/app.py index b49413db..7027b37b 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,10 @@ -from flask import Flask +from flask import Flask, render_template app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///project.db" app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.app_context().push() + +@app.route('/') +def home(): + return "Hello World!" diff --git a/instance/project.db b/instance/project.db index 880c27eb..e69d1b8f 100644 Binary files a/instance/project.db and b/instance/project.db differ diff --git a/models.py b/models.py index 8318b132..c83e8fad 100644 --- a/models.py +++ b/models.py @@ -13,6 +13,8 @@ class User(db.Model): email = db.Column(db.String(120), unique=True, nullable=False) password = db.Column(db.String(120), nullable=False) + todos = db.relationship('Todo', backref='user', lazy=True, cascade="all, delete-orphan") + def __init__(self, username, email, password): self.username = username self.email = email @@ -24,3 +26,69 @@ def set_password(self, password): def __repr__(self): return f'' + +# Add method to User model in models.py +def add_todo_category(self, todo_id, category_text): + # Fetch the todo by id + todo = Todo.query.filter_by(id=todo_id, user_id=self.id).first() + # Make sure the todo exists and belongs to the current user + if not todo: + return False + + # Check if category already exists for current user + category = Category.query.filter_by(text=category_text, user_id=self.id).first() + if not category: + # Create new category + category = Category(user_id=self.id, text=category_text) + db.session.add(category) + db.session.commit() + + # Associate todo with the category if not already associated + if category not in todo.categories: + todo.categories.append(category) + db.session.add(todo) + db.session.commit() + + return True + +class Todo(db.Model): + id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) #set userid as a foreign key to user.id + text = db.Column(db.String(255), nullable=False) + done = db.Column(db.Boolean, default=False) + + def toggle(self): + self.done = not self.done + db.session.add(self) + db.session.commit() + + def __init__(self, text): + self.text = text + + def __repr__(self): + + return f'' + +class TodoCategory(db.Model): + __tablename__ ='todo_category' + id = db.Column(db.Integer, primary_key=True) + todo_id = db.Column(db.Integer, db.ForeignKey('todo.id'), nullable=False) + category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False) + last_modified = db.Column(db.DateTime, default=func.now(), onupdate=func.now()) + + def __repr__(self): + return f'' + +class Category(db.Model): + id = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) + text = db.Column(db.String(255), nullable=False) + user = db.relationship('User', backref=db.backref('categories', lazy='joined')) + todos = db.relationship('Todo', secondary='todo_category', backref=db.backref('categories', lazy=True)) + + def __init__(self, user_id, text): + self.user_id = user_id + self.text = text + + def __repr__(self): + return f'' \ No newline at end of file diff --git a/wsgi.py b/wsgi.py index d7ebfcbc..96c89f37 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,5 +1,5 @@ import click, sys -from models import db, User +from models import db, User,Todo from app import app from sqlalchemy.exc import IntegrityError @@ -10,5 +10,122 @@ def initialize(): db.init_app(app) db.create_all() bob = User('bob', 'bob@mail.com', 'bobpass') + bob.todos.append(Todo('wash car')) print(bob) - print('database intialized') \ No newline at end of file + print('database intialized') + db.session.add(bob) + db.session.commit() + print(bob) + +@app.cli.command("get-user", help="Retrieves a User") +@click.argument('username', default='bob') +def get_user(username): + bob = User.query.filter_by(username=username).first() #.first just prints the first row + if not bob: + print(f'{username} not found!') + return + print(bob) + +@app.cli.command('get-users') +def get_users(): + # gets all objects of a model + users = User.query.all() + print(users) + +@app.cli.command("change-email") +@click.argument('username', default='bob') +@click.argument('email', default='bob@mail.com') +def change_email(username, email): + bob = User.query.filter_by(username=username).first() + if not bob: + print(f'{username} not found!') + return + bob.email = email + db.session.add(bob) + db.session.commit() + print(bob) + + +@app.cli.command('create-user') +@click.argument('username', default='rick') +@click.argument('email', default='rick@mail.com') +@click.argument('password', default='rickpass') +def create_user(username, email, password): + newuser = User(username, email, password) + try: + db.session.add(newuser) + db.session.commit() + except IntegrityError as e: + #let's the database undo any previous steps of a transaction + db.session.rollback() + # print(e.orig) #optionally print the error raised by the database + print("Username or email already taken!") #give the user a useful message + else: + print(newuser) # print the newly created user + +@app.cli.command('delete-user') +@click.argument('username', default='bob') +def delete_user(username): + bob = User.query.filter_by(username=username).first() + if not bob: + print(f'{username} not found!') + return + db.session.delete(bob) + db.session.commit() + print(f'{username} deleted') + +@app.cli.command('get-todos') +@click.argument('username', default='bob') +def get_user_todos(username): + bob = User.query.filter_by(username=username).first() + if not bob: + print(f'{username} not found!') + return + print(bob.todos) + +@app.cli.command('add-todo') +@click.argument('username', default='bob') +@click.argument('text', default='wash car') +def add_task(username, text): + bob = User.query.filter_by(username=username).first() + if not bob: + print(f'{username} not found!') + return + new_todo = Todo(text) + bob.todos.append(new_todo) + db.session.add(bob) + db.session.commit() + +@click.argument('todo_id', default=1) +@click.argument('username', default='bob') +@app.cli.command('toggle-todo') +def toggle_todo_command(todo_id, username): + user = User.query.filter_by(username=username).first() + if not user: + print(f'{username} not found!') + return + + todo = Todo.query.filter_by(id=todo_id, user_id=user.id).first() + if not todo: + print(f'{username} has no todo id {todo_id}') + + todo.toggle() + print(f'{todo.text} is {"done" if todo.done else "not done"}!') + +@click.argument('category', default='chores') +@click.argument('username', default='bob') +@click.argument('todo_id', default=1) +@app.cli.command('add-category', help="Adds a category to a todo") +def add_todo_category_command(category, todo_id, username,): + user = User.query.filter_by(username=username).first() + if not user: + print(f'user {username} not found!') + return + + res = user.add_todo_category(todo_id, category) + if not res: + print(f'{username} has no todo id {todo_id}') + return + + todo = Todo.query.get(todo_id) + print(todo) \ No newline at end of file