def getDistribution(self): """See `BugTaskSourcePackageNameWidget`""" distribution_name = self.request.form.get('field.distribution') if distribution_name is None: raise UnexpectedFormData( "field.distribution wasn't in the request") distribution = getUtility(IDistributionSet).getByName( distribution_name) if distribution is None: raise UnexpectedFormData("No such distribution: %s" % distribution_name) return distribution
def current_package(self): """Get the package whose bugs are currently being searched.""" if not (self.widgets['distribution'].hasValidInput() and self.widgets['distribution'].getInputValue()): raise UnexpectedFormData("A distribution is required") if not (self.widgets['sourcepackagename'].hasValidInput() and self.widgets['sourcepackagename'].getInputValue()): raise UnexpectedFormData("A sourcepackagename is required") distribution = self.widgets['distribution'].getInputValue() return distribution.getSourcePackage( self.widgets['sourcepackagename'].getInputValue())
def getEntriesFilteringOptions(self): """Return the selected filtering.""" target = None file_extension = None status = None target_widget = self.widgets.get('filter_target') if target_widget is not None and target_widget.hasValidInput(): target = target_widget.getInputValue() pillar_name_set = getUtility(IPillarNameSet) if target == 'all': target = None elif target.startswith('[') and target.endswith(']'): # This is a SpecialTranslationImportTargetFilter. target_code = target[1:-1] target = None for enum_item in SpecialTranslationImportTargetFilter.items: if enum_item.name == target_code: target = enum_item if target is None: raise UnexpectedFormData( "Got a bad special target option: %s" % target) elif '/' in target: # It's a distroseries, for them we have # 'distribution.name/distroseries.name' to identify it. distribution_name, distroseries_name = target.split('/', 1) pillar = pillar_name_set.getByName(distribution_name) if IDistribution.providedBy(pillar): target = pillar.getSeries(distroseries_name) else: raise UnexpectedFormData("Got a bad target option %s" % target) else: target = pillar_name_set.getByName(target) filter_extension_widget = self.widgets.get('filter_extension') if filter_extension_widget.hasValidInput(): file_extension = filter_extension_widget.getInputValue() if file_extension == 'all': file_extension = None filter_status_widget = self.widgets.get('filter_status') if filter_status_widget.hasValidInput(): status = filter_status_widget.getInputValue() if status == 'all': status = None else: status = RosettaImportStatus.items[status] return target, file_extension, status
def getInputValue(self): """See zope.formlib.interfaces.IInputWidget.""" scope = self.request.form_ng.getOne(self.name) if scope == 'all': return None elif scope == 'project': if not self.request.form_ng.getOne(self.target_widget.name): self._error = WidgetInputError( self.name, self.label, LaunchpadValidationError('Please enter a project name')) raise self._error try: return self.target_widget.getInputValue() except ConversionError: entered_name = self.request.form_ng.getOne("%s.target" % self.name) self._error = WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no project named '%s' registered in" " Launchpad" % entered_name)) raise self._error elif self.required: raise UnexpectedFormData("No valid option was selected.") else: return None
def processActiveMember(self): # This method checks the current status to ensure that we don't # crash because of users reposting a form. form = self.request.form context = self.context if form.get('deactivate'): if self.context.status == TeamMembershipStatus.DEACTIVATED: # This branch and redirect is necessary because # TeamMembership.setStatus() does not allow us to set an # already-deactivated account to deactivated, causing # double form posts to crash there. We instead manually # ensure that the double-post is harmless. self.request.response.redirect('%s/+members' % canonical_url(context.team)) return new_status = TeamMembershipStatus.DEACTIVATED elif form.get('change'): if (form.get('admin') == "no" and context.status == TeamMembershipStatus.ADMIN): new_status = TeamMembershipStatus.APPROVED elif (form.get('admin') == "yes" and context.status == TeamMembershipStatus.APPROVED): new_status = TeamMembershipStatus.ADMIN else: # No status change will happen new_status = self.context.status else: raise UnexpectedFormData( "None of the expected actions were found.") if self._setMembershipData(new_status): self.request.response.redirect('%s/+members' % canonical_url(context.team))
def initialize(self): self.storeTokenContext() try: form = get_oauth_authorization(self.request) except UnicodeDecodeError: raise UnexpectedFormData("Invalid UTF-8.") key = form.get('oauth_token') if key: self.token = getUtility(IOAuthRequestTokenSet).getByKey(key) callback = self.request.form.get('oauth_callback') if (self.token is not None and self.token.consumer.is_integrated_desktop): # Nip problems in the bud by appling special rules about # what desktop integrations are allowed to do. if callback is not None: # A desktop integration is not allowed to specify a callback. raise Unauthorized( "A desktop integration may not specify an " "OAuth callback URL.") # A desktop integration token can only have one of two # permission levels: "Desktop Integration" and # "Unauthorized". It shouldn't even be able to ask for any # other level. for action in self.visible_actions: if action.permission not in ( OAuthPermission.DESKTOP_INTEGRATION, OAuthPermission.UNAUTHORIZED): raise Unauthorized( ("Desktop integration token requested a permission " '("%s") not supported for desktop-wide use.') % action.label) super(OAuthAuthorizeTokenView, self).initialize()
def getInputValue(self): """See zope.formlib.interfaces.IInputWidget.""" self.setUpSubWidgets() form_value = self.request.form_ng.getOne(self.name) if form_value == 'product': try: return self.product_widget.getInputValue() except MissingInputError: self._error = WidgetInputError( self.name, self.label, LaunchpadValidationError('Please enter a project name')) raise self._error except ConversionError: entered_name = self.request.form_ng.getOne("%s.product" % self.name) self._error = WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no project named '%s' registered in" " Launchpad" % entered_name)) raise self._error elif form_value == 'package': try: distribution = self.distribution_widget.getInputValue() except ConversionError: entered_name = self.request.form_ng.getOne("%s.distribution" % self.name) self._error = WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no distribution named '%s' registered in" " Launchpad" % entered_name)) raise self._error if self.package_widget.hasInput(): try: package_name = self.package_widget.getInputValue() if package_name is None: return distribution if IDistributionSourcePackage.providedBy(package_name): dsp = package_name else: source_name = ( distribution.guessPublishedSourcePackageName( package_name.name)) dsp = distribution.getSourcePackage(source_name) except (ConversionError, NotFoundError): entered_name = self.request.form_ng.getOne('%s.package' % self.name) self._error = WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no package named '%s' published in %s." % (entered_name, distribution.displayname))) raise self._error return dsp else: return distribution else: raise UnexpectedFormData("No valid option was selected.")
def _setupMappedStates(self, tag): """Build self.state and self.availableStates structures. self.state is the corresponding dbschema for requested state_tag self.available_states is a dictionary containing the options with suitables attributes (name, value, selected) to easily fill an HTML <select> section. Raise UnexpectedFormData if no corresponding state for passed 'tag' was found. """ # Default states map. state_map = { 'built': BuildStatus.FULLYBUILT, 'failed': BuildStatus.FAILEDTOBUILD, 'depwait': BuildStatus.MANUALDEPWAIT, 'chrootwait': BuildStatus.CHROOTWAIT, 'superseded': BuildStatus.SUPERSEDED, 'uploadfail': BuildStatus.FAILEDTOUPLOAD, 'all': None, } # Include pristine (not yet assigned to a builder) builds, # if requested. if self.show_builder_info: extra_state_map = { 'building': BuildStatus.BUILDING, 'pending': BuildStatus.NEEDSBUILD, } state_map.update(**extra_state_map) # Lookup for the correspondent state or fallback to the default # one if tag is empty string. if tag: try: self.state = state_map[tag] except (KeyError, TypeError): raise UnexpectedFormData( 'No suitable state found for value "%s"' % tag) else: self.state = self.default_build_state # Build a dictionary with organized information for rendering # the HTML <select> section. self.available_states = [] for tag, state in state_map.items(): if state: name = state.title.strip() else: name = 'All states' if state == self.state: selected = 'selected' else: selected = None self.available_states.append( dict(name=name, value=tag, selected=selected))
def getDistribution(self): """See `SourcePackageNameWidgetBase`.""" distribution_name = self.request.form.get('field.distribution') if distribution_name is None: return None distribution = getUtility(IDistributionSet).getByName( distribution_name) if distribution is None: raise UnexpectedFormData("No such distribution: %s" % distribution_name) return distribution
def storeTokenContext(self): """Store the context given by the consumer in this view.""" self.token_context = None # We have no guarantees that lp.context will be together with the # OAuth parameters, so we need to check in the Authorization header # and on the request's form if it's not in the former. try: oauth_data = get_oauth_authorization(self.request) except UnicodeDecodeError: raise UnexpectedFormData("Invalid UTF-8.") context = oauth_data.get('lp.context') if not context: context = self.request.form.get('lp.context') if not context: return try: context = lookup_oauth_context(context) except ValueError: raise UnexpectedFormData("Unknown context.") self.token_context = context
def getDistribution(self): """See `SourcePackageNameWidgetBase`.""" distroseries_token = self.request.form.get('field.distroseries') if distroseries_token is None: # Fall back to the POTemplate's current distribution. return self.context.context.distribution distroseries_vocab = DistroSeriesVocabulary() try: term = distroseries_vocab.getTermByToken(distroseries_token) except LookupError: raise UnexpectedFormData("No such distribution series: %s" % distroseries_token) return term.value.distribution
def update_action(self, action, data): branch_type = data.get('branch_type') if branch_type == LINK_LP_BZR: branch_location = data.get('branch_location') if branch_location != self.context.branch: self.context.branch = branch_location # Request an initial upload of translation files. getUtility(IRosettaUploadJobSource).create( self.context.branch, NULL_REVISION) else: self.context.branch = branch_location self.request.response.addInfoNotification( 'Series code location updated.') else: branch_name = data.get('branch_name') branch_owner = data.get('branch_owner') if branch_type == IMPORT_EXTERNAL: rcs_type = data.get('rcs_type') if rcs_type == RevisionControlSystems.CVS: cvs_root = data.get('repo_url') cvs_module = data.get('cvs_module') url = None else: cvs_root = None cvs_module = None url = data.get('repo_url') rcs_item = RevisionControlSystems.items[rcs_type.name] try: code_import = getUtility(ICodeImportSet).new( owner=branch_owner, registrant=self.user, target=IBranchTarget(self.context.product), branch_name=branch_name, rcs_type=rcs_item, url=url, cvs_root=cvs_root, cvs_module=cvs_module) except BranchExists as e: self._setBranchExists(e.existing_branch, 'branch_name') self.errors_in_action = True # Abort transaction. This is normally handled # by LaunchpadFormView, but we are already in # the success handler. self._abort() return self.context.branch = code_import.branch self.request.response.addInfoNotification( 'Code import created and branch linked to the series.') else: raise UnexpectedFormData(branch_type)
def _submitTranslations(self): """See BaseTranslationView._submitTranslations.""" for key in self.request.form: match = re.match('msgset_(\d+)$', key) if not match: continue id = int(match.group(1)) potmsgset = self.context.potemplate.getPOTMsgSetByID(id) if potmsgset is None: # This should only happen if someone tries to POST his own # form instead of ours, and he uses a POTMsgSet id that # does not exist for this POTemplate. raise UnexpectedFormData( "Got translation for POTMsgID %d which is not in the " "template." % id) error = self._receiveTranslations(potmsgset) if error and potmsgset.getSequence(self.context.potemplate) != 0: # There is an error, we should store it to be rendered # together with its respective view. # # The check for potmsgset.getSequence() != 0 is meant to catch # messages which are not current anymore. This only # happens as part of a race condition, when someone gets # a translation form, we get a new template for # that context that disables some entries in that # translation form, and after that, the user submits the # form. We accept the translation, but if it has an # error, we cannot render that error so we discard it, # that translation is not being used anyway, so it's not # a big loss. self.errors[potmsgset] = error if self.errors: if len(self.errors) == 1: message = ("There is an error in a translation you provided. " "Please correct it before continuing.") else: message = ("There are %d errors in the translations you " "provided. Please correct them before " "continuing." % len(self.errors)) self.request.response.addErrorNotification(message) return False if self.batchnav.batch.nextBatch() is not None: # Update the start of the next batch by the number of messages # that were removed from the batch. self.batchnav.batch.start -= self.start_offset self._redirectToNextPage() return True
def __call__(self, context): import_queue = getUtility(ITranslationImportQueue) if hasattr(self, 'view'): user = self.view.user else: user = None targets = import_queue.getRequestTargets(user) filtered_targets = set() # Read filter_status, in order to mark targets that have requests with # that status pending. This works because we set up the filter_status # widget before the filter_target one, which uses this vocabulary # factory. status_widget = self.view.widgets['filter_status'] if status_widget.hasInput(): try: status_filter = status_widget.getInputValue() except ConversionError: raise UnexpectedFormData("Invalid status parameter.") if status_filter != 'all': try: status = RosettaImportStatus.items[status_filter] filtered_targets = set( import_queue.getRequestTargets(user=None, status=status)) except LookupError: # Unknown status. Ignore. pass terms = [SimpleTerm('all', 'all', 'All targets')] for item in SpecialTranslationImportTargetFilter.items: term_name = '[%s]' % item.name terms.append(SimpleTerm(term_name, term_name, item.title)) for target in targets: if IDistroSeries.providedBy(target): # Distroseries are not pillar names, we need to note # distribution.name/distroseries.name term_name = '%s/%s' % (target.distribution.name, target.name) else: term_name = target.name displayname = target.displayname if target in filtered_targets: displayname += '*' terms.append(SimpleTerm(term_name, term_name, displayname)) return SimpleVocabulary(terms)
def restoreRequestFromSession(self): """Get the OpenIDRequest from our session.""" session = self.getSession() cache = get_property_cache(self) try: cache.openid_parameters = session[OPENID_REQUEST_SESSION_KEY] except KeyError: raise UnexpectedFormData("No OpenID request in session") # Decode the request parameters and create the request object. self.openid_request = self.openid_server.decodeRequest( self.openid_parameters) assert zisinstance( self.openid_request, CheckIDRequest), ('Invalid OpenIDRequest in session')
def setupQueueList(self): """Setup a batched queue list. Returns None, so use tal:condition="not: view/setupQueueList" to invoke it in template. """ # recover selected queue state and name filter self.name_filter = self.request.get('queue_text', '') try: state_value = int(self.request.get('queue_state', '')) except ValueError: state_value = PackageUploadStatus.NEW.value try: self.state = PackageUploadStatus.items[state_value] except KeyError: raise UnexpectedFormData( 'No suitable status found for value "%s"' % state_value) self.queue = self.context.getPackageUploadQueue(self.state) valid_states = [ PackageUploadStatus.NEW, PackageUploadStatus.ACCEPTED, PackageUploadStatus.REJECTED, PackageUploadStatus.DONE, PackageUploadStatus.UNAPPROVED, ] self.filtered_options = [] for state in valid_states: selected = (state == self.state) self.filtered_options.append( dict(name=state.title, value=state.value, selected=selected)) queue_items = self.context.getPackageUploads(status=self.state, name=self.name_filter) self.batchnav = BatchNavigator(queue_items, self.request, size=QUEUE_SIZE)
def processProposedMember(self): if self.context.status != TeamMembershipStatus.PROPOSED: # Catch a double-form-post. self.errormessage = _( 'The membership request for %s has already been processed.' % self.context.person.displayname) return assert self.context.status == TeamMembershipStatus.PROPOSED if self.request.form.get('decline'): status = TeamMembershipStatus.DECLINED elif self.request.form.get('approve'): status = TeamMembershipStatus.APPROVED else: raise UnexpectedFormData( "None of the expected actions were found.") if self._setMembershipData(status): self.request.response.redirect('%s/+members' % canonical_url(self.context.team))
def render(self): """Handle all OpenID requests and form submissions.""" # NB: Will be None if there are no parameters in the request. self.openid_request = self.openid_server.decodeRequest( self.openid_parameters) if self.openid_request.mode == 'checkid_setup': referer = self.request.get("HTTP_REFERER") if referer: self.request.response.setCookie("openid_referer", referer) # Log the user out and present the login page so that they can # authenticate as somebody else if they want. logoutPerson(self.request) return self.showLoginPage() elif self.openid_request.mode == 'checkid_immediate': raise UnexpectedFormData( 'We do not handle checkid_immediate requests.') else: return self.renderOpenIDResponse( self.openid_server.handleRequest(self.openid_request))
def _getSelectedPOTMsgSets(self): """Return a list of the POTMsgSets that will be rendered.""" # The set of message sets we get is based on the selection of kind # of strings we have in our form. get_functions = { 'all': self._handleShowAll, 'translated': self.context.getPOTMsgSetTranslated, 'untranslated': self.context.getPOTMsgSetUntranslated, 'new_suggestions': self.context.getPOTMsgSetWithNewSuggestions, 'changed_in_ubuntu': self.context.getPOTMsgSetDifferentTranslations, } if self.show not in get_functions: raise UnexpectedFormData('show = "%s"' % self.show) # We cannot listify the results to avoid additional count queries, # because we could end up with a list of more than 32000 items with # an average list of 5000 items. # The batch system will slice the list of items so we will fetch only # the exact number of entries we need to render the page. return get_functions[self.show]()
def getInputValue(self): """See zope.formlib.interfaces.IInputWidget.""" self.setUpSubWidgets() form_value = self.request.form_ng.getOne(self.name) if form_value == 'product': try: return self.product_widget.getInputValue() except MissingInputError: raise WidgetInputError( self.name, self.label, LaunchpadValidationError('Please enter a project name')) except ConversionError: entered_name = self.request.form_ng.getOne("%s.product" % self.name) raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no project named '%s' registered in" " Launchpad" % entered_name)) elif form_value == 'personal': return '+junk' else: raise UnexpectedFormData("No valid option was selected.")
def __call__(self): """Create a request token and include its key/secret in the response. If the consumer key is empty or the signature doesn't match, respond with a 401 status. If the key is not empty but there's no consumer with it, we register a new consumer. """ try: form = get_oauth_authorization(self.request) except UnicodeDecodeError: raise UnexpectedFormData("Invalid UTF-8.") consumer_key = form.get('oauth_consumer_key') if not consumer_key: self.request.unauthorized(OAUTH_CHALLENGE) return u'' consumer_set = getUtility(IOAuthConsumerSet) consumer = consumer_set.getByKey(consumer_key) if consumer is None: consumer = consumer_set.new(key=consumer_key) if not check_oauth_signature(self.request, consumer, None): return u'' token, secret = consumer.newRequestToken() if self.request.headers.get('Accept') == HTTPResource.JSON_TYPE: # Don't show the client the DESKTOP_INTEGRATION access # level. If they have a legitimate need to use it, they'll # already know about it. permissions = [ permission for permission in OAuthPermission.items if (permission != OAuthPermission.DESKTOP_INTEGRATION) ] return self.getJSONRepresentation( permissions, token, secret=secret) return u'oauth_token=%s&oauth_token_secret=%s' % (token.key, secret)
def getInputValue(self): """See `zope.formlib.interfaces.IInputWidget`.""" self.setUpSubWidgets() form_value = self.request.form_ng.getOne(self.name) if form_value == "repository_owner": return GitGranteeType.REPOSITORY_OWNER elif form_value == "person": try: return self.person_widget.getInputValue() except MissingInputError: raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "Please enter a person or team name")) except ConversionError: entered_name = self.request.form_ng.getOne("%s.person" % self.name) raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no person or team named '%s' registered in " "Launchpad" % entered_name)) else: raise UnexpectedFormData("No valid option was selected.")
def initialize(self): """Useful initialization for this view class.""" super(TranslationImportQueueView, self).initialize() target_filter = self.widgets['filter_target'] if target_filter.hasInput() and not target_filter.hasValidInput(): raise UnexpectedFormData("Unknown target.")
def _toFieldValue(self, input): if isinstance(input, list): raise UnexpectedFormData('Only a single value is expected') return super(URIWidget, self)._toFieldValue(input)
def change_status_action(self, action, data): """Handle a queue submission changing the status of its entries.""" # The user must be logged in. if self.user is None: raise UnexpectedFormData( 'Users not logged cannot submit this form.') number_of_changes = 0 for form_item in data: if not form_item.startswith('status_'): # We are not interested on this form_item. continue # It's an form_item to handle. try: # 'ignored' is 'status' due to the previous check, so we could # ignore that part. ignored, id_string = form_item.split('_') # The id is an integer id = int(id_string) except ValueError: # We got an form_item with more than one '_' char or with an # id that is not a number, that means that someone is playing # badly with our system so it's safe to just ignore the # request. raise UnexpectedFormData( 'Ignored your request because it is broken.') # Get the entry we are working on. import_queue_set = getUtility(ITranslationImportQueue) entry = import_queue_set.get(id) new_status_name = data.get(form_item) if new_status_name == entry.status.name: # The entry's status didn't change we can jump to the next # entry. continue # The status changed. number_of_changes += 1 # Determine status enum from from value. new_status = None for status in RosettaImportStatus.items: if new_status_name == status.name: new_status = status break if new_status is None: # We are trying to set a bogus status. # That means that it's a broken request. raise UnexpectedFormData( 'Ignored the request to change the status from %s to %s.' % (entry.status.name, new_status_name)) else: # This will raise an exception if the user is not authorized. entry.setStatus(new_status, self.user) # Update the date_status_change field. UTC = pytz.timezone('UTC') entry.date_status_changed = datetime.datetime.now(UTC) if number_of_changes == 0: self.request.response.addWarningNotification( "Ignored your status change request as you didn't select any" " change.") else: self.request.response.addInfoNotification( "Changed the status of %d queue entries." % number_of_changes)
def getInputValue(self): """See `zope.formlib.interfaces.IInputWidget`.""" self.setUpSubWidgets() form_value = self.request.form_ng.getOne(self.name) if form_value == "project": try: return self.project_widget.getInputValue() except MissingInputError: raise WidgetInputError( self.name, self.label, LaunchpadValidationError("Please enter a project name")) except ConversionError: entered_name = self.request.form_ng.getOne("%s.project" % self.name) raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no project named '%s' registered in " "Launchpad" % entered_name)) elif form_value == "package": try: distribution = self.distribution_widget.getInputValue() except ConversionError: entered_name = self.request.form_ng.getOne("%s.distribution" % self.name) raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no distribution named '%s' registered in " "Launchpad" % entered_name)) try: if self.package_widget.hasInput(): if bool(getFeatureFlag('disclosure.dsp_picker.enabled')): self.package_widget.vocabulary.setDistribution( distribution) package_name = self.package_widget.getInputValue() else: package_name = None if package_name is None: raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "Please enter a package name")) if IDistributionSourcePackage.providedBy(package_name): dsp = package_name else: source_name = distribution.guessPublishedSourcePackageName( package_name.name) dsp = distribution.getSourcePackage(source_name) except (ConversionError, NotFoundError): entered_name = self.request.form_ng.getOne("%s.package" % self.name) raise WidgetInputError( self.name, self.label, LaunchpadValidationError( "There is no package named '%s' published in %s." % (entered_name, distribution.displayname))) return dsp elif form_value == "personal": return None else: raise UnexpectedFormData("No valid option was selected.")
def __call__(self): name = self.request.form.get('name') if name is None: raise MissingInputError('name', '') search_text = self.request.form.get('search_text') if search_text is None: raise MissingInputError('search_text', '') search_filter = self.request.form.get('search_filter') try: factory = getUtility(IVocabularyFactory, name) except ComponentLookupError: raise UnexpectedFormData( 'Unknown vocabulary %r' % name) vocabulary = factory(self.context) if IHugeVocabulary.providedBy(vocabulary): matches = vocabulary.searchForTerms(search_text, search_filter) total_size = matches.count() else: matches = list(vocabulary) total_size = len(matches) batch_navigator = BatchNavigator(matches, self.request) # We need to collate what IPickerEntrySource adapters are required for # the items in the current batch. We expect that the batch will be # homogenous and so only one adapter instance is required, but we # allow for the case where the batch may contain disparate entries # requiring different adapter implementations. # A mapping from adapter class name -> adapter instance adapter_cache = {} # A mapping from adapter class name -> list of vocab terms picker_entry_terms = {} for term in batch_navigator.currentBatch(): picker_entry_source = IPickerEntrySource(term.value) adapter_class = picker_entry_source.__class__.__name__ picker_terms = picker_entry_terms.get(adapter_class) if picker_terms is None: picker_terms = [] picker_entry_terms[adapter_class] = picker_terms adapter_cache[adapter_class] = picker_entry_source picker_terms.append(term.value) # A mapping from vocab terms -> picker entries picker_term_entries = {} # For the list of terms associated with a picker adapter, we get the # corresponding picker entries by calling the adapter. for adapter_class, term_values in picker_entry_terms.items(): picker_entries = adapter_cache[adapter_class].getPickerEntries( term_values, self.context) for term_value, picker_entry in izip(term_values, picker_entries): picker_term_entries[term_value] = picker_entry result = [] for term in batch_navigator.currentBatch(): entry = dict(value=term.token, title=term.title) # The canonical_url without just the path (no hostname) can # be passed directly into the REST PATCH call. api_request = IWebServiceClientRequest(self.request) try: entry['api_uri'] = canonical_url( term.value, request=api_request, path_only_if_possible=True) except NoCanonicalUrl: # The exception is caught, because the api_url is only # needed for inplace editing via a REST call. The # form picker doesn't need the api_url. entry['api_uri'] = 'Could not find canonical url.' picker_entry = picker_term_entries[term.value] if picker_entry.description is not None: if len(picker_entry.description) > MAX_DESCRIPTION_LENGTH: entry['description'] = ( picker_entry.description[:MAX_DESCRIPTION_LENGTH - 3] + '...') else: entry['description'] = picker_entry.description if picker_entry.image is not None: entry['image'] = picker_entry.image if picker_entry.css is not None: entry['css'] = picker_entry.css if picker_entry.alt_title is not None: entry['alt_title'] = picker_entry.alt_title if picker_entry.title_link is not None: entry['title_link'] = picker_entry.title_link if picker_entry.details is not None: entry['details'] = picker_entry.details if picker_entry.alt_title_link is not None: entry['alt_title_link'] = picker_entry.alt_title_link if picker_entry.link_css is not None: entry['link_css'] = picker_entry.link_css if picker_entry.badges: entry['badges'] = picker_entry.badges if picker_entry.metadata is not None: entry['metadata'] = picker_entry.metadata if picker_entry.target_type is not None: entry['target_type'] = picker_entry.target_type result.append(entry) self.request.response.setHeader('Content-type', 'application/json') return simplejson.dumps(dict(total_size=total_size, entries=result))