feat: implement user authentication, session management, and core database models for notepads, notes, and collaboration features.

This commit is contained in:
Ben Miller 2026-06-23 14:06:36 -05:00
parent 314d47ed00
commit 1d80b47a3d
9 changed files with 25 additions and 3 deletions

1
app.py
View file

@ -32,3 +32,4 @@ with app.app_context():
if __name__ == "__main__": if __name__ == "__main__":
app.run(debug=True) app.run(debug=True)

View file

@ -50,6 +50,7 @@ def login():
user.last_ip = ip_address user.last_ip = ip_address
db.session.commit() db.session.commit()
session.permanent = True
session['user_id'] = user.id session['user_id'] = user.id
return jsonify({'message': 'Login successful', 'user': user.to_dict()}), 200 return jsonify({'message': 'Login successful', 'user': user.to_dict()}), 200

View file

@ -1,4 +1,5 @@
import os import os
from datetime import timedelta
basedir = os.path.abspath(os.path.dirname(__file__)) basedir = os.path.abspath(os.path.dirname(__file__))
@ -7,3 +8,4 @@ class Config:
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'spotnotes.db') 'sqlite:///' + os.path.join(basedir, 'spotnotes.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
PERMANENT_SESSION_LIFETIME = timedelta(days=30)

View file

@ -5,3 +5,6 @@ class BannedIP(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
ip_address = db.Column(db.String(45), unique=True, nullable=False) ip_address = db.Column(db.String(45), unique=True, nullable=False)
created_at = db.Column(db.DateTime, default=datetime.utcnow) created_at = db.Column(db.DateTime, default=datetime.utcnow)
def __init__(self, **kwargs):
super().__init__(**kwargs)

View file

@ -15,6 +15,9 @@ class Collaborator(db.Model):
db.UniqueConstraint('notepad_id', 'user_id', name='unique_collaborator'), db.UniqueConstraint('notepad_id', 'user_id', name='unique_collaborator'),
) )
def __init__(self, **kwargs):
super().__init__(**kwargs)
def to_dict(self): def to_dict(self):
return { return {
'id': self.id, 'id': self.id,

View file

@ -8,3 +8,6 @@ class Favorite(db.Model):
__table_args__ = ( __table_args__ = (
db.UniqueConstraint('user_id', 'notepad_id', name='unique_favorite'), db.UniqueConstraint('user_id', 'notepad_id', name='unique_favorite'),
) )
def __init__(self, **kwargs):
super().__init__(**kwargs)

View file

@ -11,6 +11,9 @@ class Note(db.Model):
is_hidden = db.Column(db.Boolean, default=False) is_hidden = db.Column(db.Boolean, default=False)
notepad_id = db.Column(db.Integer, db.ForeignKey('notepad.id'), nullable=False) notepad_id = db.Column(db.Integer, db.ForeignKey('notepad.id'), nullable=False)
def __init__(self, **kwargs):
super().__init__(**kwargs)
def to_dict(self): def to_dict(self):
return { return {
'id': self.id, 'id': self.id,

View file

@ -12,6 +12,9 @@ class Notepad(db.Model):
notes = db.relationship('Note', backref='notepad', lazy='dynamic', cascade="all, delete-orphan") notes = db.relationship('Note', backref='notepad', lazy='dynamic', cascade="all, delete-orphan")
def __init__(self, **kwargs):
super().__init__(**kwargs)
def to_dict(self): def to_dict(self):
return { return {
'id': self.id, 'id': self.id,

View file

@ -11,6 +11,9 @@ class User(db.Model):
is_banned = db.Column(db.Boolean, default=False) is_banned = db.Column(db.Boolean, default=False)
last_ip = db.Column(db.String(45)) last_ip = db.Column(db.String(45))
def __init__(self, **kwargs):
super().__init__(**kwargs)
def set_password(self, password): def set_password(self, password):
self.password_hash = generate_password_hash(password) self.password_hash = generate_password_hash(password)