Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/neilshaabi/mindli
Browse files Browse the repository at this point in the history
  • Loading branch information
neilshaabi committed Feb 23, 2024
2 parents 72bcc88 + 7ff30f4 commit e6fa2d7
Show file tree
Hide file tree
Showing 23 changed files with 588 additions and 385 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
**/__pycache__/
.venv/*
*.sqlite
.env
21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
venv:
@echo "\nCreating virtual environment..."
python3 -m venv .venv
@echo "\nNote: You will need to activate the virtual environment in your shell manually using:"
@echo "source .venv/bin/activate"

deps:
@echo "\nInstalling dependencies..."
pip install -r requirements.txt

app:
@echo "\nRunning Flask app locally..."
flask run

clean:
@echo "\nCleaning up directory..."
rm -rf .venv
find . -type d -name '__pycache__' -exec rm -r {} +
find . -type f -name '*.pyc' -delete

.PHONY: venv deps app clean
6 changes: 3 additions & 3 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@


def create_app(config: Config = selected_config):
"""Application factory method"""

app = Flask(__name__)
app.config.from_object(config)

Expand All @@ -29,7 +27,8 @@ def create_app(config: Config = selected_config):
app.serialiser = URLSafeTimedSerializer(app.config["SECRET_KEY"])

# Reset database
from app.models import insertDummyData
from app.models import User, insertDummyData

if app.config["RESET_DB"]:
with app.app_context():
db.drop_all()
Expand All @@ -38,6 +37,7 @@ def create_app(config: Config = selected_config):

# Register blueprints
from app.views import auth, main

app.register_blueprint(main.bp)
app.register_blueprint(auth.bp)

Expand Down
6 changes: 2 additions & 4 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Config(object):
SQLALCHEMY_TRACK_MODIFICATIONS: bool = False

# Flask Mail setup
MAIL_SERVER: str = "smtppro.zoho.eu"
MAIL_SERVER: str = "smtp.gmail.com"
MAIL_PORT: int = 465
MAIL_USE_SSL: bool = True
MAIL_USE_TLS: bool = False
Expand All @@ -25,9 +25,7 @@ class Config(object):
class DevConfig(Config):
DEBUG: bool = True
RESET_DB: bool = True
SQLALCHEMY_DATABASE_URI: str = (
"sqlite:///" + os.path.join(basedir, "mindli.sqlite")
)
SQLALCHEMY_DATABASE_URI: str = "sqlite:///" + os.path.join(basedir, "mindli.sqlite")


class ProdConfig(Config):
Expand Down
179 changes: 160 additions & 19 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import date
from enum import Enum
from typing import List
from datetime import date, time
from enum import Enum, unique
from typing import List, Optional

import sqlalchemy as sa
import sqlalchemy.orm as so
Expand All @@ -15,39 +15,178 @@ def load_user(user_id: str):
return User.query.get(int(user_id))


@unique
class UserRole(Enum):
"""Enumeration for the user role (client or therapist)"""

CLIENT = "client"
THERAPIST = "therapist"


class User(UserMixin, db.Model):
"""Model of a User stored in the database"""
@unique
class SessionFormat(Enum):
FACE = "Face to Face"
AUDIO = "Audio Call"
VIDEO = "Video Call"


@unique
class Gender(Enum):
MALE = "Male"
FEMALE = "Female"
NON_BINARY = "Non-Binary"


therapist_language = sa.Table(
"therapist_language",
db.Model.metadata,
sa.Column("therapist_id", sa.ForeignKey("therapist.id"), primary_key=True),
sa.Column("language_id", sa.ForeignKey("language.id"), primary_key=True),
)

therapist_format = sa.Table(
"therapist_format",
db.Model.metadata,
sa.Column("therapist_id", sa.ForeignKey("therapist.id"), primary_key=True),
sa.Column("session_format", sa.Enum(SessionFormat), primary_key=True),
)

therapist_specialisation = sa.Table(
"therapist_specialisation",
db.Model.metadata,
sa.Column("therapist_id", sa.ForeignKey("therapist.id"), primary_key=True),
sa.Column(
"specialisation_id", sa.ForeignKey("specialisation.id"), primary_key=True
),
)

therapist_intervention = sa.Table(
"therapist_intervention",
db.Model.metadata,
sa.Column("therapist_id", sa.ForeignKey("therapist.id"), primary_key=True),
sa.Column("intervention_id", sa.ForeignKey("intervention.id"), primary_key=True),
)


class User(UserMixin, db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
email: so.Mapped[str] = so.mapped_column(
sa.String(254), index=True, unique=True
)
password_hash: so.Mapped[str] = so.mapped_column(sa.String(256))
email: so.Mapped[str] = so.mapped_column(sa.String(254), index=True, unique=True)
password_hash: so.Mapped[str] = so.mapped_column(sa.String(255))
first_name: so.Mapped[str] = so.mapped_column(sa.String(50))
last_name: so.Mapped[str] = so.mapped_column(sa.String(50))
date_joined: so.Mapped[date] = so.mapped_column(sa.Date)
role: so.Mapped[UserRole] = so.mapped_column(sa.Enum(UserRole))
role: so.Mapped["UserRole"] = so.mapped_column(sa.Enum(UserRole))
verified: so.Mapped[bool] = so.mapped_column(sa.Boolean, default=False)
active: so.Mapped[bool] = so.mapped_column(sa.Boolean, default=True)
gender: so.Mapped[Optional["Gender"]] = so.mapped_column(sa.Enum(Gender))
photo_url: so.Mapped[Optional[str]] = so.mapped_column(sa.String(255))
therapist: so.Mapped[Optional["Therapist"]] = so.relationship(back_populates="user")

def __repr__(self) -> str:
"""
Returns a string representing a user with
their id and email address, used by print()
"""
return f"<User {self.id}: {self.email}>"
return f"<User({self.id}: {self.email}>"


def insertDummyData() -> None:
"""Insert dummy data into database"""
class Therapist(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
user_id: so.Mapped[int] = so.mapped_column(sa.ForeignKey(User.id), index=True)
country: so.Mapped[str] = so.mapped_column(sa.String(50))
affilitation: so.Mapped[Optional[str]] = so.mapped_column(sa.Text)
bio: so.Mapped[Optional[str]] = so.mapped_column(sa.Text)
link: so.Mapped[Optional[str]] = so.mapped_column(sa.String(255))
location: so.Mapped[Optional[str]] = so.mapped_column(sa.String(255))
registrations: so.Mapped[Optional[str]] = so.mapped_column(sa.Text)
qualifications: so.Mapped[Optional[str]] = so.mapped_column(sa.Text)
years_of_experience: so.Mapped[Optional[int]] = so.mapped_column(sa.Integer)
user: so.Mapped["User"] = so.relationship(back_populates="therapist")
languages: so.Mapped[List["Language"]] = so.relationship(
secondary=therapist_language, back_populates="therapists"
)
specialisations: so.Mapped[List["Specialisation"]] = so.relationship(
secondary=therapist_specialisation, back_populates="therapists"
)
interventions: so.Mapped[List["Intervention"]] = so.relationship(
secondary=therapist_intervention, back_populates="therapists"
)
session_types: so.Mapped[List["SessionType"]] = so.relationship(
back_populates="therapist"
)
availabilities: so.Mapped[List["Availability"]] = so.relationship(
back_populates="therapist"
)
unavailabilities: so.Mapped[List["Unavailability"]] = so.relationship(
back_populates="therapist"
)


class Language(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
name: so.Mapped[str] = so.mapped_column(sa.String(50), unique=True)
therapists: so.Mapped[List["Therapist"]] = so.relationship(
secondary="therapist_language", back_populates="languages"
)


class Specialisation(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
name: so.Mapped[str] = so.mapped_column(sa.String(50), unique=True)
therapists: so.Mapped[List["Therapist"]] = so.relationship(
secondary=therapist_specialisation, back_populates="specialisations"
)


class Intervention(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
name: so.Mapped[str] = so.mapped_column(sa.String(50), unique=True)
therapists: so.Mapped[List["Therapist"]] = so.relationship(
secondary=therapist_intervention, back_populates="interventions"
)


class SessionType(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
therapist_id: so.Mapped[int] = so.mapped_column(
sa.ForeignKey("therapist.id"), index=True
)
name: so.Mapped[str] = so.mapped_column(
sa.String(255)
) # e.g. "Initial Consultation"
session_duration: so.Mapped[int] = so.mapped_column(
sa.Integer
) # In minutes
fee_amount: so.Mapped[float] = so.mapped_column(sa.Float)
fee_currency: so.Mapped[str] = so.mapped_column(sa.String(3))
notes: so.Mapped[Optional[str]] = so.mapped_column(sa.Text)
therapist: so.Mapped["Therapist"] = so.relationship(back_populates="session_types")


class Availability(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
therapist_id: so.Mapped[int] = so.mapped_column(
sa.ForeignKey("therapist.id"), index=True
)
day_of_week: so.Mapped[Optional[int]] = so.mapped_column(
sa.Integer
) # 0=Monday, 6=Sunday, None for specific dates
start_time: so.Mapped[Optional[time]] = so.mapped_column(sa.Time)
end_time: so.Mapped[Optional[time]] = so.mapped_column(sa.Time)
specific_date: so.Mapped[Optional[date]] = so.mapped_column(
sa.Date
) # For non-recurring availability
therapist: so.Mapped["Therapist"] = so.relationship(back_populates="availabilities")


class Unavailability(db.Model):
id: so.Mapped[int] = so.mapped_column(primary_key=True)
therapist_id: so.Mapped[int] = so.mapped_column(
sa.ForeignKey("therapist.id"), index=True
)
start_date: so.Mapped[date] = so.mapped_column(sa.Date)
end_date: so.Mapped[date] = so.mapped_column(sa.Date)
reason: so.Mapped[Optional[str]] = so.mapped_column(sa.Text)
therapist: so.Mapped["Therapist"] = so.relationship(
back_populates="unavailabilities"
)


def insertDummyData() -> None:
users: List[User] = [
User(
email="[email protected]",
Expand All @@ -58,6 +197,7 @@ def insertDummyData() -> None:
role=UserRole.CLIENT,
verified=True,
active=True,
gender=Gender.MALE,
),
User(
email="[email protected]",
Expand All @@ -68,6 +208,7 @@ def insertDummyData() -> None:
role=UserRole.THERAPIST,
verified=False,
active=True,
gender=Gender.FEMALE,
),
]
db.session.add_all(users)
Expand Down
Loading

0 comments on commit e6fa2d7

Please sign in to comment.