From 8d7b9a3028cea03878c8bcaf60f90a6e0172f1c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Tue, 26 Nov 2019 14:00:58 +0100
Subject: [PATCH 3/6] remove support for clicrdv (#5484)

---
 auquotidien/modules/admin.py      |  58 +----
 auquotidien/modules/clicrdv.py    | 365 ------------------------------
 auquotidien/modules/connectors.py |   1 -
 3 files changed, 1 insertion(+), 423 deletions(-)
 delete mode 100644 auquotidien/modules/clicrdv.py

diff --git a/auquotidien/modules/admin.py b/auquotidien/modules/admin.py
index 4a490c7..65b8ec8 100644
--- a/auquotidien/modules/admin.py
+++ b/auquotidien/modules/admin.py
@@ -23,7 +23,7 @@ from .abelium_domino_ui import AbeliumDominoDirectory
 
 class PanelDirectory(Directory):
     _q_exports = ['', 'update', 'announces', 'permissions',
-            'announce_themes', 'strongbox', 'clicrdv', 'domino']
+            'announce_themes', 'strongbox', 'domino']
     label = N_('Control Panel')
 
     domino = AbeliumDominoDirectory()
@@ -160,60 +160,6 @@ class PanelDirectory(Directory):
             cfg_submit(form, 'misc', ('aq-strongbox',))
             return redirect('..')
 
-    def clicrdv(self):
-        if not get_publisher().has_site_option('clicrdv'):
-            raise errors.TraversalError()
-        misc_cfg = get_cfg('misc', {})
-        form = Form(enctype='multipart/form-data')
-        form.add(SingleSelectWidget, 'aq-clicrdv-server', title=_('ClicRDV Server'),
-                value=misc_cfg.get('aq-clicrdv-server', 'sandbox.clicrdv.com'), required=True,
-                options=[(str('www.clicrdv.com'), _('Production Server')),
-                         (str('sandbox.clicrdv.com'), _('Sandbox Server'))])
-        form.add(StringWidget, 'aq-clicrdv-api-key', title=_('API Key'),
-                value=misc_cfg.get('aq-clicrdv-api-key'), required=False,
-                size=40, hint=_('Empty to disable ClicRDV support'))
-        form.add(StringWidget, 'aq-clicrdv-api-username', title=_('Username'),
-                value=misc_cfg.get('aq-clicrdv-api-username'), required=False)
-        form.add(StringWidget, 'aq-clicrdv-api-password', title=_('Password'),
-                value=misc_cfg.get('aq-clicrdv-api-password'), required=False)
-
-        form.add_submit('submit', _('Submit'))
-        form.add_submit('cancel', _('Cancel'))
-
-        if form.get_widget('cancel').parse():
-            return redirect('..')
-
-        if not form.is_submitted() or form.has_errors():
-            get_response().breadcrumb.append(('aq/clicrdv', _('ClicRDV Integration')))
-            html_top('settings', _('ClicRDV Integration'))
-            r = TemplateIO(html=True)
-            r += htmltext('<h2>%s</h2>') % _('ClicRDV Integration')
-            r += form.render()
-            r += htmltext('<p>%s</p>') % _('Available Interventions: ')
-            try:
-                from clicrdv import get_all_intervention_sets
-                intervention_sets = get_all_intervention_sets()
-                r += htmltext('<ul>')
-                for s in intervention_sets:
-                    r += htmltext('<li><strong>clicrdv_get_interventions_in_set(%s)</strong> - %s') % (
-                            s['id'], s['name'])
-                    r += htmltext('<ul>')
-                    for n, intervention in s['interventions']:
-                        r += htmltext('<li>%s (id: %s)</li>') % (intervention, n)
-                    r += htmltext('</ul></li>')
-                r += htmltext('</ul>')
-            except Exception, e:
-                r += htmltext('<p>%s (%s)</p>') % (
-                        _('Cannot access to ClicRDV service'), str(e))
-            return r.getvalue()
-        else:
-            from wcs.admin.settings import cfg_submit
-            cfg_submit(form, 'misc', ('aq-clicrdv-server',
-                                      'aq-clicrdv-api-key',
-                                      'aq-clicrdv-api-username',
-                                      'aq-clicrdv-api-password'))
-            return redirect('..')
-
 
 class SettingsDirectory(wcs.admin.settings.SettingsDirectory):
     def _q_index(self):
