Exemplo n.º 1
0
    def get(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

            # format trip data
            output = GqlEncoder().encode(trip)

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append(
                {"message": "You are not authorized to view that trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        if len(errors) > 0:
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 2
0
    def get(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

            # format trip data
            output = GqlEncoder().encode(trip)

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append({"message": "You are not authorized to view that trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        if len(errors) > 0:
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 3
0
    def delete(self, trip_key, expense_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the expense
            expense = Expense.get(expense_key)

            # verify the user is authorized to delete the expense
            authz.deleteExpense(expense)

            # delete the expense
            expense.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError:
            errors.append({"message": "You are not authorized to delete that expense"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete expense"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 4
0
    def delete(self, trip_key, expense_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the expense
            expense = Expense.get(expense_key)

            # verify the user is authorized to delete the expense
            authz.deleteExpense(expense)

            # delete the expense
            expense.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError:
            errors.append(
                {"message": "You are not authorized to delete that expense"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete expense"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 5
0
    def get(self, trip_key, expense_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # first, verify they have access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append(
                {"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # this is a read of an existing expense
        # instead of directly authorizing the read of an expense, we
        # ensure that the expense is tied to the specified trip
        try:
            # get the expense
            expense = Expense.get(expense_key)

            # ensure the expense belongs to the trip
            if expense.parent_key() != trip.key():
                raise PermissionError("Expense is not tied to that trip")

            # format expense data
            output = GqlEncoder().encode(expense)

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError as e:
            errors.append({"message": e.args})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 6
0
    def get(self, trip_key, expense_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # first, verify they have access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append({"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # this is a read of an existing expense
        # instead of directly authorizing the read of an expense, we
        # ensure that the expense is tied to the specified trip
        try:
            # get the expense
            expense = Expense.get(expense_key)

            # ensure the expense belongs to the trip
            if expense.parent_key() != trip.key():
                raise PermissionError("Expense is not tied to that trip")

            # format expense data
            output = GqlEncoder().encode(expense)

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError as e:
            errors.append({"message": e.args})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 7
0
    def get(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # verify access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append(
                {"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # next, get the list of expenses
        try:
            expenses = Expense.all()
            expenses.ancestor(trip)
            output = GqlEncoder().encode(expenses.fetch(limit=200))
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error listing expenses"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"errors": errors})

        self.response.headers["Content-type"] = "application/json"
        self.response.out.write(output)
Exemplo n.º 8
0
    def get(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # verify access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append({"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # next, get the list of expenses
        try:
            expenses = Expense.all()
            expenses.ancestor(trip)
            output = GqlEncoder().encode(expenses.fetch(limit=200))
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error listing expenses"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"errors": errors})

        self.response.headers["Content-type"] = "application/json"
        self.response.out.write(output)
Exemplo n.º 9
0
    def delete(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to delete the trip
            authz.deleteTrip(trip)

            # delete related expenses
            try:
                expenses = Expense.all()
                expenses.ancestor(trip)
                expenses.fetch(limit=200)
                db.delete(expenses)
            except Exception as e:
                logging.exception(e)
                errors.append({
                    "message":
                    "Unexpected error deleting associated expenses"
                })

            # delete the trip
            trip.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append(
                {"message": "You are not authorized to delete that trip"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 10
0
    def delete(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to delete the trip
            authz.deleteTrip(trip)

            # delete related expenses
            try:
                expenses = Expense.all()
                expenses.ancestor(trip)
                expenses.fetch(limit=200)
                db.delete(expenses)
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error deleting associated expenses"})

            # delete the trip
            trip.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append({"message": "You are not authorized to delete that trip"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 11
0
    def get(self):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the list of trips to show the user
            trips = authz.listTrips()

            # return trips to the user
            output = GqlEncoder().encode(trips)
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error listing trips"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 12
0
    def get(self):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the list of trips to show the user
            trips = authz.listTrips()

            # return trips to the user
            output = GqlEncoder().encode(trips)
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error listing trips"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 13
0
    def post(self):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # check for authorization to create new trips & verify this is in fact
        # a request to create a new trip
        try:
            # user allowed to create trips?
            authz.createTrip()

        except PermissionError as e:
            # this permission error could have come from authz or locally
            errors.append({"message": e.args})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # user is allowed, so go ahead and try to create this thing
        #logging.debug(self.request.body)

        data = TripUnpacker().unpack_post(self.request)
        #logging.debug(data)

        if data['name'] == "" or data['password'] == "":
            errors.append({"message": "Trip name and password are required."})
        else:
            try:
                trip = Trip(name=data['name'],
                            password=data['password'],
                            owner=user)

                # get traveler names
                raw_travelers = data['travelers']
                if len(raw_travelers) > Config.limits.travelers_per_trip:
                    logging.warning('Attempt to add too many travelers: %s',
                                    user.nickname)
                    raw_travelers = raw_travelers[:Config.limits.
                                                  travelers_per_trip]
                travelers = []
                for traveler in raw_travelers:
                    if traveler.strip() != "":
                        travelers.append(traveler.strip())
                trip.travelers = travelers

                # get dates
                # TODO: validation that these dates are sane and properly ordered
                start_date = dateparse(data['start_date'])
                end_date = dateparse(data['end_date'])
                trip.start_date = start_date.date()
                #logging.debug("start date = " + str(start_date.date()))
                trip.end_date = end_date.date()
                #logging.debug("end date = " + str(end_date.date()))

                trip.put()

                output = GqlEncoder().encode({
                    "id": "%s" % trip.key(),
                    'modify_date': trip.modify_date,
                    'start_date': trip.start_date,
                    'end_date': trip.end_date,
                })
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error creating trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 14
0
    def post(self, trip_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # check for authorization to create expenses for this trip & verify this
        # is in fact a request to create a new expense
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to create an expense on this trip
            authz.createExpense(trip)

        except PermissionError as e:
            # this permission error could have come from authz or locally
            errors.append({"message": e.args})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # having passed authz, let's try creating the expense
        data = ExpenseUnpacker().unpack_post(self.request)

        if data['description'] == "" or data['value'] == "" or data[
                'payer'] == "":
            errors.append(
                {"message": "Description, value, and payer are required."})
        elif len(data['travelers']) == 0:
            errors.append({
                "message":
                "At least one person must be specified as a traveler."
            })
        else:
            try:
                expense = Expense(
                    parent=trip.key(),
                    creator=user,
                    description=data['description'],
                    value=int(data['value']),
                    currency="USD",
                )

                # get the expense date
                expense_date = dateparse(data['expense_date'])
                expense.expense_date = expense_date.date()

                # TODO: make sure these travelers are actually on the trip
                expense.travelers = data['travelers']

                # TODO: ensure the payer is actually a traveler
                expense.payer = data['payer']

                expense.put()

                output = GqlEncoder().encode({
                    "id": "%s" % expense.key(),
                    'modify_date': expense.modify_date,
                    'expense_date': expense.expense_date,
                    'value': expense.value,
                })
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error creating expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 15
0
    def put(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to update the trip
            authz.updateTrip(trip)

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append(
                {"message": "You are not authorized to view that trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # now that we know the user is authorized, perform the update
        logging.debug(self.request.body)
        try:
            data = TripUnpacker().unpack_put(self.request)
            logging.debug(data)

            properties = ('name', 'password', 'start_date', 'end_date',
                          'travelers')
            for prop in properties:
                if prop in data:
                    # TODO: validate the data (for instance, dates will almost
                    #       certainly fail without some scrubbing)
                    scrubbed = self._scrub(prop, data[prop])
                    setattr(trip, prop, scrubbed)

            trip.put()

            # per the Backbone documentation, this method needs to:
            #   "[w]hen returning a JSON response, send down the attributes of
            #   the model that have been changed by the server, and need to be
            #   updated on the client"
            # Dates need to be shown because their formatting can change
            output = GqlEncoder().encode({
                'modify_date': trip.modify_date,
                'start_date': trip.start_date,
                'end_date': trip.end_date,
            })

        except NotImplementedError as e:
            errors.append({"message": e.args})
        except db.BadValueError as e:
            errors.append({"message": e.args})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error updating trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 16
0
    def put(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to update the trip
            authz.updateTrip(trip)

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append({"message": "You are not authorized to view that trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # now that we know the user is authorized, perform the update
        logging.debug(self.request.body)
        try:
            data = TripUnpacker().unpack_put(self.request)
            logging.debug(data)

            properties = ("name", "password", "start_date", "end_date", "travelers")
            for prop in properties:
                if prop in data:
                    # TODO: validate the data (for instance, dates will almost
                    #       certainly fail without some scrubbing)
                    scrubbed = self._scrub(prop, data[prop])
                    setattr(trip, prop, scrubbed)

            trip.put()

            # per the Backbone documentation, this method needs to:
            #   "[w]hen returning a JSON response, send down the attributes of
            #   the model that have been changed by the server, and need to be
            #   updated on the client"
            # Dates need to be shown because their formatting can change
            output = GqlEncoder().encode(
                {"modify_date": trip.modify_date, "start_date": trip.start_date, "end_date": trip.end_date}
            )

        except NotImplementedError as e:
            errors.append({"message": e.args})
        except db.BadValueError as e:
            errors.append({"message": e.args})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error updating trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 17
0
    def post(self):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # check for authorization to create new trips & verify this is in fact
        # a request to create a new trip
        try:
            # user allowed to create trips?
            authz.createTrip()

        except PermissionError as e:
            # this permission error could have come from authz or locally
            errors.append({"message": e.args})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # user is allowed, so go ahead and try to create this thing
        # logging.debug(self.request.body)

        data = TripUnpacker().unpack_post(self.request)
        # logging.debug(data)

        if data["name"] == "" or data["password"] == "":
            errors.append({"message": "Trip name and password are required."})
        else:
            try:
                trip = Trip(name=data["name"], password=data["password"], owner=user)

                # get traveler names
                raw_travelers = data["travelers"]
                if len(raw_travelers) > Config.limits.travelers_per_trip:
                    logging.warning("Attempt to add too many travelers: %s", user.nickname)
                    raw_travelers = raw_travelers[: Config.limits.travelers_per_trip]
                travelers = []
                for traveler in raw_travelers:
                    if traveler.strip() != "":
                        travelers.append(traveler.strip())
                trip.travelers = travelers

                # get dates
                # TODO: validation that these dates are sane and properly ordered
                start_date = dateparse(data["start_date"])
                end_date = dateparse(data["end_date"])
                trip.start_date = start_date.date()
                # logging.debug("start date = " + str(start_date.date()))
                trip.end_date = end_date.date()
                # logging.debug("end date = " + str(end_date.date()))

                trip.put()

                output = GqlEncoder().encode(
                    {
                        "id": "%s" % trip.key(),
                        "modify_date": trip.modify_date,
                        "start_date": trip.start_date,
                        "end_date": trip.end_date,
                    }
                )
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error creating trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Exemplo n.º 18
0
    def post(self, trip_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # check for authorization to create expenses for this trip & verify this
        # is in fact a request to create a new expense
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to create an expense on this trip
            authz.createExpense(trip)

        except PermissionError as e:
            # this permission error could have come from authz or locally
            errors.append({"message": e.args})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # having passed authz, let's try creating the expense
        data = ExpenseUnpacker().unpack_post(self.request)

        if data["description"] == "" or data["value"] == "" or data["payer"] == "":
            errors.append({"message": "Description, value, and payer are required."})
        elif len(data["travelers"]) == 0:
            errors.append({"message": "At least one person must be specified as a traveler."})
        else:
            try:
                expense = Expense(
                    parent=trip.key(),
                    creator=user,
                    description=data["description"],
                    value=int(data["value"]),
                    currency="USD",
                )

                # get the expense date
                expense_date = dateparse(data["expense_date"])
                expense.expense_date = expense_date.date()

                # TODO: make sure these travelers are actually on the trip
                expense.travelers = data["travelers"]

                # TODO: ensure the payer is actually a traveler
                expense.payer = data["payer"]

                expense.put()

                output = GqlEncoder().encode(
                    {
                        "id": "%s" % expense.key(),
                        "modify_date": expense.modify_date,
                        "expense_date": expense.expense_date,
                        "value": expense.value,
                    }
                )
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error creating expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)