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 presentFeed(self, proc: Processor, ccURL: str) -> XMLContent: projectName = proc.project.name yield atom.title[f'{projectName} SoftFab - Recent Jobs'] yield atom.subtitle[ f'The most recent jobs running in the {projectName} SoftFab'] yield atom.id[f'{rootURL}jobs'] yield atom.updated[self.presentTime(getTime())] yield atom.generator(uri=HOMEPAGE, version=VERSION)['SoftFab'] # TODO: Akregator for KDE4 won't show the icon, no matter what I try. # Might be related to Konqueror often losing the icon. yield atom.icon[ccURL + 'styles/SoftFabIcon.png'] #yield atom.link( #rel = 'shortcut icon', #href = ccURL + 'styles/SoftFabIcon.png', #type = 'image/png', #) # Link to the Control Center. yield atom.link( rel='alternate', href=ccURL + 'Home', type='text/html', ) # Link to the feed itself. yield atom.link( rel='self', href=ccURL + pageURL(self.name, proc.args), type='application/atom+xml', ) for job, jobTable in zip(proc.jobs, proc.tables): yield atom.entry[self.presentJob(proc, ccURL, job, jobTable)]
def createJobsURL(jobIDs: Sequence[str]) -> str: '''Returns a URL of a page that contains details about the given jobs. ''' if len(jobIDs) == 1: return createJobURL(jobIDs[0]) else: # Note: This also works fine for zero jobs. return pageURL('ShowJobs', JobIdSetArgs(jobId=jobIDs))
def createRunURL(run: TaskRun, report: Optional[str] = 'overview') -> str: """Return a URL of a page showing details of a task run.""" jobId = run.getJob().getId() taskName = run.getName() return pageURL( 'Task', TaskReportArgs(jobId=jobId, taskName=taskName, report=report) )
def makeURL(taskName: str, beginTime: int, endTime: int) -> str: if taskName is None: # TODO: The links which match all tasks are currently disabled, # but are also no longer accepted by ReportTasks. taskName = '*' return pageURL( 'ReportTasks', ReportTaskArgs(task=[taskName], ctabove=beginTime, ctbelow=endTime))
def processSelection(self) -> None: db = self.db args = self.args tagCache = self.tagCache action = args.action selected = {recordId for recordId in args.sel if recordId in db} if action == 'remove': selected -= args.bsk else: for value, label_, page in self.iterActions(): if action == value: raise Redirect(pageURL(page, SelectArgs(sel=selected))) # Determine tag key to filter by. # Empty string as key shows all records (all-pass filter). tagKey = args.tagkey tagKeys = tagCache.getKeys() if tagKey and tagKey not in tagKeys: # Drop non-existing key. tagKey = None if tagKey is None and tagKeys: # Pick default key. tagKey = tagKeys[0] # Determine tag value to filter by. # Empty string as value shows records that are not tagged # with the given tag key. if tagKey: tagValue = args.tagvalue if tagValue: if not tagCache.hasValue(tagKey, tagValue): # Unknown tag; drop non-existing value. tagValue = None if tagValue is None: # Pick default value. # If nothing is tagged with this key, show untagged. tagValue = min(tagCache.getValues(tagKey), default='') else: # A value only has meaning if we have a key. tagValue = None if (selected != args.sel or tagKey != args.tagkey or tagValue != args.tagvalue): raise ArgsCorrected(args, sel=selected, tagkey=tagKey, tagvalue=tagValue) filteredRecords = self.__filterRecords(tagKey, tagValue) self.selected = selected self.selectedRecords = [db[recordId] for recordId in selected] self.filtered = {record.getId() for record in filteredRecords} self.filteredRecords = filteredRecords
def getPageURL(cls, page: str, args: Optional[ArgsT]) -> Optional[str]: '''Gets the URL of another page, relative to this page. This URL includes in its query part the arguments shared between this page and the other page. If the other page requires arguments not present in this page, None is returned. ''' otherArgClass = cls.getPageInfo(page)['pageClass'].Arguments if args is None: # No arguments available. try: emptyArgs = otherArgClass() except KeyError: # Other page has mandatory arguments. return None else: return pageURL(page, emptyArgs) # Only gather shared arguments that are mandatory in at least one # of the pages. In practice this preserves the arguments we want # to share across pages, such as selected names, while dropping # arguments such as sort order. ourArgClass = args.__class__ sharedArgs = {} for name in otherArgClass.iterMandatoryArgs(): if hasattr(args, name) and args.isArgument(name): if getattr(ourArgClass, name) == getattr(otherArgClass, name): sharedArgs[name] = getattr(args, name) else: # We share a name with a mandatory argument, but it's not # the same argument. return None else: # Mandatory argument missing. return None for name in args.iterMandatoryArgs(): if hasattr(otherArgClass, name) and otherArgClass.isArgument(name): if getattr(ourArgClass, name) == getattr(otherArgClass, name): sharedArgs[name] = getattr(args, name) return pageURL(page, otherArgClass(sharedArgs))
async def process(self, req: Request['ChangePassword_POST.Arguments'], user: User) -> None: # pylint: disable=attribute-defined-outside-init if req.args.action is Actions.CANCEL: page = cast(ChangePassword_POST, self.page) raise Redirect(page.getCancelURL(req.args)) elif req.args.action is Actions.CHANGE: userDB = self.userDB userName = user.name # get current logged-in user if userName is None: self.retry = False raise PresentableError( xhtml["Anonymous user has no password."]) # Perform sanity checks on new password. password = req.args.password newCredentials = Credentials(userName, password) if password == req.args.password2: quality = passwordQuality(newCredentials) else: quality = PasswordMessage.MISMATCH if quality is not PasswordMessage.SUCCESS: self.retry = True raise PresentableError(xhtml[passwordStr[quality]]) oldCredentials = Credentials(userName, req.args.loginpass) try: user_ = await authenticateUser(userDB, oldCredentials) except LoginFailed as ex: self.retry = True raise PresentableError( xhtml["Verification of old password failed", f": {ex.args[0]}" if ex.args else None, "."]) # Apply changes. try: setPassword(userDB, newCredentials) except ValueError as ex: self.retry = True raise PresentableError(xhtml[ex.args[0]]) else: # Successfully changed password raise Redirect( pageURL( 'ChangePassword', ChangePassword_GET.Arguments( user=userName, msg=PasswordMessage.SUCCESS))) else: assert False, req.args.action
async def process(self, req: Request['ResourceIndex_POST.Arguments'], user: User) -> None: args = req.args # Get resource record. resource = self.getResource(args.resource) # Update suspend state. resource.setSuspend(args.action is Actions.SUSPEND, user.name or 'anonymous') # Show new status, forget commands. raise Redirect( pageURL('ResourceIndex', ResourceIndex_GET.Arguments.subset(args)))
async def process(self, req: Request['ScheduleIndex_POST.Arguments'], user: User) -> None: actions = cast(Mapping[str, str], req.args.action) for scheduleId, action in actions.items(): # Toggle suspend. scheduled = self.scheduleDB.get(scheduleId) # TODO: Report when action is not possible, instead of ignoring. if scheduled is not None: checkPrivilegeForOwned(user, 's/m', scheduled, ('suspend/resume this schedule', 'suspend/resume schedules')) if not scheduled.isDone(): scheduled.setSuspend(action is Actions.SUSPEND) raise Redirect( pageURL('ScheduleIndex', ScheduleIndex_GET.Arguments.subset(req.args)))
def subItemRelURL(self, subPath: str) -> str: '''Gets a relative URL to the given item subpath. ''' return pageURL(f'{self.page.name}/{subPath}', self.args)
def createProductDetailsURL(productDefId: str) -> str: return pageURL( 'ProductDetails', ProductDefIdArgs(id = productDefId) )
def createFrameworkDetailsURL(frameworkId: str) -> str: return pageURL( 'FrameworkDetails', FrameworkIdArgs(id = frameworkId) )
def logoutURL(req: Request) -> str: """Returns a URL of the Logout page, so that it returns to the request's URL after the user has logged out. """ return pageURL('Logout', URLArgs(url=req.getURL()))
def createUserDetailsURL(userId: str) -> str: return pageURL('UserDetails', UserIdArgs(user = userId))
def createScheduleDetailsURL(scheduleId: str) -> str: return pageURL('ScheduleDetails', ScheduleIdArgs(id=scheduleId))
def setPasswordURL(token: Credentials) -> str: return rootURL + pageURL('SetPassword', PasswordSetArgs(token=token.name, secret=token.password))
def linkTab(tab: int, text: str) -> XMLNode: return xhtml.td(class_='navother')[xhtml.a(href=pageURL( proc.page.name, proc.args.override(**{tabOffsetField: tab * recordsPerPage})), class_='nav')[text]]
def loginURL(self, **kwargs: Any) -> str: userName = cast(Optional[str], kwargs['proc'].userName) return pageURL('Login', LoginNameArgs(loginname=userName))
def createJobURL(jobId: str) -> str: '''Returns a URL of a page that contains details about the given job. ''' return pageURL('ShowReport', JobIdArgs(jobId = jobId))