Rewrote views with Restful resources.
This commit is contained in:
parent
c62941a704
commit
be1bba3bc8
@ -15,36 +15,22 @@
|
|||||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
from flask import json, request
|
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 forms.accounts import AccountForm
|
||||||
|
|
||||||
from accountant import session_scope
|
from accountant import session_scope, session_aware
|
||||||
|
|
||||||
from . import auth
|
from . import auth
|
||||||
from .. import api
|
from .. import api, api_api
|
||||||
|
|
||||||
from ..models.accounts import Account
|
from ..models.accounts import Account
|
||||||
from ..models.entries import Entry
|
from ..models.entries import Entry
|
||||||
from ..models.operations import Operation
|
from ..models.operations import Operation
|
||||||
|
|
||||||
|
from ..fields import Object
|
||||||
@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()])
|
|
||||||
|
|
||||||
|
|
||||||
@api.route("/accounts/<account_id>/<year>/<month>/")
|
@api.route("/accounts/<account_id>/<year>/<month>/")
|
||||||
@ -82,50 +68,114 @@ def get_months(account_id):
|
|||||||
} for i in query.all()])
|
} for i in query.all()])
|
||||||
|
|
||||||
|
|
||||||
@api.route("/accounts", methods=["PUT"])
|
resource_fields = {
|
||||||
@auth.login_required
|
'id': fields.Integer,
|
||||||
def add_account():
|
'name': fields.String,
|
||||||
with session_scope() as session:
|
'authorized_overdraft': fields.Fixed(decimals=2),
|
||||||
account = Account(request.json['name'],
|
'current': fields.Float,
|
||||||
request.json['authorized_overdraft'])
|
'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)
|
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"])
|
class AccountResource(Resource):
|
||||||
@auth.login_required
|
@session_aware
|
||||||
def update_account(account_id):
|
@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()
|
account_form = AccountForm()
|
||||||
|
|
||||||
if account_form.validate():
|
if account_form.validate():
|
||||||
with session_scope() as session:
|
try:
|
||||||
account = session.query(Account).get(account_id)
|
account = Account.get(session, account_id)
|
||||||
|
except NoResultFound:
|
||||||
|
return None, 404
|
||||||
|
|
||||||
account.name = request.json['name']
|
# SQLAlchemy objects ignore __dict__.update() with merge.
|
||||||
account.authorized_overdraft = request.json['authorized_overdraft']
|
for k, v in kwargs.items():
|
||||||
|
setattr(account, k, v)
|
||||||
|
|
||||||
session.merge(account)
|
session.merge(account)
|
||||||
|
|
||||||
return json.dumps("Account #%s updated." % account_id)
|
return account
|
||||||
else:
|
else:
|
||||||
return json.dumps({
|
return json.dumps({
|
||||||
'ok': False,
|
'ok': False,
|
||||||
'error_type': 'validation',
|
'error_type': 'validation',
|
||||||
'errors': account_form.errorsi
|
'errors': account_form.errors
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@api.route("/accounts/<account_id>", methods=["DELETE"])
|
api_api.add_resource(AccountListResource, '/accounts')
|
||||||
@auth.login_required
|
api_api.add_resource(AccountResource, '/accounts/<int:account_id>')
|
||||||
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)
|
|
||||||
|
@ -14,15 +14,22 @@
|
|||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
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.entries import Entry
|
||||||
from ..models.operations import Operation
|
from ..models.operations import Operation
|
||||||
|
|
||||||
|
from ..fields import Object
|
||||||
|
|
||||||
|
|
||||||
@api.route("/entries/<account_id>/<year>/<month>")
|
@api.route("/entries/<account_id>/<year>/<month>")
|
||||||
def get_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()])
|
} for i in query.all()])
|
||||||
|
|
||||||
|
|
||||||
@api.route("/entries", methods=["PUT"])
|
resource_fields = {
|
||||||
def add_entry():
|
# 'id': fields.Integer,
|
||||||
with session_scope() as session:
|
'operation_date': fields.DateTime(dt_format='iso8601'),
|
||||||
entry = Entry(
|
'label': fields.String,
|
||||||
operation_date=request.json['operation_date'],
|
'value': fields.Fixed(decimals=2),
|
||||||
pointed=request.json['pointed'],
|
'pointed': fields.Boolean,
|
||||||
label=request.json['label'],
|
'category': fields.String,
|
||||||
value=request.json['value'],
|
'account_id': fields.Integer,
|
||||||
category=request.json['category'],
|
'scheduled_operation_id': fields.Integer,
|
||||||
account_id=request.json['account_id'],
|
}
|
||||||
scheduled_operation_id=request.json['scheduled_operation_id']
|
|
||||||
)
|
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)
|
session.add(entry)
|
||||||
|
|
||||||
return json.dumps("Entry added.")
|
return entry
|
||||||
|
|
||||||
|
|
||||||
@api.route("/entries/<entry_id>", methods=["PUT"])
|
class EntryResource(Resource):
|
||||||
def update_entry(entry_id):
|
@session_aware
|
||||||
with session_scope() as session:
|
@marshal_with_field(Object(resource_fields))
|
||||||
entry = session.query(Entry).get(entry_id)
|
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
|
@session_aware
|
||||||
entry.operation_date = request.json['operation_date']
|
@marshal_with_field(Object(resource_fields))
|
||||||
entry.pointed = request.json['pointed']
|
def put(self, entry_id, session=None):
|
||||||
entry.label = request.json['label']
|
kwargs = parser.parse_args()
|
||||||
entry.value = request.json['value']
|
|
||||||
entry.category = request.json['category']
|
assert (id not in kwargs or kwargs.id is None
|
||||||
entry.account_id = request.json['account_id']
|
or kwargs.id == entry_id)
|
||||||
entry.scheduled_operation_id = request.json['scheduled_operation_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)
|
session.merge(entry)
|
||||||
|
|
||||||
return json.dumps("Entry #%s updated." % entry_id)
|
return entry
|
||||||
|
|
||||||
|
@session_aware
|
||||||
@api.route("/entries/<entry_id>", methods=["DELETE"])
|
@marshal_with_field(Object(resource_fields))
|
||||||
def delete_entry(entry_id):
|
def delete(self, entry_id, session=None):
|
||||||
with session_scope() as session:
|
try:
|
||||||
entry = session.query(Entry).filter(Entry.id == entry_id).first()
|
entry = Entry.get(session, entry_id)
|
||||||
|
except NoResultFound:
|
||||||
|
return None, 404
|
||||||
|
|
||||||
session.delete(entry)
|
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>")
|
||||||
|
@ -14,16 +14,23 @@
|
|||||||
You should have received a copy of the GNU Affero General Public License
|
You should have received a copy of the GNU Affero General Public License
|
||||||
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
|
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 ..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):
|
def get_scheduled_operations(account_id):
|
||||||
"""
|
"""
|
||||||
Return entries for an account, year, and month.
|
Return entries for an account, year, and month.
|
||||||
@ -45,57 +52,94 @@ def get_scheduled_operations(account_id):
|
|||||||
} for i in query.all()])
|
} for i in query.all()])
|
||||||
|
|
||||||
|
|
||||||
@api.route("/scheduled_operations", methods=["PUT"])
|
resource_fields = {
|
||||||
def add_scheduled_operation():
|
'id': fields.Integer,
|
||||||
with session_scope() as session:
|
'start_date': fields.DateTime(dt_format='iso8601'),
|
||||||
scheduledOperation = ScheduledOperation(
|
'stop_date': fields.DateTime(dt_format='iso8601'),
|
||||||
start_date=request.json['start_date'],
|
'day': fields.Integer,
|
||||||
stop_date=request.json['stop_date'],
|
'frequency': fields.Integer,
|
||||||
day=request.json['day'],
|
'label': fields.String,
|
||||||
frequency=request.json['frequency'],
|
'value': fields.Fixed(decimals=2),
|
||||||
label=request.json['label'],
|
'category': fields.String,
|
||||||
value=request.json['value'],
|
'account_id': fields.Integer,
|
||||||
category=request.json['category'],
|
}
|
||||||
account_id=request.json['account_id']
|
|
||||||
)
|
|
||||||
|
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)
|
session.add(scheduledOperation)
|
||||||
|
|
||||||
return json.dumps("Scheduled operation added.")
|
return scheduledOperation, 201
|
||||||
|
|
||||||
|
|
||||||
@api.route("/scheduled_operations/<scheduled_operation_id>", methods=["PUT"])
|
class ScheduledOperationResource(Resource):
|
||||||
def update_scheduled_operation(scheduled_operation_id):
|
@session_aware
|
||||||
with session_scope() as session:
|
@marshal_with_field(Object(resource_fields))
|
||||||
query = session.query(ScheduledOperation)
|
def get(self, scheduled_operation_id, session=None):
|
||||||
query = query.filter(ScheduledOperation.id == scheduled_operation_id)
|
"""
|
||||||
|
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
|
session.delete(scheduled_operation)
|
||||||
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.merge(scheduledOperation)
|
return scheduled_operation
|
||||||
|
|
||||||
return json.dumps(
|
@session_aware
|
||||||
"Scheduled operation #%s updated." % scheduled_operation_id)
|
@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"])
|
api_api.add_resource(ScheduledOperationListResource, "/scheduled_operations")
|
||||||
def delete_scheduled_operation(scheduled_operation_id):
|
api_api.add_resource(ScheduledOperationResource,
|
||||||
with session_scope() as session:
|
"/scheduled_operations/<int:scheduled_operation_id>")
|
||||||
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)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user