Ejemplo n.º 1
0
class IssueView(BaseView):
    """
    Gets an issue by its id
    """

    url = "/issues/{id}"
    with_issue = match_getter(get_issue, "issue", iid="id")

    @with_issue
    @docs(summary="Get An Issue")
    @returns(JSendSchema.of(issue=IssueSchema()))
    async def get(self, issue):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {"issue": issue.serialize(self.request.app.router)}
        }

    @with_issue
    @docs(summary="Modify An Issue")
    @expects(IssueUpdateSchema())
    @returns(JSendSchema.of(issue=IssueSchema()))
    async def patch(self, issue):
        issue = await update_issue(
            issue,
            self.request["data"].get("status"),
            self.request["data"].get("resolution", None)
        )

        return {
            "status": JSendStatus.SUCCESS,
            "data": {"issue": issue.serialize(self.request.app.router)}
        }
Ejemplo n.º 2
0
class PickupReservationsView(BaseView):
    """
    Gets or adds to a pickup point's list of reservations.
    """
    url = f"/pickups/{{id:{PICKUP_IDENTIFIER_REGEX}}}/reservations"
    with_user = match_getter(get_user, "user", firebase_id=GetFrom.AUTH_HEADER)
    with_pickup = match_getter(get_pickup_point, "pickup", pickup_id="id")

    @with_user
    @docs(summary="Get All Reservations For Pickup Point")
    @requires(UserIsAdmin())
    @returns(JSendSchema.of(reservations=Many(ReservationSchema())))
    async def get(self, user):
        reservation_ids = self.reservation_manager.reservations_in(
            self.request.match_info["id"])
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "reservations": [
                    reservation.serialize(self.request.app.router,
                                          self.reservation_manager)
                    for reservation in await get_reservations(*reservation_ids)
                ]
            }
        }

    @with_pickup
    @with_user
    @docs(summary="Create Reservation At Pickup Point")
    @expects(CreateReservationSchema())
    @returns(error=JSendSchema(),
             success=JSendSchema.of(reservation=ReservationSchema()))
    async def post(self, user, pickup):
        """
        To claim a reservation, simply rent a bike from the same pickup point as you usually
        would do. This will automatically claim that bike for you, ending your reservation,
        and starting your rental.
        """
        time = self.request["data"]["reserved_for"]
        try:
            reservation = await self.reservation_manager.reserve(
                user, pickup, time)
        except ReservationError as e:
            return "error", {
                "status": JSendStatus.FAIL,
                "data": {
                    "message": str(e)
                }
            }
        else:
            return "success", {
                "status": JSendStatus.SUCCESS,
                "data": {
                    "reservation":
                    reservation.serialize(self.request.app.router,
                                          self.reservation_manager)
                }
            }
Ejemplo n.º 3
0
class BikesView(BaseView):
    """
    Gets the bikes, or adds a new bike.
    """
    url = "/bikes"
    with_user = match_getter(get_user,
                             Optional("user"),
                             firebase_id=Optional(GetFrom.AUTH_HEADER))

    @with_user
    @docs(summary="Get All Bikes")
    @returns(JSendSchema.of(bikes=Many(BikeSchema(exclude=("public_key", )))))
    async def get(self, user):
        """Gets all the bikes from the system."""
        bikes = [
            bike.serialize(self.bike_connection_manager,
                           self.rental_manager,
                           self.reservation_manager,
                           include_location=user is not None
                           and user.type is not UserType.USER)
            for bike in await get_bikes()
        ]

        if self.request.query.get("available") == "true":
            bikes = (bike for bike in bikes if bike["status"] == "available")

        return {"status": JSendStatus.SUCCESS, "data": {"bikes": bikes}}

    @docs(summary="Register New Bike")
    @expects(BikeRegisterSchema())
    @returns(bad_key=(JSendSchema(), web.HTTPBadRequest),
             registered=JSendSchema.of(bike=BikeSchema(only=('identifier',
                                                             'available'))))
    async def post(self):
        """ Registers a bike with the system."""
        try:
            bike = await register_bike(self.request["data"]["public_key"],
                                       self.request["data"]["master_key"])
        except BadKeyError as error:
            return "bad_key", {
                "status": JSendStatus.FAIL,
                "data": {
                    "message": "The supplied master key is invalid.",
                    "errors": error.args
                },
            }
        else:
            return "registered", {
                "status": JSendStatus.SUCCESS,
                "data": {
                    "bike":
                    bike.serialize(self.bike_connection_manager,
                                   self.rental_manager,
                                   self.reservation_manager)
                }
            }
