示例#1
0
        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)))
示例#2
0
    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']]
示例#3
0
 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)
示例#4
0
    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']])
示例#5
0
 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.']
示例#6
0
 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)
示例#7
0
        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
示例#8
0
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]
示例#9
0
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)
示例#10
0
 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
示例#11
0
 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)
示例#12
0
 def presentError(self, message: XML, **kwargs: object) -> XMLContent:
     yield xhtml.p(class_='notice')[message]
示例#13
0
            ]

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:' ],
示例#14
0
 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)
示例#15
0
 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)
示例#16
0
            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]