def put(self, args, shop_id, **_kwargs): shop = Shop.query.get_or_404(shop_id) shop.name = args['name'] shop.address = args['address'] shop.position = from_shape(Point(args['lng'], args['lat']), srid=4326) for tag in shop.tags: db.session.delete(tag) try: db.session.flush() except IntegrityError: db.session.rollback() return custom_error('Address/Position/Name', ['Same address, position and name with existing shop']), \ ErrorCode.BAD_REQUEST # flush delete's to db to ensure delete stmts precede insert stmt and avoid integrity error shop.tags = [ ShopTag(name=tag, shop=shop) for tag in unique_stripped(args['tags']) ] try: db.session.commit() except IntegrityError: db.session.rollback() return custom_error( 'tags', ['Duplicate tags' ]), ErrorCode.BAD_REQUEST # we should never get here return shop_schema.dump(shop).data
def patch(self, args, prod_id, **_kwargs): del args['format'] if len(args) != 1: return custom_error('patch', ['Specify exactly one of: name, description, category or tags']),\ ErrorCode.BAD_REQUEST product = Product.query.get_or_404(prod_id) changed = next(iter(args.keys())) if changed == 'tags': for tag in product.tags: db.session.delete(tag) # delete old product tags db.session.flush() product.tags = [ ProductTag(name=tag, product=product) for tag in unique_stripped(args['tags']) ] else: setattr(product, changed, args[changed]) try: db.session.commit() except IntegrityError: db.session.rollback() custom_error('tags', ['Duplicate tags' ]), ErrorCode.BAD_REQUEST # we should never get here return prod_schema.dump(product).data
def post(self, args): user = User.query.filter(User.username == args['username']).first() if not user: return custom_error('username', ['Invalid username']), ErrorCode.BAD_REQUEST elif not user.verify_password(args['password']): return custom_error('password', ['Wrong password']), ErrorCode.BAD_REQUEST _login(user) return {'token': user.token}
def decorated(*args, **kwargs): token = request.headers.get('X-OBSERVATORY-AUTH') if not token: return custom_error('token', ['No authorization token provided']), ErrorCode.FORBIDDEN user = User.query.filter(User.token == token).first() if not user: return custom_error('token', ['Invalid token']), ErrorCode.FORBIDDEN kwargs['is_admin'] = user.is_admin kwargs['token'] = user.token return f(*args, **kwargs)
def post(self, args): user = User(username=args['username'], password=args['password']) db.session.add(user) try: db.session.commit() except IntegrityError: db.session.rollback() return custom_error('username', ['Username already in use']), ErrorCode.BAD_REQUEST return {'message': 'OK'}
def post(self, args, **_kwargs): date1 = args['dateFrom'] date2 = args['dateTo'] if not (date1 <= date2): return custom_error( 'date', ['date(From) must be before date(To)']), ErrorCode.BAD_REQUEST shop = Shop.query.filter_by(id=args['shop_id']).first() product = Product.query.filter_by(id=args['product_id']).first() if not shop: return custom_error('shop', ['Invalid shop id']), ErrorCode.NOT_FOUND elif not product: return custom_error('product', ['Invalid product id']), ErrorCode.NOT_FOUND del args['format'] del args['dateFrom'] del args['dateTo'] for d in [ date1 + timedelta(days=x) for x in range((date2 - date1).days + 1) ]: new_price = dict(**args, date=d) upsert = insert(Price).values(new_price).on_conflict_do_update( constraint="price_psd_c", set_=new_price) db.session.execute(upsert) db.session.commit() new_prices = Price.query.filter(Price.product_id == args['product_id'], Price.shop_id == args['shop_id'], Price.date.between(date1, date2)).all() return { 'start': 0, 'total': (date2 - date1).days + 1, 'count': (date2 - date1).days + 1, # why you ask ? no idea, field must be present, can't find any sensible value 'prices': PricesResource.PriceSchema(many=True).dump(new_prices).data }
def delete(self, _args, shop_id, is_admin, **_kwargs): shop = Shop.query.get(shop_id) if not shop: return custom_error('shop', ['Invalid shop id']), ErrorCode.NOT_FOUND if is_admin: db.session.delete(shop) else: shop.withdrawn = True db.session.commit() return {'message': 'OK'}
def patch(self, args, shop_id, **_kwargs): del args['format'] if len(args) != 1: return custom_error('patch', ['Specify exactly one of: name, address, lng, lat, tags']), \ ErrorCode.BAD_REQUEST shop = Shop.query.get_or_404(shop_id) changed = next(iter(args.keys())) if changed == 'tags': for tag in shop.tags: db.session.delete(tag) db.session.flush() shop.tags = [ ShopTag(name=tag, shop=shop) for tag in unique_stripped(args['tags']) ] elif changed == 'lat': old = to_shape(shop.position) shop.position = from_shape(Point(old.x, args['lat']), srid=4326) elif changed == 'lng': old = to_shape(shop.position) shop.position = from_shape(Point(args['lng'], old.y), srid=4326) else: setattr(shop, changed, args[changed]) try: db.session.commit() except IntegrityError: db.session.rollback() if changed == 'tags': return custom_error( 'tags', ['Duplicate tags' ]), ErrorCode.BAD_REQUEST # we should never get here else: return custom_error('Address/Position/Name', ['Same address, position and name with existing shop']), \ ErrorCode.BAD_REQUEST return ShopSchema().dump(shop).data
def post(self, args, **_kwargs): position = from_shape(Point(args['lng'], args['lat']), srid=4326) new_shop = Shop(name=args['name'], address=args['address'], position=position, withdrawn=False) new_shop.tags = [ ShopTag(name=tag, shop=new_shop) for tag in unique_stripped(args['tags']) ] db.session.add(new_shop) try: db.session.commit() except IntegrityError as e: db.session.rollback() if "shop_pna_c" in e.orig: return custom_error('Address/Position/Name', ['Same address, position and name with existing shop']), \ ErrorCode.BAD_REQUEST else: return custom_error( 'tags', ['Duplicate tags' ]), ErrorCode.BAD_REQUEST # we should never get here return shop_schema.dump(new_shop).data
def post(self, args, **_kwargs): product = Product(name=args['name'], description=args['description'], category=args['category'], withdrawn=False) product.tags = [ ProductTag(name=tag, product=product) for tag in unique_stripped(args['tags']) ] db.session.add(product) try: db.session.commit() except IntegrityError: db.session.rollback() return custom_error( 'tags', ['Duplicate tags' ]), ErrorCode.BAD_REQUEST # we should never get here return prod_schema.dump(product).data
def put(self, args, prod_id, **_kwargs): product = Product.query.get_or_404(prod_id) product.name = args['name'] product.description = args['description'] product.category = args['category'] for tag in product.tags: db.session.delete(tag) # delete old product tags db.session.flush() # flush delete's to db to ensure delete stmts precedes insert stmt and avoid integrity error product.tags = [ ProductTag(name=tag, product=product) for tag in unique_stripped(args['tags']) ] try: db.session.commit() except IntegrityError: db.session.rollback() return custom_error( 'tags', ['Duplicate tags' ]), ErrorCode.BAD_REQUEST # we should never get here return prod_schema.dump(product).data
def get(self, args): shop_ids = args['shops'] product_ids = args['products'] tags = args['tags'] with_geo = args['geoDist'] is not None and args[ 'geoLng'] is not None and args['geoLat'] is not None no_geo = args['geoDist'] is None and args['geoLng'] is None and args[ 'geoLat'] is None if not (with_geo or no_geo): return custom_error( 'geo', ['Invalid geo parameters combination']), ErrorCode.BAD_REQUEST with_date = (args['dateFrom'] is not None and args['dateTo'] is not None) and \ (args['dateFrom'] <= args['dateTo']) no_date = args['dateFrom'] is None and args['dateTo'] is None if not (with_date or no_date): return custom_error( 'date', ['Invalid date parameters combination']), ErrorCode.BAD_REQUEST sorts = [x.split('|') for x in args['sort']] for sort in sorts: if (sort[0] == 'geoDist' and no_geo) or (sort[0] == 'date' and no_date): return custom_error( 'sort', ['Invalid sort parameter']), ErrorCode.BAD_REQUEST # extra validation, some combinations are illegal dist_col = None if with_geo: dist = func.ST_Distance(Shop.position, from_shape(Point(args['geoLng'], args['geoLat']), srid=4326), True).\ label('dist') query = db.session.query(Price, dist) else: query = Price.query query = query.join(Price.product, Price.shop) today = date.today() date_from = args['dateFrom'] if args['dateFrom'] else today date_to = args['dateTo'] if args['dateTo'] else today query = query.filter(Price.date.between(date_from, date_to)) if shop_ids: query = query.filter(Shop.id.in_(shop_ids)) if product_ids: query = query.filter(Product.id.in_(product_ids)) if tags: query = query.filter( or_( Product.tags.any( func.lower(ProductTag.name).in_(map(str.lower, tags))), Shop.tags.any( func.lower(ShopTag.name).in_(map(str.lower, tags))))) if with_geo: subq = query.subquery() dist_col = subq.c.dist query = db.session.query(Price, dist_col).select_entity_from(subq).filter( dist_col < 1000 * args['geoDist']) # nested query to avoid recalculating distance expr # WHERE and HAVING clauses can't refer to column names (dist) def to_sort_operator(field, order): sort_field = { 'geoDist': dist_col, 'price': Price.price, 'date': Price.date }[field] sort_order = {'ASC': asc, 'DESC': desc}[order] return sort_order(sort_field) query = query.order_by( *[to_sort_operator(field, order) for field, order in sorts]) start = args['start'] count = args['count'] total = query.count() query = query.offset(start).limit(count) prices_page = query.all() prices = PricesResource.PriceSchema(many=True).dump(prices_page).data return { 'start': start, 'count': count, 'total': total, 'prices': prices }