Skip to content

Iresh #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d519273
README.md added
Death-RAW Feb 9, 2024
558c014
data-models added
Shazam007 Feb 9, 2024
80899d1
add dump file
sonaliprasadika Feb 9, 2024
5017053
README.md updated
Shazam007 Feb 20, 2024
9e065dd
Minutes 1 Added
Death-RAW Feb 20, 2024
88b5e25
markdownfix
Death-RAW Feb 20, 2024
6088b6e
rearranged structure
NirashaThennakoon Mar 3, 2024
877f93b
added data models
NirashaThennakoon Mar 3, 2024
fbe32ea
Merge pull request #1 from NirashaThennakoon/DL2_nirasha
NirashaThennakoon Mar 3, 2024
a5928a0
remote database added
sonaliprasadika Mar 4, 2024
d799d42
api key added
Death-RAW Mar 4, 2024
b5b46b3
uer funcg added
Death-RAW Mar 4, 2024
0924e9c
apikey primarykey fiexd
Death-RAW Mar 4, 2024
f8ce6c2
prmary key added to keys
Death-RAW Mar 4, 2024
e7770cd
c1_init
Death-RAW Mar 4, 2024
134365e
song resource added and Db checkup changed
Shazam007 Mar 4, 2024
863d0ce
added playlist generation logic
Shazam007 Mar 5, 2024
dd13e8b
completed playlist endpoints
Shazam007 Mar 5, 2024
2f39127
Working Auth Base 1
Death-RAW Mar 5, 2024
44fc60f
misc fixes
Shazam007 Mar 5, 2024
7517573
Merge branch 'main' of https://github.com/NirashaThennakoon/CustomWor…
Shazam007 Mar 5, 2024
f7a3069
Merge pull request #2 from NirashaThennakoon/dev-b-kavindu
Shazam007 Mar 5, 2024
fb41499
auth bse 0001
Death-RAW Mar 5, 2024
11a567f
add workout endpoints
sonaliprasadika Mar 6, 2024
ef7b77a
adding playlist id
sonaliprasadika Mar 6, 2024
6204e00
files relocated
sonaliprasadika Mar 6, 2024
f49fd73
removed pycache
sonaliprasadika Mar 6, 2024
9ab8156
added gitignore
sonaliprasadika Mar 6, 2024
ad3f5ba
pycache removed
Death-RAW Mar 6, 2024
d3bd847
resolving merger
Death-RAW Mar 6, 2024
c170b1d
User Functions added, token passing
Death-RAW Mar 6, 2024
f04f6f7
API KEy update Fixed
Death-RAW Mar 6, 2024
5d184b2
api key update fixed v2
Death-RAW Mar 6, 2024
6e25a2c
merge fixes
Death-RAW Mar 6, 2024
89d306d
Auth added to all resources
Death-RAW Mar 6, 2024
a8aa857
user fixed
Death-RAW Mar 6, 2024
fb9e58d
refined user endpoint
Death-RAW Mar 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
94 changes: 88 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,93 @@
# PWP SPRING 2024
# PROJECT NAME
# Custom Workout Playlist Generator
# Group information
* Student 1. Name and email
* Student 2. Name and email
* Student 3. Name and email
* Student 4. Name and email
* Student 1. Iresh Jayasundara - [email protected]
* Student 2. Kavindu Wijesinghe - [email protected]
* Student 3. Sonali Prasadika - [email protected]
* Student 4. Nirasha Thennakoon - [email protected]

__Remember to include all required documentation and HOWTOs, including how to create and populate the database, how to run and test the API, the url to the entrypoint and instructions on how to setup and run the client__
# Database Implementation :Custom Workout Playlist Generator
The following chapter describes the the selection of databases, libraries and instructions to setup the requirements needed for the Custom Workout Playlist Generator.



## 🔗 Dependencies and Setup

Following tools and libraries are required for setting up the database for the Custom Workout Playlist Generator. Note that the steps in this section listed below is designed as a guide for you to manually setup the database. If you wish to skip these steps and directly create the database, tables and dummy data, jump to the installing MySql step and follow the next section titled **Flask app setup.**