Ejemplo n.º 4
0
class UserIssuesView(BaseView):
    """
    Gets or adds to the users' list of issues.
    """
    url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/issues"
    name = "user_issues"
    with_issues = match_getter(get_issues, "issues", user='******')
    with_user = match_getter(get_user, 'user', user_id='id')

    @with_user
    @with_issues
    @docs(summary="Get All Issues For User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @returns(JSendSchema.of(issues=Many(IssueSchema())))
    async def get(self, user, issues):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "issues":
                [issue.serialize(self.request.app.router) for issue in issues]
            }
        }

    @with_user
    @docs(summary="Open Issue For User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @expects(IssueSchema(only=('description', 'bike_identifier')))
    @returns(
        JSendSchema.of(issue=IssueSchema(only=('id', 'user_id', 'user_url',
                                               'bike_identifier',
                                               'description', 'opened_at'))))
    async def post(self, user):
        issue_data = {
            "description": self.request["data"]["description"],
            "user": user
        }

        if "bike_identifier" in self.request["data"]:
            issue_data["bike"] = await get_bike(
                identifier=self.request["data"]["bike_identifier"])

        issue = await open_issue(**issue_data)

        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "issue": issue.serialize(self.request.app.router)
            }
        }
Ejemplo n.º 5
0
 async def test_expects_no_data(self, client: TestClient):
     """Assert that trying to register a bike with no data fails."""
     resp = await client.post('/api/v1/bikes')
     data = JSendSchema().load(await resp.json())
     assert "only accepts JSON" in data["data"]["message"]
     assert data["status"] == JSendStatus.FAIL
     assert "schema" in data["data"]
Ejemplo n.º 6
0
class UserCurrentReservationView(BaseView):
    """
    Gets the users' current reservation.
    """
    url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/reservations/current"

    with_reservation = match_getter(current_reservations,
                                    "reservations",
                                    user="******")
    with_user = match_getter(get_user, "user", user_id="id")

    @with_user
    @with_reservation
    @docs(summary="Get Current Reservations For User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @returns(JSendSchema.of(reservations=Many(CurrentReservationSchema())))
    async def get(self, user, reservations: List[Reservation]):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "reservations": [
                    reservation.serialize(self.request.app.router,
                                          self.reservation_manager)
                    for reservation in reservations
                ]
            }
        }
Ejemplo n.º 7
0
class RentalsView(BaseView):
    """
    Gets a list of all rentals.
    """
    url = "/rentals"
    name = "rentals"
    with_user = match_getter(get_user, 'user', firebase_id=GetFrom.AUTH_HEADER)

    @with_user
    @docs(summary="Get All Rentals")
    @requires(UserIsAdmin())
    @returns(
        JSendSchema.of(rentals=Many(
            RentalSchema(only=("id", "user_id", "user_url", "bike_identifier",
                               "bike_url", "start_time", "is_active")))))
    async def get(self, user):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "rentals": [
                    await rental.serialize(self.rental_manager,
                                           self.bike_connection_manager,
                                           self.reservation_manager,
                                           self.request.app.router)
                    for rental in await get_rentals()
                ]
            }
        }
