Projet

Général

Profil

0002_anonymise_forms.patch

Jérôme Schneider, 12 décembre 2013 09:29

Télécharger (9,16 ko)

Voir les différences:


  

wcs/admin/forms.py
206 206

  
207 207
class FormDefPage(Directory):
208 208
    _q_exports = ['', 'fields', 'delete', 'duplicate', 'export',
209
                  'invite', 'enable', 'workflow', 'category',
209
                  'anonymise', 'invite', 'enable', 'workflow', 'category',
210 210
                  'role', ('workflow-options', 'workflow_options'),
211 211
                  ('workflow-status-remapping', 'workflow_status_remapping'),
212 212
                  'roles', 'title', 'options', ('acl-read', 'acl_read')]
......
381 381
        r += htmltext('<li><a href="duplicate">%s</a></li>') % _('Duplicate')
382 382
        if ET:
383 383
            r += htmltext('<li><a href="export">%s</a></li>') % _('Export')
384
        r += htmltext('<li><a href="anonymise">%s</a></li>') % _('Anonymise handled forms')
384 385
        if self.formdef.roles:
385 386
            r += htmltext('<li><a href="invite">%s</a></li>') % _('Invites')
386 387
        r += htmltext('</ul>')
......
711 712
                'attachment; filename=%s.wcs' % self.formdef.url_name)
712 713
        return '<?xml version="1.0" encoding="iso-8859-15"?>\n' + ET.tostring(x)
713 714

  
715
    def anonymise(self):
716
        if get_request().form.get('job'):
717
            return self.anonymise_processing()
718

  
719
        form = Form(enctype='multipart/form-data')
720

  
721
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
722
            "You are about to irrevocably anonymise forms which are closed.")))
723
        form.add_submit('submit', _('Submit'))
724
        form.add_submit('cancel', _('Cancel'))
725

  
726
        if form.get_widget('cancel').parse():
727
            return redirect('.')
728

  
729
        if not form.is_submitted() or form.has_errors():
730
            get_response().breadcrumb.append(('anonymise', _('Anonymise')))
731
            html_top('forms', title = _('Anonymise Forms'))
732
            r = TemplateIO(html=True)
733
            r += htmltext('<h2>%s</h2>') % _('Anonymise Forms')
734
            r += form.render()
735
            return r.getvalue()
736
        else:
737
            return self.anonymise_submit(form)
738

  
739
    def anonymise_submit(self, form):
740

  
741
        class Anonymiser:
742

  
743
            def __init__(self, formdef):
744
                self.formdef = formdef
745

  
746
            def anonymise(self, job=None):
747
                all_forms = self.formdef.data_class().select()
748
                not_endpoint_status = self.formdef.workflow.get_not_endpoint_status()
749
                not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status]
750
                all_forms = [x for x in all_forms if x.status not in not_endpoint_status_ids]
751
                for formdata in all_forms:
752
                    if not formdata.anonymised:
753
                        formdata.anonymise()
754

  
755
        count = self.formdef.data_class().count()
756
        anonymiser = Anonymiser(self.formdef)
757
        if count > 100: # Arbitrary threshold
758
            job = get_response().add_after_job(
759
                str(N_('Anonymising forms')),
760
                anonymiser.anonymise)
761
            return redirect('anonymise?job=%s' % job.id)
762
        else:
763
            anonymiser.anonymise()
764

  
765
        return redirect('.')
766

  
767
    def anonymise_processing(self):
768
        try:
769
            job = AfterJob.get(get_request().form.get('job'))
770
        except KeyError:
771
            return redirect('.')
772

  
773
        html_top('forms', title=_('Anonymising'))
774
        r = TemplateIO(html=True)
775
        r += get_session().display_message()
776
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
777
        r += htmltext('<dl class="job-status">')
778
        r += htmltext('<dt>')
779
        r += _(job.label)
780
        r += htmltext('</dt>')
781
        r += htmltext('<dd>')
782
        r += htmltext('<span class="afterjob" id="%s">') % job.id
783
        r += _(job.status)
784
        r += htmltext('</span>')
785
        r += htmltext('</dd>')
786
        r += htmltext('</dl>')
787

  
788
        r += htmltext('<div class="done">')
789
        r += htmltext('<a href="./">%s</a>') % _('Back')
790
        r += htmltext('</div>')
791
        return r.getvalue()
792

  
714 793
    def invite(self):
715 794
        if not self.formdef.roles:
