Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
    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
Exemple #5
0
    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
Exemple #6
0
    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
Exemple #7
0
    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
Exemple #8
0
    def post(self):
        """create data
        """
        """create comment 

        @api {post} /rest/customer/comments create comment
        @apiVersion 0.0.5
        @apiName CreateComment
        @apiGroup campaign
        @apiPermission registered user


        @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 POST -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/comments

        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
        # 1.1 parsing 1st layer reqest

        try:
            #orgArgs = {'type': 'business', 'subtype': 'comment', 'data': {"content": "Starbucks were all over Singapore and the quality" ,"business_id": 1, "user_id": 1}}'

            orgArgs, self.args = GetTwoLayerRequestArgs(
                field_inputs_wrap_head, field_inputs_post)
            #print("self.args=", self.args)
            #return {}, 400

        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

        # TODO: make sure tranaction
        # 1.3 check name unique
        _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 not None:
            return omitError(
                'CE_DATA_DUPLICATE',
                'user_id {}, business_id {} are duplicate'.format(
                    self.args['user_id'], self.args['business_id'])), 400

        _r = rates()
        _r.business_id = self.args['business_id']
        _r.user_id = self.args['user_id']
        _r.rate = self.args['rate']

        # 4. commit to save
        try:
            db.session.add(r)
            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))[field_inputs_wrap_head].update(
            {'rate': self.args['rate']})
        next(iter(out))['type'] = 'business'
        next(iter(out))['subtype'] = 'comment'

        return out
Exemple #9
0
    def post(self, business_id):
        """push notification to all device under business id

        @api {post} /rest/pushno/send/:id send message to registed devices under business id
        @apiVersion 0.0.4
        @apiName SendNoticeToDevicesByBusinessId
        @apiGroup pushno
        @apiPermission registered user

        @apiParam {Number} id business 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        push notification's body
        @apiParam {String{..254}}   data.title  message's title
        @apiParam {String{..254}}   data.message  message
        @apiParam {String{..254}}   data.url  message's url
        @apiExample {curl} Example usage:

        curl -X POST -H "mTag: xx" -H "Content-Type:application/json" -d "
        {  
            "data":{  
                "title":"XXXX",
                "message":"scscs",
                "uri":"xxxxx"
            }
        }" http://localhost/rest/pushno/reg/1

        """

        # 1. parsing reqest
        # 1.1 parsing 1st layer reqest

        try:
            orgArgs, self.args = GetTwoLayerRequestArgs(
                field_inputs_wrap_head, field_inputs_send)
        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 = business.query.filter(business.id == business_id,
                                  business.isdel == False).scalar()

        if r is None:
            return omitError('CE_NOT_EXIST',
                             'id {} not found'.format(business_id)), 400

        # 2. validate follows spec
        r = obj.query.filter(obj.business_id == business_id,
                             obj.isdel == False).all()

        alert = {}
        alert['title'] = self.args['title']
        alert['message'] = self.args['message']
        alert['uri'] = self.args['uri']

        gcms = []
        apns = []
        for _r in r:
            # (1, 'andriod'), (2, 'ios')
            if _r.type == 1:
                gcms.append(_r.dev_id)
            elif _r.type == 2:
                apns.append(_r.dev_id)

        # ref: http://pushjack.readthedocs.io/en/latest/
        #logger.debug('gcm len %d, all items: %s', len(gcms), gcms)
        #>>> l = [1, 2, 3, 4]
        #>>> [l[i:i + 2] for i in range(0, len(l), 2)]
        #[[1, 2], [3, 4]]]
        _l = gcms
        itemsPerPage = settings.GCM_MAX_BATCH_SEND
        for chunk in [
                _l[i:i + itemsPerPage] for i in range(0, len(_l), itemsPerPage)
        ]:
            # FIXME: config it
            response = gcm_client.send(chunk,
                                       alert,
                                       collapse_key='mi',
                                       delay_while_idle=True,
                                       time_to_live=604800)
            #logger.debug("gcm r:", response, dir(response))

            #gcm errors: [GCMInvalidRegistrationError (code=InvalidRegistration): Invalid registration ID for identifier XXXXX, GCMInvalidRegistrationError (code=InvalidRegistration): Invalid registration ID for identifier XXXXX, GCMInvalidRegistrationError (code=InvalidRegistration): Invalid registration ID for identifier XXXXX]
            #gcm failures: ['XXXXX', 'XXXXX', 'XXXXX']
            #gcm data: [{'multicast_id': 5353943955785430694, 'results': [{'error': 'InvalidRegistration'}, {'error': 'InvalidRegistration'}, {'error': 'InvalidRegistration'}], 'success': 0, 'failure': 3, 'canonical_ids': 0}]
            #logger.debug('gcm errors: %s', response.errors)
            #logger.debug('gcm failures: %s', response.failures)
            #logger.debug('gcm data: %s', response.data)

            # Successfully handled registration_ids
            for reg_id in response.successes:
                logger.debug('Successfully sent notification for reg_id %d',
                             (reg_id))

            # Handling errors
            # FIXME: add error code
            if len(response.errors) > 0:
                logger.debug('gcm data: %s', response.data)
                return omitError('CE_NOT_EXIST',
                                 '{} not found'.format(response.errors)), 400

        _l = apns
        itemsPerPage = settings.APNS_MAX_BATCH_SEND
        for chunk in [
                _l[i:i + itemsPerPage] for i in range(0, len(_l), itemsPerPage)
        ]:
            response = apns_client.send(apns,
                                        alert,
                                        expiration=int(time.time() + 604800),
                                        error_timeout=5,
                                        batch_size=1000)

            print("apns r:", dir(response))

            if len(response.errors) or len(response.token_errors) > 0:
                return omitError('CE_NOT_EXIST',
                                 '{} not '.format(response)), 400

        apns_client.close()

        # 5. return all data to user
        out = SerialObjOutput(r,
                              objname=field_inputs_wrap_head,
                              resource_fields=resource_fields_send), 200

        next(iter(out))[field_inputs_wrap_head].update({'gcm_nr': len(gcms)})
        next(iter(out))[field_inputs_wrap_head].update({'apns_nr': len(apns)})
        next(iter(out))['type'] = 'pushno'
        next(iter(out))['subtype'] = 'send'

        return out
Exemple #10
0
    def post(self):
        """upload pics to business

        @api {post} /rest/pic/gallery upload multiple pictures to business
        @apiVersion 0.0.5
        @apiName UploadPicsToBusiness
        @apiGroup business
        @apiPermission registered user


        @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

        @apiHeader {String}         file[]      upload file path 
        @apiHeader {Number}         business_id upload to business
        @apiHeader {String={customer}}         type      upload type
        @apiExample {curl} Example usage:
        curl -v -i -X POST -H "Content-Type: multipart/form-data" -F "file[]=@20160618_6615.jpg" -F "business_id=1" -F type="customer" -F "file[][email protected]" http://localhost/rest/pic/gallery

        {  
            "type":"pic",
            "data":[  
                {  
                    "id":9,
                    "path":"/img/customer/1/G30SLL_20160618_6615.jpg",
                    "height":1365,
                    "width":1024
                },
                {  
                    "id":10,
                    "path":"/img/customer/1/3AZGA4_10473.jpg",
                    "height":1365,
                    "width":1024
                }
            ],
            "page":1,
            "subtype":"gallery",
            "gallery_nr":2,
            "total":6
        }

        @apiSuccess {Number}   total         total items in one business 
        @apiSuccess {String}   orderBy       the items order by column you specified
        @apiSuccess {Number}   page          page you want to request from, start with 1
        @apiSuccess {Number}   gallery_nr    current upload files number
        @apiSuccess {String}   type          request's type
        @apiSuccess {String}   subtype       request's subtype

        @apiSuccess {Object[]}   data       object

        @apiSuccess {Number}     data.id    image's id
        @apiSuccess {Number}     data.path  image's url that you could directly access
        @apiSuccess {Number}     data.height image's height(px)
        @apiSuccess {Number}     data.width image's width(px)
        """

        try:
            orgArgs, self.args = GetTwoLayerRequestArgs(
                None, field_inputs, request.form)
        except Exception as error:
            logger.debug('traceback.format_exc(%s)', traceback.format_exc())

            return omitError('CE_INVALID_PARAM', 'not found'), 400

        id = self.args['business_id']
        type = self.args['type']
        #print(self.args, 'self.args', id, type)
        #self.args = {}
        #id = request.form.get('business_id')
        #type = request.form.get('type')

        #if type not in PIC_ALLOWED_TYPE:
        #    logger.debug('%s not in PIC_ALLOWED_TYPE', type)
        #    type = None

        #if not id or not type:
        #    return omitError('CE_INVALID_PARAM', 'id {} not found'.format(id)), 400

        print("galleryed_files", request.files, "form data=", request.form)

        # 1. check id exist
        r = business.query.filter(business.id == id,
                                  business.isdel == False).scalar()

        if r is None:
            return omitError('CE_NOT_EXIST', 'id {} not found'.format(id)), 400

        # if dir not exist, create it
        # /img/business/1/
        pic_dir = os.path.join(STATIC_ROOT, PIC_PREFIX, type, str(id))
        rest_pic_prefix = os.path.join(REST_PIC_PREFIX, type, str(id))

        if not os.path.exists(pic_dir):
            os.makedirs(pic_dir)

        # TODO: review trigger time
        # 2. check last status that records are same with local
        _pics = []
        count = 0
        filenames = next(os.walk(pic_dir))[2]
        _filenames = filenames.copy()
        print("filenames=", _filenames)
        ps = obj.query.filter(obj.business_id == id).all()
        for v in ps:
            #print("filenames=", filenames, "v.path=", v.path)
            if v.path in filenames:
                count += 1
                _filenames.remove(v.path)
            else:
                # prepare remove
                _pics.append(v)

        # TODO: need check duplicate record?
        # 2.1. commit to delete not relationship records
        try:
            for v in _pics:
                db.session.delete(v)

            db.session.flush()
            db.session.commit()
        except Exception as error:
            db.session.rollback()
            logger.warning('session commit error(%s)', error)

            return omitError(ErrorMsg=repr(error)), 400

        # remove not exist db's file
        for v in _filenames:
            os.remove(os.path.join(pic_dir, v))

        # 3. validate follows spec
        if count > max:
            return omitError('CE_EXCEED_LIMIT', 'limit is {}'.format(max)), 400

        # 4. check pic name
        _pics = []
        filenames = []
        galleryed_files = request.files.getlist("file[]")
        print("galleryed_files file[]= ", galleryed_files)

        if len(galleryed_files) == 0:
            galleryed_files = request.files.getlist("customer")  # for ios
            print("galleryed_files customer= ", galleryed_files)

        for file in galleryed_files:
            # Check if the file is one of the allowed types/extensions
            if file and self.allowed_file(file.filename):
                # Make the filename safe, remove unsupported chars
                filename = secure_filename(file.filename)
                print("file.filename=", file.filename, "filename=", filename)
                # Move the file form the temporal folder to the gallery
                # folder we setup
                p = obj()
                rs = ''.join(
                    random.SystemRandom().choice(string.ascii_uppercase +
                                                 string.digits)
                    for _ in range(6))
                # 5FATMM_35e4183b.jpg.png -> 5FATMM_35e4183b.png
                extend = os.path.splitext(filename)[1]
                #print("self.remove_extend(filename)=", self.remove_extend(filename))
                p.path = '_'.join([rs, self.remove_extend(filename)]) + extend
                p.business_id = id
                # (1, 'icon'), (2, 'bg'), (3, 'gallery')
                p.type = 3

                _pics.append(p)
                filenames.append(filename)

        # 4. move to pic dir
        # FIXME: check file exist if abnormal error that db record save but pic not exist
        self.args[field_inputs_wrap_head] = []
        path = []
        _filenames = []
        for k, v in enumerate(_pics):
            filename = os.path.join(pic_dir, filenames[k])
            n_filename = os.path.join(pic_dir, v.path)

            try:
                # FIXME: handle <FileStorage: '35e4183b.jpg.png' ('application/octet-stream')>)
                galleryed_files[k].save(filename)
                #import shutil
                #shutil.copy(filename, n_filename)
                os.rename(filename, n_filename)
                _filenames.append(n_filename)

                print("n_filename = ", n_filename, "filename=", filename)
                img = Image.open(n_filename)
                s = img.size
                ratio = 0
                v.width = s[0]
                v.height = s[1]
                if s[0] > MAXWIDTH:
                    ratio = MAXWIDTH / s[0]
                    v.width = MAXWIDTH
                    v.height = int(round(s[1] * ratio))
                    img.thumbnail((v.width, v.height), Image.ANTIALIAS)
                print("img = ", img, "n_filenam=", n_filename, "format:",
                      img.format, "width:", MAXWIDTH, ", height: ",
                      int(round(s[1] * ratio)), "orgsize:", s)
                #img.save(n_filename, img.format)
                # FIXME: open 35e4183b.jpg.png error
                img.save(n_filename)

            except IOError:
                #for v in _filenames:
                #    os.remove(v)

                return omitError('CE_IMAGE_RESIZE',
                                 'image resize {} error'.format(
                                     filenames[k])), 400

        # 5. commit to save
        try:
            for v in _pics:
                db.session.add(v)

            db.session.flush()
            db.session.refresh(r)

            for v in _pics:
                _pic = dict((col, getattr(v, col))
                            for col in v.__table__.columns.keys())
                print("_pic:", _pic)
                _pic['path'] = os.path.join(rest_pic_prefix, v.path)
                self.args[field_inputs_wrap_head].append(_pic)

            db.session.commit()
        except Exception as error:
            db.session.rollback()
            logger.warning('session commit error(%s)', error)

            return omitError(ErrorMsg=repr(error)), 400

        #output = {"type": "pic", "subtype": "gallery",
        #        "imgs": {"total": count, "gallery_nr": len(_pics), "path": (path)}}

        for v in ['itemsPerPage', 'desc', 'orderBy']:
            resource_fields_wrap.pop(v, None)

        _resource_fields = {}
        resource_fields_wrap[field_inputs_wrap_head] = fields.List(
            fields.Nested(resource_fields_post))

        self.args['total'] = len(
            obj.query.filter(obj.business_id == id, obj.isdel == False).all())
        self.args['gallery_nr'] = len(_pics)
        self.args['type'] = "pic"
        self.args['subtype'] = "gallery"
        return marshal(self.args, resource_fields_wrap), 200