Ejemplo n.º 8
0
class RentalView(BaseView):
    """
    Gets or updates a single rental.
    """
    url = "/rentals/{id}"
    name = "rental"
    with_rental = match_getter(get_rental_with_distance,
                               'rental',
                               Optional('distance'),
                               rental='id')
    with_user = match_getter(get_user, 'user', firebase_id=GetFrom.AUTH_HEADER)

    @with_rental
    @with_user
    @docs(summary="Get A Rental")
    @requires(UserIsAdmin())
    @returns(
        JSendSchema.of(rental=RentalSchema(only=("id", "user_id", "user_url",
                                                 "bike_identifier", "bike_url",
                                                 "start_time", "is_active",
                                                 "distance"))))
    async def get(self, rental: Rental, user, distance: float):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "rental":
                await rental.serialize(self.rental_manager,
                                       self.bike_connection_manager,
                                       self.reservation_manager,
                                       self.request.app.router,
                                       distance=distance)
            }
        }
Ejemplo n.º 9
0
    async def test_get_pickups(self, client, random_pickup_point):
        resp = await client.get('/api/v1/pickups')

        schema = JSendSchema.of(pickups=Many(PickupPointSchema()))
        data = schema.load(await resp.json())

        assert data["status"] == JSendStatus.SUCCESS
Ejemplo n.º 10
0
class UserRentalsView(BaseView):
    """
    Gets or adds to the users list of rentals.
    """
    url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/rentals"
    name = "user_rentals"
    with_user = match_getter(get_user, 'user', user_id='id')
    with_rentals = match_getter(get_rentals, 'rentals', user='******')

    @with_user
    @with_rentals
    @docs(summary="Get All Rentals For User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @returns(JSendSchema.of(rentals=Many(RentalSchema())))
    async def get(self, user, rentals: List[Rental]):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "rentals": [
                    await rental.serialize(self.rental_manager,
                                           self.request.app.router)
                    for rental in rentals
                ]
            }
        }
Ejemplo n.º 11
0
class ClosestBikeView(BaseView):
    """
    Gets or updates a single bike.
    """
    url = f"/bikes/closest"
    name = "closest_bike"

    @docs(summary="Get The Closest Bike")
    @returns(
        JSendSchema.of(bike=BikeSchema(exclude=("public_key", )),
                       distance=Float()))
    async def get(self):
        """Gets a single bike by its id."""
        lat = self.request.query["lat"]
        long = self.request.query["lng"]
        user_location = Point(float(long), float(lat))
        bike, distance = await self.bike_connection_manager.closest_available_bike(
            user_location, self.rental_manager, self.reservation_manager)

        if bike is None:
            raise web.HTTPNotFound
        else:
            return {
                "status": JSendStatus.SUCCESS,
                "data": {
                    "bike":
                    bike.serialize(self.bike_connection_manager,
                                   self.rental_manager,
                                   self.reservation_manager),
                    "distance":
                    distance
                }
            }
Ejemplo n.º 12
0
class LowBikesView(BaseView):
    url = "/bikes/low"

    @docs(summary="Get All Low Battery Bikes")
    @returns(
        JSendSchema.of(bikes=Many(
            BikeSchema(only=("identifier", "battery", "current_location")))))
    async def get(self):
        """
        There may come a point where a bike hasn't been able to generate enough power
        to sustain its battery level. The that point (30% battery or lower), the bike
        will be listed here. If you claim and recharge one of these bikes, you will
        receive discounts on your next trip proportional to the amount charged. These
        stack up.

        If, for example, you charged 5 bikes for 92, 45, 37, 78, and 83 percent each
        then your next 5 rides will be 92% off, then 45% off, etc.
        """
        low_battery_bikes = await self.bike_connection_manager.low_battery(30)
        serialized_bikes = [
            bike.serialize(self.bike_connection_manager, self.rental_manager,
                           self.reservation_manager)
            for bike in low_battery_bikes
        ]

        serialized_bikes = [
            bike for bike in serialized_bikes if bike["available"]
        ]

        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "bikes": serialized_bikes
            }
        }
