Example #1
0
class User(Model, MongoRepository, Service, IdentityMixin):
    id = Property(str, required=True, generator=create_uuid_generator('U'))
    name = Property(str,
                    required=True,
                    validators=[NotEmpty, Regexp('[A-Za-z0-9-_]')],
                    index=UniqueIndex)
    password = Property(str,
                        required=True,
                        validators=[NotEmpty],
                        converter=content_hasher(rounds=10),
                        omit=True)
    description = Property(str, index=TextIndex)
    roles = Property(list, sub_type=str)
    created = Property(datetime,
                       required=True,
                       validators=[Past],
                       generator=date_now_generator)
    last_login = Property(datetime, marshaller=TimestampMarshaller)
    sequence = Property(int, index=Index)

    @link(rel='change_password',
          http_method='POST',
          require=[CurrentSubject(), Role('admin')])
    def change_p(self, current_password, new_password):
        if not pbkdf2_sha256.verify(current_password, self.password):
            raise ServiceException(403, _('Current password is not correct'))
        else:
            self.password = new_password
            self.save()
        return _('Password changed')

    @link(require=Anonymous())
    def get_description(self):
        return self.description
Example #2
0
class PaymentService(object):
    @resource(method='POST', require=[Role('user')])
    def authorise(self, payload):
        print(f'\n--> received as payload: {payload}\n')
        self.sink(payload)
        return payload

    @resource(method='POST', path='/authorise/form', require=[Role('user')])
    def authorise_payment(self, product_id, card_number, amount):
        print(
            f'\n--> received as payload: {product_id} / {card_number} / {amount}\n'
        )
        self.sink(product_id, card_number, amount)
        return {'authorisation_id': 'xxx-yyy-zzz'}

    @resource(method='GET',
              path='./<authorisation_id>',
              require=[Role('user')])
    def check_status(self, authorisation_id):
        if hasattr(self, 'sink'):
            self.sink(authorisation_id)
        return {'id': authorisation_id, 'status': 'OK'}

    @resource(method='GET',
              query_params=['start', 'stop'],
              require=[Role('user')])
    def list_payments(self, start=None, stop=None):
        self.sink(start, stop)
        return {'start': start, 'stop': stop}

    @resource(method='GET',
              path='./multiple/<authorisation_id>',
              query_params=['start', 'stop'],
              require=[Role('user')])
    def check_multiple_status(self, authorisation_id, start=None, stop=None):
        self.sink(authorisation_id, start, stop)
        return {'id': authorisation_id, 'start': start, 'stop': stop}

    @resource(method='DELETE',
              path='./<authorisation_id>',
              require=[Role('user')])
    def reverse(self, authorisation_id):
        self.sink(authorisation_id)
        return {'id': authorisation_id, 'status': 'OK'}

    @resource(method='DELETE',
              path='/cancel/<payment_ids>',
              require=[Role('user')])
    def delete_many(self, payment_ids):
        self.sink(payment_ids)
        return {'deleted': [pid for pid in payment_ids.split(',')]}

    @resource(method='PUT', path='./<payment_ids>', require=[Role('user')])
    def blow(self, payment_ids):
        raise AppKernelException('throwing some custom exception')
Example #3
0
def setup_function(function):
    """ executed before each method call
    """
    print('\n\nSETUP ==> ')

    global flask_app
    global kernel
    flask_app = Flask(__name__)
    flask_app.config['SECRET_KEY'] = 'S0m3S3cr3tC0nt3nt!'
    flask_app.testing = True
    kernel = AppKernelEngine('test_app', app=flask_app, cfg_dir='{}/../'.format(current_file_path()), development=True)
    kernel.enable_security()
    kernel.register(payment_service).require(Role('admin'), methods=['GET', 'PUT', 'POST', 'PATCH', 'DELETE'])
    User.delete_all()
Example #4
0
class User(Model, MongoRepository, Service):
    id = Property(str)
    name = Property(str, required=True, index=UniqueIndex)
    email = Property(str, validators=[Email], index=UniqueIndex)
    password = Property(str,
                        validators=[Regexp('(?=.{8,})')],
                        converter=content_hasher(),
                        omit=True)
    roles = Property(list, sub_type=str, default_value=['Login'])

    @link(http_method='POST', require=[CurrentSubject(), Role('admin')])
    def change_password(self, current_password, new_password):
        if not pbkdf2_sha256.verify(current_password, self.password):
            raise ServiceException(403, _('Current password is not correct'))
        else:
            self.password = new_password
            self.save()
        return _('Password changed')

    @link(require=Anonymous())
    def get_description(self):
        return self.description
