Example #1
0
    def delete(self, *args, current_user=None, **kwargs):
        with_user = current_user

        # On supprime toutes les ressources attachées au jeu de données
        Resource = apps.get_model(app_label='idgo_admin',
                                  model_name='Resource')
        for resource in Resource.objects.filter(dataset=self):
            resource.delete(current_user=current_user,
                            synchronize_dataset=False)
        # > > > > > > BETA < < < < < < #
        if BETA:
            ResourceBeta = apps.get_model(app_label='idgo_resource',
                                          model_name='Resource')
            for resource_beta in ResourceBeta.objects.filter(dataset=self):
                resource_beta._related.delete()
                resource_beta.delete()
        # > > > > > > BETA < < < < < < #

        # On supprime le package CKAN
        ckan_id = str(self.ckan_id)
        if with_user:
            username = with_user.username
            apikey = CkanHandler.get_user(username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan_user:
                ckan_user.delete_dataset(ckan_id)
        else:
            CkanHandler.delete_dataset(ckan_id)

        CkanHandler.purge_dataset(ckan_id)

        # On supprime l'instance
        super().delete(*args, **kwargs)
Example #2
0
    def delete(self, *args, current_user=None, **kwargs):
        with_user = current_user

        # On supprime la ressource CKAN
        if with_user:
            username = with_user.username
            apikey = CkanHandler.get_user(username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan_user:
                ckan_user.delete_resource(self.name)
        else:
            CkanHandler.delete_resource(self.name)

        # On supprime les ressources MRA
        try:
            MRAHandler.del_layer(self.name)
            ws_name = self.resource.dataset.organisation.slug
            if self.type == 'vector':
                MRAHandler.del_featuretype(ws_name, 'public', self.name)
            if self.type == 'raster':
                MRAHandler.del_coverage(ws_name, self.name, self.name)
                # MRAHandler.del_coveragestore(ws_name, self.name)
        except Exception as e:
            logger.error(e)
            pass

        # On supprime la table de données PostGIS
        try:
            drop_table(self.name)
        except Exception as e:
            logger.error(e)
            pass

        # Puis on supprime l'instance
        super().delete(*args, **kwargs)
Example #3
0
    def delete(self,
               *args,
               current_user=None,
               synchronize_dataset=True,
               **kwargs):
        with_user = current_user

        for layer in self.get_layers():
            layer.delete(current_user=current_user)

        # On supprime la ressource CKAN
        ckan_id = str(self.ckan_id)
        if with_user:
            username = with_user.username

            apikey = CkanHandler.get_user(username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan_user:
                ckan_user.delete_resource(ckan_id)
        else:
            CkanHandler.delete_resource(ckan_id)

        # On supprime l'instance
        super().delete(*args, **kwargs)

        # Ce n'est vraiment pas une bonne idée de synchroniser ici le dataset :
        self.dataset.date_modification = timezone.now().date()
        self.dataset.save(current_user=current_user,
                          synchronize=synchronize_dataset,
                          update_fields=['date_modification'])
Example #4
0
def delete_ckan_resource(sender, instance, **kwargs):
    """Supprimer la resource CKAN à la suppression d'une resource."""
    apikey = CkanHandler.get_user(instance.dataset.editor.username)['apikey']
    with CkanUserHandler(apikey=apikey) as ckan:
        ckan.delete_resource(str(instance.ckan_id))
    logger.info(
        "CKAN Resource \"{pk}\" has been deleted.".format(pk=instance.ckan_id))
Example #5
0
def asynchronous_tasks(filename, dir, content_type, data, user_pk, dataset_pk,
                       resource_pk, package_id, **kwargs):

    if content_type.endswith('zip'):
        unzip(filename, dir, flush=True)
    else:
        raise NotImplementedError('TODO')

    username = User.objects.get(pk=user_pk).username
    apikey = CkanHandler.get_user(username)['apikey']

    html = get_html_content(dataset_pk, resource_pk)
    upload = io.BytesIO(html.encode('utf-8'))
    data['upload'] = upload

    ckan_package = CkanHandler.get_package(package_id)
    apikey = CkanHandler.get_user(username)['apikey']
    with CkanUserHandler(apikey=apikey) as ckan:
        ckan.publish_resource(ckan_package, **data)

    upload.close()
def synchronize(instance, with_user=None):

    ckan_package = CkanHandler.get_package(str(instance.dataset.ckan_id))
    username = with_user and with_user.username or instance.dataset.editor.username
    apikey = CkanHandler.get_user(username)['apikey']

    location = os.path.join(DIRECTORY_STORAGE, str(instance.pk))

    base_url = reverse('resource:directory_storage',
                       kwargs={
                           'dataset_id': instance.dataset.pk,
                           'resource_id': instance.pk
                       })

    files = iterate(location, base_url=base_url)
    html = render_to_string('resource/store/ckan_resource_template.html',
                            context={'files': files})
    upload = io.BytesIO(html.encode('utf-8'))

    data = {
        'id': str(instance.ckan_id),
        'url': instance.store.url,
        'name': instance.title,
        'description': instance.description,
        'lang': instance.language,
        'data_type': instance.resource_type,
        'view_type': 'text_view',
        'upload': upload,
        'size': '',
        'mimetype': 'text/html',
        'format': '',
        'api': '{}',
        'restricted_by_jurisdiction': '',
        'extracting_service': 'False',
        'crs': '',
        'restricted': json.dumps({'level': 'public'}),
    }

    with CkanUserHandler(apikey=apikey) as ckan:
        ckan.publish_resource(ckan_package, **data)
    def handle(self, *args, **options):
        for resource in Resource.objects.exclude(organisations_allowed=None):
            dataset = resource.dataset

            ckan_params = {
                'id':
                str(resource.ckan_id),
                'restricted':
                json.dumps({
                    'allowed_users':
                    ','.join(
                        get_all_users_for_organisations([
                            r.pk for r in resource.organisations_allowed.all()
                        ])),
                    'level':
                    'only_allowed_users'
                })
            }

            apikey = CkanHandler.get_user(dataset.editor.username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan:
                package = ckan.get_package(str(dataset.ckan_id))
                ckan.push_resource(package, **ckan_params)
    def save_ckan_resource(self, with_user=None):
        resource = self.instance

        if with_user:
            username = with_user.username
        else:
            username = resource.dataset.editor.username

        upload = open(self.filename, 'rb')

        data = {
            'id': str(resource.ckan_id),
            'url': '',
            'name': resource.title,
            'description': resource.description,
            'lang': resource.language,
            'data_type': resource.resource_type,
            'upload': upload,
            'size': resource.upload.file_path.size,
            'format': resource.format_type.ckan_format,
            'mimetype': resource.format_type.mimetype[0],
            'view_type': resource.format_type.ckan_view,
            #
            'api': '{}',
            'restricted_by_jurisdiction': 'False',
            'extracting_service': 'False',
            'crs': '',
            'restricted': json.dumps({'level': 'public'}),
        }

        ckan_package = CkanHandler.get_package(str(resource.dataset.ckan_id))
        apikey = CkanHandler.get_user(username)['apikey']
        with CkanUserHandler(apikey=apikey) as ckan:
            ckan.publish_resource(ckan_package, **data)

        upload.close()
Example #9
0
    def synchronize(self,
                    url=None,
                    filename=None,
                    content_type=None,
                    file_extras=None,
                    with_user=None):
        """Synchronizer le jeu de données avec l'instance de CKAN."""
        # Identifiant de la resource CKAN :
        id = str(self.ckan_id)

        # Définition des propriétés du « package » :
        data = {
            'crs': self.crs and self.crs.description or '',
            'name': self.title,
            'description': self.description,
            'data_type': self.data_type,
            'extracting_service': 'False',  # I <3 CKAN
            'format': self.format_type and self.format_type.ckan_format,
            'view_type': self.format_type and self.format_type.ckan_view,
            'id': id,
            'lang': self.lang,
            'restricted_by_jurisdiction': str(self.geo_restriction),
            'url': url and url or '',
            'api': '{}'
        }

        # TODO: Factoriser

        # (0) Aucune restriction
        if self.restricted_level == 'public':
            restricted = json.dumps({'level': 'public'})
        # (1) Uniquement pour un utilisateur connecté
        elif self.restricted_level == 'registered':
            restricted = json.dumps({'level': 'registered'})
        # (2) Seulement les utilisateurs indiquées
        elif self.restricted_level == 'only_allowed_users':
            restricted = json.dumps({
                'allowed_users':
                ','.join(
                    self.profiles_allowed.exists()
                    and [p.user.username
                         for p in self.profiles_allowed.all()] or []),
                'level':
                'only_allowed_users'
            })
        # (3) Les utilisateurs de cette organisation
        elif self.restricted_level == 'same_organization':
            restricted = json.dumps({
                'allowed_users':
                ','.join(
                    get_all_users_for_organisations(
                        self.organisations_allowed.all())),
                'level':
                'only_allowed_users'
            })
        # (3) Les utilisateurs des organisations indiquées
        elif self.restricted_level == 'any_organization':
            restricted = json.dumps({
                'allowed_users':
                ','.join(
                    get_all_users_for_organisations(
                        self.organisations_allowed.all())),
                'level':
                'only_allowed_users'
            })

        data['restricted'] = restricted

        if self.referenced_url:
            data['url'] = self.referenced_url

        if self.dl_url and filename:
            downloaded_file = File(open(filename, 'rb'))
            data['upload'] = downloaded_file
            data['size'] = downloaded_file.size
            data['mimetype'] = content_type

        if self.up_file and file_extras:
            data['upload'] = self.up_file.file
            data['size'] = file_extras.get('size')
            data['mimetype'] = file_extras.get('mimetype')

        if self.ftp_file:
            if not url:
                data['upload'] = self.ftp_file.file
            data['size'] = self.ftp_file.size
            data['mimetype'] = None  # TODO

        if self.data_type == 'raw':
            if self.ftp_file or self.dl_url or self.up_file:
                data['resource_type'] = 'file.upload'
            elif self.referenced_url:
                data['resource_type'] = 'file'
        if self.data_type == 'annexe':
            data['resource_type'] = 'documentation'
        if self.data_type == 'service':
            data['resource_type'] = 'api'

        ckan_package = CkanHandler.get_package(str(self.dataset.ckan_id))

        if with_user:
            username = with_user.username

            apikey = CkanHandler.get_user(username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan:
                ckan.publish_resource(ckan_package, **data)
        else:
            return CkanHandler.publish_resource(ckan_package, **data)
Example #10
0
    def save(self,
             *args,
             current_user=None,
             synchronize=False,
             file_extras=None,
             **kwargs):

        # Version précédante de la ressource (avant modification)
        previous, created = self.pk \
            and (Resource.objects.get(pk=self.pk), False) or (None, True)

        if previous:
            # crs est immuable sauf si le jeu de données change (Cf. plus bas)
            self.crs = previous.crs

        # Quelques valeur par défaut à la création de l'instance
        if created or not (
                # Ou si l'éditeur n'est pas partenaire du CRIGE
                current_user and current_user.profile.crige_membership):

            # Mais seulement s'il s'agit de données SIG, sauf
            # qu'on ne le sait pas encore...
            self.geo_restriction = False
            self.ogc_services = True
            self.extractable = True

        # La restriction au territoire de compétence désactive toujours les services OGC
        if self.geo_restriction:
            self.ogc_services = False

        # Quelques contrôles sur les fichiers de données téléversée ou à télécharger
        filename = False
        content_type = None
        file_must_be_deleted = False  # permet d'indiquer si les fichiers doivent être supprimés à la fin de la chaine de traitement
        publish_raw_resource = True  # permet d'indiquer si les ressources brutes sont publiées dans CKAN

        if self.ftp_file:
            filename = self.ftp_file.file.name
            # Si la taille de fichier dépasse la limite autorisée,
            # on traite les données en fonction du type détecté
            if self.ftp_file.size > DOWNLOAD_SIZE_LIMIT:
                extension = self.format_type.extension.lower()
                if self.format_type.is_gis_format:
                    try:
                        gdalogr_obj = get_gdalogr_object(filename, extension)
                    except NotDataGISError:
                        # On essaye de traiter le jeux de données normalement, même si ça peut être long.
                        pass
                    else:
                        if gdalogr_obj.__class__.__name__ == 'GdalOpener':
                            s0 = str(self.ckan_id)
                            s1, s2, s3 = s0[:3], s0[3:6], s0[6:]
                            dir = os.path.join(CKAN_STORAGE_PATH, s1, s2)
                            os.makedirs(dir, mode=0o777, exist_ok=True)
                            shutil.copyfile(filename, os.path.join(dir, s3))

                            src = os.path.join(dir, s3)
                            dst = os.path.join(dir, filename.split('/')[-1])
                            try:
                                os.symlink(src, dst)
                            except FileNotFoundError as e:
                                logger.error(e)
                            else:
                                logger.debug(
                                    'Created a symbolic link {dst} pointing to {src}.'
                                    .format(dst=dst, src=src))

                        # if gdalogr_obj.__class__.__name__ == 'OgrOpener':
                        # On ne publie que le service OGC dans CKAN
                        publish_raw_resource = False

        elif (self.up_file and file_extras):
            # GDAL/OGR ne semble pas prendre de fichier en mémoire..
            # ..à vérifier mais si c'est possible comment indiquer le vsi en préfixe du filename ?
            super().save(*args, **kwargs)
            kwargs['force_insert'] = False

            filename = self.up_file.file.name
            file_must_be_deleted = True

        elif self.dl_url:
            try:
                directory, filename, content_type = download(
                    self.dl_url,
                    settings.MEDIA_ROOT,
                    max_size=DOWNLOAD_SIZE_LIMIT)
            except SizeLimitExceededError as e:
                l = len(str(e.max_size))
                if l > 6:
                    m = '{0} mo'.format(Decimal(int(e.max_size) / 1024 / 1024))
                elif l > 3:
                    m = '{0} ko'.format(Decimal(int(e.max_size) / 1024))
                else:
                    m = '{0} octets'.format(int(e.max_size))
                raise ValidationError(('La taille du fichier dépasse '
                                       'la limite autorisée : {0}.').format(m),
                                      code='dl_url')
            except Exception as e:
                if e.__class__.__name__ == 'HTTPError':
                    if e.response.status_code == 404:
                        msg = ('La ressource distante ne semble pas exister. '
                               "Assurez-vous que l'URL soit correcte.")
                    if e.response.status_code == 403:
                        msg = ("Vous n'avez pas l'autorisation pour "
                               'accéder à la ressource.')
                    if e.response.status_code == 401:
                        msg = ('Une authentification est nécessaire '
                               'pour accéder à la ressource.')
                else:
                    msg = 'Le téléchargement du fichier a échoué.'
                raise ValidationError(msg, code='dl_url')
            file_must_be_deleted = True

        # Synchronisation avec CKAN
        # =========================

        # La synchronisation doit s'effectuer avant la publication des
        # éventuelles couches de données SIG car dans le cas des données
        # de type « raster », nous utilisons le filestore de CKAN.
        if synchronize and publish_raw_resource:
            self.synchronize(content_type=content_type,
                             file_extras=file_extras,
                             filename=filename,
                             with_user=current_user)
        elif synchronize and not publish_raw_resource:
            url = reduce(urljoin, [
                settings.CKAN_URL, 'dataset/',
                str(self.dataset.ckan_id) + '/', 'resource/',
                str(self.ckan_id) + '/', 'download/',
                Path(self.ftp_file.name).name
            ])
            self.synchronize(url=url, with_user=current_user)

        # Détection des données SIG
        # =========================

        if filename:
            # On vérifie s'il s'agit de données SIG, uniquement pour
            # les extensions de fichier autorisées..
            extension = self.format_type.extension.lower()
            if self.format_type.is_gis_format:
                # Si c'est le cas, on monte les données dans la base PostGIS dédiée
                # et on déclare la couche au service OGC:WxS de l'organisation.

                # Mais d'abord, on vérifie si la ressource contient
                # déjà des « Layers », auquel cas il faudra vérifier si
                # la table de données a changée.
                existing_layers = {}
                if not created:
                    existing_layers = dict(
                        (re.sub('^(\w+)_[a-z0-9]{7}$', '\g<1>', layer.name),
                         layer.name) for layer in self.get_layers())

                try:

                    # C'est carrément moche mais c'est pour aller vite.
                    # Il faudrait factoriser tout ce bazar et créer
                    # un décorateur pour gérer le rool-back sur CKAN.

                    try:
                        gdalogr_obj = get_gdalogr_object(filename, extension)
                    except NotDataGISError:
                        tables = []
                        pass
                    else:

                        try:
                            self.format_type = ResourceFormats.objects.get(
                                extension=extension,
                                ckan_format=gdalogr_obj.format)
                        # except ResourceFormats.MultipleObjectsReturned:
                        #     pass
                        except Exception:
                            pass

                        # ==========================
                        # Jeu de données vectorielle
                        # ==========================

                        if gdalogr_obj.__class__.__name__ == 'OgrOpener':

                            # On convertit les données vers PostGIS

                            try:
                                tables = ogr2postgis(
                                    gdalogr_obj,
                                    update=existing_layers,
                                    epsg=self.crs and self.crs.auth_code
                                    or None,
                                    encoding=self.encoding)

                            except NotOGRError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    "Le fichier reçu n'est pas reconnu "
                                    'comme étant un jeu de données SIG correct.'
                                )
                                raise ValidationError(msg, code='__all__')

                            except DataDecodingError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    'Impossible de décoder correctement les '
                                    "données. Merci d'indiquer l'encodage "
                                    'ci-dessous.')
                                raise ValidationError(msg, code='encoding')

                            except WrongDataError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    'Votre ressource contient des données SIG que '
                                    'nous ne parvenons pas à lire correctement. '
                                    'Un ou plusieurs objets sont erronés.')
                                raise ValidationError(msg)

                            except NotFoundSrsError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    'Votre ressource semble contenir des données SIG '
                                    'mais nous ne parvenons pas à détecter le système '
                                    'de coordonnées. Merci de sélectionner le code du '
                                    'CRS dans la liste ci-dessous.')
                                raise ValidationError(msg, code='crs')

                            except NotSupportedSrsError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    'Votre ressource semble contenir des données SIG '
                                    'mais le système de coordonnées de celles-ci '
                                    "n'est pas supporté par l'application.")
                                raise ValidationError(msg, code='__all__')

                            except ExceedsMaximumLayerNumberFixedError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                raise ValidationError(e.__str__(),
                                                      code='__all__')

                            else:
                                # Avant de créer des relations, l'objet doit exister
                                if created:
                                    # S'il s'agit d'une création, alors on sauve l'objet.
                                    super().save(*args, **kwargs)
                                    kwargs['force_insert'] = False

                                # Ensuite, pour tous les jeux de données SIG trouvés,
                                # on crée le service ows à travers la création de `Layer`
                                try:
                                    Layer = apps.get_model(
                                        app_label='idgo_admin',
                                        model_name='Layer')
                                    for table in tables:
                                        try:
                                            Layer.objects.get(name=table['id'],
                                                              resource=self)
                                        except Layer.DoesNotExist:
                                            save_opts = {
                                                'synchronize': synchronize
                                            }
                                            Layer.vector.create(
                                                bbox=table['bbox'],
                                                name=table['id'],
                                                resource=self,
                                                save_opts=save_opts)
                                except Exception as e:
                                    logger.error(e)
                                    file_must_be_deleted and remove_file(
                                        filename)
                                    for table in tables:
                                        drop_table(table['id'])
                                    raise e

                        # ==========================
                        # Jeu de données matricielle
                        # ==========================

                        if gdalogr_obj.__class__.__name__ == 'GdalOpener':

                            coverage = gdalogr_obj.get_coverage()

                            try:
                                tables = [
                                    gdalinfo(
                                        coverage,
                                        update=existing_layers,
                                        epsg=self.crs and self.crs.auth_code
                                        or None)
                                ]

                            except NotFoundSrsError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    'Votre ressource semble contenir des données SIG '
                                    'mais nous ne parvenons pas à détecter le système '
                                    'de coordonnées. Merci de sélectionner le code du '
                                    'CRS dans la liste ci-dessous.')
                                raise ValidationError(msg, code='crs')

                            except NotSupportedSrsError as e:
                                logger.warning(e)
                                file_must_be_deleted and remove_file(filename)
                                msg = (
                                    'Votre ressource semble contenir des données SIG '
                                    'mais le système de coordonnées de celles-ci '
                                    "n'est pas supporté par l'application.")
                                raise ValidationError(msg, code='__all__')

                            else:
                                if created:
                                    # S'il s'agit d'une création, alors on sauve l'objet.
                                    super().save(*args, **kwargs)
                                    kwargs['force_insert'] = False

                            # Super Crado Code
                            s0 = str(self.ckan_id)
                            s1, s2, s3 = s0[:3], s0[3:6], s0[6:]
                            dir = os.path.join(CKAN_STORAGE_PATH, s1, s2)
                            src = os.path.join(dir, s3)
                            dst = os.path.join(dir, filename.split('/')[-1])
                            try:
                                os.symlink(src, dst)
                            except FileExistsError as e:
                                logger.warning(e)
                            except FileNotFoundError as e:
                                logger.error(e)
                            else:
                                logger.debug(
                                    'Created a symbolic link {dst} pointing to {src}.'
                                    .format(dst=dst, src=src))

                            try:
                                Layer = apps.get_model(app_label='idgo_admin',
                                                       model_name='Layer')
                                for table in tables:
                                    try:
                                        Layer.objects.get(name=table['id'],
                                                          resource=self)
                                    except Layer.DoesNotExist:
                                        Layer.raster.create(bbox=table['bbox'],
                                                            name=table['id'],
                                                            resource=self)
                            except Exception as e:
                                logger.error(e)
                                file_must_be_deleted and remove_file(filename)
                                raise e

                except Exception as e:
                    if created:
                        if current_user:
                            username = current_user.username
                            apikey = CkanHandler.get_user(username)['apikey']
                            with CkanUserHandler(apikey) as ckan:
                                ckan.delete_resource(str(self.ckan_id))
                        else:
                            CkanHandler.delete_resource(str(self.ckan_id))
                        for layer in self.get_layers():
                            layer.delete(current_user=current_user)
                    # Puis on « raise » l'erreur
                    raise e

                # On met à jour les champs de la ressource
                SupportedCrs = apps.get_model(app_label='idgo_admin',
                                              model_name='SupportedCrs')
                crs = [
                    SupportedCrs.objects.get(auth_name='EPSG',
                                             auth_code=table['epsg'])
                    for table in tables
                ]
                # On prend la première valeur (c'est moche)
                self.crs = crs and crs[0] or None

                # Si les données changent..
                if existing_layers and \
                        previous.get_layers() != self.get_layers():
                    # on supprime les anciens `layers`..
                    for layer in previous.get_layers():
                        layer.delete()
        ####
        if self.get_layers():
            extent = self.get_layers().aggregate(
                models.Extent('bbox')).get('bbox__extent')
            if extent:
                xmin, ymin = extent[0], extent[1]
                xmax, ymax = extent[2], extent[3]
                setattr(self, 'bbox', bounds_to_wkt(xmin, ymin, xmax, ymax))
        else:
            # Si la ressource n'est pas de type SIG, on passe les trois arguments
            # qui concernent exclusivement ces dernières à « False ».
            self.geo_restriction = False
            self.ogc_services = False
            self.extractable = False

        super().save(*args, **kwargs)

        # Puis dans tous les cas..
        # on met à jour le statut des couches du service cartographique..
        if not created:
            self.update_enable_layers_status()

        # on supprime les données téléversées ou téléchargées..
        if file_must_be_deleted:
            remove_file(filename)

        # [Crado] on met à jour la ressource CKAN
        if synchronize:
            CkanHandler.update_resource(str(self.ckan_id),
                                        extracting_service=str(
                                            self.extractable))

        for layer in self.get_layers():
            layer.save(synchronize=synchronize)

        self.dataset.date_modification = timezone.now().date()
        self.dataset.save(current_user=None,
                          synchronize=True,
                          update_fields=['date_modification'])
