def delete(self): """multi delete """ try: ids = request.args.get(__heads__).split(',') except Exception as error: return omitError( ErrorMsg='param `{}` not found'.format(__heads__)), 400 for id in ids: try: id = inputs.natural(id) except Exception as error: db.session.rollback() return omitError( ErrorMsg='user id `{}` not int'.format(id)), 400 # it could als cascade delete `online` user r = grp.query.filter(grp.id == id).scalar() if r is None: db.session.rollback() return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 db.session.delete(r) try: db.session.flush() db.session.commit() except Exception as error: logger.warning('session commit error(%s)', error) db.session.rollback() return omitError(ErrorMsg=repr(error)), 400 return '', 204
def get(self, id): """Get all data, getall """ # check the request is validtion, # ex: we not allow request arg 'itemsPerPage1' validSet = set(field_inputs_wrap.keys()) requestArgsSet = set(request.dataDictWrap.keys()) if not ExtraParamsIsValid(requestArgsSet, validSet): return omitError( ErrorMsg=repr(requestArgsSet.difference(validSet))), 400 # one to many # 1. parsing reqest try: for k, v in field_inputs.items(): field_inputs[k]['required'] = False orgArgs, self.args = GetRequestArgs( None, field_inputs_wrap, dict((col, request.args.get(col)) for col in request.args)) # get default value # print(self.args, 'self.args', resource_fields_wrap) self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[__heads__] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 if not hasattr(g, 'user'): return omitError('CE_NOT_EXIST', 'not login yet'), 400 r = g.user if r is None: return omitError('CE_NOT_EXIST'), 400 # 1.1 check permission if r.id != id: return omitError('CE_UNAUTHORIZED', 'id not match'), 400 # 2. export to user _r = dict((col, getattr(r, col)) for col in r.__table__.columns.keys()) self.args[field_inputs_wrap_head] = _r _resource_fields = resource_fields.copy() _resource_fields_wrap = resource_fields_wrap.copy() for col in resource_fields_wrap: if col not in ['type', 'subtype']: _resource_fields_wrap.pop(col, None) _resource_fields.pop('access_token', None) _resource_fields_wrap[field_inputs_wrap_head] = ( fields.Nested(_resource_fields)) self.args['type'] = "system" self.args['subtype'] = "regist" return marshal(self.args, _resource_fields_wrap), 200
def post(self): logger.debug('request.header: \n%s', request.headers) login = request.headers.get('login') passHash = request.headers.get('passHash') Authentication = request.headers.get('Authentication') if not login or not passHash or not Authentication: return omitError(ErrorMsg=\ 'Not Found: login(%s)/passHash(%s)/Authentication(%s)' % ( login, passHash, Authentication) ), 400 elif ('SAGITTARIUS' not in Authentication): return omitError(ErrorMsg='SAGITTARIUS not in Authentication header(%s)'\ % Authentication), 400 user = Users.get_by_loginpass(login, passHash) if not user: logger.debug("user %s not found with password %s", login, passHash) #return omitError(ErrorMsg='not Authentication ), 401 abort(401) #elif not Users.sign(user.id, login, passHash): # logger.debug("Users.sign fail") # return omitError(ErrorMsg='not Authentication ), 401 else: if user.passHash == "": # no passHash, not use email to login logger.debug( "user %s not found with password %s, use non email login", login, passHash) abort(401) self.args, _resource_fields_wrap = signin(user) # g.user = user # _resource_fields = {} # _resource_fields_wrap = resource_fields_wrap.copy() # for col in resource_fields_wrap: # if col not in ['type', 'subtype']: # _resource_fields_wrap.pop(col, None) # # _resource_fields_wrap[field_inputs_wrap_head] = fields.Nested(resource_fields) # # self.args = {} # self.args[field_inputs_wrap_head] = dict((col, getattr(user, col)) for col in user.__table__.columns.keys()) # #self.args[field_inputs_wrap_head]['sid'] = session['sid'] # token = user.generate_auth_token() # self.args[field_inputs_wrap_head]['access_token'] = token.decode('ascii') # self.args[field_inputs_wrap_head]['clientIp'] = request.environ['REMOTE_ADDR'] # # logger.debug("self.args[field_inputs_wrap_head]: %s", self.args[field_inputs_wrap_head]) # self.args['type'] = "admin" # self.args['subtype'] = "login" return marshal(self.args, _resource_fields_wrap), 200
def get(self, id): """Get all data, getall """ # check the request is validtion, # ex: we not allow request arg 'itemsPerPage1' validSet = set(field_inputs_wrap.keys()) requestArgsSet = set(request.dataDictWrap.keys()) if not ExtraParamsIsValid(requestArgsSet, validSet): return omitError( ErrorMsg=repr(requestArgsSet.difference(validSet))), 400 # one to many # 1. parsing reqest try: for k, v in field_inputs.items(): field_inputs[k]['required'] = False orgArgs, self.args = GetRequestArgs( None, field_inputs_wrap, dict((col, request.args.get(col)) for col in request.args)) # get default value # print(self.args, 'self.args', resource_fields_wrap) self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[__heads__] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 2. export to user _r = dict((col, getattr(r, col)) for col in r.__table__.columns.keys()) self.args[field_inputs_wrap_head] = _r _resource_fields = resource_fields.copy() _resource_fields_wrap = resource_fields_wrap.copy() for col in resource_fields_wrap: if col not in ['type', 'subtype']: _resource_fields_wrap.pop(col, None) _resource_fields_wrap[field_inputs_wrap_head] = ( fields.Nested(_resource_fields)) self.args['type'] = "business" self.args['subtype'] = "rate" return marshal(self.args, _resource_fields_wrap), 200
def put(self, id): """ update one item """ # 1. parsing reqest try: orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 2. get orm from db r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 3. assign request data to orm try: t = datetime.utcnow() r = PrepareObjORM(r, self.args.items()) r.mtime = t except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.merge(r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user out = SerialObjOutput(r, objname=field_inputs_wrap_head, resource_fields=resource_fields_post), 200 next(iter(out))[field_inputs_wrap_head].update({'id': id}) next(iter(out))['type'] = 'business' next(iter(out))['subtype'] = 'rate' return out
def put(self, id): requestArgsSet = set((col) for col in request.args) if not ExtraParamsIsValid(requestArgsSet): return omitError(ErrorMsg=repr(set( (col) for col in request.args))), 400 try: self.dataDict = request.get_json() request.dataDict = self.dataDict[__head__] add_argument(_reqparse, field_inputs) self.args = _reqparse.parse_args() except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) if error == type(BadRequest): return omitError(ErrorMsg='maybe json format error'), 400 return omitError(ErrorMsg='{}'.format(repr(error.args))), 400 try: checkInputIsValid(self.args) except Exception as error: return error.args r = obj.query.filter(obj.id == id).scalar() for k, v in self.args.items(): if v != None: setattr(r, k, v) db.session.add(r) try: db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 self.args[__head__] = {} _resource_fields_wrap = {} _resource_fields_wrap[__head__] = fields.Nested(resource_fields) for col in r.__table__.columns.keys(): self.args[__head__][col] = getattr(r, col) return marshal(self.args, _resource_fields_wrap), 200
def get(self): """Get all data """ # one to many # 1. parsing reqest try: # FIXME: # when i assign field_inputs['name']['required'] to True, # it could through below error: # ValueError: [name]: (name Valid Error) Missing required parameter # in dataDict # but i have no idea what it happen. if os.environ.get('EVN'): # in unit test field_inputs['name']['required'] = False logger.warning('now we are in unit test mode, turn off'\ ' field_inputs[\'name\'][\'required\']'\ ' but 1st run is ok :(') orgArgs, self.args = GetRequestArgs( None, field_inputs_wrap, dict((col, request.args.get(col)) for col in request.args)) # get default value print(self.args, 'self.args', resource_fields_wrap) self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[__sec_heads__] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 itemsPerPage = self.response['itemsPerPage'] page = self.response['page'] orderBy = getattr(sec, self.response['orderBy']) isDesc = getattr(orderBy, 'desc' if self.response['desc'] else 'asc') r = sec.query.order_by(isDesc()) _r = r.all() self.args['total'] = len(_r) if itemsPerPage is not 0: _r = r.offset(itemsPerPage * (page-1))\ .limit(itemsPerPage)\ .all() r = _r # 2. export to user data, field = SerialGroupOutput(r, resource_fields=resource_fields, omitKeys=['id', 'name']) self.args[__sec_heads__] = data _resource_fields_wrap = resource_fields_wrap.copy() _resource_fields_wrap[__sec_heads__] = fields.List( fields.Nested(field)) return marshal(self.args, _resource_fields_wrap), 200
def get(self): # check the request is validtion, # ex: we not allow request arg 'itemsPerPage1' validSet = set(__heads__, 'refBy') requestArgsSet = set(request.dataDictWrap.keys()) if not ExtraParamsIsValid(requestArgsSet, validSet): return omitError( ErrorMsg=repr(requestArgsSet.difference(validSet))), 400 try: self.args = _reqparse.parse_args() self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[__heads__] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError('CE_INVALID_PARAM', repr(error)), 400 itemsPerPage = self.response['itemsPerPage'] page = self.response['page'] orderBy = getattr(obj, self.response['orderBy']) isDesc = getattr(orderBy, 'desc' if self.response['desc'] else 'asc') # .order_by(User.login.desc()) r = obj.query.order_by(isDesc()) if itemsPerPage is 0: r = r.all() else: r = r.offset(itemsPerPage * (page-1))\ .limit(itemsPerPage)\ .all() for _r in r: __r = dict( (col, getattr(_r, col)) for col in _r.__table__.columns.keys()) self.args[__heads__].append(__r) self.args['total'] = len(r) _resource_fields_wrap[__heads__] = {} _resource_fields_wrap[__heads__] = fields.List( fields.Nested(resource_fields)) return marshal(self.args, _resource_fields_wrap), 200
def checkInputIsValid(args={}): try: # now we only support IPv4/IPv6 args['addr1'] = inputs.is_ipv4_ipv6(args['addr1'], argument=args['ipVersion']) except socket.error as error: # Not legal logger.debug('traceback.format_exc(%s)', traceback.format_exc()) raise ValueError( omitError( 'CE_INVALID_PARAM', '`{}/{}`: {}'.format(args['addr1'], args['ipVersion'], error.args)), 400) ip = args['addr1'] ver = args['ipVersion'] pre = args['addr2'] try: if args['type'] == 'Single': # TODO: maybe we limit that could not pass anything in attribute 'addr2' pass elif args['type'] == 'Range': # do the same as below pre = inputs.is_ipv4_ipv6(pre, argument=ver) # legal elif args['type'] == 'Subnet': # do the same as below if 'IPv4' == ver: #NOTICE: maybe correct user's input? try: ip = inputs.is_cidr(ip, argument=pre) except Exception as error: pre = inputs.is_netmask(pre) elif 'IPv6' == ver: pre = inputs.is_ipv6_prefix(ip, argument=pre) # legal except Exception as error: # Not legal logger.debug('traceback.format_exc(%s)', traceback.format_exc()) raise ValueError( omitError('CE_INVALID_PARAM', '`{}/{}({})`: {}'.\ format(ip, pre, ver, error.args)), 400)
def put(self, id): """ update one record """ # 1. parsing reqest try: self.args = GetRequest(__head__, field_inputs) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 2. get orm from db r = grp.query.filter(grp.id == id).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 3. assign request data to orm try: r = PrepareGroupORM(r, obj, mapping, __obj__heads__, self.args.items()) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.merge(r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user data, field = SerialGroupOutput(r, resource_fields=resource_fields) return marshal(data, field), 200
def get(self, id): """ retreive one record """ r = grp.query.filter(grp.id == id).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 data, field = SerialGroupOutput(r, resource_fields=resource_fields, omitKeys=['id', 'name']) return marshal(data, field), 200
def get(self, id): requestArgsSet = set((col) for col in request.args) if not ExtraParamsIsValid(requestArgsSet): return omitError(ErrorMsg=repr(set( (col) for col in request.args))), 400 r = obj.query.filter(obj.id == id).scalar() if r is None: return omitError('CE_NOT_EXIST', 'user id {} not found'.format(id)), 400 self.args = {} self.args[__head__] = {} _resource_fields_wrap = {} _resource_fields_wrap[__head__] = fields.Nested(resource_fields) for col in r.__table__.columns.keys(): self.args[__head__][col] = getattr(r, col) return marshal(self.args, _resource_fields_wrap), 200
def delete(self, id): requestArgsSet = set((col) for col in request.args) if not ExtraParamsIsValid(requestArgsSet): return omitError(ErrorMsg=repr(set( (col) for col in request.args))), 400 try: ids = request.args.get(__heads__).split(',') except Exception as error: return omitError( ErrorMsg='param `{}` not found'.format(__heads__)), 400 for id in ids: try: id = inputs.natural(id) except Exception as error: db.session.rollback() return omitError( ErrorMsg='user id `{}` not int'.format(id)), 400 # it could als cascade delete `online` user r = obj.query.filter(obj.id == id).scalar() if r is None: db.session.rollback() return omitError('CE_NOT_EXIST', 'admin id {} not found'.format(id)), 400 db.session.delete(r) try: db.session.flush() db.session.commit() except Exception as error: logger.warning('session commit error(%s)', error) db.session.rollback() return message, 400 return message, 204
def delete(self): """multi delete """ try: ids = request.args.get(__heads__).split(',') except Exception as error: return omitError( ErrorMsg='param `{}` not found'.format(__heads__)), 400 # TODO: use function if not hasattr(g, 'user'): return omitError('CE_NOT_EXIST', 'not login yet'), 400 r = g.user if r is None: return omitError('CE_NOT_EXIST'), 400 if r.login != superuser: return omitError('CE_UNAUTHORIZED', 'permission deny'), 400 for id in ids: try: id = inputs.natural(id) except Exception as error: return omitError(ErrorMsg='id `{}` not int'.format(id)), 400 # it could als cascade delete `online` user r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 _r = [] for id in ids: id = inputs.natural(id) # it could als cascade delete `online` user r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() r.isdel = True _r.append(r) try: for v in _r: db.session.merge(v) db.session.flush() db.session.commit() except Exception as error: logger.warning('session commit error(%s)', error) db.session.rollback() return omitError(ErrorMsg=repr(error)), 400 return '', 204
def post(self): """Create new """ # 1. parsing reqest try: self.args = GetRequest(__head__, field_inputs) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 2. validate follows spec if db.session.query(grp.id).count() > max: return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(max)), 400 if len(self.args[__obj__heads__]) > childrenMax: return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(childrenMax)), 400 # 3. assign request data to orm r = grp() try: r = PrepareGroupORM(r, obj, mapping, __obj__heads__, self.args.items()) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.add(r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user data, field = SerialGroupOutput(r, resource_fields=resource_fields) return marshal(data, field), 200
def put(self, id): """ update one item @api {put} /rest/customer/business/:id Update a item @apiVersion 0.0.5 @apiName UpdateCustomerBusiness @apiGroup business @apiPermission registered user @apiDescription todo certificate with cookies / oauth 2.0<br /> todo long/lat validation<br /> todo error / success return code in api <br /> @apiParam {Object} data object of business. @apiParam {Number} data.id item's uniq id. @apiParam {String} data.name item's name. @apiParam {Number} data.cat item's business industry category. @apiParam {float} data.lat item's entered latitude. @apiParam {float} data.long item's entered longitude. @apiParam {String} data.address item's address @apiParam {String} data.description item's description. @apiParam {String} data.image_url items's image url. @apiParam {Float} data.rate item's rate, average from each comments @apiParam {Number} data.deal one of item's deal for display in list @apiParam {Object[]} data.deals item's deals @apiParam {String} data.deals.title item's deal title @apiParam {String} data.deals.description item's deal description @apiParam {String} data.open item open time with 24h format @apiParam {String} data.open item close time with 24h format @apiParam {Number} data.dist item's distance farward with your current location, the unit is meter @apiParam {Object} data.images_url item images' path @apiParam {String} data.images_url.bg item backgound images' path @apiParam {String} data.images_url.icon item icon images' path @apiExample {curl} Example usage: curl -X PUT -H "mTag: xx" -H "Content-Type:application/json" -d " { "data":{ "dist":12245, "close":"2200", "lat":120.678, "features":"this is features", "address":"this is address", "deals":[ { "title":"10% Off Any Order", "description":"Use this promo code and save on coffee, tea, and..." } ], "cat":1, "long":23.5383, "meals":"this is meals", "deal":200, "open":"0600", "description":"early Bird Special: Get off.", "name":"Starbucks Coffee 31", "images_url":{ "icon":"/img/business/1/icon", "bg":"/img/business/1/bg" }, "id":1 }, "type":"business", "subtype":"overview" } " http://localhost/rest/customer/business/1 @apiError CE_INVALID_PARAM invalid parameter HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "ValueError('[cat]: (cat Valid Error) Missing required parameter in dataDict, error=400: Bad Request',)" } @apiError CE_NAME_CONFLICT name conflict HTTP/1.0 400 BAD REQUEST { "errorId": 2004, "message": "IntegrityError('(sqlite3.IntegrityError) UNIQUE constraint failed: customer_businesses.name',)" } @apiError CE_NOT_EXIST item not found HTTP/1.0 400 BAD REQUEST { "errorId": 2003, "message": "id 17 not found" } """ # 1. parsing reqest try: orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) RemoveRequestArgs(field_inputs_post) j = request.get_json() orgdetailImgsUrlArgs, self.detailimgsurlargs = GetTwoLayerRequestArgs( None, field_inputs_detail_images_url, j[field_inputs_wrap_head][__head_detail_images_url__]) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 2. get orm from db r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 3. assign request data to orm try: t = datetime.utcnow() _item = [] for k, v in self.args.items(): if k != "deals": _item.append((k, v)) r = PrepareObjORM(r, _item) r.mtime = t d = detail.query.filter(detail.business_id == id, detail.isdel == False).scalar() __deals = deals.query.filter(deals.business_id == id, deals.isdel == False).all() # TODO: mark isdel = True? #for v in __deals: # v.isdel = True; _deals = [] for k, v in self.args.items(): if v != None: if k == 'deals': deal = deals() for v1 in v: # each entry for k2, v2 in v1.items(): setattr(deal, k2, v2) _deals.append(deal) else: setattr(d, k, v) d.mtime = t _pics = [] _ps = pics.query.filter(pics.business_id == id, pics.isdel == False).all() # FIXME: hard code mapping for k, v in self.detailimgsurlargs.items(): # (1, 'icon'), (2, 'bg'), (3, 'gallery') p = pics() if k == 'icon': p.type = 1 elif k == 'bg': p.type = 2 if p.type: p.path = v _pics.append(p) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: #db.session.merge(r) for v in __deals: db.session.delete(v) for v in _ps: db.session.delete(v) for v in _pics: db.session.add(v) for v in _deals: db.session.add(v) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user out = SerialObjOutput(d, objname=field_inputs_wrap_head, resource_fields=resource_fields_post), 200 for k, v in field_inputs.items(): if k not in ['id', 'image_url']: next(iter(out))[field_inputs_wrap_head].update({k: orgArgs[k]}) next(iter(out))[field_inputs_wrap_head].update( {'deals': orgArgs['deals']}) next(iter(out))[field_inputs_wrap_head].update( {'images_url': orgArgs['images_url']}) next(iter(out))[field_inputs_wrap_head].update({'id': id}) next(iter(out))['type'] = 'business' next(iter(out))['subtype'] = 'overview' return out
def delete(self): """multi delete @api {delete} /rest/customer/businesses Delete items @apiName DelCustomerBusiness @apiVersion 0.0.3 @apiGroup customer @apiPermission registered user @apiDescription todo validation @apiParam {String{..254}} [ids] the items id seperate with common @apiExample {curl} Example usage: curl -X DELETE -v -b $COOKIES -H "Content-Type:application/json" http://localhost/rest/customer/businesses?id=1,2,3 HTTP/1.0 204 NO CONTENT @apiError CE_INVALID_PARAM invalid parameter HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "param `businesses` not found" } @apiError CE_NOT_EXIST item not found HTTP/1.0 400 BAD REQUEST { "errorId": 2003, "message": "id 7 not found" } """ try: ids = request.args.get(__heads__).split(',') except Exception as error: return omitError( ErrorMsg='param `{}` not found'.format(__heads__)), 400 for id in ids: try: id = inputs.natural(id) except Exception as error: return omitError(ErrorMsg='id `{}` not int'.format(id)), 400 # it could als cascade delete `online` user r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 _details = [] _pics = [] _deals = [] _r = [] for id in ids: id = inputs.natural(id) # it could als cascade delete `online` user r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() r.isdel = True _r.append(r) # must have d = detail.query.filter(detail.business_id == id, detail.isdel == False).scalar() d.isdel = True _details.append(d) p = pics.query.filter(pics.business_id == id, pics.isdel == False).all() _pics += p __deals = deals.query.filter(deals.business_id == id, deals.isdel == False).all() _deals += __deals try: for v in _deals: db.session.delete(v) for v in _pics: db.session.delete(v) for v in _r: db.session.merge(v) for v in _details: db.session.merge(v) db.session.flush() db.session.commit() except Exception as error: logger.warning('session commit error(%s)', error) db.session.rollback() return omitError(ErrorMsg=repr(error)), 400 return '', 204
def put(self, id): """ update one record @api {put} /rest/objects/ipaddr/:id update a IP Address item @apiVersion 0.0.1 @apiName UpdateIpAddr @apiVersion 0.0.1 @apiGroup objects @apiPermission registered user @apiParam {Number} id ipdate IP Address ID. @apiDescription todo validation<br /> todo certificate with cookies / oauth 2.0 @apiParam {Object} ipaddrs List of IP Addresses. @apiParam {String{..16}} ipaddrs.addr1 1st IP Address. @apiParam {String{..16}} ipaddrs.addr2 2ed IP Address. @apiParam {String{..255}} [ipaddrs.description] this items's description. @apiParam {String="IPv4","IPv6"} ipaddrs.ipVersion IP Address version. @apiParam {String{..50}} ipaddrs.name items uniq name for record. @apiParam {String="Single","Range","Subnet"} ipaddrs.type IP Address type, the possible values are 'Single', 'Range', 'Subnet'. @apiExample Example usage: BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X PUT -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddr/7 @apiSuccess {Object} ipaddrs List of IP Addresses. @apiSuccess {String} ipaddrs.addr1 1st IP Address. @apiSuccess {String} ipaddrs.addr2 2ed IP Address. @apiSuccess {String} ipaddrs.description this items's description. @apiSuccess {Number} ipaddrs.id index in database. @apiSuccess {String} ipaddrs.ipVersion IP Address version. @apiSuccess {String} ipaddrs.name items uniq name for record. @apiSuccess {String} ipaddrs.type IP Address type, the possible values are 'Single', 'Range', 'Subnet'. @apiError CE_INVALID_PARAM invalid parameter @api {put} /rest/objects/ipaddr/:id @apiErrorExample {json} we use invalid member type1 in request body BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type1" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X PUT -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddr/7 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "ValueError('[type]: (type Valid Error) Missing required parameter in dataDict, error=400: Bad Request',)" } @apiError CE_NAME_CONFLICT name conflict @api {post} /rest/objects/ipaddr/:id @apiErrorExample {json} we use duplicate name. BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X PUT -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddr/7 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2004, "message": "IntegrityError('(sqlite3.IntegrityError) UNIQUE constraint failed: objects_ipaddrs.name',)" } @apiError CE_NOT_EXIST item not found @api {get} /rest/objects/ipaddr/:id @apiErrorExample {json} we use not exist id curl -X PUT -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddr/17 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2003, "message": "id 17 not found" } """ # 1. parsing reqest try: orgArgs, self.args = GetRequestArgs(__head__, field_inputs) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 try: checkInputIsValid(self.args) except Exception as error: return error.args # 2. get orm from db r = obj.query.filter(obj.id == id).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 3. assign request data to orm try: r = PrepareObjORM(r, self.args.items()) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.merge(r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user return SerialObjOutput(r, objname=__head__, resource_fields=resource_fields), 200
def post(self): """create data """ # 1. parsing reqest # 1.1 parsing 1st layer reqest try: orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 1.3 check name unique r = obj.query.filter(obj.user_id == self.args['user_id'], obj.business_id == self.args['business_id'], obj.isdel == False).scalar() if r is not None: return omitError( 'CE_DATA_DUPLICATE', 'user_id {}, business_id {} are duplicate'.format( self.args['user_id'], self.args['business_id'])), 400 # 2. validate follows spec if db.session.query(obj).filter(obj.isdel == False).count() > max: return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(max)), 400 r = obj() try: r = PrepareObjORM(r, self.args.items()) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.add(r) db.session.flush() db.session.refresh(r) db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user out = SerialObjOutput(r, objname=field_inputs_wrap_head, resource_fields=resource_fields_post), 200 next(iter(out))[field_inputs_wrap_head].update({'id': r.id}) next(iter(out))['type'] = 'business' next(iter(out))['subtype'] = 'rate' return out
def post(self): """create data @api {post} /rest/customer/businesses Create a item @apiVersion 0.0.3 @apiName CreateCustomerBusiness @apiGroup business @apiPermission registered user @apiDescription todo validation <br/> todo certificate with cookies / oauth 2.0 <br/> todo muti-create <br /> todo error / success return code in api @apiParam {Object} data object of business. @apiParam {Number} data.id item's uniq id. @apiParam {String} data.name item's name. @apiParam {Number} data.cat item's business industry category. @apiParam {float} data.lat item's entered latitude. @apiParam {float} data.long item's entered longitude. @apiParam {String} data.address item's address @apiParam {String} data.description item's description. @apiParam {String} data.image_url items's image url. @apiParam {Float} data.rate item's rate, average from each comments @apiParam {Number} data.deal one of item's deal for display in list @apiParam {Object[]} data.deals item's deals @apiParam {String} data.deals.title item's deal title @apiParam {String} data.deals.description item's deal description @apiParam {String} data.open item open time with 24h format @apiParam {String} data.open item close time with 24h format @apiParam {Number} data.dist item's distance farward with your current location, the unit is meter @apiParam {Object} data.images_url item images' path @apiParam {String} data.images_url.bg item backgound images' path @apiParam {String} data.images_url.icon item icon images' path @apiExample {curl} Example usage: curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d ' { "data":{ "dist":12245, "close":"2200", "lat":120.678, "features":"this is features", "address":"this is address", "deals":[ { "title":"10% Off Any Order", "description":"Use this promo code and save on coffee, tea, and..." } ], "cat":1, "long":23.5383, "meals":"this is meals", "deal":200, "open":"0600", "description":"early Bird Special: Get off.", "name":"Starbucks Coffee 31", "images_url":{ "icon":"/img/business/1/icon", "bg":"/img/business/1/bg" }, "id":1 }, "type":"business", "subtype":"overview" }' http://localhost/rest/customer/businesses @apiError CE_INVALID_PARAM invalid parameter HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "ValueError('[cat]: (cat Valid Error) Missing required parameter in dataDict, error=400: Bad Request',)" } @apiError CE_NAME_CONFLICT name conflict HTTP/1.0 400 BAD REQUEST { "errorId": 2004, "message": "IntegrityError('(sqlite3.IntegrityError) UNIQUE constraint failed: customer_businesses.name',)" } @apiError CE_EXCEED_LIMIT exceed max limit HTTP/1.0 400 BAD REQUEST { "errorId": 2005, "message": "limit is 5" } """ # 1. parsing reqest # 1.1 parsing 1st layer reqest try: #orgArgs = {'type': 'business', 'subtype': 'overview', 'data': {'name': 'Starbucks Coffee 1', 'description': 'early Bird Special: Get off.', 'address': 'this is address', 'close': '2200', 'meals': 'this is meals', 'long': 23.5383, 'open': '0600', 'lat': 120.678, 'dist': 12245, 'cat': 1, 'images_url': {'icon': '/img/business/1/icon', 'bg': '/img/business/1/bg'}, 'features': 'this is features', 'deal': 200, 'deals': [{'description': 'Use this promo code and save on coffee, tea, and...', 'title': '10% Off Any Order'}]}}' orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) RemoveRequestArgs(field_inputs_post) j = request.get_json() orgdetailImgsUrlArgs, self.detailimgsurlargs = GetTwoLayerRequestArgs( None, field_inputs_detail_images_url, j[field_inputs_wrap_head][__head_detail_images_url__]) #self.args= {'name': 'Starbucks Coffee 1', 'description': 'early Bird Special: Get off.', 'address': 'this is address', 'close': '2200', 'meals': 'this is meals', 'long': '23.5383', 'open': '0600', 'lat': '120.678', 'dist': 12245, 'cat': 1, 'features': 'this is features', 'deal': 200, 'deals': [{'description': 'Use this promo code and save on coffee, tea, and...', 'title': '10% Off Any Order'}]} self.detailimgsurlargs= {'icon': '/img/business/1/icon', 'bg': '/img/business/1/bg'}} #print("self.args=", self.args, "self.detailimgsurlargs=", self.detailimgsurlargs) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 1.3 check name unique r = obj.query.filter(obj.name == self.args['name'], obj.isdel == False).scalar() if r is not None: return omitError('CE_NAME_CONFLICT', 'name {} conflict'.format(self.args['name'])), 400 # 2. validate follows spec if db.session.query(obj).filter(obj.isdel == False).count() > max: return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(max)), 400 r = obj() d = detail() _pics = [] _deals = [] try: _item = [] for k, v in self.args.items(): if k != "deals": _item.append((k, v)) r = PrepareObjORM(r, _item) # FIXME: hard code mapping for k, v in self.detailimgsurlargs.items(): # (1, 'icon'), (2, 'bg'), (3, 'gallery') p = pics() if k == 'icon': p.type = 1 elif k == 'bg': p.type = 2 if p.type: p.path = v _pics.append(p) for k, v in self.args.items(): if v != None: if k == 'deals': deal = deals() for v1 in v: # each entry for k2, v2 in v1.items(): setattr(deal, k2, v2) _deals.append(deal) else: setattr(d, k, v) #print("d.__dict__ = ", d.__dict__) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.add(r) # At this point, the object f has been pushed to the DB, # and has been automatically assigned a unique primary key id db.session.flush() # refresh updates given object in the session with its state in the DB # (and can also only refresh certain attributes - search for documentation) db.session.refresh(r) d.business_id = r.id #print("d.__dict__ = ", d.__dict__) db.session.add(d) for v in _deals: v.business_id = r.id db.session.add(v) for v in _pics: v.business_id = r.id db.session.add(v) db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user _d = db.session.query(detail).filter(detail.business_id == r.id).one() out = SerialObjOutput(_d, objname=field_inputs_wrap_head, resource_fields=resource_fields_post), 200 for k, v in field_inputs.items(): if k not in ['id', 'image_url']: next(iter(out))[field_inputs_wrap_head].update({k: orgArgs[k]}) next(iter(out))[field_inputs_wrap_head].update( {'deals': orgArgs['deals']}) next(iter(out))[field_inputs_wrap_head].update( {'images_url': orgArgs['images_url']}) next(iter(out))[field_inputs_wrap_head].update({'id': r.id}) next(iter(out))['type'] = 'business' next(iter(out))['subtype'] = 'overview' return out
def get(self): """Get all data, getall @api {get} /rest/objects/ipaddrs Read IP Addresses @apiVersion 0.0.1 @apiName GetIpAddrs @apiVersion 0.0.1 @apiGroup objects @apiPermission registered user @apiDescription todo validation @apiParam {Number=0, 25, 50, 100} [itemsPerPage=25] items for each request. @apiParam {Number} [page=1] page you want to request from, start with 1. @apiParam {String="name", "description"} [orderBy=name] the items order by column you specified. @apiParam {String="true", "false"} [desc=false] the items order by descending or asceding order. @apiExample Example usage: curl -i http://localhost/rest/objects/ipaddrs?itemsPerPage=50&page=1&orderBy=name&desc=true @apiSuccess {Number} total total items for pagination. @apiSuccess {String} orderBy the items order by column you specified. @apiSuccess {Number} page page you want to request from, start with 1. @apiSuccess {Number} itemsPerPage items for each request. @apiSuccess {String} desc the items order by descending or asceding order. @apiSuccess {Object[]} ipaddrs List of IP Addresses. @apiSuccess {String} ipaddrs.addr1 1st IP Address. @apiSuccess {String} ipaddrs.addr2 2ed IP Address. @apiSuccess {String} ipaddrs.description this items's description. @apiSuccess {Number} ipaddrs.id index in database. @apiSuccess {String} ipaddrs.ipVersion IP Address version. @apiSuccess {String} ipaddrs.name items uniq name for record. @apiSuccess {String} ipaddrs.type IP Address type, the possible values are 'Single', 'Range', 'Subnet'. @apiError CE_INVALID_PARAM invalid parameter @api {get} /rest/objects/ipaddrs @apiErrorExample {json} we use invalid parameter pages curl -i http://localhost/rest/objects/ipaddrs?pages=1 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "{'pages'}" } """ # check the request is validtion, # ex: we not allow request arg 'itemsPerPage1' validSet = set(field_inputs_wrap.keys()) requestArgsSet = set(request.dataDictWrap.keys()) if not ExtraParamsIsValid(requestArgsSet, validSet): return omitError( ErrorMsg=repr(requestArgsSet.difference(validSet))), 400 # one to many # 1. parsing reqest try: # FIXME: # when i assign field_inputs['name']['required'] to True, # it could through below error: # ValueError: [name]: (name Valid Error) Missing required parameter # in dataDict # but i have no idea what it happen. if os.environ.get('EVN'): # in unit test field_inputs['name']['required'] = False logger.warning('now we are in unit test mode, turn off'\ ' field_inputs[\'name\'][\'required\']'\ ' but 1st run is ok :(') orgArgs, self.args = GetRequestArgs( None, field_inputs_wrap, dict((col, request.args.get(col)) for col in request.args)) # get default value # print(self.args, 'self.args', resource_fields_wrap) self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[__heads__] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 itemsPerPage = self.response['itemsPerPage'] page = self.response['page'] orderBy = getattr(obj, self.response['orderBy']) isDesc = getattr(orderBy, 'desc' if self.response['desc'] else 'asc') r = obj.query.order_by(isDesc()) _r = r.all() self.args['total'] = len(_r) if itemsPerPage is not 0: _r = r.offset(itemsPerPage * (page-1))\ .limit(itemsPerPage)\ .all() r = _r # 2. export to user for _r in r: __r = dict( (col, getattr(_r, col)) for col in _r.__table__.columns.keys()) self.args[__heads__].append(__r) resource_fields_wrap[__heads__] = fields.List( fields.Nested(resource_fields)) return marshal(self.args, resource_fields_wrap), 200
def get(self, id): """ @api {get} /rest/objects/ipaddr/:id get one IP address item. @apiName GetIpAddr @apiVersion 0.0.1 @apiGroup objects @apiPermission registered user @apiDescription todo validation @apiParam {Number} id IP Address item id. @apiExample Example usage: curl -i http://localhost/rest/objects/ipaddr/7 @apiSuccess {Object[]} ipaddrs List of IP Addresses. @apiSuccess {String} ipaddrs.addr1 1st IP Address. @apiSuccess {String} ipaddrs.addr2 2ed IP Address. @apiSuccess {String} ipaddrs.description this items's description. @apiSuccess {Number} ipaddrs.id index in database. @apiSuccess {String} ipaddrs.ipVersion IP Address version. @apiSuccess {String} ipaddrs.name items uniq name for record. @apiSuccess {String} ipaddrs.type IP Address type, the possible values are 'Single', 'Range', 'Subnet'. @apiError CE_INVALID_PARAM invalid parameter @api {get} /rest/objects/ipaddr/:id @apiErrorExample {json} we use invalid parameter pages curl -X GET -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddr/7?pages=1 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "{'pages'}" } @apiError CE_NOT_EXIST item not found @api {get} /rest/objects/ipaddr/:id @apiErrorExample {json} we use not exist id curl -X GET -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddr/17 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2003, "message": "id 17 not found" } """ requestArgsSet = set((col) for col in request.args) if not ExtraParamsIsValid(requestArgsSet): return omitError(ErrorMsg=repr(set( (col) for col in request.args))), 400 r = obj.query.filter(obj.id == id).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 self.args = {} self.args[__head__] = {} _resource_fields_wrap = {} _resource_fields_wrap[__head__] = fields.Nested(resource_fields) for col in r.__table__.columns.keys(): self.args[__head__][col] = getattr(r, col) return marshal(self.args, _resource_fields_wrap), 200
def put(self, id): """ update one item """ """update comment @api {put} /rest/customer/comment/:id create comment @apiVersion 0.0.5 @apiName UpdateComment @apiGroup campaign @apiPermission registered user @apiParam {Number} id comment id @apiDescription todo certificate with cookies / oauth 2.0<br /> todo long/lat validation<br /> todo metadata for counter of registerd devices<br /> todo error / success return code in api @apiParam {Object} data object @apiParam {String{..254}} data.content message's title @apiParam {Number} data.business_id comment belong to the business_id @apiParam {Number} data.user_id user who create it @apiParam {Number={0..5}} data.rate comment's rate @apiParam {String} type request's type @apiParam {String} subtype request's subtype @apiExample {curl} Example usage: curl -X PUT -H "mTag: xx" -H "Content-Type:application/json" -d " { "subtype":"comment", "type":"business", "data":{ "content":"Starbucks were all over Singapore and the quality ", "business_id":1, "user_id":2, "rate":1 } }" http://localhost/rest/customer/comment/1 HTTP/1.0 200 OK { "data":{ "content":"Starbucks were all over Singapore and the quality ", "user_id":1, "business_id":1, "rate":1, "mtime":"2016-08-31 04:16:42.091706", "id":2 }, "type":"business", "subtype":"comment" } @apiSuccess {Object} data object @apiSuccess {String{..254}} data.content message's title @apiSuccess {Number} data.business_id comment belong to the business_id @apiSuccess {Number} data.user_id user who create it @apiSuccess {Number} data.id comment's id @apiSuccess {String{..254}} data.mtime comment's modify time @apiSuccess {Number={0..5}} data.rate comment's rate @apiSuccess {String} type request's type @apiSuccess {String} subtype request's subtype """ # 1. parsing reqest try: orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 2. get orm from db r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 3. assign request data to orm try: t = datetime.utcnow() r = PrepareObjORM(r, self.args.items()) r.mtime = t except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # TODO: make sure tranaction _r = rates.query.filter(rates.user_id == self.args['user_id'], rates.business_id == self.args['business_id'], rates.isdel == False).scalar() if _r is None: return omitError( 'CE_NOT_EXIST', 'user_id {}, business_id {} '.format( self.args['user_id'], self.args['business_id'])), 400 _r.rate = self.args['rate'] # 4. commit to save try: db.session.merge(r) db.session.merge(_r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user out = SerialObjOutput(r, objname=field_inputs_wrap_head, resource_fields=resource_fields_post), 200 next(iter(out))[field_inputs_wrap_head].update({'id': id}) next(iter(out))[field_inputs_wrap_head].update( {'rate': self.args['rate']}) next(iter(out))['type'] = 'business' next(iter(out))['subtype'] = 'comment' return out
def put(self, id): """ update one item """ # 1. parsing reqest try: orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 2. get orm from db r = obj.query.filter(obj.id == id, obj.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 # 3. assign request data to orm try: t = datetime.utcnow() if not self.args['passHash']: self.args['passHash'] = r.passHash # not allow others change expect itself # TODO: raise custome error check_permission(self.args['login'], r.login) # not allow change login name self.args['login'] = r.login r = PrepareObjORM(r, self.args.items()) r.mtime = t except Exception as error: if RuntimeError == type(error): return omitError('CE_UNAUTHORIZED', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.merge(r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user _resource_fields_post = resource_fields_post.copy() _resource_fields_post.pop('access_token', None) out = SerialObjOutput(r, objname=field_inputs_wrap_head, resource_fields=_resource_fields_post), 200 next(iter(out))['type'] = 'system' next(iter(out))['subtype'] = 'regist' return out
def post(self): """regist local user @api {post} /rest/admins regist local account @apiVersion 0.0.5 @apiName RegistOneUser @apiGroup account @apiPermission registered user @apiDescription todo certificate with cookies / oauth 2.0<br /> todo validation<br /> todo error / success return code in api @apiParam {Object[]} user user object @apiParam {String{..254}} user.name user name for display @apiParam {String{..254}} user.login user email for login @apiParam {String{..254}} user.passHash user password encode with sha1 @apiExample {curl} Example usage: curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d " { 'data':{ 'id':2, 'login':'******', 'passHash':'c4f9375f9834b4e7f0a528cc65c055702bf5f24a', 'name':'test' }, 'type':'system', 'subtype':'regist' } " http://localhost/rest/admins """ # 1. check id exist try: orgArgs, self.args = GetTwoLayerRequestArgs( field_inputs_wrap_head, field_inputs_post) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError('CE_INVALID_PARAM', 'not found'), 400 # 2. validate follows spec if db.session.query(obj).filter(obj.isdel == False).count() > max: return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(max)), 400 # 3 check name unique r = obj.query.filter(obj.login == self.args['login'], obj.isdel == False).scalar() if r is not None: return omitError( 'CE_DATA_DUPLICATE', 'login {} is duplicate'.format(self.args['login'])), 400 r = obj() try: r = PrepareObjORM(r, self.args.items()) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.add(r) db.session.flush() db.session.refresh(r) db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user _resource_fields_post = resource_fields_post.copy() _resource_fields_post.pop('access_token', None) out = SerialObjOutput(r, objname=field_inputs_wrap_head, resource_fields=_resource_fields_post), 200 next(iter(out))[field_inputs_wrap_head].update({'id': r.id}) next(iter(out))['type'] = 'system' next(iter(out))['subtype'] = 'regist' return out
def post(self): """create data @api {post} /rest/objects/ipaddrs Create a IP Address item @apiVersion 0.0.1 @apiName CreateIpAddr @apiVersion 0.0.1 @apiGroup objects @apiPermission registered user @apiDescription todo validation <br/> todo certificate with cookies / oauth 2.0 <br/> todo muti-create @apiParam {Object} ipaddrs List of IP Addresses. @apiParam {String{..16}} ipaddrs.addr1 1st IP Address. @apiParam {String{..16}} ipaddrs.addr2 2ed IP Address. @apiParam {String{..255}} [ipaddrs.description] this items's description. @apiParam {String="IPv4","IPv6"} ipaddrs.ipVersion IP Address version. @apiParam {String{..50}} ipaddrs.name items uniq name for record. @apiParam {String="Single","Range","Subnet"} ipaddrs.type IP Address type, the possible values are 'Single', 'Range', 'Subnet'. @apiExample Example usage: BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddrs @apiSuccess {Object} ipaddrs List of IP Addresses. @apiSuccess {String} ipaddrs.addr1 1st IP Address. @apiSuccess {String} ipaddrs.addr2 2ed IP Address. @apiSuccess {String} ipaddrs.description this items's description. @apiSuccess {Number} ipaddrs.id index in database. @apiSuccess {String} ipaddrs.ipVersion IP Address version. @apiSuccess {String} ipaddrs.name items uniq name for record. @apiSuccess {String} ipaddrs.type IP Address type, the possible values are 'Single', 'Range', 'Subnet'. @apiError CE_INVALID_PARAM invalid parameter @api {post} /rest/objects/ipaddrs @apiErrorExample {json} we use invalid parameter pages BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type1" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddrs ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "ValueError('[type]: (type Valid Error) Missing required parameter in dataDict, error=400: Bad Request',)" } @apiError CE_NAME_CONFLICT name conflict @api {post} /rest/objects/ipaddrs @apiErrorExample {json} we use duplicate name. BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddrs ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2004, "message": "IntegrityError('(sqlite3.IntegrityError) UNIQUE constraint failed: objects_ipaddrs.name',)" } @apiError CE_EXCEED_LIMIT exceed max limit @api {post} /rest/objects/ipaddrs @apiErrorExample {json} we create item exceed max. BODY=$(cat <<'EOF' { "ipaddr" : { "name" : "test-ipaddr-${i}8", "type" : "Single", "ipVersion" : "IPv4", "addr1" : "1.1.1.1", "description" : "xxx" } } EOF ); curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d "${BODY}" http://localhost/rest/objects/ipaddrs ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2005, "message": "limit is 5" } """ # 1. parsing reqest # 1.1 parsing 1st layer reqest try: orgArgs, self.args = GetRequestArgs(__head__, field_inputs) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 # 1.2 parsing 2ed layer reqest try: for v in set((v) for v in set(field_inputs).intersection(orgArgs) if isinstance(field_inputs[v]['validator'], set)): _type = field_inputs[v]['validator'] validator = next(iter(_type)).container.nested.items() \ if type(_type) is set else _type.items() # validate 2ed value # if is list, such as [{id: 1, name:2}, {id: 2, name:2}] for _k, _v in validator: for __v in orgArgs[v]: if (_v.get('required', False)): _v['type'](__v[_k]) self.args[v] = self.args[v] if self.args.get(v, False) else [] self.args[v].append(__v) except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 logger.debug('parsed args = (%s)', self.args) # 2. validate follows spec if db.session.query(obj.id).count() > max: return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(max)), 400 try: checkInputIsValid(self.args) except Exception as error: return error.args r = obj() try: r = PrepareObjORM(r, self.args.items()) except Exception as error: return omitError(ErrorMsg=repr(error)), 400 # 4. commit to save try: db.session.add(r) db.session.flush() db.session.commit() except Exception as error: db.session.rollback() logger.warning('session commit error(%s)', error) if exc.IntegrityError == type(error): return omitError('CE_NAME_CONFLICT', repr(error)), 400 return omitError(ErrorMsg=repr(error)), 400 # 5. return all data to user return SerialObjOutput(r, objname=__head__, resource_fields=resource_fields), 200
def get(self): """Get all data, getall """ # check the request is validtion, # ex: we not allow request arg 'itemsPerPage1' validSet = set(field_inputs_wrap.keys()) requestArgsSet = set(request.dataDictWrap.keys()) if not ExtraParamsIsValid(requestArgsSet, validSet): return omitError( ErrorMsg=repr(requestArgsSet.difference(validSet))), 400 # one to many # 1. parsing reqest try: for k, v in field_inputs.items(): field_inputs[k]['required'] = False orgArgs, self.args = GetRequestArgs( None, field_inputs_wrap, dict((col, request.args.get(col)) for col in request.args)) # get default value # print(self.args, 'self.args', resource_fields_wrap) self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[field_inputs_wrap_head] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 itemsPerPage = self.response['itemsPerPage'] page = self.response['page'] orderBy = getattr(obj, self.response['orderBy']) isDesc = getattr(orderBy, 'desc' if self.response['desc'] else 'asc') r = obj.query.filter(obj.isdel == False).order_by(isDesc()) _r = r.all() self.args['total'] = len(_r) if itemsPerPage is not 0: _r = r.offset(itemsPerPage * (page-1))\ .limit(itemsPerPage)\ .all() r = _r # 2. export to user for _r in r: __r = dict( (col, getattr(_r, col)) for col in _r.__table__.columns.keys()) self.args[field_inputs_wrap_head].append(__r) _resource_fields = resource_fields.copy() _resource_fields_wrap = resource_fields_wrap.copy() _resource_fields_wrap[field_inputs_wrap_head] = fields.List( fields.Nested(_resource_fields)) self.args['type'] = "business" self.args['subtype'] = "rate" return marshal(self.args, _resource_fields_wrap), 200
def delete(self): """multi delete @api {delete} /rest/objects/ipaddrs delete IP address items. @apiName DelIpAddrs @apiVersion 0.0.1 @apiGroup objects @apiPermission registered user @apiDescription todo validation @apiParam {String{..255}} [ids] the items id seperate with common @apiExample Example usage: curl -X DELETE -v -b $COOKIES -H "Content-Type:application/json" http://localhost/rest/objects/ipaddrs?id=1,2,3 ================================================ HTTP/1.0 204 NO CONTENT @apiError CE_INVALID_PARAM invalid parameter @api {delete} /rest/objects/ipaddrs @apiErrorExample {json} we use invalid parameter pages curl -X DELETE -v -b $COOKIES -H "Content-Type:application/json" http://localhost/rest/objects/pages?id=1,2,3 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "param `ipaddrs` not found" } @apiError CE_NOT_EXIST item not found @api {delete} /rest/objects/ipaddr @apiErrorExample {json} we use not exist id curl -X DELETE -v -b $COOKIES -H "Content-Type:application/json" http://localhost/rest/objects/pages?id=7,8,9 ================================================ HTTP/1.0 400 BAD REQUEST { "errorId": 2003, "message": "id 7 not found" } """ try: ids = request.args.get(__heads__).split(',') except Exception as error: return omitError( ErrorMsg='param `{}` not found'.format(__heads__)), 400 for id in ids: try: id = inputs.natural(id) except Exception as error: db.session.rollback() return omitError(ErrorMsg='id `{}` not int'.format(id)), 400 # it could als cascade delete `online` user r = obj.query.filter(obj.id == id).scalar() if r is None: db.session.rollback() return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 db.session.delete(r) try: db.session.flush() db.session.commit() except Exception as error: logger.warning('session commit error(%s)', error) db.session.rollback() return omitError(ErrorMsg=repr(error)), 400 return '', 204
def get(self): """Get all data, getall @api {get} /rest/customer/businesses list business @apiName GetAllCustomerBusinesses @apiVersion 0.0.3 @apiGroup business @apiPermission registered user @apiDescription modified: change category type from string to number.<br/> modified: add name attribute.<br /> modified: change deal type from string to number.<br/> todo validation<br/> query string <br /> todo error / success return code in api <br /> @apiParam {Number=0, 25, 50, 100} [itemsPerPage=25] items for each request. @apiParam {Number} [page=1] page you want to request from, start with 1. @apiParam {String="name", "description"} [orderBy=name] the items order by column you specified. @apiParam {String="true", "false"} [desc=false] the items order by descending or asceding order. @apiExample {curl} Example usage: curl -X GET -H "mTag: xx" -H "Content-Type:application/json" -i http://localhost/rest/customer/businesses?itemsPerPage=50&page=1&orderBy=name&desc=true { "page":1, "type":"business", "orderBy":"name", "desc":0, "total":1, "itemsPerPage":25, "subtype":"list", "data":[ { "lat":120.678, "id":1, "deal":200, "name":"Starbucks Coffee 31", "image_url":"", "long":23.5383, "cat":1, "description":"early Bird Special: Get off." } ] } @apiSuccess {Number} total total items for pagination @apiSuccess {String} orderBy the items order by column you specified @apiSuccess {Number} page page you want to request from, start with 1 @apiSuccess {Number} itemsPerPage items for each request @apiSuccess {String} desc the items order by descending or asceding order @apiSuccess {String} type request's type @apiSuccess {String} subtype request's subtype @apiSuccess {Object} business object of business. @apiSuccess {Number} business.id item's uniq id. @apiSuccess {String} business.name item's name. @apiSuccess {Number} business.cat item's business industry category. @apiSuccess {float} business.lat item's entered latitude. @apiSuccess {float} business.long item's entered longitude. @apiSuccess {String} business.address item's address @apiSuccess {String} business.description item's description. @apiSuccess {Number} business.deal item's deal. @apiSuccess {String} business.image_url items's image url. @apiError CE_INVALID_PARAM invalid parameter HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "{'pages'}" } """ # check the request is validtion, # ex: we not allow request arg 'itemsPerPage1' validSet = set(field_inputs_wrap.keys()) requestArgsSet = set(request.dataDictWrap.keys()) if not ExtraParamsIsValid(requestArgsSet, validSet): return omitError( ErrorMsg=repr(requestArgsSet.difference(validSet))), 400 # one to many # 1. parsing reqest try: for k, v in field_inputs.items(): field_inputs[k]['required'] = False orgArgs, self.args = GetRequestArgs( None, field_inputs_wrap, dict((col, request.args.get(col)) for col in request.args)) # get default value # print(self.args, 'self.args', resource_fields_wrap) self.response = dict( marshal(self.args, resource_fields_wrap).items()) self.args[field_inputs_wrap_head] = [] except Exception as error: logger.debug('traceback.format_exc(%s)', traceback.format_exc()) return omitError(ErrorMsg=repr(error)), 400 itemsPerPage = self.response['itemsPerPage'] page = self.response['page'] orderBy = getattr(obj, self.response['orderBy']) isDesc = getattr(orderBy, 'desc' if self.response['desc'] else 'asc') r = obj.query.filter(obj.isdel == False).order_by(isDesc()) _r = r.all() self.args['total'] = len(_r) if itemsPerPage is not 0: _r = r.offset(itemsPerPage * (page-1))\ .limit(itemsPerPage)\ .all() r = _r # 2. export to user for _r in r: __r = dict( (col, getattr(_r, col)) for col in _r.__table__.columns.keys()) #__r['description'] = getattr(_r.detail, 'description') # (1, 'icon'), (2, 'bg'), (3, 'gallery') ___r = pics.query.filter(pics.business_id == _r.id, pics.type == 1).scalar() __r['image_url'] = getattr(___r, 'path', "") self.args[field_inputs_wrap_head].append(__r) resource_fields_wrap[field_inputs_wrap_head] = fields.List( fields.Nested(resource_fields)) self.args['type'] = "business" self.args['subtype'] = "list" return marshal(self.args, resource_fields_wrap), 200
def get(self, id): """get one item @api {get} /rest/customer/business/:id get one business @apiName GetCustomerBusiness @apiVersion 0.0.4 @apiGroup customer @apiPermission registered user @apiDescription todo validation<br /> todo query target<br/> @apiParam {Number} id business id, you can get from GetAllCustomerBusinesses. @apiExample Example usage: HTTP/1.0 200 OK { "id": 1, "name": "Starbucks Coffee", "image_url": "/business/1/icon", "cat": 1, "deal": 200, "lat": 120.678469, "long": 23.538302, "description": "Early Bird Special: Get $2 off.", "detail": { "rate": 4.3, "rates": [ {"u_id": 1, "avatar_url": "/user/1/avater"}, {"u_id": 2, "avatar_url": "/user/2/avater"} ], "deals": [ {"title": "morning", "description": "for every one"} ], "open": "0600", "close": "2100", "dist": 12333333, "address": "CA", "images_url": { "bg": "/business/1/bg", "icon": "/business/1/icon" } } } @apiSuccess {Object} business object of business. @apiSuccess {Number} business.id item's uniq id. @apiSuccess {String} business.name item's name. @apiSuccess {Number} business.cat item's business industry category. @apiSuccess {float} business.lat item's entered latitude. @apiSuccess {float} business.long item's entered longitude. @apiSuccess {String} business.address item's address @apiSuccess {String} business.description item's description. @apiSuccess {Number} business.deal item's deal. @apiSuccess {String} business.image_url items's image url. @apiSuccess {Object} business.detail item's detail @apiSuccess {Float} business.detail.rate item's rate, average from each comments @apiSuccess {Object[]} business.detail.rates item's brief comments @apiSuccess {Number} business.detail.rates.u_id comment's author id @apiSuccess {String} business.detail.rates.avatar_url comment's author avatar url path @apiSuccess {Object[]} business.detail.deals item's deals @apiSuccess {String} business.detail.deals.title item's deal title @apiSuccess {String} business.detail.deals.description item's deal description @apiSuccess {String} business.detail.open item open time with 24h format @apiSuccess {String} business.detail.open item close time with 24h format @apiSuccess {Number} business.detail.dist item's distance farward with your current location, the unit is meter @apiSuccess {Object} business.detail.images_url item images' path @apiSuccess {String} business.detail.images_url.bg item backgound images' path @apiSuccess {String} business.detail.images_url.icon item icon images' path @apiError CE_INVALID_PARAM invalid parameter HTTP/1.0 400 BAD REQUEST { "errorId": 2001, "message": "{'pages'}" } @apiError CE_NOT_EXIST item not found HTTP/1.0 400 BAD REQUEST { "errorId": 2003, "message": "id 17 not found" } """ requestArgsSet = set((col) for col in request.args) if not ExtraParamsIsValid(requestArgsSet): return omitError(ErrorMsg=repr(set( (col) for col in request.args))), 400 r = detail.query.filter(detail.business_id == id, detail.isdel == False).scalar() if r is None: return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400 self.args = {} self.args[field_inputs_wrap_head] = {} #self.args[field_inputs_wrap_head][__head_detail__] = {} _resource_fields_wrap = resource_fields_wrap.copy() for col in resource_fields_wrap: if col not in ['type', 'subtype']: _resource_fields_wrap.pop(col, None) #_resource_fields_detail_wrap = {} #resource_fields_detail[__head_detail_rates__] = \ # fields.List(fields.Nested(resource_fields_detail_rates)) resource_fields_detail[__head_detail_deals__] = \ fields.List(fields.Nested(resource_fields_detail_deals)) _resource_fields_detail_rates = {} #_resource_fields_detail_rates['user'] = fields.Nested(resource_fields_detail_rates) _resource_fields_detail_rates = resource_fields_detail_rates.copy() resource_fields_detail['users'] = \ fields.List(fields.Nested(_resource_fields_detail_rates)) #resource_fields.update(resource_fields_detail) resource_fields_detail[__head_detail_images_url__] = \ fields.Nested(resource_fields_detail_images_url) #resource_fields[__head_detail__] = fields.Nested(_resource_fields_detail_wrap) #_resource_fields_wrap[field_inputs_wrap_head] = fields.Nested(resource_fields) _resource_fields_wrap[field_inputs_wrap_head] = fields.Nested( resource_fields_detail) #print('_resource_fields_wrap ', resource_fields) _r = r #for col in resource_fields.keys(): # self.args[field_inputs_wrap_head][col] = getattr(_r, col) #for col in resource_fields.keys(): for col in _r.__table__.columns.keys(): self.args[field_inputs_wrap_head][col] = getattr(_r, col) self.args[field_inputs_wrap_head]['name'] = getattr(_r.meta, 'name') rate = 0 self.args[field_inputs_wrap_head]['rate'] = rate self.args[field_inputs_wrap_head]['users'] = [] self.args[field_inputs_wrap_head][__head_detail_deals__] = [] self.args[field_inputs_wrap_head]['images_url'] = {} __r = db.session.query(rates).\ filter(rates.business_id == id).all() r_len = len(__r) self.args[field_inputs_wrap_head]['rate_nr'] = r_len if r_len > 0: for ___r in __r: rate += ___r.rate self.args[field_inputs_wrap_head]['rate'] = int(rate / r_len) # FIXME: hard code __r = db.session.query(comment).\ filter(comment.business_id == id).order_by(comment.mtime.desc()).offset(0).limit(5).all() r_len = len(__r) self.args[field_inputs_wrap_head]['user_nr'] = r_len if r_len > 0: for __r in __r: ___r = db.session.query(Users).\ filter(__r.user_id == Users.id).scalar() self.args[field_inputs_wrap_head]['users'].append( #{'user': { 'id': ___r.id, 'avatar_url': ___r.avatar_url } #} ) # TODO: get favorite by User id from session _r = deals.query.filter(deals.business_id == id).all() r_len = len(_r) if r_len: for __r in _r: self.args[field_inputs_wrap_head][ __head_detail_deals__].append({ 'title': __r.title, 'description': __r.description }) _r = pics.query.filter(pics.business_id == id).all() # (1, 'icon'), (2, 'bg'), (3, 'gallery') r_len = len(_r) if r_len > 0: # TODO: mapping table for __r in _r: if getattr(__r, 'type') == 1: self.args[field_inputs_wrap_head]['images_url']['icon'] = \ getattr(__r, 'path') r_len -= 1 elif getattr(__r, 'type') == 2: self.args[field_inputs_wrap_head]['images_url']['bg'] = \ getattr(__r, 'path') r_len -= 1 self.args[field_inputs_wrap_head]['gallery_nr'] = r_len self.args[field_inputs_wrap_head]['id'] = id self.args['type'] = "business" self.args['subtype'] = "overview" #print('self.args= ', self.args, '_resource_fields_wrap', _resource_fields_wrap) return marshal(self.args, _resource_fields_wrap), 200