def generate_zip(self): response = self.request.response with ZipGenerator() as generator: # Protocol generator.add_file(*self.get_protocol()) # Agenda items self.add_agenda_items_attachments(generator) if is_word_meeting_implementation_enabled(): self.add_agenda_item_proposal_documents(generator) # Agenda items list try: generator.add_file(*self.get_agendaitem_list()) except AgendaItemListMissingTemplate: pass if is_word_meeting_implementation_enabled(): generator.add_file(*self.get_meeting_json()) # Return zip zip_file = generator.generate() filename = '{}.zip'.format(normalize_path(self.model.title)) response.setHeader( "Content-Disposition", 'inline; filename="{0}"'.format( safe_unicode(filename).encode('utf-8'))) response.setHeader("Content-type", "application/zip") response.setHeader( "Content-Length", os.stat(zip_file.name).st_size) return filestream_iterator(zip_file.name, 'rb')
def execute(self): model = self.proposal.load_model() jsondata = {'committee_oguid': model.committee.oguid.id, 'proposal_oguid': model.oguid.id} # XXX use Transporter or API? collector = getMultiAdapter((self.proposal,), IDataCollector, name='field-data') jsondata['field-data'] = collector.extract() if is_word_meeting_implementation_enabled(): blob = self.proposal.get_proposal_document().file jsondata['file'] = { 'filename': blob.filename, 'contentType': blob.contentType, 'data': base64.encodestring(blob.data)} record = IHistory(self.proposal).append_record(u'submitted') history_data = advancedjson.dumps({'uuid': record.uuid}) request_data = { REQUEST_KEY: json.dumps(decode_for_json(jsondata)), 'history_data': history_data} response = dispatch_json_request( self.admin_unit_id, '@@create_submitted_proposal', data=request_data) self.submitted_proposal_path = response['path']
def _checkin_proposal_document_before_deciding(self): if not is_word_meeting_implementation_enabled(): # old implementation: there is no proposal document return if not self.agenda_item.has_proposal: # no proposal => no document to checkin return submitted_proposal = self.agenda_item.proposal.resolve_submitted_proposal( ) document = submitted_proposal.get_proposal_document() checkout_manager = getMultiAdapter((document, self.request), ICheckinCheckoutManager) if checkout_manager.get_checked_out_by() is None: # document is not checked out return if not checkout_manager.is_checkin_allowed(): return JSONResponse(self.request).error( _('agenda_item_cannot_decide_document_checked_out', default=u'Cannot decide agenda item: someone else has' u' checked out the document.')).remain().dump() checkout_manager.checkin()
def excerpt_template_constraint(value): if is_word_meeting_implementation_enabled(): # The excerpt template is not used when word-meeting feature is enabled return True if not value: raise Invalid() return True
def get_overview_attributes(self): data = super(SubmittedProposal, self).get_overview_attributes() model = self.load_model() # Insert dossier link if dossier exists after committee data.insert( 2, { 'label': _('label_dossier', default=u"Dossier"), 'value': self.get_dossier_link(), 'is_html': True, }) if not is_word_meeting_implementation_enabled(): # Insert considerations after proposed_action data.insert( 7, { 'label': _('label_considerations', default=u"Considerations"), 'value': self.considerations, }) # Insert discussion after considerations agenda = model.agenda_item data.insert( 8, { 'label': _('label_discussion', default=u"Discussion"), 'value': agenda and agenda.discussion or '' }) return data
def update_protocol_document(self): """Update or create meeting's protocol.""" from opengever.meeting.command import CreateGeneratedDocumentCommand from opengever.meeting.command import MergeDocxProtocolCommand from opengever.meeting.command import ProtocolOperations from opengever.meeting.command import UpdateGeneratedDocumentCommand if self.has_protocol_document( ) and not self.protocol_document.is_locked(): # The protocol should never be changed when it is no longer locked: # the user probably has made changes manually. return operations = ProtocolOperations() if is_word_meeting_implementation_enabled(): command = MergeDocxProtocolCommand( self.get_dossier(), self, operations, lock_document_after_creation=True) else: if self.has_protocol_document(): command = UpdateGeneratedDocumentCommand( self.protocol_document, self, operations) else: command = CreateGeneratedDocumentCommand( self.get_dossier(), self, operations, lock_document_after_creation=True) command.execute()
def create_proposal_document(self, source_blob=None, **kwargs): """Creates a proposal document within this proposal or submitted proposal. Only one proposal document can be created. """ if not is_word_meeting_implementation_enabled(): raise WordMeetingImplementationDisabledError() if self.get_proposal_document(): raise ValueError('There is already a proposal document.') if source_blob: kwargs.setdefault('filename', source_blob.filename) kwargs.setdefault('data', source_blob.open().read()) kwargs.setdefault('content_type', source_blob.contentType) kwargs['context'] = self kwargs.setdefault('preserved_as_paper', False) title = _(u'proposal_document_title', default=u'Proposal document ${title}', mapping={'title': safe_unicode(self.Title())}) title = translate(title, context=self.REQUEST).strip() kwargs.setdefault('title', title) with elevated_privileges(): obj = CreateDocumentCommand(**kwargs).execute() self._proposal_document_uuid = IUUID(obj) return obj
def render(self): jsondata = self.request.get(REQUEST_KEY) data = encode_after_json(json.loads(jsondata)) committee = Oguid.parse(data['committee_oguid']).resolve_object() proposal_oguid = Oguid.parse(data['proposal_oguid']) proposal = meeting_service().fetch_proposal_by_oguid(proposal_oguid) with elevated_privileges(): submitted_proposal = SubmittedProposal.create(proposal, committee) # XXX use Transporter API? collector = getMultiAdapter((submitted_proposal, ), IDataCollector, name='field-data') data['field-data']['ISubmittedProposal'] = data['field-data'].pop( 'IProposal') collector.insert(data['field-data']) if is_word_meeting_implementation_enabled(): submitted_proposal.create_proposal_document( filename=data['file']['filename'], content_type=data['file']['contentType'].encode('utf-8'), data=base64.decodestring(data['file']['data'])) history_data = advancedjson.loads(self.request.get('history_data')) IHistory(submitted_proposal).append_record( u'submitted', uuid=history_data['uuid']) self.request.response.setHeader("Content-type", "application/json") return json.dumps( {'path': '/'.join(submitted_proposal.getPhysicalPath())})
def schedule_text(self): """Schedule the given Text (request parameter `title`) for the current meeting. """ self.check_editable() title = safe_unicode(self.request.get('title')) if not title: return JSONResponse(self.request).error( _('empty_proposal', default=u"Proposal must not be empty.")).proceed().dump() if is_word_meeting_implementation_enabled(): try: self.meeting.schedule_ad_hoc(title) except MissingAdHocTemplate: return JSONResponse(self.request).error( _('missing_ad_hoc_template', default=u"No ad-hoc agenda-item template has been " u"configured.")).remain().dump() except MissingMeetingDossierPermissions: return JSONResponse(self.request).error( _('error_no_permission_to_add_document', default=u'Insufficient privileges to add a' u' document to the meeting dossier.')).remain().dump() else: self.meeting.schedule_text(title) return JSONResponse(self.request).info( _('text_added', default=u"Text successfully added.")).proceed().dump()
def get_protocol(self): if self.model.has_protocol_document(): protocol = self.model.protocol_document.resolve_document() protocol_modified = protocol.modified().asdatetime().astimezone( pytz.utc) if self.model.modified < protocol_modified: # Return current protocol return (u'{}.docx'.format(safe_unicode(protocol.Title())), protocol.file.open()) # Create new protocol operations = ProtocolOperations() if is_word_meeting_implementation_enabled(): command_class = MergeDocxProtocolCommand else: command_class = CreateGeneratedDocumentCommand command = command_class( self.context, self.model, operations, lock_document_after_creation=False) filename = u'{}.docx'.format(operations.get_title(self.model)) return (filename, StringIO(command.generate_file_data()))
def updateWidgets(self): super(AddForm, self).updateWidgets() if not is_word_meeting_implementation_enabled(): self.widgets['ad_hoc_template'].mode = HIDDEN_MODE self.widgets['paragraph_template'].mode = HIDDEN_MODE else: self.widgets['excerpt_template'].mode = HIDDEN_MODE
def proposal_templates_tab(self): if is_word_meeting_implementation_enabled(): return { 'id': 'proposaltemplates-proxy', 'title': _(u'label_proposal_templates', default=u'Proposal Templates'), } return None
def url_generate_protocol(self): if is_word_meeting_implementation_enabled(): return self.url_merge_docx_protocol() if not self.model.has_protocol_document(): return GenerateProtocol.url_for(self.model) else: return UpdateProtocol.url_for(self.model)
def __call__(self): self.install_upgrade_profile() if is_word_meeting_implementation_enabled(): query = { 'object_provides': 'opengever.meeting.proposal.ISubmittedProposal' } for obj in self.objects(query, self.__class__.__doc__): addRelations(obj, None)
def updateFields(self): super(FieldConfigurationMixin, self).updateFields() textfields = ('legal_basis', 'initial_position', 'proposed_action', 'decision_draft', 'publish_in', 'disclose_to', 'copy_for_attention') map(self.use_trix, textfields) if is_word_meeting_implementation_enabled(): map(self.omit_field, textfields)
def visible_in_actions_menu(self): """Returns ``True`` when the zip export action should be displayed in the actions menu. The action should only appear when we are on a meeting view and the word-meeting feature is enabled. """ return IMeetingWrapper.providedBy(self.context) and \ is_word_meeting_implementation_enabled()
def get_decision_number(self): if not is_word_meeting_implementation_enabled(): return self.decision_number if not self.decision_number: return self.decision_number period = Period.query.get_current_for_update(self.meeting.committee) year = period.date_from.year return '{} / {}'.format(year, self.decision_number)
def createAndAdd(self, data): if not is_word_meeting_implementation_enabled(): return super(AddForm, self).createAndAdd(data) proposal_template = data.pop('proposal_template') self.instance_schema = IProposal noaq_proposal = super(AddForm, self).createAndAdd(data) proposal = self.context.get(noaq_proposal.getId()) proposal.create_proposal_document(proposal_template.file) return proposal
def __call__(self): if is_word_meeting_implementation_enabled(): # Enable border to show the zip export action also for # committee members. Because the plone_view's `showEditableBorder` # checks for `ModifyPortalContent`, we have to enable the border # manually. self.request.set('enable_border', True) return self.word_template() else: return self.noword_template()
def updateFields(self): super(CommitteContainerFieldConfigurationMixin, self).updateFields() if is_word_meeting_implementation_enabled(): self.fields = self.fields.omit('excerpt_template', 'protocol_template') else: self.fields = self.fields.omit( 'ad_hoc_template', 'paragraph_template', 'protocol_header_template', 'protocol_suffix_template', 'agenda_item_header_template', 'agenda_item_suffix_template', 'excerpt_header_template', 'excerpt_suffix_template')
def filter_type(fti): factory_type = fti.id if factory_type in [u'opengever.meeting.sablontemplate']: return is_meeting_feature_enabled() if factory_type in [u'opengever.meeting.proposaltemplate']: return is_word_meeting_implementation_enabled() if factory_type in [u'opengever.dossier.dossiertemplate']: return is_dossier_template_feature_enabled() return True
def get_documents(self): catalog = api.portal.get_tool('portal_catalog') documents = catalog( portal_type=['opengever.document.document', 'ftw.mail.mail'], path=dict(query='/'.join(self.getPhysicalPath())), sort_on='sortable_title') ignored_documents = [self.get_excerpt()] if is_word_meeting_implementation_enabled(): ignored_documents.append(self.get_proposal_document()) all_docs = [document.getObject() for document in documents] return [doc for doc in all_docs if doc not in ignored_documents]
def get_items(self): if not is_word_meeting_implementation_enabled(): return [] items = [] for item in self.byline_items(): item['content'] = safe_unicode(item['content']) item.setdefault('class', '') item.setdefault('replace', False) items.append(item) return items
def _get_agenda_items(self): meeting = self.meeting agenda_items = [] for item in meeting.agenda_items: data = item.serialize() data['documents'] = self._serialize_submitted_documents(item) data['excerpt'] = self._serialize_submitted_excerpt(item) data['has_documents'] = self.has_documents(item) data['delete_link'] = meeting.get_url( view='agenda_items/{}/delete'.format(item.agenda_item_id)) data['edit_link'] = meeting.get_url( view='agenda_items/{}/edit'.format(item.agenda_item_id)) data['decision_number'] = item.get_decision_number() data['is_decided'] = item.is_decided() if item.is_decide_possible(): data['decide_link'] = meeting.get_url( view='agenda_items/{}/decide'.format(item.agenda_item_id)) if item.is_reopen_possible(): data['reopen_link'] = meeting.get_url( view='agenda_items/{}/reopen'.format(item.agenda_item_id)) if item.is_revise_possible(): data['revise_link'] = meeting.get_url( view='agenda_items/{}/revise'.format(item.agenda_item_id)) if item.is_paragraph: data['paragraph'] = True if is_word_meeting_implementation_enabled(): document = item.resolve_document() if document: data['document_link'] = ( IContentListingObject(document).render_link()) data.update( self._get_edit_document_options( document, item, meeting)) data['excerpts'] = self._serialize_excerpts(meeting, item) if item.can_generate_excerpt(): data['generate_excerpt_default_title'] = translate( _(u'excerpt_document_default_title', default=u'Excerpt ${title}', mapping={'title': safe_unicode(item.get_title())}), context=self.request, ).strip() data['generate_excerpt_link'] = meeting.get_url( view='agenda_items/{}/generate_excerpt'.format( item.agenda_item_id)) if item.is_decided(): data['css_class'] += ' decided' agenda_items.append(data) return agenda_items
def createAndAdd(self, data): if not is_word_meeting_implementation_enabled(): return super(AddForm, self).createAndAdd(data) proposal_template = data.pop('proposal_template') edit_after_creation = data.pop('edit_after_creation') self.instance_schema = IProposal noaq_proposal = super(AddForm, self).createAndAdd(data) proposal = self.context.get(noaq_proposal.getId()) proposal_doc = proposal.create_proposal_document( proposal_template.file) if edit_after_creation: self.checkout_and_external_edit(proposal_doc) return proposal
def after_create(self, obj): obj.create_model(self.model_arguments, self.container) if is_word_meeting_implementation_enabled(): obj.create_proposal_document( filename=u'proposal_document.docx', data=self._proposal_file_data, content_type='application/vnd.openxmlformats' '-officedocument.wordprocessingml.document') if self._transition: obj.execute_transition(self._transition) super(ProposalBuilder, self).after_create(obj)
def revise(self, agenda_item): assert self.get_state() == self.STATE_DECIDED if is_word_meeting_implementation_enabled(): document = self.resolve_submitted_proposal().get_proposal_document( ) checkout_manager = getMultiAdapter((document, document.REQUEST), ICheckinCheckoutManager) if checkout_manager.get_checked_out_by() is not None: raise ValueError( 'Cannot revise proposal when proposal document is checked out.' ) else: self.update_excerpt(agenda_item) IHistory(self.resolve_submitted_proposal()).append_record(u'revised')
def decide(self, agenda_item): if is_word_meeting_implementation_enabled(): document = self.resolve_submitted_proposal().get_proposal_document( ) checkout_manager = getMultiAdapter((document, document.REQUEST), ICheckinCheckoutManager) if checkout_manager.get_checked_out_by() is not None: raise ValueError( 'Cannot decide proposal when proposal document is checked out.' ) else: self.generate_excerpt(agenda_item) document_intid = self.copy_excerpt_to_proposal_dossier() self.register_excerpt(document_intid) IHistory(self.resolve_submitted_proposal()).append_record(u'decided') self.execute_transition('scheduled-decided')
def bodyClass(self, template, view): """Extends the default body class with the `feature-bumblebee` class, if the bumblebeefeature is enabled. """ classes = [super(GeverLayoutPolicy, self).bodyClass(template, view)] if is_bumblebee_feature_enabled(): classes.append('feature-bumblebee') if is_word_meeting_implementation_enabled(): classes.append('feature-word-meeting') if ISQLObjectWrapper.providedBy(self.context): normalize = getUtility(IIDNormalizer).normalize classes.append('model-{}'.format( normalize(type(self.context.model).__name__))) return ' '.join(classes)
def render(self): jsondata = self.request.get(REQUEST_KEY) data = json.loads(jsondata) committee = Oguid.parse(data['committee_oguid']).resolve_object() proposal_oguid = Oguid.parse(data['proposal_oguid']) proposal = meeting_service().fetch_proposal_by_oguid(proposal_oguid) with elevated_privileges(): submitted_proposal = SubmittedProposal.create(proposal, committee) if is_word_meeting_implementation_enabled(): submitted_proposal.create_proposal_document( filename=data['file']['filename'], content_type=data['file']['contentType'].encode('utf-8'), data=base64.decodestring(data['file']['data'])) self.request.response.setHeader("Content-type", "application/json") return json.dumps( {'path': '/'.join(submitted_proposal.getPhysicalPath())})