Example #11
0
    def synchronize(self, with_user=None, activate=None):
        """Synchronizer le jeu de données avec l'instance de CKAN."""

        # Identifiant du package CKAN :
        id = self.ckan_id and str(self.ckan_id) or None
        # Si la valeur est `None`, alors il s'agit d'une création.

        # Définition des propriétés du « paquet »
        # =======================================

        datatype = [item.slug for item in self.data_type.all()]

        date_creation = self.date_creation and str(self.date_creation) or ''
        date_modification = self.date_modification and str(
            self.date_modification) or ''
        date_publication = self.date_publication and str(
            self.date_publication) or ''

        broadcaster_name = self.broadcaster_name or \
            self.support and self.support.name or DEFAULT_PLATFORM_NAME
        broadcaster_email = self.broadcaster_email or \
            self.support and self.support.email or DEFAULT_CONTACT_EMAIL

        geocover = self.geocover or ''

        granularity = self.granularity and self.granularity.slug or ''

        licenses = [license['id'] for license in CkanHandler.get_licenses()]
        if self.license and self.license.ckan_id in licenses:
            license_id = self.license.ckan_id
        else:
            license_id = ''

        ows = False
        Resource = apps.get_model(app_label='idgo_admin',
                                  model_name='Resource')
        for resource in Resource.objects.filter(dataset=self):
            ows = resource.ogc_services

        spatial = self.bbox and self.bbox.geojson or ''
        support = self.support and self.support.slug or ''
        tags = [{'name': keyword.name} for keyword in self.keywords.all()]
        try:
            thumbnail = urljoin(DOMAIN_NAME, self.thumbnail.url)
        except ValueError:
            thumbnail = ''

        # On vérifie si le jeu de données est un cas particulier
        # de jeu de données moissonné CKAN/CSW/DCAT
        remote_url = None
        if ENABLE_CKAN_HARVESTER:
            # (1) DCAT
            RemoteCkanDataset = apps.get_model(app_label='idgo_admin',
                                               model_name='RemoteCkanDataset')
            try:
                remote_dataset = RemoteCkanDataset.objects.get(dataset=self)
            except RemoteCkanDataset.DoesNotExist:
                pass
            else:
                remote_url = remote_dataset.url
        if ENABLE_CSW_HARVESTER:
            # (2) CSW
            RemoteCswDataset = apps.get_model(app_label='idgo_admin',
                                              model_name='RemoteCswDataset')
            try:
                remote_dataset = RemoteCswDataset.objects.get(dataset=self)
            except RemoteCswDataset.DoesNotExist:
                pass
            else:
                remote_url = remote_dataset.url
        if ENABLE_DCAT_HARVESTER:
            # (3) DCAT
            RemoteDcatDataset = apps.get_model(app_label='idgo_admin',
                                               model_name='RemoteDcatDataset')
            try:
                remote_dataset = RemoteDcatDataset.objects.get(dataset=self)
            except RemoteDcatDataset.DoesNotExist:
                pass
            else:
                remote_url = remote_dataset.url

        data = {
            'author': self.owner_name,
            'author_email': self.owner_email,
            'datatype': datatype,
            'dataset_creation_date': date_creation,
            'dataset_modification_date': date_modification,
            'dataset_publication_date': date_publication,
            'frequency': self.update_frequency or 'unknown',
            'geocover': geocover,
            'granularity': granularity,
            'groups': [],
            'inspire_url': self.geonet_url,
            'license_id': license_id,
            'maintainer': broadcaster_name,
            'maintainer_email': broadcaster_email,
            'name': self.slug,
            'notes': self.description,
            'owner_org': str(self.organisation.ckan_id),
            'ows': str(ows),  # IMPORTANT
            'private': self.private,
            'remote_url': remote_url or '',
            'spatial': spatial,
            'support': support,
            'tags': tags,
            'title': self.title,
            'thumbnail': thumbnail,
            'url': '',  # IMPORTANT
        }

        if activate is not None:
            data['state'] = activate and 'active' or 'deleted'

        # Synchronisation des catégories :
        for category in self.categories.all():
            data['groups'].append({'name': category.slug})

        organisation_id = str(self.organisation.ckan_id)

        # Synchronisation de l'organisation ; si l'organisation
        # n'existe pas il faut la créer
        ckan_organisation = CkanHandler.get_organisation(organisation_id)
        if not ckan_organisation:
            CkanHandler.add_organisation(self.organisation)
        # et si l'organisation est désactiver il faut l'activer
        elif ckan_organisation.get('state') == 'deleted':
            CkanHandler.activate_organisation(organisation_id)

        if with_user:
            username = with_user.username

            # TODO: C'est très lourd de faire cela systématiquement -> voir pour améliorer cela
            CkanHandler.add_user_to_organisation(username, organisation_id)
            for category in self.categories.all():
                category_id = str(category.ckan_id)
                CkanHandler.add_user_to_group(username, category_id)
            #

            apikey = CkanHandler.get_user(username)['apikey']
            with CkanUserHandler(apikey=apikey) as ckan_user:
                return ckan_user.publish_dataset(id=id, **data)
        else:
            return CkanHandler.publish_dataset(id=id, **data)