1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/ihatemoney_ynh.git synced 2024-09-03 19:26:15 +02:00

REST API is now able to list stuff \o/

This commit is contained in:
Alexis Metaireau 2011-09-13 18:15:07 +02:00
parent a60b0c2b48
commit e13ceaf351
4 changed files with 74 additions and 38 deletions

View file

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from flask import * from flask import *
import werkzeug
from models import db, Project, Person, Bill from models import db, Project, Person, Bill
from utils import for_all_methods from utils import for_all_methods
from rest import RESTResource, need_auth# FIXME make it an ext from rest import RESTResource, need_auth# FIXME make it an ext
from werkzeug import Response
api = Blueprint("api", __name__, url_prefix="/api") api = Blueprint("api", __name__, url_prefix="/api")
@ -33,7 +33,7 @@ class ProjectHandler(object):
@need_auth(check_project, "project") @need_auth(check_project, "project")
def get(self, project): def get(self, project):
return "get" return project
@need_auth(check_project, "project") @need_auth(check_project, "project")
def delete(self, project): def delete(self, project):
@ -47,7 +47,10 @@ class ProjectHandler(object):
class MemberHandler(object): class MemberHandler(object):
def get(self, project, member_id): def get(self, project, member_id):
pass member = Person.query.get(member_id)
if not member or member.project != project:
return Response('Not Found', status=404)
return member
def list(self, project): def list(self, project):
return project.members return project.members
@ -59,25 +62,32 @@ class MemberHandler(object):
pass pass
def delete(self, project, member_id): def delete(self, project, member_id):
pass if project.remove_member(member_id):
return Response('OK', status=200)
class BillHandler(object): class BillHandler(object):
def get(self, project, member_id): def get(self, project, bill_id):
pass bill = Bill.query.get(project, bill_id)
if not bill:
return Response('Not Found', status=404)
return bill
def list(self, project): def list(self, project):
pass return project.get_bills().all()
def add(self, project): def add(self, project):
pass pass
def update(self, project, member_id): def update(self, project, bill_id):
pass pass
def delete(self, project, member_id): def delete(self, project, bill_id):
pass bill = Bill.query.delete(project, bill_id)
if not bill:
return Response('Not Found', status=404)
return bill
project_resource = RESTResource( project_resource = RESTResource(
@ -102,24 +112,3 @@ bill_resource = RESTResource(
app=api, app=api,
handler=BillHandler(), handler=BillHandler(),
authentifier=check_project) authentifier=check_project)
# projects: add, delete, edit, get
# GET /project/<id> → get
# PUT /project/<id> → add & edit
# DELETE /project/<id> → delete
# project members: list, add, delete
# GET /project/<id>/members → list
# POST /project/<id>/members/ → add
# PUT /project/<id>/members/<user_id> → edit
# DELETE /project/<id>/members/<user_id> → delete
# project bills: list, add, delete, edit, get
# GET /project/<id>/bills → list
# GET /project/<id>/bills/<bill_id> → get
# DELETE /project/<id>/bills/<bill_id> → delete
# POST /project/<id>/bills/ → add
# GET, PUT, DELETE: /<id> : Get, update and delete
# GET, POST: / Add & List

View file

@ -3,6 +3,8 @@ from collections import defaultdict
from datetime import datetime from datetime import datetime
from flaskext.sqlalchemy import SQLAlchemy from flaskext.sqlalchemy import SQLAlchemy
from sqlalchemy import orm
db = SQLAlchemy() db = SQLAlchemy()
# define models # define models
@ -103,6 +105,29 @@ billowers = db.Table('billowers',
) )
class Bill(db.Model): class Bill(db.Model):
class BillQuery(orm.query.Query):
def get(self, project, id):
try:
return self.join(Person, Project)\
.filter(Bill.payer_id == Person.id)\
.filter(Person.project_id == Project.id)\
.filter(Project.id == project.id)\
.filter(Bill.id == id).one()
except orm.exc.NoResultFound:
return None
def delete(self, project, id):
bill = self.get(project, id)
if bill:
db.session.delete(bill)
return bill
query_class = BillQuery
_to_serialize = ("id", "payer_id", "owers", "amount", "date", "what")
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
payer_id = db.Column(db.Integer, db.ForeignKey("person.id")) payer_id = db.Column(db.Integer, db.ForeignKey("person.id"))
@ -122,7 +147,6 @@ class Bill(db.Model):
return "<Bill of %s from %s for %s>" % (self.amount, return "<Bill of %s from %s for %s>" % (self.amount,
self.payer, ", ".join([o.name for o in self.owers])) self.payer, ", ".join([o.name for o in self.owers]))
class Archive(db.Model): class Archive(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
project_id = db.Column(db.Integer, db.ForeignKey("project.id")) project_id = db.Column(db.Integer, db.ForeignKey("project.id"))
@ -138,3 +162,4 @@ class Archive(db.Model):
def __repr__(self): def __repr__(self):
return "<Archive>" return "<Archive>"

View file

@ -1,5 +1,6 @@
import json import json
from flask import request from flask import request
import werkzeug
class RESTResource(object): class RESTResource(object):
"""Represents a REST resource, with the different HTTP verbs""" """Represents a REST resource, with the different HTTP verbs"""
@ -117,18 +118,28 @@ def need_auth(authentifier, name=None, remove_attr=True):
return wrapped return wrapped
return wrapper return wrapper
# serializers # serializers
def serialize(func): def serialize(func):
"""If the object returned by the view is not already a Response, serialize
it using the ACCEPT header and return it.
"""
def wrapped(*args, **kwargs): def wrapped(*args, **kwargs):
# get the mimetype
mime = request.accept_mimetypes.best_match(SERIALIZERS.keys()) mime = request.accept_mimetypes.best_match(SERIALIZERS.keys())
return SERIALIZERS.get(mime, "text/json")\ data = func(*args, **kwargs)
.encode(func(*args, **kwargs))
if isinstance(data, werkzeug.Response):
return data
else:
# serialize it
return SERIALIZERS.get(mime, "text/json").encode(data)
return wrapped return wrapped
class JSONEncoder(json.JSONEncoder): class JSONEncoder(json.JSONEncoder):
"""Subclass of the default encoder to support custom objects"""
def default(self, o): def default(self, o):
if hasattr(o, "_to_serialize"): if hasattr(o, "_to_serialize"):
# build up the object # build up the object
@ -136,6 +147,8 @@ class JSONEncoder(json.JSONEncoder):
for attr in o._to_serialize: for attr in o._to_serialize:
data[attr] = getattr(o, attr) data[attr] = getattr(o, attr)
return data return data
elif hasattr(o, "isoformat"):
return o.isoformat()
else: else:
return json.JSONEncoder.default(self, o) return json.JSONEncoder.default(self, o)

View file

@ -2,6 +2,7 @@ from collections import defaultdict
from flask import * from flask import *
from flaskext.mail import Mail, Message from flaskext.mail import Mail, Message
import werkzeug
# local modules # local modules
from models import db, Project, Person, Bill from models import db, Project, Person, Bill
@ -239,7 +240,11 @@ def add_bill():
@main.route("/<project_id>/delete/<int:bill_id>") @main.route("/<project_id>/delete/<int:bill_id>")
def delete_bill(bill_id): def delete_bill(bill_id):
bill = Bill.query.get_or_404(bill_id) # fixme: everyone is able to delete a bill
bill = Bill.query.get(g.project, bill_id)
if not bill:
raise werkzeug.exceptions.NotFound()
db.session.delete(bill) db.session.delete(bill)
db.session.commit() db.session.commit()
flash("The bill has been deleted") flash("The bill has been deleted")
@ -249,7 +254,11 @@ def delete_bill(bill_id):
@main.route("/<project_id>/edit/<int:bill_id>", methods=["GET", "POST"]) @main.route("/<project_id>/edit/<int:bill_id>", methods=["GET", "POST"])
def edit_bill(bill_id): def edit_bill(bill_id):
bill = Bill.query.get_or_404(bill_id) # FIXME: Test this bill belongs to this project !
bill = Bill.query.get(g.project, bill_id)
if not bill:
raise werkzeug.exceptions.NotFound()
form = get_billform_for(g.project, set_default=False) form = get_billform_for(g.project, set_default=False)
if request.method == 'POST' and form.validate(): if request.method == 'POST' and form.validate():
form.save(bill) form.save(bill)