Ejemplo n.º 13
0
class BrokenBikesView(BaseView):
    """
    Gets the list of bikes with active issues, along with the open issues for those bikes.
    """
    url = "/bikes/broken"
    with_bikes = match_getter(get_broken_bikes, "broken_bikes")
    with_admin = match_getter(get_user,
                              "user",
                              firebase_id=GetFrom.AUTH_HEADER)

    @with_admin
    @with_bikes
    @docs(summary="Get All Broken Bikes")
    @requires(UserIsAdmin())
    @returns(JSendSchema.of(bikes=Many(BikeSchema())))
    async def get(self, user, broken_bikes):
        """
        A broken bike is one that has at least one issue open. Broken bikes must be
        serviced, and so their status is shown here for use by the operators. These
        bikes can be loaded into a path-finding algorithm and serviced as needed.
        """
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "bikes": [
                    bike.serialize(self.bike_connection_manager,
                                   self.rental_manager,
                                   self.reservation_manager,
                                   issues=issues)
                    for bike, issues in broken_bikes
                ]
            }
        }
Ejemplo n.º 14
0
class UserPaymentView(BaseView):
    """
    Allows a user to get or replace their payment details.
    """

    url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/payment"
    with_user = match_getter(get_user, 'user', user_id='id')

    @with_user
    @docs(summary="Check For Existence Of Payment Details")
    @returns(None)
    async def get(self, user: User):
        if user.can_pay:
            raise web.HTTPOk
        else:
            raise web.HTTPNoContent

    @with_user
    @docs(summary="Add Or Replace Payment Details")
    @expects(PaymentSourceSchema())
    async def put(self, user: User):
        if user.can_pay:
            await self.payment_manager.update_customer(
                user, self.request["data"]["token"])
        else:
            await self.payment_manager.create_customer(
                user, self.request["data"]["token"])

        raise web.HTTPOk

    @with_user
    @docs(summary="Delete Payment Details")
    @returns(
        active_rental=JSendSchema.of(rental=RentalSchema(),
                                     message=String(),
                                     url=Url(relative=True)),
        no_details=(None, web.HTTPNotFound),
        deleted=(None, web.HTTPNoContent),
    )
    async def delete(self, user: User):

        rental = await self.rental_manager.active_rental(user)

        if rental is not None:
            return "active_rental", {
                "status": JSendStatus.FAIL,
                "data": {
                    "message":
                    "You cannot delete your payment details with an active rental.",
                    "url":
                    self.request.app.router["rental"].url_for(
                        id=str(rental.id)).path
                }
            }
        elif not user.can_pay:
            return "no_details", None
        else:
            await self.payment_manager.delete_customer(user)
            return "deleted", None
Ejemplo n.º 15
0
 async def test_expects_malformed_json(self, client: TestClient):
     """Assert that trying to register a bike with no data fails."""
     resp = await client.post('/api/v1/bikes',
                              data="[",
                              headers={"Content-Type": "application/json"})
     data = JSendSchema().load(await resp.json())
     assert data["status"] == JSendStatus.FAIL
     assert "Could not parse" in data["data"]["message"]
Ejemplo n.º 16
0
        async def new_func(self: View, **kwargs):
            try:
                params = resolve_match_map(self.request, match_map)
            except (ValueError, TypeError) as error:
                response = {
                    "status": JSendStatus.FAIL,
                    "data": {
                        "message": "Errors with your request.",
                        "errors": flatten(error)
                    }
                }
                raise web.HTTPBadRequest(text=JSendSchema().dumps(response), content_type='application/json')
            item = getter_function(**params)
            if isawaitable(item):
                item = await item

            # if the getter function returns multiple items,
            # and there are multiple parameter names,
            # then set those keys in the decorated function
            if isinstance(injection_parameters, tuple) and isinstance(item, tuple) and len(injection_parameters) == len(
                item):
                optional_injected_kwargs = dict(zip(injection_parameters, item))
            else:
                optional_injected_kwargs = {injection_parameters[0]: item}

            not_found = []
            injected_kwargs = {}
            for key, item in optional_injected_kwargs.items():
                if item is None and not isinstance(key, Optional):
                    not_found.append(key)
                elif isinstance(key, Optional):
                    injected_kwargs[key.value] = item
                else:
                    injected_kwargs[key] = item

            if not_found:
                response = {
                    "status": JSendStatus.FAIL,
                    "data": {
                        "message": f'Could not find {", ".join(not_found)} with the given params.',
                        "params": params
                    }
                }
                raise web.HTTPNotFound(text=JSendSchema().dumps(response), content_type='application/json')

            return await original_function(self, **kwargs, **injected_kwargs)
