Rewrote views with Restful resources.

This commit is contained in:
Alexis Lahouze 2015-06-11 23:32:55 +02:00
parent c62941a704
commit be1bba3bc8
3 changed files with 283 additions and 140 deletions

View File

@ -15,36 +15,22 @@
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
"""
from flask import json, request
from flask.ext.restful import Resource, fields, reqparse, marshal_with_field
from sqlalchemy.orm.exc import NoResultFound
from forms.accounts import AccountForm
from accountant import session_scope
from accountant import session_scope, session_aware
from . import auth
from .. import api
from .. import api, api_api
from ..models.accounts import Account
from ..models.entries import Entry
from ..models.operations import Operation
@api.route("/accounts", methods=["GET"])
@auth.login_required
def get_accounts():
"""
Returns accounts with their solds.
"""
with session_scope() as session:
query = Account.get_accounts(session)
return json.dumps([{
"id": i.id,
"name": i.name,
"authorized_overdraft": i.authorized_overdraft,
"current": str(i.current),
"pointed": str(i.pointed),
"future": str(i.future)
} for i in query.all()])
from ..fields import Object
@api.route("/accounts/<account_id>/<year>/<month>/")
@ -82,50 +68,114 @@ def get_months(account_id):
} for i in query.all()])
@api.route("/accounts", methods=["PUT"])
@auth.login_required
def add_account():
with session_scope() as session:
account = Account(request.json['name'],
request.json['authorized_overdraft'])
resource_fields = {
'id': fields.Integer,
'name': fields.String,
'authorized_overdraft': fields.Fixed(decimals=2),
'current': fields.Float,
'pointed': fields.Float,
'future': fields.Float,
}
parser = reqparse.RequestParser()
parser.add_argument('name', type=str, required=True)
parser.add_argument('authorized_overdraft', type=float, required=True)
class AccountListResource(Resource):
@session_aware
@marshal_with_field(fields.List(Object(resource_fields)))
def get(self, session=None):
"""
Returns accounts with their balances.
"""
return Account.get_accounts(session).all(), 200
def put(self):
"""
Batch update, not implemented.
"""
raise NotImplementedError()
@session_aware
@marshal_with_field(Object(resource_fields))
def post(self, session=None):
"""
Create a new account.
"""
kwargs = parser.parse_args()
account = Account(**kwargs)
session.add(account)
return json.dumps("Account added.")
return account, 201
def delete(self):
"""
Batch delete, not implemented.
"""
raise NotImplementedError()
@api.route("/accounts/<account_id>", methods=["PUT"])
@auth.login_required
def update_account(account_id):
class AccountResource(Resource):
@session_aware
@marshal_with_field(Object(resource_fields))
def get(self, account_id, session=None):
"""
Get account.
"""
try:
return Account.get(session, account_id)
except NoResultFound:
return None, 404
@session_aware
@marshal_with_field(Object(resource_fields))
def delete(self, account_id, session=None):
try:
account = Account.get(session, account_id)
except NoResultFound:
return None, 404
session.delete(account)
return account
def patch(self, id):
pass
@session_aware
@marshal_with_field(Object(resource_fields))
def put(self, account_id, session=None):
kwargs = parser.parse_args()
assert (id not in kwargs or kwargs.id is None
or kwargs.id == account_id)
account_form = AccountForm()
if account_form.validate():
with session_scope() as session:
account = session.query(Account).get(account_id)
try:
account = Account.get(session, account_id)
except NoResultFound:
return None, 404
account.name = request.json['name']
account.authorized_overdraft = request.json['authorized_overdraft']
# SQLAlchemy objects ignore __dict__.update() with merge.
for k, v in kwargs.items():
setattr(account, k, v)
session.merge(account)
return json.dumps("Account #%s updated." % account_id)
return account
else:
return json.dumps({
'ok': False,
'error_type': 'validation',
'errors': account_form.errorsi
'errors': account_form.errors
})
@api.route("/accounts/<account_id>", methods=["DELETE"])
@auth.login_required
def delete_account(account_id):
with session_scope() as session:
query = session.query(Account)
query = query.filter(Account.id == account_id)
account = query.first()
session.delete(account)
return json.dumps("Account #%s deleted." % account_id)
api_api.add_resource(AccountListResource, '/accounts')
api_api.add_resource(AccountResource, '/accounts/<int:account_id>')

View File

@ -14,15 +14,22 @@
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
"""
from flask import json, request
import dateutil.parser
from accountant import session_scope
from flask import json
from flask.ext.restful import Resource, fields, reqparse, marshal_with_field
from .. import api
from sqlalchemy.orm.exc import NoResultFound
from accountant import session_scope, session_aware
from .. import api, api_api
from ..models.entries import Entry
from ..models.operations import Operation
from ..fields import Object
@api.route("/entries/<account_id>/<year>/<month>")
def get_entries(account_id, year, month):
@ -47,48 +54,90 @@ def get_entries(account_id, year, month):
} for i in query.all()])
@api.route("/entries", methods=["PUT"])
def add_entry():
with session_scope() as session:
entry = Entry(
operation_date=request.json['operation_date'],
pointed=request.json['pointed'],
label=request.json['label'],
value=request.json['value'],
category=request.json['category'],
account_id=request.json['account_id'],
scheduled_operation_id=request.json['scheduled_operation_id']
)
resource_fields = {
# 'id': fields.Integer,
'operation_date': fields.DateTime(dt_format='iso8601'),
'label': fields.String,
'value': fields.Fixed(decimals=2),
'pointed': fields.Boolean,
'category': fields.String,
'account_id': fields.Integer,
'scheduled_operation_id': fields.Integer,
}
parser = reqparse.RequestParser()
# Must use lambda because the parser passes other parameters badly interpreted
# by dateutil.parser.parse
parser.add_argument('operation_date', type=lambda a: dateutil.parser.parse(a))
parser.add_argument('label', type=str)
parser.add_argument('value', type=float)
parser.add_argument('pointed', type=bool)
parser.add_argument('category', type=str)
parser.add_argument('account_id', type=int)
parser.add_argument('scheduled_operation_id', type=int)
class EntryListResource(Resource):
def put(self, *args):
return self.post()
@session_aware
@marshal_with_field(Object(resource_fields))
def post(self, session=None):
kwargs = parser.parse_args()
entry = Entry(**kwargs)
session.add(entry)
return json.dumps("Entry added.")
return entry
@api.route("/entries/<entry_id>", methods=["PUT"])
def update_entry(entry_id):
with session_scope() as session:
entry = session.query(Entry).get(entry_id)
class EntryResource(Resource):
@session_aware
@marshal_with_field(Object(resource_fields))
def get(self, entry_id, session=None):
"""
Get entry.
"""
try:
return Entry.get(session, entry_id)
except NoResultFound:
return None, 404
entry.id = entry_id
entry.operation_date = request.json['operation_date']
entry.pointed = request.json['pointed']
entry.label = request.json['label']
entry.value = request.json['value']
entry.category = request.json['category']
entry.account_id = request.json['account_id']
entry.scheduled_operation_id = request.json['scheduled_operation_id']
@session_aware
@marshal_with_field(Object(resource_fields))
def put(self, entry_id, session=None):
kwargs = parser.parse_args()
assert (id not in kwargs or kwargs.id is None
or kwargs.id == entry_id)
try:
entry = Entry.get(session, entry_id)
except NoResultFound:
return None, 404
# SQLAlchemy objects ignore __dict__.update() with merge.
for k, v in kwargs.items():
setattr(entry, k, v)
session.merge(entry)
return json.dumps("Entry #%s updated." % entry_id)
return entry
@api.route("/entries/<entry_id>", methods=["DELETE"])
def delete_entry(entry_id):
with session_scope() as session:
entry = session.query(Entry).filter(Entry.id == entry_id).first()
@session_aware
@marshal_with_field(Object(resource_fields))
def delete(self, entry_id, session=None):
try:
entry = Entry.get(session, entry_id)
except NoResultFound:
return None, 404
session.delete(entry)
return json.dumps("Entry #%s deleted." % entry_id)
return entry
api_api.add_resource(EntryListResource, "/entries")
api_api.add_resource(EntryResource, "/entries/<int:entry_id>")

