Projet

Général

Profil

0001_anonymise_forms.patch

Jérôme Schneider, 10 décembre 2013 16:10

Télécharger (10,5 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
                  'archive', '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="archive">%s</a></li>') % _('Archive')
384
        r += htmltext('<li><a href="anonymise">%s</a></li>') % _('Anonymise')
385 385
        if self.formdef.roles:
386 386
            r += htmltext('<li><a href="invite">%s</a></li>') % _('Invites')
387 387
        r += htmltext('</ul>')
......
712 712
                'attachment; filename=%s.wcs' % self.formdef.url_name)
713 713
        return '<?xml version="1.0" encoding="iso-8859-15"?>\n' + ET.tostring(x)
714 714

  
715
    def archive(self):
716
        if get_request().form.get('job'):
717
            return self.archive_processing()
718
        if get_request().form.get('download'):
719
            return self.archive_download()
720

  
715
    def anonymise(self):
721 716
        form = Form(enctype='multipart/form-data')
722 717

  
723
        form.add(DateWidget, 'date', title = _('Archive forms handled before'))
724
        form.add(CheckboxWidget, 'not-done', title = _('Include forms that have not been handled'),
725
                value = False)
726
        form.add(CheckboxWidget, 'keep', title = _('Do not remove forms'),
727
                value = False)
718
        form.widgets.append(HtmlWidget('<p>%s</p>' % _(
719
            "You are about to irrevocably anonymise forms which are closed.")))
728 720
        form.add_submit('submit', _('Submit'))
729 721
        form.add_submit('cancel', _('Cancel'))
730 722

  
......
732 724
            return redirect('.')
733 725

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

  
744
    def archive_submit(self, form):
736
    def anonymise_submit(self, form):
745 737

  
746
        class Archiver:
747
            def __init__(self, formdef):
748
                self.formdef = formdef
738
        all_forms = self.formdef.data_class().select()
749 739

  
750
            def archive(self, job=None):
751
                all_forms = self.formdef.data_class().select()
752

  
753
                if form.get_widget('not-done').parse() is False:
754
                    not_endpoint_status = self.formdef.workflow.get_not_endpoint_status()
755
                    not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status]
756
                    all_forms = [x for x in all_forms if x.status not in not_endpoint_status_ids]
757

  
758
                if form.get_widget('date').parse():
759
                    date = form.get_widget('date').parse()
760
                    date = time.strptime(date, misc.date_format())
761
                    all_forms = [x for x in all_forms if (
762
                        x.evolution and x.evolution[-1].time < date) or (
763
                        x.receipt_time < date)]
764

  
765
                self.fd = StringIO()
766
                t = tarfile.open('wcs.tar.gz', 'w:gz', fileobj=self.fd)
767
                t.add(self.formdef.get_object_filename(), 'formdef')
768
                for formdata in all_forms:
769
                    t.add(formdata.get_object_filename(), '%s/%s' % (self.formdef.url_name, str(formdata.id)))
770
                t.close()
771

  
772
                if form.get_widget('keep').parse() is False:
773
                    for f in all_forms:
774
                        f.remove_self()
775

  
776
                if job:
777
                    job.file_content = self.fd.getvalue()
778
                    job.store()
779

  
780
        count = self.formdef.data_class().count()
781
        archiver = Archiver(self.formdef)
782
        if count > 100: # Arbitrary threshold
783
            job = get_response().add_after_job(
784
                str(N_('Archiving forms')),
785
                archiver.archive)
786
            return redirect('archive?job=%s' % job.id)
787
        else:
788
            archiver.archive()
740
        not_endpoint_status = self.formdef.workflow.get_not_endpoint_status()
741
        not_endpoint_status_ids = ['wf-%s' % x.id for x in not_endpoint_status]
742
        all_forms = [x for x in all_forms if x.status not in not_endpoint_status_ids]
789 743

  
790
            response = get_response()
791
            response.set_content_type('application/x-wcs-archive')
792
            response.set_header('content-disposition',
793
                'attachment; filename=%s-archive.wcs' % self.formdef.url_name)
794
            return archiver.fd.getvalue()
744
        for formdata in all_forms:
745
            if not formdata.anonymised:
746
                formdata.anonymise()
795 747

  
796
    def archive_processing(self):
797
        try:
798
            job = AfterJob.get(get_request().form.get('job'))
799
        except KeyError:
800
            return redirect('.')
801

  
802
        html_top('forms', title=_('Archiving'))
803
        r = TemplateIO(html=True)
804
        r += get_session().display_message()
805
        get_response().add_javascript(['jquery.js', 'afterjob.js'])
806
        r += htmltext('<dl class="job-status">')
807
        r += htmltext('<dt>')
808
        r += _(job.label)
809
        r += htmltext('</dt>')
810
        r += htmltext('<dd>')
811
        r += htmltext('<span class="afterjob" id="%s">') % job.id
812
        r += _(job.status)
813
        r += htmltext('</span>')
814
        r += htmltext('</dd>')
815
        r += htmltext('</dl>')
816

  
817
        r += htmltext('<div class="done">')
818
        r += htmltext('<a href="archive?download=%s">%s</a>') % (job.id, _('Download Archive'))
819
        r += htmltext('</div>')
820
        return r.getvalue()
821

  
822
    def archive_download(self):
823
        try:
824
            job = AfterJob.get(get_request().form.get('download'))
825
        except KeyError:
826
            return redirect('.')
827

  
828
        if not job.status == 'completed':
829
            raise TraversalError()
830
        response = get_response()
831
        response.set_content_type('application/x-wcs-archive')
832
        response.set_header('content-disposition',
833
            'attachment; filename=%s-archive.wcs' % self.formdef.url_name)
834
        return job.file_content
748
        return redirect('.')
835 749

  
836 750
    def invite(self):
837 751
        if not self.formdef.roles:
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

  
......
1099 1104
        r.append(' '.join([column.center(max_width) for column in ['/']+self.columns]))
1100 1105
        r.append(' '.join(['='*max_width]*(len(self.columns)+1)))
1101 1106
        for i, row in enumerate(self.rows):
1102
            r.append(' '.join([cell.center(max_width) for cell in [row] + 
1107
            r.append(' '.join([cell.center(max_width) for cell in [row] +
1103 1108
                    [value[i][x] for x in range(len(self.columns))]]))
1104 1109
        r.append(' '.join(['='*max_width]*(len(self.columns)+1)))
1105 1110
        return '\n'.join([indent + x for x in r])
......
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
23 23
from qommon.storage import StorableObject
24 24
import qommon.misc
25 25
from qommon.substitution import Substitutions
26

  
26
from wcs.fields import StringField
27 27

  
28 28
def get_dict_with_varnames(fields, data):
29 29
    new_data = {}
......
130 130
    user_hash = None
131 131
    receipt_time = None
132 132
    status = None
133
    anonymised = False
133 134
    page_no = None # page to use when restoring from draft
134 135
    evolution = None
135 136
    data = None
......
139 140
    workflow_data = None
140 141
    workflow_roles = None
141 142

  
143

  
142 144
    _formdef = None
143 145
    def get_formdef(self):
144 146
        if self._formdef:
......
438 440

  
439 441
        return status_action_roles
440 442

  
443
    def anonymise(self):
444
        for field in self.formdef.fields:
445
            if field.anonymise:
446
                self.data[field.id] = None
447
        self.user_id = None
448
        self.user_hash = None
449
        self.anonymised = True
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)