summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Siraut <csiraut@entrouvert.com>2019-01-30 10:41:53 (GMT)
committerFrédéric Péters <fpeters@entrouvert.com>2019-08-21 07:15:28 (GMT)
commitc0924dcfcdb99e7f8ff2b0c86f1e6ca13a3c1baa (patch)
tree933874939c596ac296291cf81a51364dc8ea3e9d
parent953e6fcd2bfba7704e3a9cb2db43bc6851e9298b (diff)
downloadpublik-client-scripts-c0924dcfcdb99e7f8ff2b0c86f1e6ca13a3c1baa.zip
publik-client-scripts-c0924dcfcdb99e7f8ff2b0c86f1e6ca13a3c1baa.tar.gz
publik-client-scripts-c0924dcfcdb99e7f8ff2b0c86f1e6ca13a3c1baa.tar.bz2
add publik-cd06-scripts (#30175)v1.8
-rw-r--r--.gitignore2
-rw-r--r--clients/cd06/Makefile9
-rw-r--r--clients/cd06/cd06/__init__.py0
-rw-r--r--clients/cd06/cd06/signature.py74
-rw-r--r--clients/cd06/cd06/wcs_api.py318
-rw-r--r--clients/cd06/script.py162
-rw-r--r--debian/cd06/example.conf6
-rw-r--r--debian/control8
-rw-r--r--debian/publik-cd06-scripts.cron.hourly10
-rw-r--r--debian/publik-cd06-scripts.dirs2
-rw-r--r--debian/publik-cd06-scripts.install2
11 files changed, 592 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index e063cf6..1c05b03 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,6 @@ debian/.debhelper/
debian/*.debhelper.log
debian/publik-strasbourg-scripts/
debian/publik-montpellier-scripts/
+debian/publik-cd06-scripts/
sdist
+__pycache__
diff --git a/clients/cd06/Makefile b/clients/cd06/Makefile
new file mode 100644
index 0000000..dbf5ef7
--- /dev/null
+++ b/clients/cd06/Makefile
@@ -0,0 +1,9 @@
+.PHONY: all
+
+VAR_DIR=/var/lib/publik/clients/cd06/data
+
+all:
+ test -d $(VAR_DIR) || mkdir $(VAR_DIR)
+ python3 script.py $(VAR_DIR)
+ rm -rf $(VAR_DIR)/tmp
+ lftp -e 'set sftp:connect-program "ssh -a -x -o HostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"; mirror -e -R $(VAR_DIR) $(SFTP_DIRECTORY); exit' $(SFTP_URL)
diff --git a/clients/cd06/cd06/__init__.py b/clients/cd06/cd06/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/clients/cd06/cd06/__init__.py
diff --git a/clients/cd06/cd06/signature.py b/clients/cd06/cd06/signature.py
new file mode 100644
index 0000000..83479a6
--- /dev/null
+++ b/clients/cd06/cd06/signature.py
@@ -0,0 +1,74 @@
+import datetime
+import base64
+import hmac
+import hashlib
+import urllib
+import random
+import urllib.parse as urlparse
+
+'''Simple signature scheme for query strings'''
+
+
+def sign_url(url, key, algo='sha256', timestamp=None, nonce=None):
+ parsed = urlparse.urlparse(url)
+ new_query = sign_query(parsed.query, key, algo, timestamp, nonce)
+ return urlparse.urlunparse(parsed[:4] + (new_query,) + parsed[5:])
+
+
+def sign_query(query, key, algo='sha256', timestamp=None, nonce=None):
+ if timestamp is None:
+ timestamp = datetime.datetime.utcnow()
+ timestamp = timestamp.strftime('%Y-%m-%dT%H:%M:%SZ')
+ if nonce is None:
+ nonce = hex(random.SystemRandom().getrandbits(128))[2:-1]
+ new_query = query
+ if new_query:
+ new_query += '&'
+ new_query += urlparse.urlencode((
+ ('algo', algo),
+ ('timestamp', timestamp),
+ ('nonce', nonce)))
+ signature = base64.b64encode(sign_string(new_query, key, algo=algo))
+ new_query += '&signature=' + urlparse.quote(signature)
+ return new_query
+
+
+def sign_string(s, key, algo='sha256', timedelta=30):
+ digestmod = getattr(hashlib, algo)
+ if isinstance(s, str):
+ s = s.encode('utf-8')
+ if isinstance(key, str):
+ key = key.encode('utf-8')
+ hash = hmac.HMAC(key, digestmod=digestmod, msg=s)
+ return hash.digest()
+
+
+def check_url(url, key, known_nonce=None, timedelta=30):
+ parsed = urlparse.urlparse(url, 'https')
+ return check_query(parsed.query, key)
+
+
+def check_query(query, key, known_nonce=None, timedelta=30):
+ parsed = urlparse.parse_qs(query)
+ signature = base64.b64decode(parsed['signature'][0])
+ algo = parsed['algo'][0]
+ timestamp = parsed['timestamp'][0]
+ timestamp = datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ')
+ nonce = parsed['nonce']
+ unsigned_query = query.split('&signature=')[0]
+ if known_nonce is not None and known_nonce(nonce):
+ return False
+ if abs(datetime.datetime.utcnow() - timestamp) > datetime.timedelta(seconds=timedelta):
+ return False
+ return check_string(unsigned_query, signature, key, algo=algo)
+
+
+def check_string(s, signature, key, algo='sha256'):
+ # constant time compare
+ signature2 = sign_string(s, key, algo=algo)
+ if len(signature2) != len(signature):
+ return False
+ res = 0
+ for a, b in zip(signature, signature2):
+ res |= ord(a) ^ ord(b)
+ return res == 0
diff --git a/clients/cd06/cd06/wcs_api.py b/clients/cd06/cd06/wcs_api.py
new file mode 100644
index 0000000..dde02eb
--- /dev/null
+++ b/clients/cd06/cd06/wcs_api.py
@@ -0,0 +1,318 @@
+import requests
+import urllib.parse as urlparse
+import urllib
+import isodate
+import logging
+import base64
+
+from . import signature
+
+
+logger = logging.getLogger(__name__)
+
+
+class WcsApiError(Exception):
+ pass
+
+
+class JSONFile(object):
+ def __init__(self, d):
+ self.d = d
+
+ @property
+ def filename(self):
+ return self.d.get('filename', '')
+
+ @property
+ def content_type(self):
+ return self.d.get('content_type', 'application/octet-stream')
+
+ @property
+ def content(self):
+ return base64.b64decode(self.d['content'])
+
+
+class BaseObject(object):
+ def __init__(self, wcs_api, **kwargs):
+ self._wcs_api = wcs_api
+ self.__dict__.update(**kwargs)
+
+
+class FormDataWorkflow(BaseObject):
+ status = None
+ fields = None
+
+ def __init__(self, wcs_api, **kwargs):
+ super(FormDataWorkflow, self).__init__(wcs_api, **kwargs)
+ if self.status is not None:
+ self.status = BaseObject(wcs_api, **self.status)
+ self.fields = self.fields or {}
+
+
+class EvolutionUser(BaseObject):
+ id = None
+ name = None
+ NameID = None
+ email = None
+
+
+class Evolution(BaseObject):
+ who = None
+ status = None
+ parts = None
+
+ def __init__(self, wcs_api, **kwargs):
+ super(Evolution, self).__init__(wcs_api, **kwargs)
+ self.time = isodate.parse_datetime(self.time)
+ if self.parts:
+ self.parts = [BaseObject(wcs_api, **part) for part in self.parts]
+ if self.who:
+ self.who = EvolutionUser(wcs_api, **self.who)
+
+
+class FormData(BaseObject):
+ geolocations = None
+ evolution = None
+ submissions = None
+ workflow = None
+ roles = None
+
+ def __init__(self, wcs_api, **kwargs):
+ super(FormData, self).__init__(wcs_api, **kwargs)
+ self.receipt_time = isodate.parse_datetime(self.receipt_time)
+ if self.submissions:
+ self.submission = BaseObject(wcs_api, **self.submission)
+ if self.workflow:
+ self.workflow = FormDataWorkflow(wcs_api, **self.workflow)
+ self.evolution = [Evolution(wcs_api, **evo) for evo in self.evolution or []]
+ self.functions = {}
+ self.concerned_roles = []
+ self.action_roles = []
+ for function in self.roles or []:
+ roles = [Role(wcs_api, **r) for r in self.roles[function]]
+ if function == 'concerned':
+ self.concerned_roles.extend(roles)
+ elif function == 'actions':
+ self.concerned_roles.extend(roles)
+ else:
+ try:
+ self.functions[function] = roles[0]
+ except IndexError:
+ self.functions[function] = None
+ if 'roles' in self.__dict__:
+ del self.roles
+ self.with_files = False
+
+ def __repr__(self):
+ return '<{klass} {display_id!r}>'.format(klass=self.__class__.__name__,
+ display_id=self.id)
+
+ @property
+ def full_fields(self):
+ if not self.with_files:
+ data = self._wcs_api.get_json(
+ self._wcs_api.forms_url,
+ self.formdef_slug + '/',
+ str(self.id.rsplit('/')[-1]) + '/')
+ self.fields = data['fields']
+ self.with_files = True
+ return self.fields
+
+ @property
+ def endpoint_delay(self):
+ '''Compute delay as the time when the last not endpoint status precedes an endpoint
+ status.'''
+ statuses_map = self.formdef.schema.workflow.statuses_map
+ s = 0
+ for evo in self.evolution[::-1]:
+ if evo.status:
+ try:
+ status = statuses_map[evo.status]
+ except KeyError: # happen when workflow has changed
+ return
+ if status.endpoint:
+ s = 1
+ last = evo.time - self.receipt_time
+ else:
+ if s == 1:
+ return last
+ else:
+ return
+
+ def __getitem__(self, key):
+ value = self.full_fields.get(key)
+ if not value:
+ return value
+ # unserialize files
+ if isinstance(value, dict) and 'content' in value:
+ return JSONFile(value)
+ return value
+
+
+class Workflow(BaseObject):
+ statuses = None
+ fields = None
+
+ def __init__(self, wcs_api, **kwargs):
+ super(Workflow, self).__init__(wcs_api, **kwargs)
+ self.statuses = [BaseObject(wcs_api, **v) for v in (self.statuses or [])]
+ assert not hasattr(self.statuses[0], 'startpoint'), 'startpoint is exported by w.c.s. FIXME'
+ for status in self.statuses:
+ status.startpoint = False
+ self.statuses[0].startpoint = True
+ self.statuses_map = dict((s.id, s) for s in self.statuses)
+ self.fields = [Field(wcs_api, **field) for field in (self.fields or [])]
+
+
+class Field(BaseObject):
+ items = None
+ options = None
+ varname = None
+ in_filters = False
+ anonymise = None
+
+
+class Schema(BaseObject):
+ category_id = None
+ category = None
+ geolocations = None
+
+ def __init__(self, wcs_api, **kwargs):
+ super(Schema, self).__init__(wcs_api, **kwargs)
+ self.workflow = Workflow(wcs_api, **self.workflow)
+ self.fields = [Field(wcs_api, **f) for f in self.fields]
+ self.geolocations = sorted((k, v) for k, v in (self.geolocations or {}).items())
+
+
+class FormDef(BaseObject):
+ geolocations = None
+
+ def __init__(self, wcs_api, **kwargs):
+ self._wcs_api = wcs_api
+ self.__dict__.update(**kwargs)
+
+ def __unicode__(self):
+ return self.title
+
+ @property
+ def datas(self):
+ datas = self._wcs_api.get_formdatas(self.slug, full=True)
+ for data in datas:
+ data.formdef = self
+ yield data
+
+ @property
+ def schema(self):
+ return self._wcs_api.get_schema(self.slug)
+
+ def __repr__(self):
+ return '<{klass} {slug!r}>'.format(klass=self.__class__.__name__, slug=self.slug)
+
+
+class Role(BaseObject):
+ pass
+
+
+class Category(BaseObject):
+ pass
+
+
+class WcsApi(object):
+ def __init__(self, url, orig, key, name_id=None, verify=True, slugs=None, batch_size=1000):
+ self.url = url
+ self.orig = orig
+ self.key = key
+ self.verify = verify
+ self.cache = {}
+ self.slugs = slugs or []
+ self.batch_size = batch_size
+ self.name_id = name_id
+
+ @property
+ def formdefs_url(self):
+ return urlparse.urljoin(self.url, 'api/formdefs/')
+
+ @property
+ def forms_url(self):
+ return urlparse.urljoin(self.url, 'api/forms/')
+
+ @property
+ def roles_url(self):
+ return urlparse.urljoin(self.url, 'api/roles')
+
+ def build_url(self, url_parts):
+ url = url_parts[0]
+ for url_part in url_parts[1:]:
+ url = urlparse.urljoin(url, url_part)
+ return url
+
+ def get_json(self, *url_parts):
+ url = self.build_url(url_parts)
+ params = {'orig': self.orig}
+ if self.name_id:
+ params['NameID'] = self.name_id
+ query_string = urlparse.urlencode(params)
+ presigned_url = url + ('&' if '?' in url else '?') + query_string
+ if presigned_url in self.cache:
+ return self.cache[presigned_url]
+ signed_url = signature.sign_url(presigned_url, self.key)
+ try:
+ response = requests.get(signed_url, verify=self.verify)
+ response.raise_for_status()
+ except requests.RequestException as e:
+ raise WcsApiError('GET request failed', signed_url, e)
+ else:
+ try:
+ content = response.json()
+ self.cache[presigned_url] = content
+ return content
+ except ValueError as e:
+ raise WcsApiError('Invalid JSON content', signed_url, e)
+
+ @property
+ def roles(self):
+ return [Role(wcs_api=self, **d) for d in self.get_json(self.roles_url)['data']]
+
+ @property
+ def formdefs(self):
+ result = self.get_json(self.formdefs_url)
+ if isinstance(result, dict):
+ if result['err'] == 0:
+ data = result['data']
+ else:
+ logger.error(u'could not retrieve formdefs from %s, err_desc: %s',
+ self.formdefs_url, result.get('err_desc'))
+ return []
+ else:
+ data = result
+ return [FormDef(wcs_api=self, **d) for d in data
+ if not self.slugs or d['slug'] in self.slugs]
+
+ @property
+ def categories(self):
+ d = {}
+ for f in self.formdefs:
+ if hasattr(f.schema, 'category'):
+ d[f.schema.category_id] = f.schema.category
+ return [Category(wcs_api=self, id=k, name=v) for k, v in d.items()]
+
+ def get_formdatas(self, slug, full=True):
+ offset = 0
+ limit = self.batch_size
+ while True:
+ data = self.get_json(
+ self.forms_url,
+ slug + '/list?full=%s&offset=%d&limit=%d' % (
+ 'on' if full else 'off', offset, limit))
+ for d in data:
+ # w.c.s. had a bug where some formdata lost their draft status, skip them
+ if not d.get('receipt_time'):
+ continue
+ yield FormData(wcs_api=self, formdef_slug=slug, **d)
+ if len(data) < limit:
+ break
+ offset += limit
+
+ def get_schema(self, slug):
+ json_schema = self.get_json(self.formdefs_url, slug + '/', 'schema?anonymise')
+ return Schema(wcs_api=self, **json_schema)
diff --git a/clients/cd06/script.py b/clients/cd06/script.py
new file mode 100644
index 0000000..ebd5f52
--- /dev/null
+++ b/clients/cd06/script.py
@@ -0,0 +1,162 @@
+# -*- coding: utf-8 -*-
+
+from __future__ import unicode_literals
+
+import logging
+import logging.handlers
+import sys
+import os
+import shutil
+from cd06.wcs_api import WcsApi, WcsApiError
+
+FORMDEFS = {
+ 'premiere-demande-d-apa-a-domicile': {
+ 'DIRECTORY': 'premiere-demande-apa',
+ 'MAPPINGS': [
+ # ('Nom', 'Variable', 'Nommage fichier',)
+ ('Mandat de délégation signé', 'mandat', 'MANDAT_DELEGATION.PDF',),
+ ('Copie du jugement mesure de protection par une personne',
+ 'jugement_mesure_protection_personne',
+ 'JUGEMENT_MESURE_DE_PROTECTION_PERSONNE.PDF',),
+ ('Copie du jugement mesure de protection par un organisme personne',
+ 'jugement_mesure_protection_organisme',
+ 'JUGEMENT_MESURE_DE_PROTECTION_ORGANISME.PDF',),
+ ('Justificatif d\'identité demandeur', 'piece_identite_demandeur', 'JUSTIF_IDENT_DEMANDEUR.PDF',),
+ ('RIB demandeur', 'rib_demandeur', 'RIB_RIP_DEMANDEUR.PDF',),
+ ('Taxe foncière 1er bien', 'taxe_fonciere_1', 'TAXE_FONCIERE_BIEN_1.PDF',),
+ ('Taxe foncière 2ème bien', 'taxe_fonciere_2', 'TAXE_FONCIERE_BIEN_2.PDF',),
+ ('Taxe foncière 3ème bien', 'taxe_fonciere_3', 'TAXE_FONCIERE_BIEN_3.PDF',),
+ ('Avis d\'imposition', 'avis_imposition', 'AVIS_IMPOSITION.PDF',),
+ ('Document supplémentaire 1', 'document_supplementaire_1', 'DOCUMENT_SUPPLEMENTAIRE_1.PDF',),
+ ('Document supplémentaire 2', 'document_supplementaire_2', 'DOCUMENT_SUPPLEMENTAIRE_2.PDF',),
+ ('Document supplémentaire 3', 'document_supplementaire_3', 'DOCUMENT_SUPPLEMENTAIRE_3.PDF',),
+ ],
+ 'ANONYMISATION_STATUS': 'Anonymisation',
+ },
+ 'demande-de-revision-apa-a-domicile': {
+ 'DIRECTORY': 'aggravation-apa',
+ 'MAPPINGS': [
+ # ('Nom', 'Variable', 'Nommage fichier',)
+ ('Mandat de délégation signé', 'mandat', 'MANDAT_DELEGATION.PDF',),
+ ('Copie du jugement mesure de protection par une personne',
+ 'jugement_mesure_protection_personne',
+ 'JUGEMENT_MESURE_DE_PROTECTION_PERSONNE.PDF',),
+ ('Copie du jugement mesure de protection par un organisme personne',
+ 'jugement_mesure_protection_organisme',
+ 'JUGEMENT_MESURE_DE_PROTECTION_ORGANISME.PDF',),
+ ('Taxe foncière 1er bien', 'taxe_fonciere_1', 'TAXE_FONCIERE_BIEN_1.PDF',),
+ ('Taxe foncière 2ème bien', 'taxe_fonciere_2', 'TAXE_FONCIERE_BIEN_2.PDF',),
+ ('Taxe foncière 3ème bien', 'taxe_fonciere_3', 'TAXE_FONCIERE_BIEN_3.PDF',),
+ ('Avis d\'imposition', 'avis_imposition', 'AVIS_IMPOSITION.PDF',),
+ ],
+ 'ANONYMISATION_STATUS': 'Anonymisation',
+ },
+}
+
+logger = logging.getLogger('cd06.cron.apa')
+logger.setLevel(logging.DEBUG)
+logger.propagate = False
+
+syslog_formatter = logging.Formatter('%(levelname)s - %(name)s - %(message)s')
+syslog_handler = logging.handlers.SysLogHandler(address='/dev/log')
+syslog_handler.setLevel(logging.INFO)
+syslog_handler.setFormatter(syslog_formatter)
+
+console_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
+console_handler = logging.StreamHandler(sys.stderr)
+console_handler.setLevel(logging.DEBUG)
+console_handler.setFormatter(console_formatter)
+
+memory_handler = logging.handlers.MemoryHandler(
+ capacity=1024 * 100,
+ flushLevel=logging.ERROR,
+ target=console_handler,
+)
+logger.addHandler(memory_handler)
+logger.addHandler(syslog_handler)
+
+
+def do():
+ api = WcsApi(os.environ['WCS_URL'],
+ os.environ['WCS_ORIG'],
+ os.environ['WCS_APIKEY'],
+ name_id=os.environ['USER_UUID'])
+
+ target_dir = sys.argv[1]
+
+ tmp_dir = os.path.join(target_dir, 'tmp')
+ if not os.path.exists(tmp_dir):
+ logger.info('creating %s', tmp_dir)
+ os.makedirs(tmp_dir)
+
+ for formdef in api.formdefs:
+ if formdef.slug not in FORMDEFS:
+ continue
+ logger.debug('handling formdef %s', formdef.slug)
+ FORMDEF = FORMDEFS[formdef.slug]
+ MAPPINGS = FORMDEF['MAPPINGS']
+ DIRECTORY = FORMDEF['DIRECTORY']
+ ANONYMISATION_STATUS = FORMDEF['ANONYMISATION_STATUS']
+ formdef_dir = os.path.join(target_dir, DIRECTORY)
+ if not os.path.exists(formdef_dir):
+ logger.info('creating %s', formdef_dir)
+ os.makedirs(formdef_dir)
+
+ known_ids = set()
+ statuses = {s.id: s.name for s in formdef.schema.workflow.statuses}
+
+
+ try:
+ for formdata in formdef.datas:
+ form_id = str(formdata.id).rsplit('/')[-1]
+ logging.debug('handling formdata %s', form_id)
+ known_ids.add(form_id)
+ formdata_dir = os.path.join(formdef_dir, form_id)
+ formdata_tmp_dir = os.path.join(tmp_dir, DIRECTORY, form_id)
+
+ if os.path.exists(formdata_dir):
+ status_name = statuses[formdata.evolution[-1].status]
+
+ if status_name == ANONYMISATION_STATUS:
+ if os.listdir(formdata_dir):
+ logger.info('anonymizing %s', formdata_dir)
+ for name in os.listdir(formdata_dir):
+ os.unlink(os.path.join(formdata_dir, name))
+ else:
+ logger.debug('already anonymized %s', formdata_dir)
+ else:
+ logger.info('%s: copying formdata %s', formdef.slug, form_id)
+ try:
+ shutil.rmtree(formdata_tmp_dir, True)
+ os.makedirs(formdata_tmp_dir)
+ for name, key, filename in MAPPINGS:
+ value = formdata[key]
+ if not value:
+ logger.debug('no file for "%s"', name)
+ continue
+ prefix, suffix = os.path.splitext(filename)
+ new_filename = prefix + os.path.splitext(value.filename)[1]
+ attachment_path = os.path.join(formdata_tmp_dir, new_filename)
+ logger.info('putting %s into %s for "%s"', value.filename, attachment_path, name)
+ with open(attachment_path, 'wb') as f:
+ f.write(value.content)
+ os.rename(formdata_tmp_dir, formdata_dir)
+ finally:
+ shutil.rmtree(formdata_tmp_dir, True)
+
+ existing_ids = set(os.listdir(formdef_dir))
+ for old_id in (existing_ids - known_ids):
+ path_to_delete = os.path.join(formdef_dir, old_id)
+ logger.delete('deleting %s', path_to_delete)
+ shutil.rmtree(path_to_delete)
+ except WcsApiError:
+ logger.exception('retrieving formdata failed for %s', formdef.slug)
+
+logger.info('start sending APA requests')
+try:
+ do()
+except Exception:
+ logger.exception('unexpected failure')
+logger.info('end sending APA requests')
+# clear buffered log records, to prevent flush on close
+super(logging.handlers.MemoryHandler, memory_handler).flush()
diff --git a/debian/cd06/example.conf b/debian/cd06/example.conf
new file mode 100644
index 0000000..b2abdde
--- /dev/null
+++ b/debian/cd06/example.conf
@@ -0,0 +1,6 @@
+USER_UUID=xxxxxxxxxxxxxxxxxxxxxxxxx
+
+WCS_URL=https://demarches-departement06.test.entrouvert.org/
+WCS_ORIG=demarches-departement06.test.entrouvert.org
+WCS_APIKEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
diff --git a/debian/control b/debian/control
index 580c62c..463b253 100644
--- a/debian/control
+++ b/debian/control
@@ -11,7 +11,8 @@ Architecture: all
Depends: ${misc:Depends},
publik-montpellier-scripts,
publik-strasbourg-scripts,
- publik-orleans-scripts
+ publik-orleans-scripts,
+ publik-cd06-scripts
Description: Meta package with all Publik client scripts
Package: publik-strasbourg-scripts
@@ -28,3 +29,8 @@ Package: publik-orleans-scripts
Architecture: all
Depends: ${misc:Depends}
Description: Publik scripts for Orléans
+
+Package: publik-cd06-scripts
+Architecture: all
+Depends: ${misc:Depends}, python3-isodate, lftp, make, python3-requests
+Description: Publik scripts for CD06
diff --git a/debian/publik-cd06-scripts.cron.hourly b/debian/publik-cd06-scripts.cron.hourly
new file mode 100644
index 0000000..4268a0b
--- /dev/null
+++ b/debian/publik-cd06-scripts.cron.hourly
@@ -0,0 +1,10 @@
+#! /bin/bash
+
+test -d /var/lib/wcs || exit 0
+grep 'DISABLE_CRON_JOBS = True' /etc/wcs/settings.d/* && exit 0
+
+instance=`hostname -f`
+config=/etc/publik/clients/cd06/${instance}.conf
+test -r $config || exit 0
+source $config
+cd /usr/lib/publik/clients/cd06 && make --quiet
diff --git a/debian/publik-cd06-scripts.dirs b/debian/publik-cd06-scripts.dirs
new file mode 100644
index 0000000..ddb8546
--- /dev/null
+++ b/debian/publik-cd06-scripts.dirs
@@ -0,0 +1,2 @@
+/usr/lib/publik/clients/cd06
+/var/lib/publik/clients/cd06
diff --git a/debian/publik-cd06-scripts.install b/debian/publik-cd06-scripts.install
new file mode 100644
index 0000000..61eee0f
--- /dev/null
+++ b/debian/publik-cd06-scripts.install
@@ -0,0 +1,2 @@
+usr/lib/publik/clients/cd06/
+debian/cd06/example.conf /etc/publik/clients/cd06/