class ShippingService(object):
    def ship(self, address, products):
        print(f'request shipping to: {address} | products: {products}')
        return str(uuid.uuid4())

    @resource(method='POST', path='./', require=[Role('user')])
    def shipping_request(self, request: Shipping):
        code, reservation = client.wrap(
            f'/reservations/{request.reservation_id}/commit').patch()
        if code == 200:
            tracking_id = self.ship(request.delivery_address,
                                    reservation.products)
            code, reservation = client.wrap(
                f'/reservations/{request.reservation_id}/execute').patch(
                    {'tracking_id': tracking_id})
            return reservation
        else:
            msg = reservation.get('message') if hasattr(
                reservation,
                'message') else 'Error while calling reservation service.'
            return create_custom_error(code,
                                       msg,
                                       upstream_service='ShippingService')
Example #6
0
class PaymentService(object):
    @resource(http_method='POST', require=[Role('user')])
    def authorize(self, authorisation: AuthorisationRequest):
        assert authorisation is not None
        return {'auth_id': str(uuid.uuid4())}
Example #7
0
def default_config():
    user_service = kernel.register(User, methods=['GET', 'PUT', 'POST', 'PATCH', 'DELETE'])
    user_service.deny_all().require(Role('user'), methods='GET').require(Role('admin'),
                                                                         methods=['PUT', 'POST', 'PATCH', 'DELETE'])
    return create_basic_user()
Example #8
0
class Reservation(Model, MongoRepository):
    id = Property(str, generator=create_uuid_generator('R'))
    order_id = Property(str, required=True)
    order_date = Property(datetime, required=True, generator=date_now_generator)
    products = Property(list, sub_type=Product, required=True, validators=NotEmpty())
    state = Property(ReservationState, required=True, default_value=ReservationState.RESERVED)
    stocks = Property(dict, sub_type=dict)
    tracking_id = Property(str)

    def group_products_by_code(self):
        products_by_code = dict()
        for product in self.products:
            size_and_quantity = products_by_code.get(product.code, {product.size.name: 0})
            size_and_quantity[product.size.name] = size_and_quantity.get(product.size.name, 0) + 1
            products_by_code[product.code] = size_and_quantity
        return products_by_code

    @classmethod
    def before_post(cls, *args, **kwargs):
        # method called before the reservation id is sent
        for pcode, size_and_quantity in kwargs['model'].group_products_by_code().items():
            for psize, quantity in size_and_quantity.items():
                # todo: what if there are multiple stock items with the same product code
                query = Stock.where(
                    (Stock.product.code == pcode) & (Stock.product.size == psize) & (Stock.available >= quantity))
                reserved_stock = query.find_one_and_update(available=Stock.available - quantity,
                                                           reserved=Stock.reserved + quantity)
                if not reserved_stock:
                    raise ReservationException(f"There's no stock available for code: {pcode} and size: {psize}.")
                if hasattr(kwargs['model'], 'stocks') and kwargs['model'].stocks is not None:
                    size_and_qty = kwargs['model'].stocks.get(pcode, {psize: {'qty': quantity}})
                    if psize not in size_and_qty:
                        size_and_qty[psize] = {'qty': quantity}
                else:
                    size_and_qty = {psize: {'qty': quantity}}
                    kwargs['model'].stocks = {}
                size_and_qty[psize]['stock'] = reserved_stock.id
                kwargs['model'].stocks[pcode] = size_and_qty

    @classmethod
    def after_post(cls, *args, **kwargs):
        reservation: Reservation = kwargs.get('model')
        print(f'reservation id: {reservation.id}')

    @action(method='PATCH', require=[Role('user')])
    def commit(self):
        self.state = ReservationState.COMMITTED
        self.save()
        return self

    @action(method='PATCH', require=[Role('user')])
    def execute(self, tracking_id):
        self.state = ReservationState.EXECUTED
        self.tracking_id = tracking_id
        self.save()
        for pcode, sizes in self.stocks.items():
            for size, quantity_and_stock in sizes.items():
                stock_id = quantity_and_stock.get('stock')
                query = Stock.where(Stock.id == stock_id)
                modified_count = query.update_one(reserved=Stock.reserved - quantity_and_stock.get('qty'))
                if modified_count != 1:
                    config.app_engine.logger.warn(f'quantities were not reduced for stock: {stock_id}')
        return self

    @action(method='PATCH', require=[Role('user')])
    def cancel(self):
        error = False
        for pcode, sizes in self.stocks.items():
            for size, quantity_and_stock in sizes.items():
                stock_id = quantity_and_stock.get('stock')
                query = Stock.where(Stock.id == stock_id)
                qty = quantity_and_stock.get('qty')
                modified_count = query.update_one(reserved=Stock.reserved - qty, available=Stock.available + qty)
                if modified_count != 1:
                    error = True
                    config.app_engine.logger.warn(f'quantities were not reduced for stock: {stock_id}')
        if not error:
            self.state = ReservationState.CANCELLED
            self.save()
        return self