예제 #1
0
    def put(self, **kwargs):
        '''
            Update or create a relationship child item

            to be used to create or update one-to-many mappings but also works for many-to-many etc.
        '''

        parent, child, relation = self.parse_args(**kwargs)
        
        data  = request.get_json()

        if child and not child.id == kwargs.get('id'):
            raise ValidationError('ID mismatch')

        child = self.child_class(**data)

        if not child:
            raise ValidationError('Child Not found')
        
        relation = getattr(parent, self.rel_name )
        relation.append(child)
        
        # arguments for GET : {ParentId} , {ChildId}
        obj_args = { 
                     self.parent_object_id : parent.id,
                     self.child_object_id  : child.id
                    }
        
        obj_data = self.get(**obj_args)
        
        # Retrieve the object json and return it to the client
        response = make_response(obj_data, 201)
        # Set the Location header to the newly created object
        response.headers['Location'] = url_for(self.endpoint, **obj_args)
        return response
예제 #2
0
    def parse_args(self, **kwargs):
        '''
            Parse relationship args
            An error is raised if the parent doesn't exist. 
            An error is raised if the child doesn't exist and the 
            "require_child" argument is set in kwargs, 
            
            Returns
                parent, child, relation
        '''

        parent_id = kwargs.get(self.parent_object_id,'')
        parent = self.parent_class.get_instance(parent_id)
        if not parent:
            raise ValidationError('Invalid Parent Id')
        child = None
        child_id = kwargs.get(self.child_object_id,None)
        if child_id != None:
            child = self.child_class.get_instance(child_id)
        if not child and kwargs.get('require_child', False):
            raise ValidationError('Invalid Child Id')

        relation = getattr(parent, self.rel_name )

        return parent, child, relation
예제 #3
0
    def post(self, **kwargs):
        '''
            HTTP POST: apply actions
            Retrieves objects from the DB based on a given query filter (in POST data)
            Returns a dictionary usable by jquery-bootgrid
        ''' 

        id = kwargs.get(self.object_id, None)
        method_name = kwargs.get('method_name','')
        
        json_data = request.get_json()
        if not method_name:
            method_name = json_data.get('method',None)
        args = json_data.get('args') if json_data else dict(request.args)
        
        if not id:
            id = request.args.get('id')
        
        if id:
            instance = self.SAFRSObject.get_instance(id)
            if not instance:
                # If no instance was found this means the user supplied 
                # an invalid ID
                raise ValidationError('Invalid ID')
        
        else:
            # No ID was supplied, apply method to the class itself
            instance = self.SAFRSObject

        if method_name:
            # call the method specified by method_name
            method_result = self.call_method_by_name(instance, method_name, args)
            result = { 'result' : method_result }
            return jsonify(result)

        # No id given, return all instances matching the filter
        try:
            filter      = json_data.get('filter',{})
            sort        = json_data.get('sort', '' )
            current     = int(json_data.get('current',0)) 
            row_count   = int(json_data.get('rowCount',50))
            search      = json_data.get('searchPhrase','')
        except:
            raise ValidationError('Invalid arguments')
        
        instances = self.get_instances(filter, sort, search)
        if current < 0 : current = 1
        
        result = {  'current'  : current,
                    'rows'     : instances[ current : current + row_count ],
                    'rowCount' : row_count,
                    'total'    : instances.count()
                 }

        return jsonify( result )
예제 #4
0
    def get(self, **kwargs):
        '''
            HTTP GET: return instances
            If no id is given: return all instances
            If an id is given, get an instance by id
            If a method is given, call the method on the instance
        '''
        
        id = kwargs.get(self.object_id,None)
        #method_name = kwargs.get('method_name','')

        if not id:
            # If no id is given, check if it's passed through a request arg
            id = request.args.get('id')

        if id:
            instance = self.SAFRSObject.get_instance(id)
            if not instance:
                raise ValidationError('Invalid {}'.format(self.object_id))
            # Call the method if it doesn't exist, return instance :)
            #method = getattr(instance, method_name, lambda : instance)
            #result = { 'result' : method() }
            result = instance
        else:
            instances = self.SAFRSObject.query.all()
            details = request.args.get('details',None)
            if details == None:
                result = [ item.id for item in instances ]
                log.debug(result)
                
            else:
                result = [ item for item in instances ]
            
        return jsonify(result)    