716 795
            return template.error_page(
wcs/fields.py
115 115
    prefill = None
116 116
    store_display_value = None
117 117

  
118
    anonymise = True
118 119
    stats = None
119 120

  
120 121
    def __init__(self, **kwargs):
......
547 548

  
548 549
    widget_class = CheckboxWidget
549 550
    required = False
551
    anonymise = False
550 552

  
551 553
    def perform_more_widget_changes(self, form, kwargs, edit = True):
552 554
        if not edit:
......
626 628
    key = 'file'
627 629
    description = N_('File Upload')
628 630

  
631
    anonymise = False
629 632
    widget_class = FileWithPreviewWidget
630 633

  
631 634
    def get_view_value(self, value):
......
757 760

  
758 761
    items = []
759 762
    show_as_radio = False
763
    anonymise = False
760 764
    widget_class = SingleSelectHintWidget
761 765
    data_source = {}
762 766

  
......
891 895

  
892 896
    items = []
893 897
    max_choices = 0
898
    anonymise = False
894 899

  
895 900
    widget_class = CheckboxesWidget
896 901

  
......
1309 1314
    items = []
1310 1315
    randomize_items = False
1311 1316
    widget_class = RankedItemsWidget
1317
    anonymise = False
1312 1318

  
1313 1319
    def perform_more_widget_changes(self, form, kwargs, edit = True):
1314 1320
        kwargs['elements'] = self.items or []
wcs/formdata.py
130 130
    user_hash = None
131 131
    receipt_time = None
132 132
    status = None
133
    anonymised = None
133 134
    page_no = None # page to use when restoring from draft
134 135
    evolution = None
135 136
    data = None
......
438 439

  
439 440
        return status_action_roles
440 441

  
442
    def anonymise(self):
443
        for field in self.formdef.fields:
444
            if field.anonymise:
445
                self.data[field.id] = None
446

  
447
        self.anonymised = time.localtime()
448
        self.user_id = None
449
        self.user_hash = None
450
        self.editable_by = None
451
        self._signature = None
452
        self.workflow_data = None
453
        self.workflow_roles = None
454

  
455
        for evo in self.evolution:
456
            evo.who = None
457
            evo.parts = None
458
            evo.comment = None
459
            evo.parts = None
460
        self.store()
461

  
441 462
    def export_to_json(self):
442 463
        data = {}
443 464
        data['id'] = '%s/%s' % (self.formdef.url_name, self.id)
wcs/sql.py
112 112
                                    user_id varchar,
113 113
                                    user_hash varchar,
114 114
                                    receipt_time timestamp,
115
                                    anonymised timestamp,
115 116
                                    status varchar,
116 117
                                    page_no varchar,
117 118
                                    workflow_data bytea,
......
131 132

  
132 133
    needed_fields = set(['id', 'user_id', 'user_hash', 'receipt_time',
133 134
        'status', 'workflow_data', 'id_display', 'fts', 'page_no',
134
        'workflow_roles', 'workflow_roles_array'])
135
        'anonymised', 'workflow_roles', 'workflow_roles_array'])
135 136

  
136 137
    # migrations
137 138
    if not 'fts' in existing_fields:
......
147 148
    if not 'page_no' in existing_fields:
148 149
        cur.execute('''ALTER TABLE %s ADD COLUMN page_no varchar''' % table_name)
149 150

  
151
    if not 'anonymised' in existing_fields:
152
        cur.execute('''ALTER TABLE %s ADD COLUMN anonymised timestamp''' % table_name)
153

  
150 154
    # add new fields
151 155
    for field in formdef.fields:
152 156
        assert field.id is not None
......
449 453
        ('receipt_time', 'timestamp'),
450 454
        ('status', 'varchar'),
451 455
        ('page_no', 'varchar'),
456
        ('anonymised', 'timestamp'),
452 457
        ('workflow_data', 'bytea'),
453 458
        ('id_display', 'varchar'),
454 459
        ('workflow_roles', 'bytea'),
......
506 511
                'page_no': self.page_no,
507 512
                'workflow_data': bytearray(cPickle.dumps(self.workflow_data)),
508 513
                'id_display': self.id_display,
514
                'anonymised': self.anonymised,
509 515
        }
510 516
        if self.receipt_time:
511 517
            sql_dict['receipt_time'] = datetime.datetime.fromtimestamp(time.mktime(self.receipt_time)),
512 518
        else:
513 519
            sql_dict['receipt_time'] = None
520

  
521
        if self.anonymised:
522
            sql_dict['anonymised'] = datetime.datetime.fromtimestamp(time.mktime(self.anonymised)),
523
        else:
524
            sql_dict['anonymised'] = None
525

  
514 526
        if self.workflow_roles:
515 527
            sql_dict['workflow_roles'] = bytearray(cPickle.dumps(self.workflow_roles))
516 528
            sql_dict['workflow_roles_array'] = [int(x) for x in self.workflow_roles.values()]