def __call__(self, redirect=''): self.context.reload_image_folder() self.send_message(_('Image folder was synchronised.')) url = self.url('@@overview.html') if redirect.lower() != 'false': self.redirect(url) return url
def _toFieldValue(self, value): value = super(SolrQueryWidget, self)._toFieldValue(value) try: zeit.find.search.search(value, rows=1) except pysolr.SolrError: raise zope.formlib.interfaces.ConversionError( _('Invalid solr query'), value) return value
def _check_duplicate_item(self, folder, name): if name in folder: transaction.doom() self.errors = (DuplicateVolumeWarning(),) self.status = _('There were errors') self.form_reset = False return True return False
def ask_before_adding_author_twice(self, author): if self.confirmed_duplicate or not author.exists: return False transaction.doom() self.need_confirmation_checkbox = True self.errors = (DuplicateAuthorWarning(),) self.status = _('There were errors') self.form_reset = False return True
class TargetSource(zc.sourcefactory.basic.BasicSourceFactory): values = {'_blank': _('New window')} def getValues(self): return ('_blank', ) def getTitle(self, value): return self.values.get(value, value)
def __call__(self): parent = self.context.__parent__ title = self.context.title del parent[self.context.__name__] self.send_message( _('"${name}" was removed from the clipboard.', mapping=dict(name=title))) self.redirect(self.url(parent)) return u''
def __call__(self, unique_id): source = zeit.cms.interfaces.ICMSContent(unique_id) copier = zope.copypastemove.interfaces.IObjectCopier(source) new_name = copier.copyTo(self.context) new_obj = self.context[new_name] self.send_message( _('${source} was copied to ${target}.', mapping=dict(source=unique_id, target=new_obj.uniqueId))) self.redirect(self.url(new_obj))
class SocialEditForm(SocialBase, zeit.cms.browser.form.EditForm): form_fields = zope.formlib.form.FormFields() @zope.formlib.form.action(_('Apply'), condition=zope.formlib.form.haveInputWidgets) def handle_edit_action(self, action, data): self.applyAccountData(self.context, data) super(SocialEditForm, self).handle_edit_action.success(data)
class FormBase(zeit.cms.browser.form.CharlimitMixin): _form_fields = zope.formlib.form.FormFields( zeit.content.author.interfaces.IAuthor, zeit.cms.interfaces.ICMSContent) omit_fields = [] field_groups = ( gocept.form.grouped.Fields(_("Contact"), ('title', 'firstname', 'lastname', 'email', 'twitter', 'facebook', 'instagram'), css_class='column-left'), gocept.form.grouped.RemainingFields(_("misc."), css_class='column-right'), gocept.form.grouped.Fields( _("Author Favourites"), ('favourite_content', 'topiclink_label_1', 'topiclink_url_1', 'topiclink_label_2', 'topiclink_url_2', 'topiclink_label_3', 'topiclink_url_3'), css_class='wide-widgets column-left'), ) def __init__(self, context, request): super(FormBase, self).__init__(context, request) self.form_fields = self._form_fields.omit(*self.omit_fields) source = zeit.content.author.interfaces.BIOGRAPHY_QUESTIONS( self.context) for name in source: field = zope.schema.Text(title=source.title(name), required=False) field.__name__ = name field.interface = ( zeit.content.author.interfaces.IBiographyQuestions) self.form_fields += zope.formlib.form.FormFields(field) self.field_groups += (gocept.form.grouped.Fields( _("Biography"), ('summary', 'biography') + tuple(source), css_class='wide-widgets full-width'), ) def setUpWidgets(self, *args, **kw): super(FormBase, self).setUpWidgets(*args, **kw) for field in self.form_fields: if getattr(field.field, 'max_length', None): self.set_charlimit(field.__name__)
def doc(self): text, encoding, e = self.args return _( 'Could not encode charachters ${start}-${end} to ${encoding} ' '(${characters}): ${reason}', mapping=dict(start=e.start, end=e.end, encoding=encoding, characters=text[e.start:e.end], reason=e.reason))
class AreaFactory(zeit.edit.block.ElementFactory): grok.context(zeit.content.cp.interfaces.IRegion) produces = Area # XML tags are named "region", thus do not change. tag_name = 'region' title = _('Area') def get_xml(self): return getattr(lxml.objectify.E, self.tag_name)()
class ImageBrowser(object): title = _("Images") def images(self): for obj in self.context.values(): if not zeit.content.image.interfaces.IImage.providedBy(obj): continue metadata = zeit.content.image.interfaces.IImageMetadata(obj) yield dict(image=obj, metadata=metadata)
class ICMSContent(zope.interface.Interface): """Interface for all CMS content being loaded from the repository. """ uniqueId = zope.interface.Attribute("Unique Id") __name__ = zope.schema.TextLine(title=_("File name"), readonly=True, constraint=valid_name)
def canCheckin(self): if not zeit.cms.workingcopy.interfaces.ILocalContent.providedBy( self.context): self.last_validation_error = _('Object is not local content') return False lockable = zope.app.locking.interfaces.ILockable(self.context, None) if (lockable is not None and not lockable.ownLock() and lockable.locked()): self.last_validation_error = _('Cannot acquire lock') return False workingcopy = self.context.__parent__ if not workingcopy.temporary: event = zeit.cms.checkout.interfaces.ValidateCheckinEvent( self.context, workingcopy, self.principal) zope.event.notify(event) self.last_validation_error = event.vetoed if self.last_validation_error is not None: return False return True
class RecensionForms(zeit.edit.browser.form.FoldableFormGroup): """Article recension forms.""" title = _('Recensions') def render(self): if not zeit.cms.checkout.interfaces.ILocalContent.providedBy( self.context): return '' return super(RecensionForms, self).render()
def cell_formatter(self, value, item, formatter): img = zope.component.getMultiAdapter( (value, formatter.request), name='preview').tag() master = '' if zeit.content.image.interfaces.IMasterImage.providedBy(value): master = '<div class="master-image">%s</div>' % ( zope.i18n.translate(_('Master image'), context=formatter.request)) return img + master
class EditJobTicker(zeit.edit.browser.form.InlineForm): legend = '' undo_description = _('edit jobbox ticker') form_fields = zope.formlib.form.FormFields( zeit.content.article.edit.interfaces.IJobTicker).select('feed') @property def prefix(self): return 'jobticker.{0}'.format(self.context.__name__)
class FeedType(zeit.cms.type.XMLContentTypeDeclaration): interface = zeit.cms.syndication.interfaces.IFeed factory = Feed type = 'channel' title = _('Channel') addform = 'zeit.cms.syndication.feed.Add' def register_as_type(self, config): return config.hasFeature('zeit.cms.decentral-syndication')
class View(zeit.cms.browser.listing.Listing): title = _('Image group') filter_interface = zeit.content.image.interfaces.IImage columns = ( zeit.cms.browser.listing.LockedColumn(u'', name='locked'), zeit.cms.browser.listing.GetterColumn( title=_("File name"), # zc.table can't deal with spaces in colum names name='filename', getter=lambda i, f: i.__name__), zeit.cms.browser.listing.GetterColumn( title=_('Dimensions'), getter=lambda i, f: i.context.getImageSize(), cell_formatter=lambda v, i, f: 'x'.join(str(i) for i in v)), ImageColumn(title=_('Image')), zeit.cms.browser.listing.MetadataColumn(u'Metadaten', name='metadata'), )
class CheckoutMenuItem(MenuItem): """MenuItem for checking out.""" title = _('Checkout ^O') base_action = 'checkout' accesskey = 'o' def is_visible(self): manager = zeit.cms.checkout.interfaces.ICheckoutManager(self.context) return manager.canCheckout
class StudyCourse(zeit.edit.browser.form.InlineForm): legend = '' undo_description = _('edit study course') form_fields = zope.formlib.form.FormFields( zeit.campus.interfaces.IStudyCourse).select('course') @property def prefix(self): return 'studycourse.{0}'.format(self.context.__name__)
def __call__(self): return (u'<input type="text" class="autocomplete" ' u'placeholder={placeholder} ' u'cms:autocomplete-source="{url}" />').format( url=zope.component.queryMultiAdapter( (self.source, self.request), zeit.cms.browser.interfaces.ISourceQueryURL), placeholder=xml.sax.saxutils.quoteattr( zope.i18n.translate(_('Type to find entries ...'), context=self.request)))
class IAdjustSemanticPublish(zope.interface.Interface): """Schema for admin form to adjust date_last_published_semantic. Setting date_last_published_semantic to another date is not enough, since has_semantic_change and last_semantic_change might need changes as well. Therefore we use this separate interface and take care of all attributes in one place. """ adjust_semantic_publish = zope.schema.Datetime( title=_('Adjust last published with semantic change'), required=False, max=zeit.cms.interfaces.MAX_PUBLISH_DATE) adjust_first_released = zope.schema.Datetime( title=_('Adjust first released'), required=False, max=zeit.cms.interfaces.MAX_PUBLISH_DATE)
def log_success(self): self.object_log.log( _( 'Push notification for "${name}" sent.' ' (Message: "${message}", Details: ${details})', mapping={ 'name': self.type.capitalize(), 'message': self.text, 'details': self.log_message_details }))
def update(self): self.undo_description = _( "add '${type}' block", mapping=dict(type=self.type)) factory = zope.component.getAdapter( self.context, zeit.edit.interfaces.IElementFactory, name=self.type) created = factory() self.reload() self.signal('after-reload', 'added', created.__name__)
class AssetWorkflow(WorkflowForm): zope.component.adapts(zeit.cms.interfaces.IAsset, zeit.cms.browser.interfaces.ICMSLayer) field_groups = (gocept.form.grouped.Fields(_("Status"), WorkflowForm.modified_fields, css_class='column-left'), gocept.form.grouped.RemainingFields( _("Settings"), css_class='column-right'), gocept.form.grouped.Fields(_("Log"), fields=('logs', ), css_class='full-width')) form_fields = (zope.formlib.form.FormFields( zeit.workflow.interfaces.IAssetWorkflow, zeit.objectlog.interfaces.ILog, zeit.cms.workflow.interfaces.IModified, zeit.cms.content.interfaces.ISemanticChange).omit( *WorkflowForm.omit_fields))
class EditFormCO(zeit.cms.browser.form.EditForm): form_fields = zope.formlib.form.Fields( zeit.cms.content.interfaces.ICommonMetadata).select( 'banner', 'banner_content', 'banner_outer', 'hide_adblocker_notification') # Without field group it will look weird when context is an Article. field_groups = (gocept.form.grouped.RemainingFields( _('admin-field-group'), 'column-left-small'), )
def __call__(self, unique_id, view=''): obj = zeit.cms.interfaces.ICMSContent(unique_id, None) if obj is None: msg = _("The object '${id}' could not be found.", mapping=dict(id=unique_id)) return '<div class="error">%s</div>' % zope.i18n.translate( msg, context=self.request) self.request.response.setHeader('Cache-Control', 'no-cache') self.redirect(self.url(obj, view), status=301) return u''
class IVideo(zeit.edit.interfaces.IBlock, ILayoutable): video = zope.schema.Choice( title=_('Video'), description=_("Drag a video here"), required=False, source=zeit.content.video.interfaces.videoOrPlaylistSource) layout = zope.schema.Choice(title=_('Layout'), source=VideoLayoutSource(), default=u'large', required=False) # XXX it would be nice if could somehow express that IVideo actually # is a kind of IReference (only it has video/video_2 instead of references) is_empty = zope.schema.Bool( title=_('true if this block has no reference; benefits XSLT'), required=False, default=True)
class IAccessCounter(zope.interface.Interface): """Give information about how many times an object was accessed.""" hits = zope.schema.Int( title=_('Hits today'), description=_('Indicates how many times a page viewed today.'), required=False, default=None) total_hits = zope.schema.Int( title=_('Total hits'), description=_('Indicates how many times a page was viewed in total, ' 'i.e. during its entire life time.'), required=False, default=None) detail_url = zope.schema.URI(title=_('URI to the access counting details'), required=False, default=None)
class IContentAdder(zope.interface.Interface): type_ = zope.schema.Choice( title=_("Type"), source=zeit.cms.content.sources.AddableCMSContentTypeSource()) ressort = zope.schema.Choice( title=_("Ressort"), source=zeit.cms.content.sources.RessortSource(), required=False) sub_ressort = zope.schema.Choice( title=_('Sub ressort'), source=zeit.cms.content.sources.SubRessortSource(), required=False) year = zope.schema.Int(title=_("Year"), min=1900, max=2100) month = zope.schema.Int(title=_("Month"), min=1, max=12)
def publish(self, priority=None, background=True, **kw): """Publish object.""" info = zeit.cms.workflow.interfaces.IPublishInfo(self.context) if info.can_publish() == CAN_PUBLISH_ERROR: raise zeit.cms.workflow.interfaces.PublishingError( "Publish pre-conditions not satisifed.") return self._execute_task( PUBLISH_TASK, [self.context.uniqueId], priority, background, _('Publication scheduled'), **kw)
class QueryTypeSource(SimpleDictSource): values = collections.OrderedDict([ ('channels', _('query-type-channels')), ('serie', _('query-type-serie')), ('product', _('query-type-product')), ('ressort', _('query-type-ressort')), ('genre', _('query-type-genre')), ('authorships', _('query-type-authorships')), ('access', _('query-type-access')), ('content_type', _('query-type-content-type')), ])
class IPushMessages(zope.interface.Interface): """Configures push services that are notified if context is published. Available services are stored in `message_config` on checkin of context. When the context is published, send a push notification for each stored service whose configuration defines it as `enabled` by looking up a named `IMessage` adapter that forwards the actual push to an `IPushNotifier` utility. """ date_last_pushed = zope.schema.Datetime(title=_('Last push'), required=False, readonly=True) # BBB deprecated, Facebook texts are now stored per account in # message_config. long_text = zope.schema.Text(title=_('Long push text'), required=False) short_text = zope.schema.TextLine( title=_('Short push text'), required=False, # 117 + 1 Space + 23 characters t.co-URL = 140 # # XXX It's not yet clear what we can do when the user enters another # URL as part of the tweet and that URL gets *longer* during the # shortening process. max_length=116) """A message configuration is a dict with at least the following keys: - type: Kind of service (twitter, facebook, ...). Must correspond to the utility name of an IPushNotifier. - enabled: Boolean. This allows keeping the message configuration even when it should not be used at the moment, e.g. for different text to different accounts. Any other keys are type-dependent. (A common additional key is ``account``, e.g. Twitter and Facebook support posting to different accounts.) """ message_config = zope.schema.Tuple(required=False, default=()) messages = zope.interface.Attribute( 'List of IMessage objects, one for each enabled message_config entry')
class XMLBlockFactory(zeit.content.cp.blocks.block.BlockFactory): produces = XMLBlock title = _('Raw XML block') def get_xml(self): container = super(XMLBlockFactory, self).get_xml() raw = lxml.objectify.E.raw(u'\n\n\n') lxml.objectify.deannotate(raw) container.append(raw) return container
def action_set_copyrights(self, action, data): changed = [] for name in self.context: obj = self.context[name] metadata = zeit.content.image.interfaces.IImageMetadata(obj, None) if metadata is None: continue zeit.cms.checkout.helper.with_checked_out(obj, lambda x: self.set_copyrights(x, data["copyrights"])) changed.append(name) self.send_message(_("Copyright changed for: ${changes}", mapping=dict(changes=", ".join(changed))))
def prevent_mismatched_checkout(context, event): other_iface = zeit.content.cp.interfaces.ICP2009 current_iface = zeit.content.cp.interfaces.ICP2015 if other_iface.providedBy(context): raise zeit.cms.checkout.interfaces.CheckinCheckoutError( context.uniqueId, _( 'The centerpage ${uniqueId} is of type ${content_type},' ' but this vivi handles ${current_type}.', mapping={ 'uniqueId': context.uniqueId, 'content_type': other_iface.__name__, 'current_type': current_iface.__name__, }))
def initialize_block(self): content = zeit.cms.interfaces.ICMSContent(self.uniqueId, None) if content is None: raise ValueError( _('The object "${name}" does not exist.', mapping=dict( name=self.uniqueId))) self.block.insert(0, content) if self.relateds: related = zeit.cms.related.interfaces.IRelatedContent( content, None) if related is not None: for i, related in enumerate(related.related): self.block.insert(i + 1, related)
def __init__(self, context, request): super(FormBase, self).__init__(context, request) self.form_fields = self._form_fields.omit(*self.omit_fields) source = zeit.content.author.interfaces.BIOGRAPHY_QUESTIONS( self.context) for name in source: field = zope.schema.Text(title=source.title(name), required=False) field.__name__ = name field.interface = ( zeit.content.author.interfaces.IBiographyQuestions) self.form_fields += zope.formlib.form.FormFields(field) self.field_groups += (gocept.form.grouped.Fields( _("Biography"), ('summary', 'biography') + tuple(source), css_class='wide-widgets full-width'),)
def teasers(self): teasers = [] for content in self.context: metadata = zeit.cms.content.interfaces.ICommonMetadata( content, None) url = None if metadata is None: editable = False title = content.uniqueId else: editable = True title = metadata.teaserTitle try: url = self.url(content) except TypeError: # For example, IXMLTeaser cannot be viewed that way. pass teasers.append(dict( css_class='edit-bar teaser', deletable=True, editable=editable, teaserTitle=title, uniqueId=content.uniqueId, url=url, viewable=bool(url), )) columns = zeit.content.cp.interfaces.ITeaserBlockColumns(self.context) if len(columns) == 2: left = columns[0] teasers.insert(left, dict( css_class='edit-bar column-separator', deletable=False, editable=False, teaserTitle=_('^ Left | Right v'), uniqueId=COLUMN_ID, viewable=False, )) return teasers
def warn_about_free_teasers(context, event): relations = zope.component.getUtility(zeit.cms.relation.interfaces.IRelations) relating_objects = relations.get_relations(context) for obj in relating_objects: if zeit.content.cp.interfaces.ICenterPage.providedBy(obj): # BBB Before the uniqueId/href convention, the content uniqueId was # stored in the ``{link}href`` attribute. blocks = obj.xml.xpath( "//block[@cp:free-teaser " "and (@href={id} or @link:href={id})]".format(id=xml.sax.saxutils.quoteattr(context.uniqueId)), namespaces=dict(link="http://namespaces.zeit.de/CMS/link", cp="http://namespaces.zeit.de/CMS/cp"), ) if blocks: # Close enough source = zope.component.getUtility(z3c.flashmessage.interfaces.IMessageSource, name="session") source.send( _( '"${name}" is referenced by a free teaser in "${teaser}"', mapping=dict(name=context.uniqueId, teaser=obj.uniqueId), ), "error", ) break
def doc(self): return _( u'An author with the given name already exists. ' u'If you\'d like to create another author with the same ' u'name anyway, check "Add duplicate author" ' u'and save the form again.')
from zeit.cms.i18n import MessageFactory as _ import zeit.cms.content.property import zeit.content.cp.blocks.block import zeit.content.cp.interfaces import zeit.edit.block import zope.interface class FrameBlock(zeit.content.cp.blocks.block.Block): zope.interface.implements(zeit.content.cp.interfaces.IFrameBlock) url = zeit.cms.content.property.ObjectPathProperty( '.url', zeit.content.cp.interfaces.IFrameBlock['url']) zeit.edit.block.register_element_factory( [zeit.content.cp.interfaces.IArea], 'frame', _('Frame block'))
def doc(self): return _(u'A volume with the given name already exists.')
def _generate_file_name(self): toc_file_string = _("Table of Content").lower().replace(" ", "_") volume_formatted = self._fill_template("{year}_{name}") return "{}_{}.csv".format(toc_file_string, volume_formatted)
from zeit.cms.i18n import MessageFactory as _ import zeit.cms.content.property import zeit.content.cp.blocks.block import zeit.content.cp.interfaces import zeit.edit.block import zope.interface class HeaderImageBlock(zeit.content.cp.blocks.block.Block): zope.interface.implements(zeit.content.cp.interfaces.IHeaderImageBlock) image = zeit.cms.content.property.SingleResource('.image') zeit.edit.block.register_element_factory( [zeit.content.cp.interfaces.IArea], 'headerimage', _('Header image block'))
def doc(self): return _('Text is to long. Allowed: ${maximum}, got: ${got}', mapping=dict(maximum=self.maximum, got=self.got))
zope.interface.implements(zope.container.interfaces.IContained, zeit.content.cp.interfaces.ICPExtraBlock) @property def cpextra(self): return self.xml.get('module') @cpextra.setter def cpextra(self, value): self.xml.set('module', value) self.xml['cp_extra'] = lxml.objectify.E.cp_extra(id=value) zeit.edit.block.register_element_factory( zeit.content.cp.interfaces.IArea, 'cpextra', _('CP extra'), module='') # This method only applies to "old" (lead/informatives/mosaic) centerpages @grokcore.component.subscribe( zeit.content.cp.interfaces.ICenterPage, zeit.cms.repository.interfaces.IBeforeObjectAddEvent) def add_blocks_to_newly_created_cp(context, event): # The BeforeObjectAddEvent is sent whenever an object is added or changed. # We need to check if this is the first add or not. if zeit.cms.interfaces.ICMSContent(context.uniqueId, None) is not None: # It's already in the repository, do nothing return if 'informatives' not in context: # It's a new-style centerpage, do nothing return
def doc(self): return _('The uploaded image could not be identified.')
from zeit.cms.content.property import ObjectPathAttributeProperty from zeit.cms.i18n import MessageFactory as _ from zeit.content.cp.interfaces import ICardstackBlock import zeit.cms.content.property import zeit.content.cp.blocks.block import zeit.content.cp.interfaces import zeit.edit.block import zope.interface class CardstackBlock(zeit.content.cp.blocks.block.Block): zope.interface.implements(ICardstackBlock) card_id = ObjectPathAttributeProperty( '.', 'card_id', ICardstackBlock['card_id']) is_advertorial = ObjectPathAttributeProperty( '.', 'is_advertorial', ICardstackBlock['is_advertorial']) zeit.edit.block.register_element_factory( [zeit.content.cp.interfaces.IArea], 'cardstack', _('Cardstack block'))