예제 #5
0
    def call_method_by_name(self, instance, method_name, args):
        '''
            Call the instance method specified by method_name
        '''

        method = getattr(instance, method_name, False)
            
        if not method:
            # Only call methods for Campaign and not for superclasses (e.g. db.Model)
            raise ValidationError('Invalid method "{}"'.format(method_name))
        if not is_public(method):
            raise ValidationError('Method is not public')

        if not args: args = {}
            
        result = method(**args)    
        return result
예제 #6
0
    def delete(self, **kwargs):
        '''
            Delete an object by id or by filter
        '''    
        
        id = kwargs.get(self.object_id, None)
        
        filter = {}
        if id:
            filter = dict(id = id)
        else:
            json_data = request.get_json()
            if json_data:
                filter = json_data.get('filter', {} )
        if not filter:
            raise ValidationError('Invalid ID or Filter {} {}'.format(kwargs,self.object_id))
        
        for instance in self.SAFRSObject.query.filter_by(**filter).all():
            db.session.delete(instance)
            db.session.commit()

        return jsonify({}) , 204
예제 #7
0
    def add_resource(self, resource, *urls, **kwargs):
        '''
            This method is partly copied from flask_restful_swagger_2/__init__.py

            I changed it because we don't need path id examples when 
            there's no {id} in the path. We filter out the unwanted parameters

        '''
        
        from flask_restful_swagger_2 import validate_definitions_object, parse_method_doc
        from flask_restful_swagger_2 import validate_path_item_object, extract_swagger_path

        path_item = {}
        definitions = {}
        resource_methods = kwargs.get('methods',['GET','PUT','POST','DELETE'])

        for method in [m.lower() for m in resource.methods]:
            if not method.upper() in resource_methods:
                continue
            f = resource.__dict__.get(method, None)
            if not f:
                continue

            operation = f.__dict__.get('__swagger_operation_object', None)
            if operation:
                operation, definitions_ = self._extract_schemas(operation)
                path_item[method] = operation
                definitions.update(definitions_)
                summary = parse_method_doc(f, operation)
                if summary:
                    operation['summary'] = summary

        validate_definitions_object(definitions)
        self._swagger_object['definitions'].update(definitions)
        
        if path_item:
            validate_path_item_object(path_item)
            for url in urls:
                if not url.startswith('/'):
                    raise ValidationError('paths must start with a /')
                swagger_url = extract_swagger_path(url)
                for method in [m.lower() for m in resource.methods]:
                    method_doc = copy.deepcopy(path_item.get(method))
                    if not method_doc:
                        continue

                    filtered_parameters = []
                    for parameter in method_doc.get('parameters',[]):
                        object_id = '{%s}'%parameter.get('name')

                        if method == 'get' and not swagger_url.endswith('Id}') :
                            param = {'default': 'all', 'type': 'string', 'name': 'details', 'in': 'query'}
                            if not param in filtered_parameters:
                                filtered_parameters.append(param)
                        
                        if method == 'post' and not swagger_url.endswith('Id}') and not parameter.get('description','').endswith('(classmethod)'):
                            # Only classmethods should be added when there's no {id} in the POST path for this method
                            continue
                        if not ( parameter.get('in') == 'path' and not object_id in swagger_url ):
                            # Only if a path param is in path url then we add the param
                            filtered_parameters.append(parameter)
 
                    #log.debug(method_doc)  
                    method_doc['parameters'] = filtered_parameters
                    path_item[method] = method_doc

                    if method == 'get' and not swagger_url.endswith('Id}'):
                        # If no {id} was provided, we return a list of all the objects
                        try:
                            method_doc['description'] += ' list (See GET /{id} for details)'
                            method_doc['responses']['200']['schema'] = ''
                        except:
                            pass

                self._swagger_object['paths'][swagger_url] = path_item


        self._swagger_object['securityDefinitions'] = {
                "api_key": {
                    "type": "apiKey",
                    "name": "api_key",
                    "in": "query"
                }}

        self._swagger_object['security'] = [ "api_key" ]
        super(ApiBase, self).add_resource(resource, *urls, **kwargs)