Ejemplo n.º 17
0
 async def test_get_issue(self, client, random_admin):
     issue = await open_issue(random_admin, "An issue!")
     response = await client.get(
         f"/api/v1/issues/{issue.id}",
         headers={"Authorization": f"Bearer {random_admin.firebase_id}"})
     response_data = JSendSchema.of(issue=IssueSchema()).load(
         await response.json())
     assert response_data["status"] == JSendStatus.SUCCESS
     assert response_data["data"]["issue"]["id"] == issue.id
Ejemplo n.º 18
0
    async def test_get_issues(self, client, random_admin):
        schema = JSendSchema.of(issues=Many(IssueSchema()))
        await open_issue(random_admin, "test issue!")
        resp = await client.get(
            '/api/v1/issues',
            headers={"Authorization": f"Bearer {random_admin.firebase_id}"})

        data = schema.load(await resp.json())
        assert len(data["data"]["issues"]) == 1
Ejemplo n.º 19
0
 async def test_expects_invalid_data(self, client: TestClient):
     """Assert that trying to register a bike with invalid data fails."""
     resp = await client.post('/api/v1/bikes',
                              json={"wrong": "data"},
                              headers={"Content-Type": "application/json"})
     data = JSendSchema().load(await resp.json())
     assert data["status"] == JSendStatus.FAIL
     assert "did not validate" in data["data"]["message"]
     assert "public_key" in data["data"]["errors"]
Ejemplo n.º 20
0
class BikeIssuesView(BaseView):
    url = f"/bikes/{{identifier:{BIKE_IDENTIFIER_REGEX}}}/issues"
    with_issues = match_getter(partial(get_issues, is_active=True),
                               'issues',
                               bike=('identifier', str))
    with_bike = match_getter(get_bike, 'bike', identifier=('identifier', str))
    with_user = match_getter(get_user, "user", firebase_id=GetFrom.AUTH_HEADER)

    @with_issues
    @with_user
    @docs(summary="Get All Open Issues On Bike")
    @requires(UserIsAdmin())
    @returns(JSendSchema.of(issues=Many(IssueSchema())))
    async def get(self, issues: List[Issue], user):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "issues":
                [issue.serialize(self.request.app.router) for issue in issues]
            }
        }

    @with_user
    @with_bike
    @docs(summary="Open A New Issue About Bike")
    @expects(IssueSchema(only=('description', )))
    @returns(
        JSendSchema.of(issue=IssueSchema(only=('id', 'user_id', 'user_url',
                                               'bike_identifier',
                                               'description', 'opened_at'))))
    async def post(self, user, bike):
        issue = await open_issue(
            description=self.request["data"]["description"],
            user=user,
            bike=bike)

        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "issue": issue.serialize(self.request.app.router)
            }
        }
Ejemplo n.º 21
0
class ReservationView(BaseView):
    """
    Gets or updates a single reservation.
    """
    url = "/reservations/{id}"
    name = "reservation"
    with_reservation = match_getter(get_reservation, 'reservation', rid="id")
    with_user = match_getter(get_user, 'user', firebase_id=GetFrom.AUTH_HEADER)

    @with_user
    @with_reservation
    @docs(summary="Get A Reservation")
    @requires(UserIsAdmin() | UserOwnsReservation())
    @returns(JSendSchema.of(reservation=ReservationSchema()))
    async def get(self, reservation: Reservation, user):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {"reservation": reservation.serialize(self.request.app.router, self.reservation_manager)}
        }

    @with_user
    @with_reservation
    @docs(summary="Delete A Reservation")
    @requires(UserIsAdmin() | UserOwnsReservation())
    @returns(
        already_ended=(JSendSchema(), web.HTTPBadRequest),
        cancelled=JSendSchema.of(reservation=ReservationSchema()),
    )
    async def delete(self, reservation: Reservation, user):

        if reservation.outcome is not None:
            return "already_ended", {
                "status": JSendStatus.FAIL,
                "data": {"message": "The requested rental cannot be cancelled because it is not currently active."}
            }

        await self.reservation_manager.cancel(reservation)

        return "cancelled", {
            "status": JSendStatus.SUCCESS,
            "data": {"reservation": reservation.serialize(self.request.app.router, self.reservation_manager)}
        }
