Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6635118
[ITEM TABLE] + form and actions in table
phil-form Jul 20, 2022
ba4c094
[AJAX CONFIG] add global header config
phil-form Jul 22, 2022
4e53bb8
tableV2 to test
CrenierAmaury Jul 22, 2022
4b198ae
Merge branch 'main' of https://github.com/phil-form/pythonORM into se…
CrenierAmaury Jul 22, 2022
11ade11
[AJAX CONFIG] add global header config
phil-form Jul 22, 2022
a4f5861
basket items base
CrenierAmaury Jul 22, 2022
9257d04
Merge branch 'main' of https://github.com/phil-form/pythonORM into se…
CrenierAmaury Jul 22, 2022
0cac660
display list of items in a basket
CrenierAmaury Jul 22, 2022
73e90b4
[TABLE BASKET]
phil-form Jul 22, 2022
ffcef3a
Merge branch 'main' of https://github.com/phil-form/pythonORM into se…
CrenierAmaury Jul 22, 2022
b431f76
[USER] with JWT
phil-form Aug 23, 2022
ed82d32
add last changes
CrenierAmaury Aug 23, 2022
61d0b46
Merge branch 'main' of https://github.com/phil-form/pythonORM into se…
CrenierAmaury Aug 23, 2022
3af22d0
[USER] with JWT
phil-form Aug 23, 2022
b42b25e
Merge branch 'main' of https://github.com/phil-form/pythonORM into se…
CrenierAmaury Aug 23, 2022
883df21
[API]
phil-form Aug 24, 2022
776caa4
[DOTENV]
phil-form Aug 25, 2022
8a6a17e
Update README.md
phil-form Aug 25, 2022
7aa8e03
Update README.md
phil-form Aug 25, 2022
9601ea1
Update README.md
phil-form Aug 25, 2022
64920a6
Update README.md
phil-form Aug 25, 2022
01577ed
Update README.md
phil-form Aug 25, 2022
94a035c
Update .env.local
phil-form Aug 25, 2022
30e8715
Update sqlAlchemy.sh
phil-form Aug 25, 2022
7ff907b
Update sqlAlchemy.sh
phil-form Aug 25, 2022
e414bf8
Merge branch 'main' of https://github.com/phil-form/pythonORM into se…
CrenierAmaury Aug 30, 2022
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
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
DEBUG=True
FLASK_ENV=development
DATABASE_URL=postgresql://app:1234@127.0.0.1:5435/app
JWT_KEY=1234
CORS_ORIGIN=*
7 changes: 7 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# commentaire
# exemple d'une db de prod
# le .env.local sur une vraie application ne sera jamais push sur un git et ne servira qu'aux configurations locale
# d'un serveur de production ou d'acceptance/test.
# DATABASE_URL=postgresql://proddbuser:ASkjkmKAMM19os88!@*mamksjdui@prod url and port/proddb
JWT_KEY=asdkj9AK2j1ak5jsmnAs152MAJnKJAMskjad53
# CORS_ORIGIN=https://www.odoo.front.com/
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ celerybeat-schedule
*.sage.py

# Environments
.env
.venv
env/
venv/
Expand Down
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,84 @@
# pythonORM

## 1) models
from app import db
from app.models.base_entity import BaseEntity

class Role(BaseEntity, db.Model):
__tablename__ = "roles"
roleid = db.Column(db.Integer, primary_key=True)
rolename = db.Column(db.String(50), nullable=False, unique=True, index=True)
self.data = data

### 1.2) relationship one to many
class Parent(BaseEntity, db.Model):
__tablename__ = "parents"
parentid = db.Column(db.Integer, primary_key=True)
childid = db.Column(db.ForeignKey('children.childid'))
children = db.relationship("Child", cascade='all, delete-orphan')

class Child(BaseEntity, db.Model):
__tablename__ = "children"
childid = db.Column(db.Integer, primary_key=True)
parent = db.relationship("User", back_populates="children")

## 2) formulares
class ExampleForm(FlaskForm):
# désactiver CSRF pour les api
class Meta:
csrf = False
exampleData = StringField('exampleData', validators=[])
exampleData2 = StringField('exampleData2', validators=[DataRequired()])

## 3) mappers
Créer les mapper pour passer des entités au dtos, et mettre à jours les entité
à partir des forms.

