async def process(self, req: Request['UserList_POST.Arguments'], user: User) -> None: # Find user record. userName = req.args.user try: subject = self.userDB[userName] except KeyError: raise PresentableError( xhtml.p(class_='notice') [f'There is no user named "{userName}"']) # Parse and check all changes. requestUserName = user.name newRoles = uiRoleToSet(req.args.role) if (userName == requestUserName and not rolesGrantPrivilege(newRoles, 'u/m')): # Prevent user from revoking their own 'u/m' privilege. raise PresentableError(xhtml[xhtml.p( class_='notice' )['Revoking your own privileges could lead to ' 'a situation from which recovery is impossible.'], xhtml.p[ f'If you want to change the role of user "{userName}", ' f'please log in as another user with operator ' f'privileges.'], ]) # Changes are OK, commit them. subject.roles = newRoles raise Redirect( pageURL('UserList', UserList_GET.Arguments.subset(req.args)))
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(BatchExecute_GET.Processor, kwargs['proc']) for notice in proc.notices: yield xhtml.p(class_='notice')[notice] configs = proc.configs if configs: yield xhtml.h3['Selected configurations:'] yield BatchConfigTable.instance.present(**kwargs) taskSet = proc.taskSet if taskSet is None: yield xhtml.p['Cannot execute because of conflict.'] else: yield makeForm(args=ParentArgs.subset(proc.args))[ BatchInputTable.instance, submitButtons, decoration[ xhtml.hr, ParamTable.instance, # Second set of submit buttons after parameter tables. submitButtons], (hiddenInput(name=f'config.{i:d}', value=cfg.getId()) for i, cfg in enumerate(configs)), ].present( taskSet=taskSet, **kwargs) return else: yield xhtml.h3['No configurations selected'] yield xhtml.p[xhtml.a( href=proc.args.refererURL or parentPage)['Back to Configurations']]
def presentError(self, message: XML, **kwargs: object) -> XMLContent: proc = cast(ChangePassword_GET.Processor, kwargs['proc']) yield xhtml.p(class_='notice')[message] if proc.retry: yield presentForm(**kwargs) else: yield self.backToReferer(proc.args)
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(ConfigTagsBase.Processor[ArgsT], kwargs['proc']) for notice in proc.notices: yield xhtml.p(class_='notice')[notice] configs = proc.configs if configs: yield xhtml.h3['Selected Configurations:'] yield TagConfigTable.instance.present(**kwargs) yield xhtml.h3['Common Selection Tags:'] tagKeys = proc.project.getTagKeys() commonTags = getCommonTags(tagKeys, (config.tags for config in configs)) yield makeForm(args=ParentArgs.subset(proc.args).override( sel={config.getId() for config in configs} ))[ConfigTagValueEditTable.instance, xhtml.p[actionButtons(Actions)], (hiddenInput(name=f'commontags.{index:d}', value=tagName) for index, tagKey in enumerate(tagKeys) for tagName in commonTags[tagKey])].present( getValues=lambda key: valuesToText(commonTags[key]), **kwargs) else: yield (xhtml.h3['No configurations selected'], xhtml.p[xhtml.a(href=proc.args.refererURL or parentPage) ['Back to Configurations']])
def __formatError(self, req: Request, ex: Exception) -> Iterator[XMLNode]: '''Yields HTML informing the user of the given exception. ''' yield xhtml.p( class_='notice')['An error occurred while generating this page.'] if req.displayTracebacks: tb = TracebackException.from_exception(ex) yield xhtml.pre[tb.format()] else: yield xhtml.p['Details were written to the server log.']
def getResponder(self, path: Optional[str], proc: 'DocPage.Processor') -> Responder: self.renderContent() proc.content = self.postProcess() if self.errors: message = xhtml.p(class_='notice')[ f"Error in documentation {self.errors}.", xhtml.br, 'Please check the Control Center log for details.'] return DocErrorResponder(self, proc, message) else: return super().getResponder(path, proc)
async def process(self, req: Request['Notifications_POST.Arguments'], user: User) -> None: args = req.args action = args.action smtpRelay = args.smtpRelay mailSender = args.mailSender if action is Actions.CANCEL: page = cast(Notifications_POST, self.page) raise Redirect(page.getParentURL(req.args)) elif action is Actions.TEST: # pylint: disable=attribute-defined-outside-init recipient = args.mailRecipient if not recipient: raise PresentableError( xhtml.p(class_='notice')[ 'Please enter a recipient address ' 'to send the test-email to']) self.mailTestTime = time.localtime() try: addresses: Iterable[Tuple[bytes, int, bytes]] numOk_, addresses = await sendTestMail( smtpRelay, mailSender, args.mailRecipient) except Exception as ex: raise PresentableError( xhtml.p(class_='notice') [f'Sending test mail failed: {ex}']) self.mailTestResult = tuple( (address.decode(errors='replace'), f"{resp.decode(errors='replace')} ({code:d})") for address, code, resp in addresses) elif action is Actions.SAVE: if mailSender and not reMailAddress.match(mailSender): raise PresentableError( xhtml.p(class_='notice') ['Mail sender ', xhtml.code[mailSender], ' does not look like an e-mail address.']) self.project.setMailConfig(args.mailNotification, smtpRelay, mailSender) else: assert False, action
def _backAndNextButton(backName: Optional[str], nextLabel: Optional[str]) -> XML: back = backButton(name=backName) if nextLabel is None: return xhtml.p[back] else: # Make the 'next' button appear in the HTML first, so that it # becomes the default button of the form. return xhtml.p(style='display: flex; ' 'flex-direction: row-reverse; ' 'justify-content: flex-end')[ submitButton(value='next', tabindex=3)[nextLabel], xhtml.span['\u00A0'], back]
def presentForm(args: MailConfigArgs, **kwargs: object) -> XMLContent: yield xhtml.h3['E-mail'] if sendmail is None: yield xhtml.p(class_='notice')['Cannot send e-mail notifications.'] yield xhtml.p['Notifications by e-mail require the ', xhtml.code['twisted.mail'], ' package, which is not installed.'] if (twistedVersion.major, twistedVersion.minor) < (17, 5): yield xhtml.p[ 'The Python 3 version of ', xhtml.code['twisted.mail'], ' is only available since Twisted 17.5.0, ' 'while this SoftFab is currently running on Twisted ', twistedVersion.public(), '.'] yield makeForm(args=args)[presentEmailForm()].present(**kwargs)
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(Notifications_POST.Processor, kwargs['proc']) action = proc.args.action if action is Actions.TEST: yield xhtml.p( class_='notice')['Result for notification test of %s:' % time.strftime('%H:%M:%S', proc.mailTestTime)] yield xhtml.p[xhtml.br.join( (address, ' : ', result) for address, result in proc.mailTestResult)] yield presentForm(proc.args, **kwargs) elif action is Actions.SAVE: yield xhtml.p['Notification settings saved.'] yield self.backToParent(proc.args) else: assert False, action
def presentError(self, message: XML, **kwargs: object) -> XMLContent: proc = cast(SetPassword_POST.Processor, kwargs['proc']) yield xhtml.p(class_='notice')[message] if proc.userName is not None: yield presentForm(**kwargs)
def presentError(self, message: XML, **kwargs: object) -> XMLContent: yield xhtml.p(class_='notice')[message]
] decoratedInputTable = decoration[ xhtml.p[ 'Configuration consumes the following inputs:' ], InputTable.instance ] def presentInputConflicts(**kwargs: object) -> XMLContent: proc = cast('ConfigDetails_GET.Processor', kwargs['proc']) return unorderedList[ proc.config.iterInputConflicts() ].present(**kwargs) decoratedConflictsList = decoration[ xhtml.p(class_ = 'notice')[ 'The following problems exist with the stored inputs:' ], PresenterFunction(presentInputConflicts) ] class SchedulesTable(Table): columns = 'Schedule', hideWhenEmpty = True def iterRows(self, **kwargs: object) -> Iterator[XMLContent]: proc = cast('ConfigDetails_GET.Processor', kwargs['proc']) for scheduleId in sorted(proc.scheduleIds): yield createScheduleDetailsLink(scheduleId), decoratedSchedulesTable = decoration[ xhtml.p[ 'Configuration can be instantiated by the following schedules:' ],
def presentContent(self, **kwargs: object) -> XMLContent: proc = cast(DialogProcessorBase, kwargs['proc']) if proc.errorMessage is not None: yield xhtml.p(class_='notice')[proc.errorMessage] yield proc.step.presentContent(**kwargs)
def presentError(self, message: XML, **kwargs: object) -> XMLContent: proc = cast(AddUser_POST.Processor, kwargs['proc']) yield xhtml.p(class_ = 'notice')[ message ] yield self.presentForm(proc.args, **kwargs)
svg = self.graphCache[name] except KeyError: svg = xhtml.span(class_='notice')['Graph rendering failed'] return xhtml.div(class_='graph')[xhtml.div[svg]] class ExtractedInfo: """Fragments extracted from a documentation page.""" def __init__(self, title: str, abstract: XML): super().__init__() self.title = title self.abstract = abstract extractionFailedInfo = ExtractedInfo('Error', xhtml.p(class_='notice')['Error']) class ExtractionProcessor(Treeprocessor): def run(self, root: Element) -> None: # pylint: disable=attribute-defined-outside-init # Extract title from level 1 header. titleElem = root.find('./h1') assert titleElem is not None title = titleElem.text assert title is not None root.remove(titleElem) # Extract first paragraph to use as an abstract. abstractElem = root[0]