Ejemplo n.º 22
0
    async def test_get_reservation(self, client, reservation_manager, random_user, random_pickup_point):
        reservation = await reservation_manager.reserve(
            random_user, random_pickup_point, datetime.now(timezone.utc) + timedelta(hours=4)
        )

        response = await client.get(
            f"/api/v1/reservations/{reservation.id}",
            headers={"Authorization": f"Bearer {random_user.firebase_id}"}
        )
        response_data = JSendSchema().load(await response.json())
        assert response_data["data"]["reservation"]["user_id"] == random_user.id
Ejemplo n.º 23
0
        async def new_func(self: View, **kwargs):
            """Checks the given request against the supplied permission and gracefully fails."""
            try:
                await permission(self, **kwargs)
            except RoutePermissionError as error:
                response_schema = JSendSchema()
                return web.json_response(response_schema.dump({
                    "status":
                    JSendStatus.FAIL,
                    "data": {
                        "message":
                        f"You cannot do that because because {str(error)}.",
                        "reasons": error.serialize()
                    }
                }),
                                         status=HTTPStatus.UNAUTHORIZED)
            except Exception as error:
                raise type(error)(original_function, *error.args) from error

            return await original_function(self, **kwargs)
Ejemplo n.º 24
0
 async def test_get_pickup_reservations(self, client, random_pickup_point,
                                        reservation_manager, random_admin):
     await reservation_manager.reserve(
         random_admin, random_pickup_point,
         datetime.now(timezone.utc) + timedelta(hours=4))
     response = await client.get(
         f'/api/v1/pickups/{random_pickup_point.id}/reservations',
         headers={"Authorization": f"Bearer {random_admin.firebase_id}"})
     response_data = JSendSchema.of(
         reservations=Many(ReservationSchema())).load(await response.json())
     assert len(response_data["data"]["reservations"]) == 1
Ejemplo n.º 25
0
class UserCurrentRentalView(BaseView):
    """
    Gets or ends the user's current rental.
    """
    url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}/rentals/current"
    name = "user_current_rental"
    with_user = match_getter(get_user, 'user', user_id='id')

    @with_user
    @docs(summary="Get Current Rental For User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @returns(no_rental=(JSendSchema(), web.HTTPNotFound),
             rental_exists=JSendSchema.of(rental=CurrentRentalSchema(
                 only=('id', 'bike_identifier', 'bike_url', 'user_id',
                       'user_url', 'start_time', 'is_active',
                       'estimated_price', 'start_location',
                       'current_location'))))
    async def get(self, user: User):
        if not self.rental_manager.has_active_rental(user):
            return "no_rental", {
                "status": JSendStatus.FAIL,
                "data": {
                    "message": f"You have no current rental."
                }
            }

        current_rental, start_location, current_location = await self.rental_manager.active_rental(
            user, with_locations=True)
        return "rental_exists", {
            "status": JSendStatus.SUCCESS,
            "data": {
                "rental":
                await
                current_rental.serialize(self.rental_manager,
                                         self.bike_connection_manager,
                                         self.reservation_manager,
                                         self.request.app.router,
                                         start_location=start_location,
                                         current_location=current_location)
            }
        }