View File

@ -14,16 +14,23 @@
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
"""
from flask import json, request
import dateutil.parser
from accountant import session_scope
from flask import json, request
from flask.ext.restful import Resource, fields, reqparse, marshal_with_field
from sqlalchemy.orm.exc import NoResultFound
from accountant import session_scope, session_aware
from ..models.scheduled_operations import ScheduledOperation
from .. import api
from .. import api, api_api
from ..fields import Object
@api.route("/scheduled_operations/<account_id>")
@api.route("/scheduled_operations/<int:account_id>")
def get_scheduled_operations(account_id):
"""
Return entries for an account, year, and month.
@ -45,57 +52,94 @@ def get_scheduled_operations(account_id):
} for i in query.all()])
@api.route("/scheduled_operations", methods=["PUT"])
def add_scheduled_operation():
with session_scope() as session:
scheduledOperation = ScheduledOperation(
start_date=request.json['start_date'],
stop_date=request.json['stop_date'],
day=request.json['day'],
frequency=request.json['frequency'],
label=request.json['label'],
value=request.json['value'],
category=request.json['category'],
account_id=request.json['account_id']
)
resource_fields = {
'id': fields.Integer,
'start_date': fields.DateTime(dt_format='iso8601'),
'stop_date': fields.DateTime(dt_format='iso8601'),
'day': fields.Integer,
'frequency': fields.Integer,
'label': fields.String,
'value': fields.Fixed(decimals=2),
'category': fields.String,
'account_id': fields.Integer,
}
parser = reqparse.RequestParser()
parser.add_argument('start_date', type=lambda a: dateutil.parser.parse(a))
parser.add_argument('stop_date', type=lambda a: dateutil.parser.parse(a))
parser.add_argument('day', type=int)
parser.add_argument('frequency', type=int)
parser.add_argument('label', type=str)
parser.add_argument('value', type=float)
parser.add_argument('category', type=str)
parser.add_argument('account_id', type=int)
class ScheduledOperationListResource(Resource):
@session_aware
@marshal_with_field(Object(resource_fields))
def put(self, session=None):
"""
Add a new scheduled operation.
"""
kwargs = parser.parse_args()
scheduledOperation = ScheduledOperation(**kwargs)
session.add(scheduledOperation)
return json.dumps("Scheduled operation added.")
return scheduledOperation, 201
@api.route("/scheduled_operations/<scheduled_operation_id>", methods=["PUT"])
def update_scheduled_operation(scheduled_operation_id):
with session_scope() as session:
query = session.query(ScheduledOperation)
query = query.filter(ScheduledOperation.id == scheduled_operation_id)
class ScheduledOperationResource(Resource):
@session_aware
@marshal_with_field(Object(resource_fields))
def get(self, scheduled_operation_id, session=None):
"""
Get scheduled operation.
"""
try:
return ScheduledOperation.get(session, scheduled_operation_id)
except NoResultFound:
return None, 404
scheduledOperation = query.first()
@session_aware
@marshal_with_field(Object(resource_fields))
def delete(self, scheduled_operation_id, session=None):
try:
scheduled_operation = ScheduledOperation.get(
session, scheduled_operation_id)
except NoResultFound:
return None, 404
scheduledOperation.id = scheduled_operation_id
scheduledOperation.start_date = request.json['start_date'],
scheduledOperation.stop_date = request.json['stop_date'],
scheduledOperation.day = request.json['day'],
scheduledOperation.frequency = request.json['frequency'],
scheduledOperation.label = request.json['label']
scheduledOperation.value = request.json['value']
scheduledOperation.category = request.json['category']
scheduledOperation.account_id = request.json['account_id']
session.delete(scheduled_operation)
session.merge(scheduledOperation)
return scheduled_operation
return json.dumps(
"Scheduled operation #%s updated." % scheduled_operation_id)
@session_aware
@marshal_with_field(Object(resource_fields))
def put(self, scheduled_operation_id, session=None):
kwargs = parser.parse_args()
assert (id not in kwargs or kwargs.id is None
or kwargs.id == scheduled_operation_id)
try:
scheduled_operation = ScheduledOperation.get(
session, scheduled_operation_id)
except NoResultFound:
return None, 404
# SQLAlchemy objects ignore __dict__.update() with merge.
for k, v in kwargs.items():
setattr(scheduled_operation, k, v)
session.merge(scheduled_operation)
return scheduled_operation
@api.route("/scheduled_operations/<scheduled_operation_id>", methods=["DELETE"])
def delete_scheduled_operation(scheduled_operation_id):
with session_scope() as session:
query = session.query(ScheduledOperation)
query = query.filter(ScheduledOperation.id == scheduled_operation_id)
scheduledOperation = query.first()
session.delete(scheduledOperation)
return json.dumps(
"Scheduled operation #%s deleted." % scheduled_operation_id)
api_api.add_resource(ScheduledOperationListResource, "/scheduled_operations")
api_api.add_resource(ScheduledOperationResource,
"/scheduled_operations/<int:scheduled_operation_id>")