def before_view(self, pkg_dict):
        """
        Extend the group controller to show resource information
        The resource information will come from elastic search
        """
        # use r as query string
        r = c.r = request.params.get(
            'r', default=None)  # unicode format (decoded from utf8)

        # format r to send to elastic search
        if r is None:
            query = {
                "sort": {
                    "data": {
                        "order": "desc"
                    },
                },
                "query": {
                    "match_all": {}
                }
            }
        else:
            query = {
                "sort": {
                    "data": {
                        "order": "desc"
                    },
                },
                "query": {r}
            }

        # Now send query to elastic search
        self._load_elastic_config()
        client = DataStoreClient(urlparse.urljoin(self.url, pkg_dict['name']))
        headers = dict()
        headers['Authorization'] = self.user.get('apikey')
        #req = urllib2.Request(webstore_request_url, post_data, headers)
        client._headers = headers
        response = client.query(query)

        # Now we have to parse the result back to package dict
        hits = response.get('hits')
        resources = list()
        for res in hits['hits']:
            # Store it in extras
            resources.append(res['_source'])

        # Add a new field on pkg_dict
        pkg_dict['elastic_resources'] = resources

        return pkg_dict
 def before_view(self,pkg_dict):
     """
     Extend the group controller to show resource information
     The resource information will come from elastic search
     """
     # use r as query string
     r = c.r = request.params.get('r', default=None) # unicode format (decoded from utf8)
     
     # format r to send to elastic search
     if r is None:
         query = {
                  "sort": {
                     "data" : {"order" : "desc"},
                   },
                  "query": {
                            "match_all":{}
                            }
         }
     else:
         query = {
                  "sort": {
                     "data" : {"order" : "desc"},
                   },
                  "query":{r}
                  }
     
     # Now send query to elastic search
     self._load_elastic_config()
     client = DataStoreClient(urlparse.urljoin(self.url, pkg_dict['name'])) 
     headers = dict()
     headers['Authorization'] = self.user.get('apikey')
     #req = urllib2.Request(webstore_request_url, post_data, headers)
     client._headers = headers
     response = client.query(query)
     
     # Now we have to parse the result back to package dict
     hits = response.get('hits')
     resources = list()
     for res in hits['hits']:
         # Store it in extras
         resources.append(res['_source'])
     
     # Add a new field on pkg_dict
     pkg_dict['elastic_resources'] = resources
     
     return pkg_dict
    def datatable(self, resource_name, resource_id):
        from ckanext.recombinant.tables import get_chromo
        t = get_chromo(resource_name)
        echo = int(request.params['sEcho'])
        search_text = unicode(request.params['sSearch'])
        offset = int(request.params['iDisplayStart'])
        limit = int(request.params['iDisplayLength'])
        sort_cols = int(request.params['iSortingCols'])
        if sort_cols:
            sort_by_num = int(request.params['iSortCol_0'])
            sort_order = 'desc' if request.params['sSortDir_0'] == 'desc' else 'asc'

        lc = LocalCKAN(username=c.user)

        unfiltered_response = lc.action.datastore_search(
            resource_id=resource_id,
            limit=1,
            )

        cols = [f['datastore_id'] for f in t['fields']]
        sort_str = ''
        if sort_cols:
            sort_str = cols[sort_by_num] + ' ' + sort_order

        response = lc.action.datastore_search(
            q=search_text,
            resource_id=resource_id,
            fields=cols,
            offset=offset,
            limit=limit,
            sort=sort_str)

        return json.dumps({
            'sEcho': echo,
            'iTotalRecords': unfiltered_response.get('total', 0),
            'iTotalDisplayRecords': response.get('total', 0),
            'aaData': [
                [row[colname] for colname in cols]
                for row in response['records']],
            })
    def before_view_resource(self,pkg_name,resource_id):
        """
        Extend the group controller to show resource information
        The resource information will come from elastic search
        """
        query = {
                "query": {
                          "query_string": {
                           "default_field":  "id",
                           "query": resource_id
                           }
                },
                "size":"1"
        }
        
        # Now send query to elastic search
        self._load_elastic_config()
        self.url = urlparse.urljoin(self.url, pkg_name)
        client = DataStoreClient(self.url)
        headers = dict()
        headers['Authorization'] = self.user.get('apikey')
        #req = urllib2.Request(webstore_request_url, post_data, headers)
        client._headers = headers
        response = client.query(query)
        
        # Now we have to parse the result back to package dict
        hits = response.get('hits')
        resources = dict()
        for res in hits['hits']:
            # Store it in extras
            resources = res['_source']
            # Return only first item
            break

        # Check not found
        if not resources:
            abort(404, _('Resource not found'))
        else:
            return resources
    def before_view_resource(self, pkg_name, resource_id):
        """
        Extend the group controller to show resource information
        The resource information will come from elastic search
        """
        query = {
            "query": {
                "query_string": {
                    "default_field": "id",
                    "query": resource_id
                }
            },
            "size": "1"
        }

        # Now send query to elastic search
        self._load_elastic_config()
        self.url = urlparse.urljoin(self.url, pkg_name)
        client = DataStoreClient(self.url)
        headers = dict()
        headers['Authorization'] = self.user.get('apikey')
        #req = urllib2.Request(webstore_request_url, post_data, headers)
        client._headers = headers
        response = client.query(query)

        # Now we have to parse the result back to package dict
        hits = response.get('hits')
        resources = dict()
        for res in hits['hits']:
            # Store it in extras
            resources = res['_source']
            # Return only first item
            break

        # Check not found
        if not resources:
            abort(404, _('Resource not found'))
        else:
            return resources
    def datatable(self, resource_id):
        draw = int(request.params['draw'])
        search_text = unicode(request.params['search[value]'])
        offset = int(request.params['start'])
        limit = int(request.params['length'])
        sort_by_num = int(request.params['order[0][column]'])
        sort_order = ('desc' if request.params['order[0][dir]'] == 'desc'
                      else 'asc'
                      )

        lc = LocalCKAN(username=c.user)

        unfiltered_response = lc.action.datastore_search(
            resource_id=resource_id,
            limit=1,
        )

        cols = [f['id'] for f in unfiltered_response['fields']][1:]
        sort_str = cols[sort_by_num] + ' ' + sort_order

        response = lc.action.datastore_search(
            q=search_text,
            resource_id=resource_id,
            offset=offset,
            limit=limit,
            sort=sort_str
        )

        return json.dumps({
            'draw': draw,
            'iTotalRecords': unfiltered_response.get('total', 0),
            'iTotalDisplayRecords': response.get('total', 0),
            'aaData': [
                [row[colname] for colname in cols]
                for row in response['records']
            ],
        })
    def before_view(self,pkg_dict):
        """
        Extend the group controller to show resource information
        The resource information will come from elastic search
        """
        # use r as query string
        q = c.q = request.params.get('q', default=None) # unicode format (decoded from utf8)
        page = c.page =  request.params.get('page', default=None)

        # TODO: put this as a parameter
        rows = 20

        if page is None:
            start = 0
        else:
            # Start with the first element in this page
            start = ((int(page) * rows) - rows)

        # format q to send to elastic search
        if q is None or q is '*:*':
            query = {
                     "sort": {
                        "data" : {"order" : "desc"},
                      },
                     "query": {
                               "match_all":{}
                               },
                     "size" : rows,
                     "from" : start
            }
        else:
            query = {
                     "sort": {
                        "data" : {"order" : "desc"},
                      },
                     "query": {
                                "query_string": {
                                                 "query": q,
                                                 "default_operator": "AND"
                                                 }
                               },
                     "size" : rows,
                     "from" : start
            }

        # Now send query to elastic search
        self._load_elastic_config()
        client = DataStoreClient(urlparse.urljoin(self.url, pkg_dict['name']))
        headers = dict()
        headers['Authorization'] = self.user.get('apikey')
        #req = urllib2.Request(webstore_request_url, post_data, headers)
        client._headers = headers

        # do not fail on search errors
        try:
            response = client.query(query)
        except:
            # there's an error in search params
            import traceback
            response = dict()
            errmsg = 'Error searching query string \n %s \n Message\n%s' % (query,traceback.format_exc())
            log.error(errmsg)

            raise SearchError(errmsg)
        
        
        # Now we have to parse the result back to package dict
        hits = response.get('hits')
        resources = list()
        if hits is not None:
            for res in hits['hits']:
                # Store it in extras
                resources.append(res['_source'])
        
            # Add a new field on pkg_dict
            pkg_dict['elastic_resources'] = resources
            pkg_dict['elastic_hits'] = hits.get('total')

        else:
            # Add a new field on pkg_dict
            pkg_dict['elastic_resources'] = dict()
            pkg_dict['elastic_hits'] = 0

        return pkg_dict
    def before_view(self, pkg_dict):
        """
        Extend the group controller to show resource information
        The resource information will come from elastic search
        """
        # use r as query string
        q = c.q = request.params.get(
            'q', default=None)  # unicode format (decoded from utf8)
        page = c.page = request.params.get('page', default=None)

        # TODO: put this as a parameter
        rows = 20

        if page is None:
            start = 0
        else:
            # Start with the first element in this page
            start = ((int(page) * rows) - rows)

        # format q to send to elastic search
        if q is None or q is '*:*':
            query = {
                "sort": {
                    "data": {
                        "order": "desc"
                    },
                },
                "query": {
                    "match_all": {}
                },
                "size": rows,
                "from": start
            }
        else:
            query = {
                "sort": {
                    "data": {
                        "order": "desc"
                    },
                },
                "query": {
                    "query_string": {
                        "query": q,
                        "default_operator": "AND"
                    }
                },
                "size": rows,
                "from": start
            }

        # Now send query to elastic search
        self._load_elastic_config()
        client = DataStoreClient(urlparse.urljoin(self.url, pkg_dict['name']))
        headers = dict()
        headers['Authorization'] = self.user.get('apikey')
        #req = urllib2.Request(webstore_request_url, post_data, headers)
        client._headers = headers

        # do not fail on search errors
        try:
            response = client.query(query)
        except:
            # there's an error in search params
            import traceback
            response = dict()
            errmsg = 'Error searching query string \n %s \n Message\n%s' % (
                query, traceback.format_exc())
            log.error(errmsg)

            raise SearchError(errmsg)

        # Now we have to parse the result back to package dict
        hits = response.get('hits')
        resources = list()
        if hits is not None:
            for res in hits['hits']:
                # Store it in extras
                resources.append(res['_source'])

            # Add a new field on pkg_dict
            pkg_dict['elastic_resources'] = resources
            pkg_dict['elastic_hits'] = hits.get('total')

        else:
            # Add a new field on pkg_dict
            pkg_dict['elastic_resources'] = dict()
            pkg_dict['elastic_hits'] = 0

        return pkg_dict