@@ -234,8 +180,6 @@ class SettingsDirectory(wcs.admin.settings.SettingsDirectory):
             r += htmltext('<li><a href="aq/announce_themes">%s</a></li>') % _('Announce Themes')
         if get_publisher().has_site_option('strongbox'):
             r += htmltext('<li><a href="aq/strongbox">%s</a></li>') % _('Strongbox Support')
-        if get_publisher().has_site_option('clicrdv'):
-            r += htmltext('<li><a href="aq/clicrdv">%s</a></li>') % _('ClicRDV Integration')
         if get_publisher().has_site_option('domino'):
             r += htmltext('<li><a href="aq/domino">%s</a></li>') % _('Abelium Domino Integration')
         r += htmltext('</ul>')
diff --git a/auquotidien/modules/clicrdv.py b/auquotidien/modules/clicrdv.py
deleted file mode 100644
index b850f28..0000000
--- a/auquotidien/modules/clicrdv.py
+++ /dev/null
@@ -1,365 +0,0 @@
-import base64
-import datetime
-import urllib2
-
-try:
-    import json
-except ImportError:
-    import simplejson as json
-
-import time
-import vobject
-
-from wcs.qommon import _
-from wcs.qommon import get_cfg
-from wcs.qommon.misc import format_time
-from wcs.qommon.form import *
-
-from wcs.data_sources import register_data_source_function
-from wcs.formdata import Evolution
-from wcs.forms.common import FormStatusPage
-from wcs.workflows import Workflow, WorkflowStatusItem, register_item_class
-
-def get_clicrdv_req(url):
-    misc_cfg = get_cfg('misc', {})
-
-    url = 'https://%s/api/v1/%s' % (
-                misc_cfg.get('aq-clicrdv-server', 'sandbox.clicrdv.com'), url)
-    if '?' in url:
-       url = url + '&apikey=%s&format=json' % misc_cfg.get('aq-clicrdv-api-key')
-    else:
-       url = url + '?apikey=%s&format=json' % misc_cfg.get('aq-clicrdv-api-key')
-
-    req = urllib2.Request(url)
-    username = misc_cfg.get('aq-clicrdv-api-username')
-    password = misc_cfg.get('aq-clicrdv-api-password')
-    authheader = 'Basic ' + base64.encodestring('%s:%s' % (username, password))[:-1]
-    req.add_header('Authorization', authheader)
-    return req
-
-def get_json(url):
-    return json.load(urllib2.urlopen(get_clicrdv_req(url)))
-
-def as_str(s):
-    if type(s) is unicode:
-        return s.encode(get_publisher().site_charset)
-    return s
-
-def get_all_intervention_sets():
-    interventions_set = []
-    for interventionset in sorted(get_json('interventionsets').get('records'), 
-            lambda x,y: cmp(x['sort'],y['sort'])):
-        interventions = []
-        for intervention in sorted(get_json('interventionsets/%s/interventions' % interventionset.get('id')).get('records'),
-                lambda x,y: cmp(x['sort'], y['sort'])):
-            if intervention.get('deleted') == True:
-                continue
-            name = '%s' % as_str(intervention.get('publicname'))
-            if not name:
-                name = '%s' % as_str(intervention.get('name'))
-            interventions.append((intervention.get('id'), as_str(name)))
-        interventions_set.append({
-                'id': interventionset.get('id'),
-                'group_id': interventionset.get('group_id'),
-                'name': as_str(interventionset.get('name')),
-                'publicname': as_str(interventionset.get('publicname')) or '',
-                'description': as_str(interventionset.get('description')) or '',
-                'interventions': interventions
-                })
-    return interventions_set
-
-def get_all_interventions():
-    interventions = []
-    for s in get_all_intervention_sets():
-        for i, publicname in s['interventions']:
-            intervention_label = '%s - %s' % (s['publicname'], publicname)
-            interventions.append((i, as_str(intervention_label)))
-    return interventions
-
-def get_interventions_in_set(interventionset_id):
-    interventions = []
-    interventions_json = get_json('interventionsets/%s/interventions' % interventionset_id)
-    for intervention in interventions_json.get('records'):
-        if intervention.get('deleted') != True:
-            name = '%s' % as_str(intervention.get('publicname'))
-            if not name:
-                name = '%s' % as_str(intervention.get('name'))
-            interventions.append((intervention.get('id'), name))
-    return interventions
-
-def get_available_timeslots(intervention, date_start=None, date_end=None):
-    timeslots = []
-    iid = intervention
-    gid = get_json('interventions/%s' % iid).get('group_id')
-    request_url = 'availabletimeslots?intervention_ids[]=%s&group_id=%s' % (iid, gid)
-    if date_start is None:
-        date_start = datetime.datetime.today().strftime('%Y-%m-%d')
-    if date_end is None:
-        date_end = (datetime.datetime.today() + datetime.timedelta(366)).strftime('%Y-%m-%d')
-    if date_start:
-        request_url = request_url + '&start=%s' % urllib2.quote(date_start)
-    if date_end:
-        request_url = request_url + '&end=%s' % urllib2.quote(date_end)
-    for timeslot in get_json(request_url).get('availabletimeslots'):
-        timeslots.append(timeslot.get('start'))
-    timeslots.sort()
-    return timeslots
-
-def get_available_dates(intervention):
-    dates = []
-    for timeslot in get_available_timeslots(intervention):
-        parsed = time.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
-        date_tuple = (time.strftime('%Y-%m-%d', parsed),
-                      format_time(parsed, '%(weekday_name)s %(day)0.2d/%(month)0.2d/%(year)s'))
-        if date_tuple in dates:
-            continue
-        dates.append(date_tuple)
-    return dates
-
-def get_available_times(intervention, date):
-    times = []
-    timeslots = get_available_timeslots(intervention,
-                    date_start='%s 00:00:00' % date,
-                    date_end='%s 23:59:59' % date)
-    for timeslot in timeslots:
-        parsed = time.strptime(timeslot, '%Y-%m-%d %H:%M:%S')
-        time_tuple = (time.strftime('%H:%M:%S', parsed),
-                      time.strftime('%Hh%M', parsed))
-        times.append(time_tuple)
-    times.sort()
-    return times
-
-register_data_source_function(get_all_interventions, 'clicrdv_get_all_interventions')
-register_data_source_function(get_interventions_in_set, 'clicrdv_get_interventions_in_set')
-register_data_source_function(get_available_dates, 'clicrdv_get_available_dates')
-register_data_source_function(get_available_times, 'clicrdv_get_available_times')
-
-def form_download_event(self):
-    self.check_receiver()
-
-    found = False
-    for evo in self.filled.evolution:
-        if evo.parts:
-            for p in evo.parts:
-                if not isinstance(p, AppointmentPart):
-                    continue
-                cal = vobject.iCalendar()
-                cal.add('prodid').value = '-//Entr\'ouvert//NON SGML Publik'
-                vevent = vobject.newFromBehavior('vevent')
-                vevent.add('uid').value = 'clicrdv-%s' % p.id
-                vevent.add('summary').value = p.json_dict.get('group_name')
-                vevent.add('dtstart').value = datetime.datetime.strptime(
-                                p.json_dict.get('start'), '%Y-%m-%d %H:%M:%S')
-                vevent.add('dtend').value = datetime.datetime.strptime(
-                                p.json_dict.get('end'), '%Y-%m-%d %H:%M:%S')
-                vevent.add('location').value = p.json_dict.get('location')
-                cal.add(vevent)
-
-                response = get_response()
-                response.set_content_type('text/calendar')
-                return cal.serialize()
-
-    raise TraversalError()
-
-
-class AppointmentPart(object):
-    def __init__(self, json_dict):
-        self.id = json_dict.get('id')
-        self.json_dict = json_dict
-
-    def view(self):
-        return htmltext('<p class="appointment"><a href="clicrdvevent">%s</a></p>' % (
-                                _('Download Appointment')))
-
-
-class AppointmentErrorPart(object):
-    def __init__(self, msg):
-        self.msg = msg
-
-    def view(self):
-        return htmltext('<p class="appointment-error">%s</p>' % str(self.msg))
-
-
-class ClicRdvCreateAppointment(WorkflowStatusItem):
-    description = N_('Create a ClicRDV Appointment')
-    key = 'clicrdv-create'
-    category = 'interaction'
-
-    endpoint = False
-
-    var_firstname = None
-    var_lastname = None
-    var_email = None
-    var_firstphone = None
-    var_secondphone = None
-    var_datetime = None
-    var_intervention_id = None
-    status_on_success = None
-    status_on_failure = None
-
-    def init(cls):
-        FormStatusPage._q_extra_exports.append('clicrdvevent')
-        FormStatusPage.clicrdvevent = form_download_event
-    init = classmethod(init)
-
-    def is_available(self, workflow=None):
-        return get_publisher().has_site_option('clicrdv')
-    is_available = classmethod(is_available)
-
-    def render_as_line(self):
-        return _('Create an appointment in ClicRDV')
-
-    def get_parameters(self):
-        return ('var_firstname', 'var_lastname', 'var_email', 'var_firstphone',
-                'var_secondphone', 'var_datetime', 'var_intervention_id',
-                'status_on_success', 'status_on_failure')
-
-    def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
-        parameter_labels = {
-            'var_firstname': N_('First Name'),
-            'var_lastname': N_('Last Name'),
-            'var_email': N_('Email'),
-            'var_firstphone': N_('Phone (1st)'),
-            'var_secondphone':  N_('Phone (2nd)'),
-            'var_datetime': N_('Date/time'),
-            'var_intervention_id': N_('Intervention Id'),
-        }
-        for parameter in self.get_parameters():
-            if not parameter in parameter_labels:
-                continue
-            if parameter in parameters:
-                form.add(StringWidget, '%s%s' % (prefix, parameter),
-                         title=_(parameter_labels.get(parameter)),
-                         value=getattr(self, parameter),
-                         required=False)
-        if 'status_on_success' in parameters:
-            form.add(SingleSelectWidget, '%sstatus_on_success' % prefix,
-                    title=_('Status On Success'), value=self.status_on_success,
-                    options = [(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status])
-        if 'status_on_failure' in parameters:
-            form.add(SingleSelectWidget, '%sstatus_on_failure' % prefix,
-                    title=_('Status On Failure'), value=self.status_on_failure,
-                    options = [(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status])
-
-    def perform(self, formdata):
-        args = {}
-        for parameter in self.get_parameters():
-            args[parameter] = self.compute(getattr(self, parameter))
-            if not args.get(parameter):
-                del args[parameter]
-        message = {'appointment':
-                      {'fiche': {'firstname': args.get('var_firstname', '-'),
-                                 'lastname': args.get('var_lastname', '-'),
-                                 'email': args.get('var_email'),
-                                 'firstphone': args.get('var_firstphone'),
-                                 'secondphone': args.get('var_secondphone'),
-                                },
-                       'date': args.get('var_datetime'),
-                       'intervention_ids': [int(args.get('var_intervention_id'))],
-                       # 'comments': '-',
-                       'websource': 'Publik'}
-                  }
-
-        req = get_clicrdv_req('appointments')
-        req.add_data(json.dumps(message))
-        req.add_header('Content-Type', 'application/json')
-
-        try:
-            fd = urllib2.urlopen(req)
-        except urllib2.HTTPError, e:
-            success = False
-            try:
-                msg = json.load(e.fp)[0].get('error')
-            except:
-                msg = _('unknown error')
-
-            if formdata.evolution:
-                evo = formdata.evolution[-1]
-            else:
-                formdata.evolution = []
-                evo = Evolution()
-                evo.time = time.localtime()
-                evo.status = formdata.status
-                formdata.evolution.append(evo)
-            evo.add_part(AppointmentErrorPart(msg))
-        else:
-            success = True
-            response = json.load(fd)
-            appointment_id = response.get('records')[0].get('id')
-
-            # add a message in formdata.evolution
-            if formdata.evolution:
-                evo = formdata.evolution[-1]
-            else:
-                formdata.evolution = []
-                evo = Evolution()
-                evo.time = time.localtime()
-                evo.status = formdata.status
-                formdata.evolution.append(evo)
-            evo.add_part(AppointmentPart(response.get('records')[0]))
-
-        formdata.store()
-
-        if (success and self.status_on_success) or (success is False and self.status_on_failure):
-            if success:
-                formdata.status = 'wf-%s' % self.status_on_success
-            else:
-                formdata.status = 'wf-%s' % self.status_on_failure
-
-register_item_class(ClicRdvCreateAppointment)
-
-
-class ClicRdvCancelAppointment(WorkflowStatusItem):
-    description = N_('Cancel a ClicRDV Appointment')
-    key = 'clicrdv-cancel'
-    category = 'interaction'
-
-    endpoint = False
-
-    status_on_success = None
-    status_on_failure = None
-
-    def get_parameters(self):
-        return ('status_on_success', 'status_on_failure')
-
-    def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
-        if 'status_on_success' in parameters:
-            form.add(SingleSelectWidget, '%sstatus_on_success' % prefix,
-                    title=_('Status On Success'), value=self.status_on_success,
-                    options = [(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status])
-        if 'status_on_failure' in parameters:
-            form.add(SingleSelectWidget, '%sstatus_on_failure' % prefix,
-                    title=_('Status On Failure'), value=self.status_on_failure,
-                    options = [(None, '---')] + [(x.id, x.name) for x in self.parent.parent.possible_status])
-
-    def is_available(self, workflow=None):
-        return get_publisher().has_site_option('clicrdv')
-    is_available = classmethod(is_available)
-
-    def render_as_line(self):
-        return _('Cancel an appointment in ClicRDV')
-
-    def perform(self, formdata):
-        success = True
-
-        for evo in [evo for evo in formdata.evolution if evo.parts]:
-            for part in [part for part in evo.parts if isinstance(part, AppointmentPart)]:
-                appointment_id = part.id
-                try:
-                    req = get_clicrdv_req('appointments/%s' % appointment_id)
-                    req.get_method = (lambda: 'DELETE')
-                    fd = urllib2.urlopen(req)
-                    none = fd.read()
-                except urllib2.URLError:
-                    # clicrdv will return a "Bad Request" (HTTP 400) response
-                    # when it's not possible to remove an appointment
-                    # (for example because it's too late)
-                    success = False
-
-        if (success and self.status_on_success) or (success is False and self.status_on_failure):
-            if success:
-                formdata.status = 'wf-%s' % self.status_on_success
-            else:
-                formdata.status = 'wf-%s' % self.status_on_failure
-
-register_item_class(ClicRdvCancelAppointment)
diff --git a/auquotidien/modules/connectors.py b/auquotidien/modules/connectors.py
index bfd89c6..6ce6d89 100644
--- a/auquotidien/modules/connectors.py
+++ b/auquotidien/modules/connectors.py
@@ -1,2 +1 @@
-from . import clicrdv
 from . import abelium_domino_workflow
-- 
2.24.0