## 4) services
- des fonctions pour contacter la db :
- findOne => retourne une entité en fonction de son id
- findOneBy => retourne une entité en fonction d'un
paramètre passé (données d'une des colonnes)
- findAll => retourne toutes les data
- update => met à jours les donnés en DB
- insert => insert des nouvelles donnée en DB
- delete => delete une entrée en DB

## 5) controllers
class ExampleController:
# http://servername/path
@app.route('/path', methods=['GET', 'POST'])
def getAllData():
return jsonify([example.get_json_parseable() for example in service.findAll()])
# http://servername/path/1
@app.route('/path/<int:dataid>', methods=['GET', 'POST'])
def getAllData(dataid):
return jsonify(service.findOne().get_json_parseable())


## 6) Dépendence
les mappers dépendent des modèles, des DTOs et des forms
les services dépendent des modèles et des mappers
les controllers dépendent des services.

## 7) database
la connection string doit être modifiée dans le .env ou .env.local
pour initialiser la db utiliser :
$ ./sqlAlchemy.sh -i

pour créer de nouvelles migrations :
$ ./sqlAlchemy.sh -m nom_de_la_migration

Le fichier de la migration peut être modifier si nécéssaire pour mettre à jours ou rajouter
des données dans la DB.

une fois les migrations créées on peut les appliquer avec la commande :
$ ./sqlAlchemy.sh -u

## 8) lancer le serveur
$ python3 runserver.py

pour lancer le serveur en debug depuis votre ide, il faudra soit créer un launch.json
via l'onglet de debugging de VSCode.
Soit on peut créer une nouvelle configuration de debugging dans Pycharm et mettre le runserver.py
comme programme de lancement.
21 changes: 18 additions & 3 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
import os
from pathlib import Path

import wtforms_json
from flask import Flask
from flask_cors import CORS
from flask_debugtoolbar import DebugToolbarExtension
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_wtf import CSRFProtect
from dotenv import load_dotenv

envvars = Path().cwd() / '.env.local'
load_dotenv()

if os.path.exists(envvars):
load_dotenv(envvars, override=True, verbose=True)

app = Flask('app')
app.debug = True
app.secret_key = 'superSecretKey01@'
app.debug = os.environ.get("DEBUG")
app.secret_key = os.environ.get("JWT_KEY")
wtforms_json.init()

toolbar = DebugToolbarExtension(app)
app.config['DEBUG_TB_INTERCEPT_REDIRECTS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://app:1234@127.0.0.1:5435/app'
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get("DATABASE_URL")
print(os.environ.get("DATABASE_URL"))
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# csrf_protect = CSRFProtect(app)

cors = CORS(app, resources={'/api/*': {'origins': os.environ.get("CORS_ORIGIN")}})
db = SQLAlchemy(app)
migrate = Migrate(app, db)

Expand Down
55 changes: 28 additions & 27 deletions app/controllers/basket_controller.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,48 @@
from flask import render_template, session, request, redirect, url_for

from flask import render_template, session, request, redirect, url_for, jsonify
from app import app
from app.framework.decorators.auth_required import auth_required
from app.forms.basket.basket_add_item_form import BasketAddItemForm
from app.framework.decorators.inject import inject
from app.services.auth_service import AuthService
from app.services.basket_service import BasketService
from app.services.item_service import ItemService
from app.services.user_service import UserService

basketService = BasketService()
itemService = ItemService()
userService = UserService()

@app.route('/basket/all')
@app.route('/api/basket/all')
@auth_required(level="ADMIN")
def getAllBaskets():
return render_template('baskets/list.html', baskets=basketService.find_all())
@inject
@inject
def getAllBaskets(basketService: BasketServicebasketService: BasketService):
return jsonify([basket.get_json_parsable() for basket in basketService.find_all()])

@app.route('/basket')
@app.route('/api/basket')
@auth_required()
def getBasketDetail(basketService: BasketService):
basket = basketService.find_one_by(userid=session.get('userid'), basketclosed=False)
return render_template('baskets/details.html',
basket=basket, items=basket.items, is_basket=True)
@inject
def getBasketDetail(basketService: BasketService, authService: AuthService):
user = authService.get_current_user()
basket = basketService.find_one_by(userid=user.userid, basketclosed=False)
return jsonify(basket.get_json_parsable())

@app.route('/basket/add', methods=['POST'])
@app.route('/api/basket/', methods=['PUT'])
@auth_required()
def add_item_to_basket():
item_to_add = BasketAddItemForm(request.form)
@inject
def add_item_to_basket(basketService: BasketService):
item_to_add = BasketAddItemForm.from_json(request.json)

basketService.add_item(item_to_add)
basket = basketService.add_item(item_to_add)

return redirect(url_for('getBasketDetail'))
return jsonify({ 'status': 'added' })

@app.route('/basket/remove/<int:itemid>', methods=['POST'])
@app.route('/api/basket/<int:itemid>', methods=['DELETE'])
@auth_required()
def remove_item_to_basket(itemid: int):
@inject
def remove_item_to_basket(itemid: int, basketService: BasketService):
basketService.remove_item(itemid)

return redirect(url_for('getBasketDetail'))
return jsonify({ 'status': 'removed' })

@app.route('/basket/checkout', methods=['POST'])
@app.route('/api/basket/checkout', methods=['POST'])
@auth_required()
def checkout_basket():
@inject
def checkout_basket(basketService: BasketService):
basketService.checkout_basket()

return redirect(url_for('getBasketDetail'))
return jsonify({ 'status': 'checkout' })
4 changes: 2 additions & 2 deletions app/controllers/home_controller.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from app import app
from flask import render_template, redirect
from flask import render_template, redirect, jsonify


@app.route('/', methods=['GET'])
def index():
return render_template('home/home.html')
return jsonify({'error': 'invalid credentials'}), 500
84 changes: 40 additions & 44 deletions app/controllers/item_controller.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,52 @@
from flask import render_template, request, redirect, url_for
from flask import render_template, request, redirect, url_for, jsonify
from app import app
from app.forms.basket.basket_add_item_form import BasketAddItemForm
from app.forms.item.item_form import ItemForm
from app.framework.decorators.auth_required import auth_required
from app.framework.decorators.inject import inject
from app.services.item_service import ItemService

itemService = ItemService()

@app.route('/items')
def getItemList():
return render_template('items/list.html', items=itemService.find_all())

@app.route('/items/<int:itemid>')
def getItemDetails(itemid):
form = BasketAddItemForm()

return render_template('items/details.html', item=itemService.find_one(itemid), form=form)

@app.route('/items/add', methods=['GET','POST'])
def addItem():
form = ItemForm(request.form)

if request.method == 'POST':
if form.validate():
item = itemService.insert(form)

return redirect(url_for('getItemList'))

print(form.errors)
form.itemname.data = ''
form.itemdescription.data = ''
form.itemstock.data = 1

return render_template('items/add_or_update.html', form=form)

@app.route('/items/update/<int:itemid>', methods=['GET','POST'])
def updateItem(itemid: int):
@app.route('/api/items')
@inject
def getItemListAsJson(itemService: ItemService):
return jsonify([item.get_json_parsable() for item in itemService.find_all()])

@app.route('/api/items/<int:itemid>')
@inject
def getItemDetails(itemid, itemService: ItemService):
return jsonify(itemService.find_one(itemid).get_json_parsable())

@app.route('/api/items/add', methods=['POST'])
@inject
@auth_required(level="ADMIN")
@inject
def addItem(itemService: ItemServiceitemService: ItemService):
form = ItemForm.from_json(request.json)
error = {
"code": 0,
"message": ""
}

if form.validate():
item = itemService.insert(form)

return jsonify(item.get_json_parsable())

return jsonify(form.errors)

@app.route('/api/items/<int:itemid>', methods=['PUT'])
@auth_required(level="ADMIN")
@inject
def updateItem(itemid: int, itemService: ItemService):
item = itemService.find_one(itemid)

if item is None:
return redirect(url_for('getItemList'))
return jsonify({ 'errors': "item not found" })

form = ItemForm(request.form)

if request.method == 'POST':
if form.validate():
item = itemService.update(itemid, form)

return redirect(url_for('getItemList'))
if form.validate():
item = itemService.update(itemid, form)

print(form.errors)
form.itemname.data = item.itemname
form.itemdescription.data = item.itemdescription
form.itemstock.data = item.itemquantity
return jsonify(item.get_json_parsable())

return render_template('items/add_or_update.html', form=form)
return jsonify(form.errors)
Loading