Exemple #9
0
class lightbaseReportsController(PackageController):
    """
    Add controller to Reports
    """
    def _load_elastic_config(self):
        """
        Load elastic search configuration
        """
        self.user = get_action('get_site_user')({
            'model': model,
            'ignore_auth': True
        }, {})
        ckan_url = config.get('ckan.site_url').rstrip('/')
        self.url = '%s/api/data/' % (ckan_url)
        # FIXME: Parametrize this
        self.url = urlparse.urljoin(self.url, 'lbdf/')

    def report_action(self, id, data=None, errors=None, error_summary=None):
        """
        Reports action page
        """
        # Setup dataset information
        package_type = self._get_package_type(id.split('@')[0])
        #context = {'model': model, 'session': model.Session,
        #           'user': c.user or c.author, 'extras_as_string': True,
        #           'schema': self._form_to_db_schema(package_type=package_type)}
        context = {
            'model': model,
            'session': model.Session,
            'save': 'save' in request.params,
            'user': c.user or c.author,
            'extras_as_string': True
        }
        data_dict = {'id': id}

        #check if package exists
        try:
            c.pkg_dict = get_action('package_update')(context, data_dict)
            c.pkg = context['package']
            c.pkg_json = json.dumps(c.pkg_dict)
        except NotFound:
            abort(404, _('Dataset not found'))
        except NotAuthorized:
            abort(401, _('Unauthorized to edit package %s') % id)

        data = data or clean_dict(
            unflatten(
                tuplize_dict(
                    parse_params(request.params, ignore_keys=[CACHE_PARAMETER
                                                              ]))))

        errors = errors or {}
        error_summary = error_summary or {}
        vars = {'data': data, 'errors': errors, 'error_summary': error_summary}

        # Save data if requested
        if context.get('save') and data:
            result = self._save_report_action_new(data)
            # Return error message
            if not result:
                errors['name'] = 'Insertion error'
                error_summary[_(u'Ação')] = _(
                    u'Erro inserindo elemento na base de dados')

        # Add actual reports actions information
        data['actions'] = model.Session.query(lightbaseDatasetActions).all()

        self._setup_template_variables(context, {'id': id})
        c.form = render('package/reports/actions_new_form.html',
                        extra_vars=vars)

        return render('package/reports/actions_new.html')

    def _save_report_action_new(self, data):
        """
        Save report action data
        """
        # Save everything or fail everything
        try:

            # First save clean element
            action_elm = data.pop('name', None)
            if action_elm:
                data_elm = lightbaseDatasetActions(action_name=action_elm)
                model.Session.add(data_elm)
                log.warning('Adding element %s' % data_elm)

            # Get elements to be updated
            for key in data.keys():
                # find items to update
                field, separator, identifier = key.partition(':')
                if field == 'name' and separator == ':':
                    data_elm = model.Session.query(lightbaseDatasetActions).\
                      filter_by(dataset_action_id=identifier).all()[0]

                    # Assing new value to this object
                    if data_elm:
                        data_elm.action_name = data.get(key)

            # Now find elements to be deleted
            if isinstance(data.get('deleted'), (list, tuple)):
                # Use it to iterate throught the objects
                for elm in data.get('deleted'):
                    data_elm = model.Session.query(lightbaseDatasetActions).\
                      filter_by(dataset_action_id=elm).all()

                    report_elm = model.Session.query(lightbaseDatasetReports).\
                      filter_by(dataset_action_id=elm).all()

                    # Remove it from reports first
                    for report in report_elm:
                        log.warning('Removing report %s' % report)
                        model.Session.delete(report)

                    model.Session.commit()

                    if len(data_elm) > 0:
                        data_elm = data_elm[0]

                    log.warning('Removing element %s' % elm)

                    # As it's not in the list anymore, remove it
                    model.Session.delete(data_elm)
            elif data.get('deleted'):
                elm = data.get('deleted')

                data_elm = model.Session.query(lightbaseDatasetActions).\
                  filter_by(dataset_action_id=elm).all()

                report_elm = model.Session.query(lightbaseDatasetReports).\
                  filter_by(dataset_action_id=elm).all()

                # Remove it from reports first
                for report in report_elm:
                    log.warning('Removing report %s' % report)
                    model.Session.delete(report)

                model.Session.commit()

                if len(data_elm) > 0:
                    data_elm = data_elm[0]

                log.warning('Removing element %s' % elm)

                # As it's not in the list anymore, remove it
                model.Session.delete(data_elm)

            # Commit changes
            model.Session.commit()

            return True
        except:
            import traceback
            # For now just fail in any error
            log.error('Error adding value.\n%s' % traceback.format_exc())
            return False

    def report_new(self, id, data=None, errors=None, error_summary=None):
        """
        Controller to add a new report
        """
        # Setup dataset information
        package_type = self._get_package_type(id.split('@')[0])
        context = {
            'model': model,
            'session': model.Session,
            'user': c.user or c.author,
            'extras_as_string': True,
            'schema': self._form_to_db_schema(package_type=package_type),
            'save': 'save' in request.params
        }
        data_dict = {'id': id}

        #check if package exists
        try:
            c.pkg_dict = get_action('package_show')(context, data_dict)
            c.pkg = context['package']
            c.pkg_json = json.dumps(c.pkg_dict)
        except NotFound:
            abort(404, _('Dataset not found'))
        except NotAuthorized:
            abort(401, _('Unauthorized to read package %s') % id)

        # Only package admins can see this page
        try:
            check_access('package_update', context)
        except NotAuthorized, e:
            abort(401, _('User %r not authorized to edit %s') % (c.user, id))

        # Load Elastic Search parameters and configuration
        self._load_elastic_config()
        self.url = self.url + c.pkg_dict.get('name')
        client = DataStoreClient(self.url)
        headers = dict()
        headers['Authorization'] = self.user.get('apikey')
        client._headers = headers

        # Now return mapping info
        try:
            response = client.mapping()
        except:
            # Error retrieving information from elastic search
            abort(404, _('Index not found on Elastic Search'))

        # In this list every resource has an specific set of items
        pkg_resources = response.get(c.pkg_dict.get('name'))

        if pkg_resources is None:
            # Dataset not found on elastic search. Abort
            abort(404, _('Dataset not found'))

        key_dict = dict()
        # We loop throught every key on every resource
        for key in pkg_resources.get('properties').keys():
            if key not in key_dict:
                # Add i18n translation of field to the dict
                key_aux = {'i18n': _(key)}
                key_dict[key] = key_aux

        # Get mapping from reports
        session = model.Session()

        results = session.query(lightbaseDatasetReports,lightbaseDatasetActions.action_name).\
          filter(lightbaseDatasetReports.dataset_action_id == lightbaseDatasetActions.dataset_action_id).\
          filter(lightbaseDatasetReports.dataset_id == c.pkg_dict.get('id')).all()

        # This dict will contain all reports and mapped fields
        report_dict = dict()
        for report in results:
            # Store the action and fields necessary for this dataset
            if report[0].source:
                source = report[0].source
            else:
                source = None
            report_dict[report[0].dataset_id] = {
                report[1]: {
                    'fields_list': report[0].fields_list,
                    'source': source
                }
            }

        # Map actions options
        report_actions = session.query(lightbaseDatasetActions).all()

        # This is required to save data
        data = data or clean_dict(
            unflatten(
                tuplize_dict(
                    parse_params(request.params, ignore_keys=[CACHE_PARAMETER
                                                              ]))))

        vars = {
            'data': data,
            'errors': errors,
            'error_summary': error_summary,
            'report': report_dict,
            'keys': key_dict,
            'report_actions': report_actions
        }

        # Save data if requested
        if context.get('save') and data:
            result = self._save_report_new(data, key_dict)
            # Return error message
            if result:
                # Redirect
                h.redirect_to(
                    controller=
                    'ckanext.lightbase.controllers.reports:lightbaseReportsController',
                    action='report_read',
                    id=id,
                    report_id=self.report_id)
            else:
                # Show error message
                errors['name'] = 'Insertion error'
                error_summary[_(u'Ação')] = _(
                    u'Erro inserindo elemento na base de dados')

        errors = errors or {}
        error_summary = error_summary or {}

        c.form = render('package/reports/new_form.html', extra_vars=vars)

        return render('package/reports/new.html')