Ejemplo n.º 26
0
class UsersView(BaseView):
    """
    Gets or adds to the list of users.
    """
    url = "/users"
    name = "users"
    with_user = match_getter(get_user, 'user', firebase_id=GetFrom.AUTH_HEADER)

    @with_user
    @docs(summary="Get All Users")
    @requires(UserIsAdmin())
    @expects(None)
    @returns(JSendSchema.of(users=Many(UserSchema())))
    async def get(self, user):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "users": await get_users()
            }
        }

    @docs(summary="Create A User")
    @requires(ValidToken())
    @expects(UserSchema(only=('first', 'email')))
    @returns(JSendSchema.of(user=UserSchema()))
    async def post(self):
        """
        Anyone who has already authenticated with firebase can then create a user in the system.
        This must be done before you use the rest of the system, but only has to be done once.
        """
        try:
            user = await create_user(**self.request["data"],
                                     firebase_id=self.request["token"])
        except UserExistsError:
            user = await get_user(firebase_id=self.request["token"])
            user = await update_user(user, **self.request["data"])

        return {"status": JSendStatus.SUCCESS, "data": {"user": user}}
Ejemplo n.º 27
0
class UserView(BaseView):
    """
    Gets, replaces or deletes a single user.
    """
    url = f"/users/{{id:{USER_IDENTIFIER_REGEX}}}"
    name = "user"
    with_user = match_getter(get_user, 'user', user_id='id')

    @with_user
    @docs(summary="Get A User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @expects(None)
    @returns(JSendSchema.of(user=UserSchema()))
    async def get(self, user: User):
        return {
            "status": JSendStatus.SUCCESS,
            "data": {
                "user": user.serialize()
            }
        }

    @with_user
    @docs(summary="Replace A User")
    @requires(UserMatchesToken() | UserIsAdmin())
    @expects(UserSchema(only=('first', 'email')))
    @returns(JSendSchema.of(user=UserSchema()))
    async def put(self, user: User):
        user = await update_user(user, **self.request["data"])
        return {"status": JSendStatus.SUCCESS, "data": {"user": user}}

    @with_user
    @docs(summary="Delete A User")
    @requires(UserMatchesToken() | UserIsAdmin())
    async def delete(self, user: User):
        if user.can_pay:
            await self.payment_manager.delete_customer(user)
        await delete_user(user)
        raise web.HTTPNoContent
Ejemplo n.º 28
0
    async def test_create_pickup_reservation(self, client, random_pickup_point,
                                             reservation_manager, random_user):
        request_data = CreateReservationSchema().dump(
            {"reserved_for": datetime.now(timezone.utc) + timedelta(hours=4)})

        response = await client.post(
            f"/api/v1/pickups/{random_pickup_point.id}/reservations",
            headers={"Authorization": f"Bearer {random_user.firebase_id}"},
            json=request_data)

        response_data = JSendSchema.of(reservation=ReservationSchema()).load(
            await response.json())
        assert response_data["data"]["reservation"][
            "user_id"] == random_user.id
Ejemplo n.º 29
0
    async def test_get_rentals(self, client: TestClient, random_admin,
                               random_bike):
        """Assert that you can get a list of all rentals."""
        await client.app["rental_manager"].create(random_admin, random_bike)

        response = await client.get(
            '/api/v1/rentals',
            headers={"Authorization": f"Bearer {random_admin.firebase_id}"})
        response_schema = JSendSchema.of(rentals=Many(RentalSchema()))
        response_data = response_schema.load(await response.json())
        assert response_data["status"] == JSendStatus.SUCCESS
        assert len(response_data["data"]["rentals"]) == 1
        rental = response_data["data"]["rentals"][0]
        assert rental["bike_identifier"] == random_bike.identifier
        assert (await client.get(rental["bike_url"])).status != 404
Ejemplo n.º 30
0
    async def _me_handler(self):
        """
        Accepts all types of request, does some checking against the user, and forwards them on to the appropriate user.
        """
        user = await get_user(firebase_id=self.request["token"])

        if user is None:
            response_schema = JSendSchema()
            create_user_url = str(self.request.app.router['users'].url_for())
            return web.json_response(response_schema.dump({
                "status":
                JSendStatus.FAIL,
                "data": {
                    "message":
                    "User does not exist. Please use your jwt to create a user and try again.",
                    "url": create_user_url,
                    "method": "POST"
                }
            }),
                                     status=HTTPStatus.BAD_REQUEST)

        concrete_url = MeView._get_concrete_user_url(
            self.request.path, self.request.match_info.get("tail"), user)
        raise web.HTTPTemporaryRedirect(concrete_url)