class ProductReleaseEditView(LaunchpadEditFormView): """Edit view for ProductRelease objects""" schema = IProductRelease field_names = [ "datereleased", "release_notes", "changelog", ] custom_widget('datereleased', DateTimeWidget) custom_widget('release_notes', TextAreaWidget, height=7, width=62) custom_widget('changelog', TextAreaWidget, height=7, width=62) @property def label(self): """The form label.""" return smartquote('Edit %s release details' % self.context.title) page_title = label @action('Change', name='change') def change_action(self, action, data): self.updateContextFromData(data) self.next_url = canonical_url(self.context) @property def cancel_url(self): return canonical_url(self.context)
class BrandingChangeView(LaunchpadEditFormView): """This is a base class that MUST be subclassed for each object, because each object will have a different description for its branding that is part of its own interface. For each subclass, specify the schema ("IPerson") and the field_names (some subset of icon, logo, mugshot). """ @property def label(self): return ('Change the images used to represent %s in Launchpad' % self.context.displayname) page_title = "Change branding" custom_widget('icon', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) custom_widget('logo', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) custom_widget('mugshot', ImageChangeWidget, ImageChangeWidget.EDIT_STYLE) @action("Change Branding", name='change') def change_action(self, action, data): self.updateContextFromData(data) @property def next_url(self): return canonical_url(self.context) cancel_url = next_url
class ProductSeriesEditView(LaunchpadEditFormView): """A View to edit the attributes of a series.""" schema = IProductSeries field_names = [ 'name', 'summary', 'status', 'branch', 'releasefileglob'] custom_widget('summary', TextAreaWidget, height=7, width=62) custom_widget('releasefileglob', StrippedTextWidget, displayWidth=40) @property def label(self): """The form label.""" return 'Edit %s %s series' % ( self.context.product.displayname, self.context.name) page_title = label def validate(self, data): """See `LaunchpadFormView`.""" branch = data.get('branch') if branch is not None: message = get_series_branch_error(self.context.product, branch) if message: self.setFieldError('branch', message) @action(_('Change'), name='change') def change_action(self, action, data): """Update the series.""" self.updateContextFromData(data) @property def next_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) cancel_url = next_url
class DistroBugTrackerCreationStep(BugTrackerCreationStep): _next_step = DistroBugTaskCreationStep _field_names = ['distribution', 'sourcepackagename', 'bug_url'] custom_widget('distribution', DropdownWidget, visible=False) custom_widget('sourcepackagename', DropdownWidget, visible=False) label = "Also affects distribution/package" template = ViewPageTemplateFile( '../templates/bugtask-confirm-bugtracker-creation.pt')
class SprintAddView(LaunchpadFormView): """Form for creating sprints""" schema = ISprint label = "Register a meeting" field_names = ['name', 'title', 'summary', 'home_page', 'driver', 'time_zone', 'time_starts', 'time_ends', 'address', ] custom_widget('summary', TextAreaWidget, height=5) custom_widget('time_starts', DateTimeWidget, display_zone=False) custom_widget('time_ends', DateTimeWidget, display_zone=False) custom_widget('address', TextAreaWidget, height=3) sprint = None def setUpWidgets(self): LaunchpadFormView.setUpWidgets(self) timeformat = '%Y-%m-%d %H:%M' self.widgets['time_starts'].timeformat = timeformat self.widgets['time_ends'].timeformat = timeformat time_zone_widget = self.widgets['time_zone'] if time_zone_widget.hasValidInput(): tz = pytz.timezone(time_zone_widget.getInputValue()) self.widgets['time_starts'].required_time_zone = tz self.widgets['time_ends'].required_time_zone = tz def validate(self, data): time_starts = data.get('time_starts') time_ends = data.get('time_ends') if time_starts and time_ends and time_ends < time_starts: self.setFieldError( 'time_ends', "This event can't start after it ends") @action(_('Add Sprint'), name='add') def add_action(self, action, data): self.sprint = getUtility(ISprintSet).new( owner=self.user, name=data['name'], title=data['title'], summary=data['summary'], home_page=data['home_page'], driver=data['driver'], time_zone=data['time_zone'], time_starts=data['time_starts'], time_ends=data['time_ends'], address=data['address'], ) self.request.response.addInfoNotification('Sprint created.') @property def next_url(self): assert self.sprint is not None, 'No sprint has been created' return canonical_url(self.sprint) @property def cancel_url(self): return canonical_url(getUtility(ISprintSet))
class CodeImportBaseView(LaunchpadFormView): """A base view for both new and edit code import views.""" schema = ICodeImport custom_widget('cvs_root', StrippedTextWidget, displayWidth=50) custom_widget('cvs_module', StrippedTextWidget, displayWidth=20) custom_widget('url', URIWidget, displayWidth=50) @cachedproperty def _super_user(self): """Is the user an admin or member of vcs-imports?""" role = IPersonRoles(self.user) return role.in_admin or role.in_vcs_imports def showOptionalMarker(self, field_name): """Don't show the optional marker for rcs locations.""" # No field in either the new or edit view needs an optional marker, # so we can be simple here. return False def setSecondaryFieldError(self, field, error): """Set the field error only if there isn't an error already.""" if not self.getFieldError(field): self.setFieldError(field, error) def _validateCVS(self, cvs_root, cvs_module, existing_import=None): """If the user has specified cvs, then we need to make sure that there isn't already an import with those values.""" if cvs_root is None: self.setSecondaryFieldError( 'cvs_root', 'Enter a CVS root.') if cvs_module is None: self.setSecondaryFieldError( 'cvs_module', 'Enter a CVS module.') if cvs_root and cvs_module: code_import = getUtility(ICodeImportSet).getByCVSDetails( cvs_root, cvs_module) if (code_import is not None and code_import != existing_import): self.addError(structured(""" Those CVS details are already specified for the imported branch <a href="%s">%s</a>.""", canonical_url(code_import.branch), code_import.branch.unique_name)) def _validateURL(self, url, existing_import=None, field_name='url'): """If the user has specified a url, we need to make sure that there isn't already an import with that url.""" if url is None: self.setSecondaryFieldError( field_name, 'Enter the URL of a foreign VCS branch.') else: reason = validate_import_url(url, existing_import) if reason: self.setFieldError(field_name, reason)
class UpstreamBugTrackerCreationStep(BugTrackerCreationStep): schema = IAddBugTaskWithUpstreamLinkForm _next_step = ProductBugTaskCreationStep _field_names = ['product', 'bug_url', 'link_upstream_how'] custom_widget('product', DropdownWidget, visible=False) custom_widget('link_upstream_how', LaunchpadRadioWidget, visible=False) label = "Confirm project" template = ViewPageTemplateFile( '../templates/bugtask-confirm-bugtracker-creation.pt')
class ProductSeriesTranslationsSettingsView(ReturnToReferrerMixin, LaunchpadEditFormView, ProductSeriesTranslationsMixin, ): """Edit settings for translations import and export.""" schema = IProductSeries label = "Translations synchronization settings" page_title = "Settings" field_names = ['translations_autoimport_mode'] settings_widget = custom_widget('translations_autoimport_mode', SettingsRadioWidget) @action(u"Save settings", name="save_settings") def change_settings_action(self, action, data): """Change the translation settings.""" if (self.context.translations_autoimport_mode != data['translations_autoimport_mode']): self.updateContextFromData(data) # Request an initial upload of translation files. getUtility(IRosettaUploadJobSource).create( self.context.branch, NULL_REVISION) else: self.updateContextFromData(data) self.request.response.addInfoNotification( _("The settings have been updated."))
class AnnouncementAddView(LaunchpadFormView): """A view for creating a new Announcement.""" schema = AddAnnouncementForm label = "Make an announcement" page_title = label custom_widget('publication_date', AnnouncementDateWidget) @action(_('Make announcement'), name='announce') def announce_action(self, action, data): """Registers a new announcement.""" self.context.announce(user=self.user, title=data.get('title'), summary=data.get('summary'), url=data.get('url'), publication_date=data.get('publication_date')) self.next_url = canonical_url(self.context) @property def action_url(self): return "%s/+announce" % canonical_url(self.context) @property def cancel_url(self): """The project's URL.""" return canonical_url(self.context)
class NameBlacklistAddView(NameBlacklistValidationMixin, LaunchpadFormView): """View for adding a blacklist expression.""" schema = INameBlacklist field_names = ['regexp', 'admin', 'comment'] label = "Add a new blacklist expression" page_title = label custom_widget('regexp', TextWidget, displayWidth=60) @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) next_url = cancel_url @action("Add to blacklist", name='add') def add_action(self, action, data): name_blacklist_set = getUtility(INameBlacklistSet) name_blacklist_set.create( regexp=data['regexp'], comment=data['comment'], admin=data['admin'], ) self.request.response.addInfoNotification( 'Regular expression "%s" has been added to the name blacklist.' % data['regexp'])
class FeaturedProjectsView(LaunchpadFormView): """A view for adding and removing featured projects.""" label = 'Manage featured projects in Launchpad' page_title = label schema = FeaturedProjectForm custom_widget('remove', LabeledMultiCheckBoxWidget) @action(_('Update featured project list'), name='update') def update_action(self, action, data): """Add and remove featured projects.""" add = data.get('add') if add is not None: getUtility(IPillarNameSet).add_featured_project(add) remove = data.get('remove') if remove is not None: for project in remove: getUtility(IPillarNameSet).remove_featured_project(project) self.next_url = canonical_url(self.context) @action(_("Cancel"), name="cancel", validator='validate_cancel') def action_cancel(self, action, data): self.next_url = canonical_url(self.context) @property def action_url(self): return "/+featuredprojects"
class BugMarkAsAffectingUserView(LaunchpadFormView): """Page for marking a bug as affecting the user.""" schema = BugMarkAsAffectingUserForm field_names = ['affects'] label = "Does this bug affect you?" page_title = label custom_widget('affects', LaunchpadRadioWidgetWithDescription) @property def initial_values(self): """See `LaunchpadFormView.`""" affected = self.context.bug.isUserAffected(self.user) if affected or affected is None: affects = BugAffectingUserChoice.YES else: affects = BugAffectingUserChoice.NO return {'affects': affects} @action('Change', name='change') def change_action(self, action, data): """Mark the bug according to the selection.""" self.context.bug.markUserAffected( self.user, data['affects'] == BugAffectingUserChoice.YES) self.request.response.redirect(canonical_url(self.context.bug))
class ProductSeriesReviewView(LaunchpadEditFormView): """A view to review and change the series `IProduct` and name.""" schema = IProductSeries field_names = ['product', 'name'] custom_widget('name', TextWidget, displayWidth=20) @property def label(self): """The form label.""" return 'Administer %s %s series' % ( self.context.product.displayname, self.context.name) page_title = label @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) @action(_('Change'), name='change') def change_action(self, action, data): """Update the series.""" self.updateContextFromData(data) self.request.response.addInfoNotification( _('This Series has been changed')) self.next_url = canonical_url(self.context)
class MilestoneAddView(MilestoneTagBase, LaunchpadFormView): """A view for creating a new Milestone.""" schema = IMilestone field_names = ['name', 'code_name', 'dateexpected', 'summary'] label = "Register a new milestone" custom_widget('dateexpected', DateWidget) @action(_('Register Milestone'), name='register') def register_action(self, action, data): """Use the newMilestone method on the context to make a milestone.""" milestone = self.context.newMilestone( name=data.get('name'), code_name=data.get('code_name'), dateexpected=data.get('dateexpected'), summary=data.get('summary')) tags = data.get('tags') if tags: milestone.setTags(tags.lower().split(), self.user) self.next_url = canonical_url(self.context) @property def action_url(self): """See `LaunchpadFormView`.""" return "%s/+addmilestone" % canonical_url(self.context) @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context)
class ProjectAddView(LaunchpadFormView): schema = IProjectGroup field_names = [ 'name', 'displayname', 'title', 'summary', 'description', 'owner', 'homepageurl', ] custom_widget('homepageurl', TextWidget, displayWidth=30) label = _('Register a project group with Launchpad') page_title = label project = None @action(_('Add'), name='add') def add_action(self, action, data): """Create the new Project from the form details.""" self.project = getUtility(IProjectGroupSet).new( name=data['name'].lower().strip(), displayname=data['displayname'], title=data['title'], homepageurl=data['homepageurl'], summary=data['summary'], description=data['description'], owner=data['owner'], ) notify(ObjectCreatedEvent(self.project)) @property def next_url(self): assert self.project is not None, 'No project has been created' return canonical_url(self.project)
class LanguageAdminView(LaunchpadEditFormView): """Handle an admin form submission.""" rootsite = 'translations' schema = ILanguage custom_widget('countries', LabeledMultiCheckBoxWidget, orientation='vertical') field_names = [ 'code', 'englishname', 'nativename', 'pluralforms', 'pluralexpression', 'visible', 'direction', 'countries' ] page_title = "Change details" @property def label(self): """The form label""" return "Edit %s in Launchpad" % describe_language(self.context) @property def cancel_url(self): """See LaunchpadFormView.""" return canonical_url(self.context, rootsite=self.rootsite) @property def next_url(self): return canonical_url(self.context, rootsite=self.rootsite) @action("Admin Language", name="admin") def admin_action(self, action, data): self.updateContextFromData(data) def _validateCode(self, new_code): """Validate a change in language code.""" language_set = getUtility(ILanguageSet) if language_set.getLanguageByCode(new_code) is not None: self.setFieldError('code', 'There is already a language with that code.') def _validatePluralData(self, pluralforms, pluralexpression): """Validate plural expression and number of plural forms.""" try: make_friendly_plural_forms(pluralexpression, pluralforms) except BadPluralExpression as e: self.setFieldError('pluralexpression', str(e)) def validate(self, data): new_code = data.get('code') if new_code != self.context.code: self._validateCode(new_code) pluralexpression = data.get('pluralexpression') pluralforms = data.get('pluralforms') if pluralexpression is not None: self._validatePluralData(pluralforms, pluralexpression)
class ProductReleaseAddViewBase(LaunchpadFormView): """Base class for creating a release from an existing or new milestone. Subclasses need to define the field_names a form action. """ schema = IProductRelease custom_widget('datereleased', DateTimeWidget) custom_widget('release_notes', TextAreaWidget, height=7, width=62) custom_widget('changelog', TextAreaWidget, height=7, width=62) def _prependKeepMilestoneActiveField(self): keep_milestone_active_checkbox = FormFields( Bool( __name__='keep_milestone_active', title=_("Keep the %s milestone active." % self.context.name), description=_( "Only select this if bugs or blueprints still need " "to be targeted to this project release's milestone.")), render_context=self.render_context) self.form_fields = keep_milestone_active_checkbox + self.form_fields def _createRelease(self, milestone, data): """Create product release for this milestone.""" newrelease = milestone.createProductRelease( self.user, changelog=data['changelog'], release_notes=data['release_notes'], datereleased=data['datereleased']) # Set Milestone.active to false, since bugs & blueprints # should not be targeted to a milestone in the past. if data.get('keep_milestone_active') is False: milestone.active = False self.next_url = canonical_url(newrelease.milestone) notify(ObjectCreatedEvent(newrelease)) @property def label(self): """The form label.""" return smartquote('Create a new release for %s' % self.context.product.displayname) page_title = label @property def cancel_url(self): return canonical_url(self.context)
class SprintEditView(LaunchpadEditFormView): """Form for editing sprints""" schema = ISprint label = "Edit sprint details" field_names = ['name', 'title', 'summary', 'home_page', 'driver', 'time_zone', 'time_starts', 'time_ends', 'address', ] custom_widget('summary', TextAreaWidget, height=5) custom_widget('time_starts', DateTimeWidget, display_zone=False) custom_widget('time_ends', DateTimeWidget, display_zone=False) custom_widget('address', TextAreaWidget, height=3) def setUpWidgets(self): LaunchpadEditFormView.setUpWidgets(self) timeformat = '%Y-%m-%d %H:%M' self.widgets['time_starts'].timeformat = timeformat self.widgets['time_ends'].timeformat = timeformat time_zone_widget = self.widgets['time_zone'] # What time zone are the start and end values relative to? if time_zone_widget.hasValidInput(): tz = pytz.timezone(time_zone_widget.getInputValue()) else: tz = pytz.timezone(self.context.time_zone) self.widgets['time_starts'].required_time_zone = tz self.widgets['time_ends'].required_time_zone = tz def validate(self, data): time_starts = data.get('time_starts') time_ends = data.get('time_ends') if time_starts and time_ends and time_ends < time_starts: self.setFieldError( 'time_ends', "This event can't start after it ends") @action(_('Change'), name='change') def change_action(self, action, data): self.updateContextFromData(data) @property def next_url(self): return canonical_url(self.context) @property def cancel_url(self): return canonical_url(self.context)
class BugSubscriptionFilterEditViewBase(LaunchpadEditFormView, AdvancedSubscriptionMixin): """Base class for edit or create views of `IBugSubscriptionFilter`.""" schema = IBugSubscriptionFilter field_names = ( "description", "statuses", "importances", "information_types", "tags", "find_all_tags", ) custom_widget("description", TextWidget, displayWidth=50) custom_widget("statuses", LabeledMultiCheckBoxWidget) custom_widget("importances", LabeledMultiCheckBoxWidget) custom_widget("information_types", LabeledMultiCheckBoxWidget) custom_widget("tags", BugTagsFrozenSetWidget, displayWidth=35) # Define in concrete subclass to be the target of the # structural subscription that we are modifying. target = None # This is used by the AdvancedSubscriptionMixin. current_user_subscription = None @cachedproperty def _bug_notification_level_descriptions(self): return bug_notification_level_description_mapping( 'a bug in %s' % self.target.displayname) def setUpFields(self): """Set up fields for form. Overrides the usual implementation to also set up bug notification.""" super(BugSubscriptionFilterEditViewBase, self).setUpFields() self._setUpBugNotificationLevelField() @property def next_url(self): """Return to the user's structural subscriptions page.""" return canonical_url(self.user, view_name="+structural-subscriptions") cancel_url = next_url
class BugEditView(BugEditViewBase): """The view for the edit bug page.""" field_names = ['title', 'description', 'tags'] custom_widget('title', TextWidget, displayWidth=30) custom_widget('tags', BugTagsWidget) @property def label(self): """The form label.""" return 'Edit details for bug #%d' % self.context.bug.id page_title = label @action('Change', name='change') def change_action(self, action, data): """Update the bug with submitted changes.""" self.updateBugFromData(data)
class BuilderSetAddView(LaunchpadFormView): """View class for adding new Builders.""" schema = IBuilder label = "Register a new build machine" field_names = [ 'name', 'title', 'processor', 'url', 'active', 'virtualized', 'vm_host', 'owner' ] custom_widget('owner', HiddenUserWidget) custom_widget('url', TextWidget, displayWidth=30) custom_widget('vm_host', TextWidget, displayWidth=30) @action(_('Register builder'), name='register') def register_action(self, action, data): """Register a new builder.""" builder = getUtility(IBuilderSet).new( processor=data.get('processor'), url=data.get('url'), name=data.get('name'), title=data.get('title'), owner=data.get('owner'), active=data.get('active'), virtualized=data.get('virtualized'), vm_host=data.get('vm_host'), ) notify(ObjectCreatedEvent(builder)) self.next_url = canonical_url(builder) @property def page_title(self): """Return a relevant page title for this view.""" return self.label @property def cancel_url(self): """Canceling the add action should go back to the build farm.""" return canonical_url(self.context)
class AnnouncementPublishView(AnnouncementFormMixin, LaunchpadFormView): """A view to publish an annoucement.""" schema = AddAnnouncementForm field_names = ['publication_date'] page_title = 'Publish announcement' custom_widget('publication_date', AnnouncementDateWidget) @action(_('Publish'), name='publish') def publish_action(self, action, data): publication_date = data['publication_date'] self.context.setPublicationDate(publication_date) self.next_url = canonical_url(self.context.target) + '/+announcements'
class DistroSeriesEditView(LaunchpadEditFormView, SeriesStatusMixin): """View class that lets you edit a DistroSeries object. It redirects to the main distroseries page after a successful edit. """ schema = IDistroSeries field_names = ['displayname', 'title', 'summary', 'description'] custom_widget('status', LaunchpadDropdownWidget) @property def label(self): """See `LaunchpadFormView`.""" return 'Edit %s details' % self.context.title @property def page_title(self): """The page title.""" return self.label @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) def setUpFields(self): """See `LaunchpadFormView`. In addition to setting schema fields, also initialize the 'status' field. See `createStatusField` method. """ LaunchpadEditFormView.setUpFields(self) self.is_derivative = ( not self.context.distribution.full_functionality) self.has_admin = check_permission('launchpad.Admin', self.context) if self.has_admin or self.is_derivative: # The user is an admin or this is an IDerivativeDistribution. self.form_fields = ( self.form_fields + self.createStatusField()) @action("Change") def change_action(self, action, data): """Update the context and redirects to its overviw page.""" if self.has_admin or self.is_derivative: self.updateDateReleased(data.get('status')) self.updateContextFromData(data) self.request.response.addInfoNotification( 'Your changes have been applied.') self.next_url = canonical_url(self.context)
class DistroSeriesAdminView(LaunchpadEditFormView, SeriesStatusMixin): """View class for administering a DistroSeries object. It redirects to the main distroseries page after a successful edit. """ schema = IDistroSeries field_names = ['name', 'version', 'changeslist'] custom_widget('status', LaunchpadDropdownWidget) @property def label(self): """See `LaunchpadFormView`.""" return 'Administer %s' % self.context.title @property def page_title(self): """The page title.""" return self.label @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) def setUpFields(self): """Override `LaunchpadFormView`. In addition to setting schema fields, also initialize the 'status' field. See `createStatusField` method. """ LaunchpadEditFormView.setUpFields(self) self.form_fields = ( self.form_fields + self.createStatusField()) @action("Change") def change_action(self, action, data): """Update the context and redirects to its overviw page. Also, set 'datereleased' when a unstable distroseries is made CURRENT. """ self.updateDateReleased(data.get('status')) self.updateContextFromData(data) self.request.response.addInfoNotification( 'Your changes have been applied.') self.next_url = canonical_url(self.context)
class AppFrontPageSearchView(LaunchpadFormView): schema = IAppFrontPageSearchForm custom_widget('scope', ProjectScopeWidget) @property def scope_css_class(self): """The CSS class for used in the scope widget.""" if self.scope_error: return 'error' else: return None @property def scope_error(self): """The error message for the scope widget.""" return self.getFieldError('scope')
class PollOptionEditView(LaunchpadEditFormView): """Edit one of a poll's options.""" schema = IPollOption label = "Edit option details" page_title = 'Edit option' field_names = ["name", "title"] custom_widget("title", TextWidget, displayWidth=30) @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context.poll) @action("Save", name="save") def save_action(self, action, data): self.updateContextFromData(data) self.next_url = canonical_url(self.context.poll)
class BugAttachmentPatchConfirmationView(LaunchpadFormView): """Confirmation of the "patch" flag setting. If the user sets the "patch" flag to a value that is inconsistent with the result of a call of guess_content_type() for this attachment, we show this view to ask the user if he is sure about his selection. """ schema = IBugAttachmentIsPatchConfirmationForm custom_widget('patch', LaunchpadBooleanRadioWidget) def __init__(self, context, request): LaunchpadFormView.__init__(self, context, request) self.next_url = self.cancel_url = (canonical_url( ICanonicalUrlData(context).inside)) def initialize(self): super(BugAttachmentPatchConfirmationView, self).initialize() self.widgets['patch'].setRenderedValue(self.is_patch) @property def label(self): return smartquote('Confirm attachment type of "%s"') % ( self.context.title) page_title = 'Confirm attachment type' @action('Change', name='change') def change_action(self, action, data): current_patch_setting = self.context.type == BugAttachmentType.PATCH if data['patch'] != current_patch_setting: if data['patch']: self.context.type = BugAttachmentType.PATCH #xxxxxxxxxx adjust content type! # xxx use mixin, together with BugAttachmnetEditView else: self.context.type = BugAttachmentType.UNSPECIFIED @property def is_patch(self): """True if this attachment contains a patch, else False.""" return self.context.type == BugAttachmentType.PATCH
class PollOptionAddView(LaunchpadFormView): """Create a new option in a given poll.""" schema = IPollOption label = "Create new poll option" page_title = "New option" field_names = ["name", "title"] custom_widget("title", TextWidget, displayWidth=30) @property def cancel_url(self): """See `LaunchpadFormView`.""" return canonical_url(self.context) @action("Create", name="create") def create_action(self, action, data): polloption = self.context.newOption(data['name'], data['title']) self.next_url = canonical_url(self.context) notify(ObjectCreatedEvent(polloption))
class FAQCreateView(LaunchpadFormView): """A view to create a new FAQ.""" schema = IFAQ label = _('Create a new FAQ') field_names = ['title', 'keywords', 'content'] custom_widget('keywords', TokensTextWidget) @property def page_title(self): return 'Create a FAQ for %s' % self.context.displayname @action(_('Create'), name='create') def create__action(self, action, data): """Creates the FAQ.""" faq = self.context.newFAQ(self.user, data['title'], data['content'], keywords=data['keywords']) self.next_url = canonical_url(faq)
class LanguageSetView(LaunchpadFormView): """View class to render main ILanguageSet page.""" label = "Languages in Launchpad" page_title = "Languages" schema = ILanguageSetSearch custom_widget('search_lang', TextWidget, displayWidth=30) def initialize(self): """See `LaunchpadFormView`.""" LaunchpadFormView.initialize(self) self.language_search = None search_lang_widget = self.widgets.get('search_lang') if (search_lang_widget is not None and search_lang_widget.hasValidInput()): self.language_search = search_lang_widget.getInputValue() self.search_requested = self.language_search is not None @cachedproperty def search_results(self): return self.context.search(text=self.language_search) @cachedproperty def search_matches(self): if self.search_results is not None: return self.search_results.count() else: return 0 @cachedproperty def user_languages(self): """The user's preferred languages, or English if none are set.""" languages = list(self.user.languages) if len(languages) == 0: languages = [getUtility(ILaunchpadCelebrities).english] return ", ".join(map(_format_language, languages))