class KeyTypes(AdminPage): # For XMLRPC methods in this class. exposed = False id = widgets.HiddenField(name='id') key_name = widgets.TextField(name='key_name', label=_(u'Name')) numeric = widgets.CheckBox(name='numeric', label=_(u'Numeric')) form = HorizontalForm( 'keytypes', fields = [id, key_name, numeric], action = 'save_data', submit_text = _(u'Submit Data'), ) def __init__(self,*args,**kw): kw['search_url'] = url("/keytypes/by_name?anywhere=1"), kw['search_name'] = 'key' super(KeyTypes,self).__init__(*args,**kw) self.search_col = Key.key_name self.search_mapper = Key @expose(template='bkr.server.templates.form') def new(self, **kw): return dict( title=_(u'New Key Type'), form = self.form, action = './save', options = {}, value = kw, ) @expose(template='bkr.server.templates.form') def edit(self,**kw): values = [] if kw.get('id'): key = Key.by_id(kw['id']) values = dict( id = key.id, key_name = key.key_name, numeric = key.numeric ) return dict( form = self.form, action = './save', options = {}, value = values, ) @expose() @error_handler(edit) def save(self, **kw): if kw['id']: key = Key.by_id(kw['id']) key.key_name = kw['key_name'] else: key = Key(key_name=kw['key_name']) session.add(key) if 'numeric' in kw: key.numeric = kw['numeric'] flash( _(u"OK") ) redirect(".") @expose(template="bkr.server.templates.admin_grid") @paginate('list') def index(self,*args,**kw): keytypes = session.query(Key) list_by_letters = set([elem.key_name[0].capitalize() for elem in keytypes]) results = self.process_search(**kw) if results: keytypes = results.order_by(Key.key_name) keytypes_grid = myPaginateDataGrid(fields=[ ('Key', lambda x: make_edit_link(x.key_name, x.id)), ('Numeric', lambda x: x.numeric), (' ', lambda x: make_remove_link(x.id)), ], add_action='./new') return dict(title="Key Types", grid = keytypes_grid, search_widget = self.search_widget_form, alpha_nav_bar = AlphaNavBar(list_by_letters,self.search_name), list = keytypes) @expose() def remove(self, **kw): remove = Key.by_id(kw['id']) session.delete(remove) flash( _(u"%s Deleted") % remove.key_name ) raise redirect(".") @expose(format='json') def by_name(self,input,*args,**kw): if 'anywhere' in kw: search = Key.list_by_name(input,find_anywhere=True) else: search = Key.list_by_name(input) keys = [elem.key_name for elem in search] return dict(matches=keys)
class OSVersions(AdminPage): # For XMLRPC methods in this class. exposed = False id = widgets.HiddenField(name="id") alias = widgets.TextField(name="alias", validator=validators.UnicodeString(if_empty=None)) arches = CheckBoxList(name="arches", label="Arches", options=lambda: [(arch.id, arch.arch) for arch in Arch.query], validator=validators.Int()) osmajor_form = HorizontalForm( fields = [id, alias], submit_text = _(u"Edit OSMajor"), ) osversion_form = HorizontalForm( fields = [id, arches], action = "edit osversion", submit_text = _(u"Edit OSVersion"), ) def __init__(self,*args,**kw): kw['search_name'] = 'osversion' kw['search_url'] = url("/osversions/by_name?anywhere=1") super(OSVersions,self).__init__(*args,**kw) self.search_col = OSMajor.osmajor self.join = [OSVersion.osmajor] self.search_mapper = OSVersion self.add = False @identity.require(identity.in_group("admin")) @expose(template="bkr.server.templates.form") def edit(self, id=None, *args, **kw): try: osversion = OSVersion.by_id(id) except InvalidRequestError: flash(_(u"Invalid OSVersion ID %s" % id)) redirect(".") return dict(title = unicode(osversion), value = dict(id = osversion.id, arches = [arch.id for arch in osversion.arches]), form = self.osversion_form, action = "./save", options = None) @identity.require(identity.in_group("admin")) @expose(template="bkr.server.templates.osmajor") def edit_osmajor(self, id=None, *args, **kw): try: osmajor = OSMajor.by_id(id) except InvalidRequestError: flash(_(u"Invalid OSMajor ID %s" % id)) redirect(".") return dict(title = "OSMajor", value = osmajor, form = self.osmajor_form, action = "./save_osmajor", options = None) @identity.require(identity.in_group("admin")) @expose() @validate(form=osmajor_form) def save_osmajor(self, id=None, alias=None, *args, **kw): try: osmajor = OSMajor.by_id(id) except InvalidRequestError: flash(_(u"Invalid OSMajor ID %s" % id)) redirect(".") if osmajor.alias != alias: if alias: try: existing = OSMajor.by_name_alias(alias) except NoResultFound: pass else: flash(_(u'Cannot save alias %s, it is already used by %s') % (alias, existing)) redirect('.') osmajor.alias = alias flash(_(u"Changes saved for %s" % osmajor)) else: flash(_(u"No changes for %s" % osmajor)) redirect(".") @identity.require(identity.in_group('admin')) @expose() def save_osmajor_installopts(self, osmajor_id=None, installopts=None): try: osmajor = OSMajor.by_id(osmajor_id) except InvalidRequestError: flash(_(u"Invalid OSMajor ID %s" % id)) redirect(".") for arch, options in installopts.iteritems(): # arch=None means applied to all arches io = OSMajorInstallOptions.lazy_create(osmajor_id=osmajor.id, arch_id=Arch.by_name(arch).id if arch else None) io.ks_meta = options['ks_meta'] io.kernel_options = options['kernel_options'] io.kernel_options_post = options['kernel_options_post'] flash(_(u'Install options saved for %s') % osmajor) redirect('.') @identity.require(identity.in_group("admin")) @expose() @validate(form=osversion_form) def save(self, id=None, arches=None, *args, **kw): try: osversion = OSVersion.by_id(id) except InvalidRequestError: flash(_(u"Invalid OSVersion ID %s" % id)) redirect(".") arch_objects = [Arch.by_id(arch) for arch in arches] if osversion.arches != arch_objects: osversion.arches = arch_objects flash(_(u"Changes Saved for %s" % osversion)) else: flash(_(u"No Changes for %s" % osversion)) redirect(".") @expose(format='json') def by_name(self, input,*args,**kw): input = input.lower() if 'anywhere' in kw: search = OSVersion.list_osmajor_by_name(input, find_anywhere=True) else: search = OSVersion.list_osmajor_by_name(input) osmajors = ["%s" % (match.osmajor.osmajor) for match in search] osmajors = list(set(osmajors)) return dict(matches=osmajors) @expose(template="bkr.server.templates.admin_grid") @paginate('list',limit=50, default_order='osmajor.osmajor') def index(self,*args,**kw): osversions = self.process_search(*args,**kw) list_by_letters = [] for elem in osversions: osmajor_name = elem.osmajor.osmajor if osmajor_name: list_by_letters.append(osmajor_name[0].capitalize()) alpha_nav_data = set(list_by_letters) template_data = self.osversions(osversions,*args, **kw) nav_bar = self._build_nav_bar(alpha_nav_data,self.search_name) template_data['alpha_nav_bar'] = nav_bar template_data['search_widget'] = self.search_widget_form return template_data def osversions(self, osversions=None, *args, **kw): q = session.query(self.search_mapper) # This line +3 dupes the start of process_search if osversions is None: for j in self.join: q = q.join(j) osversions = q osversions_grid = myPaginateDataGrid(fields=[ myPaginateDataGrid.Column(name='osmajor.osmajor', getter=lambda x: make_link(url = './edit_osmajor?id=%s' % x.osmajor.id, text = x.osmajor), title='OS Major', options=dict(sortable=True)), myPaginateDataGrid.Column(name='osmajor.alias', getter=lambda x: x.osmajor.alias, title='Alias', options=dict(sortable=True)), myPaginateDataGrid.Column(name='osminor', getter=lambda x: make_link(url = './edit?id=%s' % x.id, text = x.osminor), title='OS Minor', options=dict(sortable=True)), myPaginateDataGrid.Column(name='arches', getter=lambda x: " ".join([arch.arch for arch in x.arches]), title='Arches', options=dict(sortable=True)), ]) return dict(title="OS Versions", grid = osversions_grid, addable = False, list = osversions) default = index
class Users(AdminPage): # For XMLRPC methods in this class. exposed = True user_id = widgets.HiddenField(name='user_id') user_name = widgets.TextField(name='user_name', label=_(u'Login')) display_name = widgets.TextField(name='display_name', label=_(u'Display Name')) email_address = widgets.TextField(name='email_address', label=_(u'Email Address')) password = widgets.PasswordField(name='password', label=_(u'Password')) disabled = widgets.CheckBox(name='disabled', label=_(u'Disabled')) user_form = HorizontalForm( 'User', fields=[ user_id, user_name, display_name, email_address, password, disabled ], action='save_data', submit_text=_(u'Save'), ) def __init__(self, *args, **kw): kw['search_url'] = url("/users/by_name?anywhere=1&ldap=0") kw['search_name'] = 'user' super(Users, self).__init__(*args, **kw) self.search_col = User.user_name self.search_mapper = User @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.form') def new(self, **kw): return dict( form=self.user_form, action='./save', options={}, value=kw, ) @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.user_edit_form') def edit(self, id=None, **kw): if id: user = User.by_id(id) title = _(u'User %s') % user.user_name value = user else: user = None title = _(u'New user') value = kw return_vals = dict(form=self.user_form, action='./save', title=title, options={}, value=value) if id: return_vals['groupsgrid'] = self.show_groups() else: return_vals['groupsgrid'] = None return return_vals @identity.require(identity.in_group("admin")) @expose() @validate(user_form, validators=UserFormSchema()) @error_handler(edit) def save(self, **kw): if kw.get('user_id'): user = User.by_id(kw['user_id']) else: user = User() session.add(user) user.display_name = kw['display_name'] user.user_name = kw['user_name'] user.email_address = kw['email_address'] if kw.get('disabled') != user.disabled: user.disabled = kw.get('disabled') if user.disabled: self._disable(user, method="WEBUI") if kw['password'] != user.password: user.password = kw['password'] flash(_(u"%s saved" % user.display_name)) redirect(".") def make_remove_link(self, user): if user.removed is not None: return XML('<a class="btn" href="unremove?id=%s">' '<i class="fa fa-plus"/> Re-Add</a>' % user.user_id) else: return XML('<a class="btn" href="remove?id=%s">' '<i class="fa fa-times"/> Remove</a>' % user.user_id) @expose(template="bkr.server.templates.admin_grid") @paginate('list', default_order='user_name', limit=20) def index(self, *args, **kw): users = session.query(User) list_by_letters = set( [elem.user_name[0].capitalize() for elem in users]) result = self.process_search(**kw) if result: users = result users_grid = myPaginateDataGrid(fields=[ ('Login', lambda x: make_edit_link(x.user_name, x.user_id)), ('Display Name', lambda x: x.display_name), ('Disabled', lambda x: x.disabled), ('', lambda x: self.make_remove_link(x)), ], add_action='./new') return dict(title="Users", grid=users_grid, alpha_nav_bar=AlphaNavBar(list_by_letters, 'user'), search_widget=self.search_widget_form, list=users) @identity.require(identity.in_group("admin")) @expose() def remove(self, id, **kw): try: user = User.by_id(id) except InvalidRequestError: flash(_(u'Invalid user id %s' % id)) raise redirect('.') try: self._remove(user=user, method='WEBUI') except BX, e: flash( _(u'Failed to remove User %s, due to %s' % (user.user_name, e))) raise redirect('.') else:
class Jobs(RPCRoot): # For XMLRPC methods in this class. exposed = True job_list_action_widget = JobActionWidget() job_page_action_widget = JobPageActionWidget() recipeset_widget = RecipeSetWidget() recipe_widget = RecipeWidget() priority_widget = PriorityWidget( ) #FIXME I have a feeling we don't need this as the RecipeSet widget declares an instance of it product_widget = ProductWidget() retention_tag_widget = RetentionTagWidget() job_type = {'RS': RecipeSet, 'J': Job} whiteboard_widget = JobWhiteboard() hidden_id = widgets.HiddenField(name='id') confirm = widgets.Label(name='confirm', default="Are you sure you want to cancel?") message = widgets.TextArea(name='msg', label=_(u'Reason?'), help_text=_(u'Optional')) _upload = widgets.FileField(name='filexml', label='Job XML') form = HorizontalForm('jobs', fields=[_upload], action='save_data', submit_text=_(u'Submit Data')) del _upload cancel_form = widgets.TableForm('cancel_job', fields=[hidden_id, message, confirm], action='really_cancel', submit_text=_(u'Yes')) job_form = JobForm() job_schema_doc = lxml.etree.parse( pkg_resources.resource_stream('bkr.common', 'schema/beaker-job.rng')) @classmethod def success_redirect(cls, id, url='/jobs/mine', *args, **kw): flash(_(u'Success! job id: %s' % id)) redirect('%s' % url) @expose(template='bkr.server.templates.form-post') @identity.require(identity.not_anonymous()) def new(self, **kw): return dict( title='New Job', form=self.form, action='./clone', options={}, value=kw, ) def _check_job_deletability(self, t_id, job): if not isinstance(job, Job): raise TypeError('%s is not of type %s' % (t_id, Job.__name__)) if not job.can_delete(identity.current.user): raise BeakerException( _(u'You do not have permission to delete %s' % t_id)) def _delete_job(self, t_id): job = TaskBase.get_by_t_id(t_id) self._check_job_deletability(t_id, job) Job.delete_jobs([job]) return [t_id] @expose() @identity.require(identity.not_anonymous()) @restrict_http_method('post') def delete_job_page(self, t_id): try: self._delete_job(t_id) flash(_(u'Succesfully deleted %s' % t_id)) except (BeakerException, TypeError): flash(_(u'Unable to delete %s' % t_id)) redirect('.') redirect('./mine') @expose() @identity.require(identity.not_anonymous()) @restrict_http_method('post') def delete_job_row(self, t_id): try: self._delete_job(t_id) return [t_id] except (BeakerException, TypeError), e: log.debug(str(e)) response.status = 400 return ['Unable to delete %s' % t_id]
class Preferences(RPCRoot): exposed = True delete_link = DeleteLinkWidgetForm() beaker_password = widgets.PasswordField(name='password', label='Beaker Password') root_password = widgets.TextField(name='_root_password', label='Root Password') rootpw_expiry = widgets.TextField(name='rootpw_expiry', label='Root Password Expiry', attrs={'disabled': True}) email = widgets.TextField(name='email_address', label='Email Address', validator=validators.Email()) prefs_form = HorizontalForm( 'UserPrefs', fields=[email, beaker_password, root_password, rootpw_expiry], action='save', submit_text=_(u'Change'), ) sshkey = widgets.TextArea( name='ssh_pub_key', label='Public SSH Key', validator=beaker_validators.SSHPubKey(not_empty=True)) ssh_key_add_form = InlineForm( 'ssh_key_add', fields=[sshkey], action='ssh_key_add', submit_text=_(u'Add'), ) rootpw_grid = BeakerDataGrid(fields=[ BeakerDataGrid.Column('root_password', title=_(u'Root Password'), getter=lambda x: x.value), BeakerDataGrid.Column('effective_from', title=_(u'Effective from'), getter=lambda x: x.valid_from, options=dict(datetime=True)), ]) auto_users = AutoCompleteField(name='user', search_controller=url("../users/by_name"), search_param="input", result_name="matches") submission_delegate_form = InlineForm( 'SubmissionDelegates', fields=[auto_users], action='save_data', submit_text=_(u'Add'), ) remove_submission_delegate_link = DoAndConfirmForm() def show_submission_delegates(self, user): user_fields = [ ('Submission Delegate', lambda x: x.display_name), ('Action', lambda x: self.remove_submission_delegate_link. \ display({'delegate_id': x.user_id}, action=url('remove_submission_delegate'), look='link', msg='Are you sure you want to remove %s as a submitter?' % x, action_text='Remove (-)')),] return BeakerDataGrid(fields=user_fields) @expose(template='bkr.server.templates.prefs') @identity.require(identity.not_anonymous()) def index(self, *args, **kw): user = identity.current.user # Show all future root passwords, and the previous five rootpw = ConfigItem.by_name('root_password') rootpw_values = rootpw.values().filter(rootpw.value_class.valid_from > datetime.utcnow())\ .order_by(rootpw.value_class.valid_from.desc()).all()\ + rootpw.values().filter(rootpw.value_class.valid_from <= datetime.utcnow())\ .order_by(rootpw.value_class.valid_from.desc())[:5] return dict( title='User Prefs', delete_link=self.delete_link, prefs_form=self.prefs_form, ssh_key_form=self.ssh_key_add_form, widgets={}, ssh_keys=user.sshpubkeys, value=user, rootpw=rootpw.current_value(), rootpw_grid=self.rootpw_grid, rootpw_values=rootpw_values, options=None, #Hack, to insert static content for submission_delegate remove_submission_delegate=self.remove_submission_delegate_link, submission_delegates_grid=self.show_submission_delegates(user), submission_delegate_form=self.submission_delegate_form) # XMLRPC interface @expose() @identity.require(identity.not_anonymous()) def remove_submission_delegate_by_name(self, delegate_name, service=u'XMLRPC'): user = identity.current.user try: submission_delegate = User.by_user_name(delegate_name) except NoResultFound: raise BX(_(u'%s is not a valid user name' % delegate_name)) try: user.remove_submission_delegate(submission_delegate, service=service) except ValueError: raise BX(_(u'%s is not a submission delegate of %s' % \ (delegate_name, user))) return delegate_name # UI interface @expose() @identity.require(identity.not_anonymous()) def remove_submission_delegate(self, delegate_id, service=u'WEBUI'): user = identity.current.user try: submission_delegate = User.by_id(delegate_id) except NoResultFound: flash(_(u'%s is not a valid user id' % delegate_id)) redirect('.') user.remove_submission_delegate(submission_delegate, service=service) flash(_(u'%s removed as a submission delegate' % submission_delegate)) redirect('.') # XMLRPC Interface @expose() @identity.require(identity.not_anonymous()) def add_submission_delegate_by_name(self, new_delegate_name, service=u'XMLRPC'): user = identity.current.user new_delegate = User.by_user_name(new_delegate_name) if not new_delegate: raise BX(_(u'%s is not a valid user' % new_delegate_name)) user.add_submission_delegate(new_delegate, service) return new_delegate_name # UI Interface @expose() @identity.require(identity.not_anonymous()) def add_submission_delegate(self, **kwargs): user = identity.current.user new_delegate_name = kwargs['user']['text'] new_delegate = User.by_user_name(new_delegate_name) if not new_delegate: flash(_(u'%s is not a valid user' % new_delegate_name)) redirect('.') try: user.add_submission_delegate(new_delegate, u'WEBUI') except NoChangeException, e: flash(_(unicode(e))) redirect('.') flash(_(u'Added %s as a submission delegate' % new_delegate_name)) redirect('.')
class PowerTypes(AdminPage): # For XMLRPC methods in this class. exposed = False id = widgets.HiddenField(name='id') name = widgets.TextField(name='name', label=_(u'Name')) form = HorizontalForm( 'powertypes', fields=[id, name], action='save_data', submit_text=_(u'Save'), ) def __init__(self, *args, **kw): kw['search_url'] = url("/powertypes/by_name?anywhere=1"), kw['search_name'] = 'power' super(PowerTypes, self).__init__(*args, **kw) self.search_col = PowerType.name self.search_mapper = PowerType @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.form') def new(self, **kw): return dict( form=self.form, title=_(u'New Power Type'), action='./save', options={}, value=kw, ) @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.form') def edit(self, **kw): title = _(u'New Power Type') values = [] if kw.get('id'): powertype = PowerType.by_id(kw['id']) title = powertype.name values = dict( id=powertype.id, name=powertype.name, ) return dict( form=self.form, title=title, action='./save', options={}, value=values, ) @identity.require(identity.in_group("admin")) @expose() @error_handler(edit) def save(self, **kw): if kw['id']: edit = PowerType.by_id(kw['id']) edit.name = kw['name'] elif kw.get('name'): new = PowerType(name=kw['name']) session.add(new) else: flash(_(u"Invalid Power Type entry")) redirect(".") flash(_(u"OK")) redirect(".") @expose(format='json') def by_name(self, input, *args, **kw): if 'anywhere' in kw: search = PowerType.list_by_name(input, find_anywhere=True) else: search = PowerType.list_by_name(input) powers = [elem.name for elem in search] return dict(matches=powers) @expose(template="bkr.server.templates.admin_grid") @paginate('list', default_order='name', limit=20) def index(self, *args, **kw): powertypes = session.query(PowerType) list_by_letters = set( [elem.name[0].capitalize() for elem in powertypes if elem.name]) results = self.process_search(**kw) if results: powertypes = results can_edit = identity.current.user and identity.current.user.is_admin() powertypes_grid = myPaginateDataGrid( fields=[ ('Power Type', lambda x: make_edit_link(x.name, x.id) if can_edit else x.name), (' ', lambda x: make_remove_link(x.id) if can_edit else None), ], add_action='./new' if can_edit else None) return dict(title="Power Types", grid=powertypes_grid, search_widget=self.search_widget_form, alpha_nav_bar=AlphaNavBar(list_by_letters, 'power'), list=powertypes) @identity.require(identity.in_group("admin")) @expose() def remove(self, **kw): remove = PowerType.by_id(kw['id']) session.delete(remove) flash(_(u"%s Deleted") % remove.name) raise redirect(".")
class Tasks(RPCRoot): # For XMLRPC methods in this class. exposed = True task_list_action_widget = TaskActionWidget() task_form = TaskSearchForm() task_widget = TasksWidget() _upload = widgets.FileField(name='task_rpm', label='Task RPM') form = HorizontalForm('task', fields=[_upload], action='save_data', submit_text=_(u'Upload')) del _upload @expose(template='bkr.server.templates.form-post') @identity.require(identity.not_anonymous()) def new(self, **kw): return_dict = dict( title='New Task', form=self.form, action='./save', options={}, value=kw, ) return return_dict @cherrypy.expose def filter(self, filter): """ Returns a list of tasks filtered by the given criteria. The *filter* argument must be an XML-RPC structure (dict), with any of the following keys: 'distro_name' Distro name. Include only tasks which are compatible with this distro. 'osmajor' OSVersion OSMajor, like RedHatEnterpriseLinux6. Include only tasks which are compatible with this OSMajor. 'names' Task name. Include only tasks that are named. Useful when combined with 'osmajor' or 'distro_name'. 'packages' List of package names. Include only tasks which have a Run-For entry matching any of these packages. 'types' List of task types. Include only tasks which have one or more of these types. 'valid' bool 0 or 1. Include only tasks which are valid or not. 'destructive' bool 0 or 1. Set to 0 for only non-destructive tasks. Set to 1 for only destructive tasks. The return value is an array of dicts, which are name and arches. name is the name of the matching tasks. arches is an array of arches which this task does not apply for. Call :meth:`tasks.to_dict` to fetch metadata for a particular task. .. versionchanged:: 0.9 Changed 'install_name' to 'distro_name' in the *filter* argument. """ if filter.get('distro_name'): distro = Distro.by_name(filter['distro_name']) tasks = distro.tasks() elif 'osmajor' in filter and filter['osmajor']: try: osmajor = OSMajor.by_name(filter['osmajor']) except InvalidRequestError: raise BX(_('Invalid OSMajor: %s' % filter['osmajor'])) tasks = osmajor.tasks() else: tasks = Task.query # Filter by valid task if requested if 'valid' in filter: tasks = tasks.filter(Task.valid == bool(filter['valid'])) # Filter by destructive if requested if 'destructive' in filter: tasks = tasks.filter( Task.destructive == bool(filter['destructive'])) # Filter by name if specified # /distribution/install, /distribution/reservesys if 'names' in filter and filter['names']: # if not a list, make it into a list. if isinstance(filter['names'], str): filter['names'] = [filter['names']] or_names = [] for tname in filter['names']: or_names.append(Task.name == tname) tasks = tasks.filter(or_(*or_names)) # Filter by packages if specified # apache, kernel, mysql, etc.. if 'packages' in filter and filter['packages']: # if not a list, make it into a list. if isinstance(filter['packages'], str): filter['packages'] = [filter['packages']] tasks = tasks.filter( Task.runfor.any( or_(*[ TaskPackage.package == package for package in filter['packages'] ]))) # Filter by type if specified # Tier1, Regression, KernelTier1, etc.. if 'types' in filter and filter['types']: # if not a list, make it into a list. if isinstance(filter['types'], str): filter['types'] = [filter['types']] tasks = tasks.join('types') or_types = [] for type in filter['types']: try: tasktype = TaskType.by_name(type) except InvalidRequestError, err: raise BX(_('Invalid Task Type: %s' % type)) or_types.append(TaskType.id == tasktype.id) tasks = tasks.filter(or_(*or_types)) # Return all task names return [ dict(name=task.name, arches=[str(arch.arch) for arch in task.excluded_arch]) for task in tasks ]
class Configuration(AdminPage): exposed = False id = widgets.HiddenField(name='id') value_str = widgets.TextArea(name='value', label=_(u'Value')) value_int = widgets.TextField(name='value', label=_(u'Value'), validator=validators.Int()) valid_from = widgets.TextField( name='valid_from', label=_(u'Effective from date'), help_text= u"Enter date and time (YYYY-MM-DD HH:MM) in the future or leave blank for setting to take immediate effect" ) string_form = HorizontalForm( 'configitem', fields=[id, value_str, valid_from], action='save_data', submit_text=_(u'Save'), ) int_form = HorizontalForm( 'configitem', fields=[id, value_int, valid_from], action='save_data', submit_text=_(u'Save'), ) value_grid = BeakerDataGrid(fields=[ ('Value', lambda x: x.value), ('Effective from', lambda x: x.valid_from, {'datetime': True}), ('Set by', lambda x: x.user), ('Date set', lambda x: x.modified, {'datetime': True}), ('', lambda x: x.valid_from <= datetime.utcnow() and " " or \ make_link(url = 'delete?item=%s&id=%s' % (x.config_item.id, x.id), text = 'Delete')), ]) def __init__(self, *args, **kw): kw['search_url'] = url("/configuration/by_name?anywhere=1"), kw['search_name'] = 'name' super(Configuration, self).__init__(*args, **kw) self.search_col = ConfigItem.name self.search_mapper = ConfigItem @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.config_edit') def edit(self, **kw): if kw.get('id'): item = ConfigItem.by_id(kw['id']) form_values = dict(id=item.id, numeric=item.numeric, value=item.current_value()) else: flash(_(u"Error: No item ID specified")) raise redirect(".") # Show all future values, and the previous five config_values = item.values().filter(item.value_class.valid_from > datetime.utcnow()).order_by(item.value_class.valid_from.desc()).all() \ + item.values().filter(item.value_class.valid_from <= datetime.utcnow()).order_by(item.value_class.valid_from.desc())[:5] if item.readonly: form = None elif item.numeric: form = self.int_form else: form = self.string_form return dict( title=item.name, subtitle=item.description, form=form, action='./save', options={}, value=form_values, list=config_values, grid=self.value_grid, warn_msg=item.readonly and "This item is read-only", ) @expose() @error_handler(edit) @identity.require(identity.in_group("admin")) def save(self, **kw): if 'id' in kw and kw['id']: item = ConfigItem.by_id(kw['id']) else: flash(_(u"Error: No item ID")) raise redirect(".") if kw['valid_from']: try: valid_from = datetime.strptime(kw['valid_from'], '%Y-%m-%d %H:%M') except ValueError: flash( _(u"Invalid date and time specification, use: YYYY-MM-DD HH:MM" )) raise redirect("/configuration/edit?id=%d" % item.id) else: valid_from = None try: item.set(kw['value'], valid_from, identity.current.user) except Exception, msg: flash(_(u"Failed to save setting: %s" % msg)) raise redirect("/configuration/edit?id=%d" % item.id) flash(_(u"%s saved" % item.name)) redirect(".")
class CSV(RPCRoot): # For XMLRPC methods in this class. exposed = False export_help_text = XML( u'<span>Refer to the <a href="http://beaker-project.org/docs/' 'admin-guide/interface.html#export" target="_blank">' 'documentation</a> to learn more about the exported data.</span>' ).expand() import_help_text = XML( u'<span>Refer to the <a href="http://beaker-project.org/docs/' 'admin-guide/interface.html#import" target="_blank">' 'documentation</a> for details about the supported CSV format.</span>' ).expand() upload = widgets.FileField(name='csv_file', label='Import CSV', \ help_text = import_help_text) download = RadioButtonList(name='csv_type', label='CSV Type', options=[ ('system', 'Systems'), ('system_id', 'Systems (for modification)'), ('labinfo', 'System LabInfo'), ('power', 'System Power'), ('exclude', 'System Excluded Families'), ('install', 'System Install Options'), ('keyvalue', 'System Key/Values'), ('system_pool', 'System Pools'), ('user_group', 'User Groups') ], default='system', help_text=export_help_text) importform = HorizontalForm( 'import', fields=[upload], action='import data', submit_text=_(u'Import CSV'), ) exportform = HorizontalForm( 'export', fields=[download], action='export data', submit_text=_(u'Export CSV'), ) @expose(template='bkr.server.templates.form') @identity.require(identity.not_anonymous()) def index(self, **kw): return dict( form=self.exportform, title=_(u'CSV Export'), action='./action_export', options={}, value=kw, ) @expose(template='bkr.server.templates.form-post') @identity.require(identity.in_group('admin')) def csv_import(self, **kw): return dict( form=self.importform, title=_(u'CSV Import'), action='./action_import', options={}, value=kw, ) @expose() @identity.require(identity.not_anonymous()) def action_export(self, csv_type, *args, **kw): file = NamedTemporaryFile() log = self.to_csv(file, csv_type) file.seek(0) return serve_file(file.name, contentType="text/csv", disposition="attachment", name="%s.csv" % csv_type) def _import_row(self, data, log): if data['csv_type'] in system_types and ('fqdn' in data or 'id' in data): if data.get('id', None): try: system = System.query.filter(System.id == data['id']).one() except InvalidRequestError as e: raise ValueError('Non-existent system id') else: try: system = System.query.filter( System.fqdn == data['fqdn']).one() except InvalidRequestError: # Create new system with some defaults # Assume the system is broken until proven otherwise. # Also assumes its a machine. we have to pick something system = System(fqdn=data['fqdn'], owner=identity.current.user, type=SystemType.machine, status=SystemStatus.broken) session.add(system) # new systems are visible to everybody by default system.custom_access_policy = SystemAccessPolicy() system.custom_access_policy.add_rule(SystemPermission.view, everybody=True) if not system.can_edit(identity.current.user): raise ValueError('You are not the owner of %s' % system.fqdn) # we change the FQDN only when a valid system id is supplied if not data.get('id', None): data.pop('fqdn') self.from_csv(system, data, log) elif data['csv_type'] == 'user_group' and 'user' in data: user = User.by_user_name(data['user']) if user is None: raise ValueError('%s is not a valid user' % data['user']) CSV_GroupUser.from_csv(user, data, log) else: raise ValueError('Invalid csv_type %s or missing required fields' % data['csv_type']) @expose(template='bkr.server.templates.csv_import') @identity.require(identity.in_group('admin')) def action_import(self, csv_file, *args, **kw): """ TurboGears method to import data from csv """ log = [] try: # ... process CSV file contents here ... missing = object() reader = UnicodeDictReader(csv_file.file, restkey=missing, restval=missing) is_empty = True for data in reader: is_empty = False if missing in data: log.append('Too many fields on line %s (expecting %s)' % (reader.line_num, len(reader.fieldnames))) continue if any(value is missing for value in data.itervalues()): missing_fields = [ field for field, value in data.iteritems() if value is missing ] log.append('Missing fields on line %s: %s' % (reader.line_num, ', '.join(missing_fields))) continue if 'csv_type' not in data: log.append('Missing csv_type on line %s' % reader.line_num) continue try: with session.begin_nested(): self._import_row(data, log) except Exception, e: # log and continue processing more rows log.append('Error importing line %s: %s' % (reader.line_num, e)) if is_empty: log.append('Empty CSV file supplied') except csv.Error, e: session.rollback() log.append('Error parsing CSV file: %s' % e)
class RetentionTag(AdminPage): exposed = False tag = widgets.TextField(name='tag', label=_(u'Tag')) default = widgets.SingleSelectField(name='default', label=(u'Default'), options=[(0,'False'),(1,'True')]) id = widgets.HiddenField(name='id') expire_in_days = widgets.TextField(name='expire_in_days', label=_(u'Expire In Days'), help_text=_(u'Number of days after which jobs will expire')) needs_product = widgets.CheckBox('needs_product', label=u'Needs Product') tag_form = HorizontalForm( 'Retention Tag', fields = [tag, default, expire_in_days, needs_product, id], action = 'save_data', submit_text = _(u'Save'), ) def __init__(self,*args,**kw): kw['search_url'] = url("/retentiontag/by_tag") kw['search_name'] = 'tag' kw['widget_action'] = './admin' super(RetentionTag,self).__init__(*args,**kw) self.search_col = Tag.tag self.search_mapper = Tag @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.form') def new(self, **kw): return dict( form = self.tag_form, action = './save', options = {}, value = kw, ) @identity.require(identity.in_group("admin")) @expose() @validate(form=tag_form, validators=TagFormSchema()) @error_handler(new) def save(self, id=None, **kw): retention_tag = Tag(kw['tag'], kw['default'], kw['needs_product']) retention_tag.expire_in_days = kw['expire_in_days'] session.add(retention_tag) flash(_(u"OK")) redirect("./admin") @expose(format='json') def by_tag(self, input, *args, **kw): input = input.lower() search = Tag.list_by_tag(input) tags = [match.tag for match in search] return dict(matches=tags) @expose(template="bkr.server.templates.admin_grid") @identity.require(identity.in_group('admin')) @paginate('list', default_order='tag', limit=20) def admin(self, *args, **kw): tags = self.process_search(*args, **kw) alpha_nav_data = set([elem.tag[0].capitalize() for elem in tags]) nav_bar = self._build_nav_bar(alpha_nav_data,'tag') template_data = self.tags(tags, identity.current.user, *args, **kw) template_data['alpha_nav_bar'] = nav_bar template_data['addable'] = True return template_data @identity.require(identity.in_group('admin')) @expose() def delete(self, id): tag = Tag.by_id(id) if not tag.can_delete(): # Trying to be funny... flash(u'%s is not applicable for deletion' % tag.tag) redirect('/retentiontag/admin') session.delete(tag) flash(u'Successfully deleted %s' % tag.tag) redirect('/retentiontag/admin') @identity.require(identity.in_group("admin")) @expose(template='bkr.server.templates.form') def edit(self, id, **kw): tag = Tag.by_id(id) return dict( form = self.tag_form, title=_(u'Retention tag %s' % tag.tag), action = './save_edit', options = {}, value = tag, disabled_fields = ['tag'] ) @identity.require(identity.in_group("admin")) @expose() @validate(form=tag_form, validators=TagFormSchema()) @error_handler(edit) def save_edit(self, id=None, **kw): retention_tag = Tag.by_id(id) retention_tag.tag = kw['tag'] retention_tag.default = kw['default'] retention_tag.expire_in_days = kw['expire_in_days'] retention_tag.needs_product = kw['needs_product'] flash(_(u"OK")) redirect("./admin") @expose(template="bkr.server.templates.grid") @paginate('list', default_order='tag', limit=20) def index(self, *args, **kw): return self.tags() def tags(self, tags=None, user=None, *args, **kw): if tags is None: tags = Tag.get_all() def show_delete(x): if x.can_delete(): return XML('<a class="btn" href="./delete/%s">' '<i class="fa fa-times"/> Delete</a>' % x.id) else: return None def show_tag(x): if x.is_default: #If we are the default, we can't change to not default return x.tag elif user and user.is_admin(): return make_edit_link(x.tag,x.id) else: #no perms to edit return x.tag my_fields = [myPaginateDataGrid.Column(name='tag', title='Tags', getter=lambda x: show_tag(x),options=dict(sortable=True)), myPaginateDataGrid.Column(name='default', title='Default', getter=lambda x: x.default,options=dict(sortable=True)), myPaginateDataGrid.Column(name='delete', title='Delete', getter=lambda x: show_delete(x))] tag_grid = myPaginateDataGrid(fields=my_fields, add_action='./new') return_dict = dict(title='Tags', grid = tag_grid, search_bar = None, search_widget = self.search_widget_form, list = tags) return return_dict