[![Python](https://img.shields.io/badge/Python-FFD43B?style=for-the-badge&logo=python&logoColor=blue)](https://www.python.org)

- [x] Install latest python version from [here.](https://www.python.org) 3.11.5 is recommended
- [x] Install pip from [here.](https://pip.pypa.io/en/stable/installation/) 23.2.1 is recommended.
Note: pip will be available as a part of your python installation. you can check the pip version for verifying.
```bash
pip --version
```
[![Flask](https://img.shields.io/badge/Flask-000000?style=for-the-badge&logo=flask&logoColor=white)](https://flask.palletsprojects.com/en/3.0.x/)

Flask is a web application framework written in Python. Read more abput flask from [here.](https://flask.palletsprojects.com/en/3.0.x/) Install flask 2.2.2 using the following command.
```bash
pip install flask
```


![Static Badge](https://img.shields.io/badge/SQLAlchemy--00353fe)

The Flask SQL Alchemy SQL Toolkit and Object Relational Mapper is a comprehensive set of tools for working with databases and Python. It has several distinct areas of functionality which can be used individually or combined together. Its major components are illustrated below, with component dependencies organized into layers: [Read more here](https://docs.sqlalchemy.org/en/20/intro.html)

- [x] Install FlaskSQLAlchemy. Use pip to install or refer [here](https://docs.sqlalchemy.org/en/20/intro.html#installation) for other methods of installation.
```bash
pip install flask-sqlalchemy sqlalchemy
```
![Static Badge](https://img.shields.io/badge/mysqlclient-2299ff)

Mysqlclient is an interface to the MySQL database server that provides the Python database API.

```bash
pip install mysqlclient
```

[![MySQL](https://img.shields.io/badge/MySQL-005C84?style=for-the-badge&logo=mysql&logoColor=white)](https://www.mysql.com/downloads/)

MySQL was chosen as a database for the project because it's free to use, widely used, and performs well with large amounts of data. It's easy to scale up as projects grow and works with many programming languages. Plus, it's secure and stable, making it a reliable option for important tasks.

- [x] install MySQL communuty edition from [here](https://www.mysql.com/products/community/)
- [x] When prompted for the credentials duting the installation wizard, use the **username root and password root.** if you wish to use a different credentials, make sure to update the modified credentials when runng the app.py in the next section.
- [x] Configre the MySQL server to run on your OS with your credentials.



#Database Setup (Flask App and Environment Setup)

If you have skipped the manual setup to install the required libraries, you can use the **Requirements.txt** file to install the nessacery libraries.

- [x] We recommend you use a Python Virtual Environment for setting-up the next steps.
- [x] Create a folder of your choosing for the virtual Environment
- [x] Clone our repo to the folder
- [x] Use the folder path to create the Virtual Environment
```bash
python3 -m venv /path/to/the/virtualenv
```
- [x] Activate the Virtual Environment

```bash
c:\path\to\the\virtualenv\Scripts\activate.bat
on OSX
source /path/to/the/virtualenv/bin/activate
```
```bash
pip install -r requirements.txt
```
- [x] Run the flask App. this will create all the tables and relationships in your environment. make sure to change the password install to the database url if you have used a password of your own.
```python
app.config["SQLALCHEMY_DATABASE_BASE_URI"] = "mysql+mysqldb://root@localhost/"
```
```bash
python .\app.py
```
- [x] To add sample data to the tables, you can run the provided sql dump using the following command.

```bash
use workout_playlists
source /path/to/sql/your_sql_file.sql
```
42 changes: 42 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from flask import Flask, jsonify, request
from flask_restful import Api, Resource
from flask_sqlalchemy import SQLAlchemy
import sqlalchemy
from sqlalchemy import text
from extensions import db
from api import api_bp
from middleware_Auth import authenticate
from flask_jwt_extended import JWTManager

app = Flask(__name__)
# app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'
app.config["SQLALCHEMY_DATABASE_BASE_URI"] = "mysql+mysqldb://admin:pwpdb7788@workoutplaylists.cpcoaea0i7dq.us-east-1.rds.amazonaws.com"
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+mysqldb://admin:pwpdb7788@workoutplaylists.cpcoaea0i7dq.us-east-1.rds.amazonaws.com/workout_playlists"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config['JWT_SECRET_KEY'] = 'ireshisthe key'
jwt = JWTManager(app)

db.init_app(app)

def create_database():
engine = sqlalchemy.create_engine(app.config['SQLALCHEMY_DATABASE_BASE_URI'], echo=True)
conn = engine.connect()
try:
query = "CREATE DATABASE IF NOT EXISTS workout_playlists;"
conn.execute(text(query))
print("Database created successfully.")
except Exception as e:
print("Error creating database:", e)
conn.close()

def create_tables():
db.metadata.create_all(bind=db.engine, checkfirst=True)

with app.app_context():
create_database()
db.create_all()

app.register_blueprint(api_bp, url_prefix='/api')
app.before_request(authenticate)
if __name__ == "__main__":
app.run(debug=True)
28 changes: 28 additions & 0 deletions api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from flask import Blueprint
from flask_restful import Api
from resources.workout import WorkoutResource,WorkoutsResource
from resources.workoutPlan import WorkoutPlanResource, WorkoutPlanAddingResource, WorkoutPlanItemResource
from resources.song import SongResource
from resources.song import SongListResource
from resources.playlist import PlaylistResource
from resources.playlist import CreatePlaylistResource
from resources.user import UserRegistrationResource, UserLoginResource, UserResource, ApiKeyUpdateResource



api_bp = Blueprint('api', __name__)
api = Api(api_bp)

api.add_resource(WorkoutResource, "/workout/<workout_id>")
api.add_resource(WorkoutsResource, "/workout")
api.add_resource(WorkoutPlanResource, "/workoutPlan/<workout_plan_id>")
api.add_resource(WorkoutPlanAddingResource, "/workoutPlan")
api.add_resource(WorkoutPlanItemResource, "/workoutPlanItem/<workout_plan_id>")
api.add_resource(SongResource, "/song/<song_id>/")
api.add_resource(SongListResource, "/song/")
api.add_resource(PlaylistResource, "/playlist/<playlist_id>/")
api.add_resource(CreatePlaylistResource, "/playlist/")
api.add_resource(UserRegistrationResource, "/user/register")
api.add_resource(UserLoginResource, "/user/login")
api.add_resource(UserResource, "/user/<int:user_id>")
api.add_resource(ApiKeyUpdateResource, "/user/update_api_key/<int:user_id>")
97 changes: 97 additions & 0 deletions data_models/dump.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
-- MySQL dump 10.13 Distrib 8.0.36, for Win64 (x86_64)
--
-- Host: localhost Database: workout_playlists
-- ------------------------------------------------------
-- Server version 8.0.36

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!50503 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Dumping data for table `playlist`
--

LOCK TABLES `playlist` WRITE;
/*!40000 ALTER TABLE `playlist` DISABLE KEYS */;
INSERT INTO `playlist` VALUES (1,120),(2,90);
/*!40000 ALTER TABLE `playlist` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `playlist_item`
--

LOCK TABLES `playlist_item` WRITE;
/*!40000 ALTER TABLE `playlist_item` DISABLE KEYS */;
INSERT INTO `playlist_item` VALUES (1,1,1),(2,2,1),(3,3,2);
/*!40000 ALTER TABLE `playlist_item` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `song`
--

LOCK TABLES `song` WRITE;
/*!40000 ALTER TABLE `song` DISABLE KEYS */;
INSERT INTO `song` VALUES (1,'Song1','Artist1','Pop',3.5),(2,'Song2','Artist2','Rock',4.2),(3,'Song3','Artist3','Hip Hop',5);
/*!40000 ALTER TABLE `song` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `user`
--

LOCK TABLES `user` WRITE;
/*!40000 ALTER TABLE `user` DISABLE KEYS */;
INSERT INTO `user` VALUES (1,'[email protected]','password123',170.5,65.2,'regular','token123','2024-02-09 12:00:00'),(2,'[email protected]','pass456',160,55.8,'premium','token456','2024-02-10 14:30:00');
/*!40000 ALTER TABLE `user` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `workout`
--

LOCK TABLES `workout` WRITE;
/*!40000 ALTER TABLE `workout` DISABLE KEYS */;
INSERT INTO `workout` VALUES (1,'Cardio Blast',30,'High','Treadmill','Cardio'),(2,'Strength Training',45,'Medium','Dumbbells','Strength'),(3,'Yoga Flow',60,'Low','Yoga Mat','Flexibility');
/*!40000 ALTER TABLE `workout` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `workout_plan`
--

LOCK TABLES `workout_plan` WRITE;
/*!40000 ALTER TABLE `workout_plan` DISABLE KEYS */;
INSERT INTO `workout_plan` VALUES (1,'Morning Routine',90,1,1),(2,'Evening Workout',75,2,2);
/*!40000 ALTER TABLE `workout_plan` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Dumping data for table `workout_plan_item`
--

LOCK TABLES `workout_plan_item` WRITE;
/*!40000 ALTER TABLE `workout_plan_item` DISABLE KEYS */;
INSERT INTO `workout_plan_item` VALUES (1,1,1),(2,1,2),(3,2,3);
/*!40000 ALTER TABLE `workout_plan_item` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2024-02-09 12:56:25
97 changes: 97 additions & 0 deletions data_models/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import hashlib
from extensions import db
#from sqlalchemy import event

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), nullable=False)
password = db.Column(db.String(64), nullable=False)
height = db.Column(db.Float, nullable=False)
weight = db.Column(db.Float, nullable=False)
user_type = db.Column(db.String(32), nullable=False)
user_token = db.Column(db.String(64), nullable=False)
token_expiration = db.Column(db.DateTime, nullable=False)

api_key = db.relationship("ApiKey", back_populates="user", cascade="all, delete-orphan")
workout_plan = db.relationship("WorkoutPlan", back_populates="user")

@staticmethod
def password_hash(password):
return hashlib.sha256(password.encode()).hexdigest()

def verify_password(self, password):
hashed_password = User.password_hash(password)
return self.password == hashed_password

class Workout(db.Model):
workout_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
workout_name = db.Column(db.String(64), nullable=False)
duration = db.Column(db.Float, nullable=False)
workout_intensity = db.Column(db.String(32), nullable=False)
equipment = db.Column(db.String(64), nullable=False)
workout_type = db.Column(db.String(64), nullable=False)

workout_plan_item = db.relationship("WorkoutPlanItem", back_populates="workout")

class WorkoutPlanItem(db.Model):
item_id = db.Column(db.Integer, primary_key=True)
workout_plan_id = db.Column(db.Integer, db.ForeignKey("workout_plan.workout_plan_id"))
workout_id = db.Column(db.Integer, db.ForeignKey("workout.workout_id"))

workout_plan = db.relationship("WorkoutPlan", back_populates="workout_plan_item")
workout = db.relationship("Workout", back_populates="workout_plan_item")

class WorkoutPlan(db.Model):
workout_plan_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
plan_name = db.Column(db.String(64), nullable=False)
duration = db.Column(db.Float, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
playlist_id = db.Column(db.Integer, db.ForeignKey("playlist.playlist_id"))

workout_plan_item = db.relationship("WorkoutPlanItem", back_populates="workout_plan")
user = db.relationship("User", back_populates="workout_plan")
playlist = db.relationship("Playlist", back_populates="workout_plan")

class Playlist(db.Model):
playlist_id = db.Column(db.Integer, primary_key=True)
playlist_duration = db.Column(db.Float, nullable=False)
playlist_name = db.Column(db.String(64), nullable=False)

playlist_item = db.relationship("PlaylistItem", back_populates="playlist")
workout_plan = db.relationship("WorkoutPlan", back_populates="playlist")

class PlaylistItem(db.Model):
item_id = db.Column(db.Integer, primary_key=True)
song_id = db.Column(db.Integer, db.ForeignKey("song.song_id"))
playlist_id = db.Column(db.Integer, db.ForeignKey("playlist.playlist_id"))

song = db.relationship("Song", back_populates="playlist_item")
playlist = db.relationship("Playlist", back_populates="playlist_item")

class Song(db.Model):
song_id = db.Column(db.Integer, primary_key=True)
song_name = db.Column(db.String(64), nullable=False)
song_artist = db.Column(db.String(64), nullable=False)
song_genre = db.Column(db.String(64), nullable=False)
song_duration = db.Column(db.Float, nullable=False)

playlist_item = db.relationship("PlaylistItem", back_populates="song")

class ApiKey(db.Model):
id = db.Column(db.Integer, primary_key=True)
key = db.Column(db.String(32), nullable=False, unique=True)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
admin = db.Column(db.Boolean, default=False)

user = db.relationship("User", back_populates="api_key", uselist=False)

@staticmethod
def key_hash(key):
return hashlib.sha256(key.encode()).digest()

# @event.listens_for(User, 'after_delete')
# def delete_api_keys(mapper, connection, target):
# api_keys = ApiKey.query.filter_by(user_id=target.id).all()
# for api_key in api_keys:
# db.session.delete(api_key)
# db.session.commit()
Binary file added data_models/requirements.txt
Binary file not shown.
2 changes: 2 additions & 0 deletions extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
Binary file added instance/db.sqlite3
Binary file not shown.
Loading