def change_pr_approval (db, cl, nodeid, new_values) : common.require_attributes \ (_, cl, nodeid, new_values, 'purchase_request', 'order') app = cl.getnode (nodeid) rol = new_values.get ('role', cl.get (nodeid, 'role')) rid = new_values.get ('role_id', cl.get (nodeid, 'role_id')) if rol and not rid : new_values ['role_id'] = db.pr_approval_order.lookup (rol) if 'status' in new_values : pr_open = db.pr_status.lookup ('open') pr_approving = db.pr_status.lookup ('approving') os = app.status ns = new_values ['status'] if os != ns : pr = db.purchase_request.getnode (app.purchase_request) if pr.status not in (pr_open, pr_approving) : raise Reject (_ ("No change of approvals for this PR")) new_values ['by'] = db.getuid () new_values ['date'] = Date ('.') approvals = cl.filter (None, dict (purchase_request = pr.id)) assert nodeid in approvals elif new_values.keys () == ['role_id'] : n = db.pr_approval_order.get (new_values ['role_id'], 'role') if cl.get (nodeid, 'role') != n : raise Reject ("Inconsistent role_id") elif app.status != db.pr_approval_status.lookup ('undecided') : raise Reject (_ ("May not change approval status parameters")) elif 'msg' in new_values and new_values ['msg'] is not None : # Don't link random message to approval if status isn't changing del new_values ['msg']
def check_range(db, nodeid, uid, first_day, last_day): """ Check length of range and if there are any records in the given time-range for this user. This means either the first day of an existing record is inside the new range or the last day is inside the new range or the first day is lower than the first day *and* the last day is larger (new interval is contained in existing interval). """ if first_day > last_day: raise Reject(_("First day may not be after last day")) if (last_day - first_day) > Interval('30d'): raise Reject(_("Max. 30 days for single leave submission")) range = common.pretty_range(first_day, last_day) both = (first_day.pretty(';%Y-%m-%d'), last_day.pretty('%Y-%m-%d;')) stati = [ x for x in db.leave_status.getnodeids(retired=False) if db.leave_status.get(x, 'name') not in ('declined', 'cancelled') ] for f, l in ((range, None), (None, range), both): d = dict(user=uid, status=stati) if f: d['first_day'] = f if l: d['last_day'] = l r = [x for x in db.leave_submission.filter(None, d) if x != nodeid] if r: raise Reject \ (_ ("You already have vacation requests in this time range"))
def check_tp_cc_consistency (db, cl, nodeid, new_values, org = None) : """ Check that the organisation in tp or cc is correct and consistent with the organisation stored in the PR. Also check that the tp or cc is valid. """ pr = cl.getnode (nodeid) tc = new_values.get ('time_project', pr.time_project) cc = new_values.get ('sap_cc', pr.sap_cc) # Can happen only for order item: if not tc and not cc : return org = org or pr.organisation if tc : node = db.time_project.getnode (tc) st = db.time_project_status.getnode (node.status) if not st.active : time_project = _ ('time_project') name = node.name + ' ' + node.description raise Reject \ (_ ("Non-active %(time_project)s: %(name)s") % locals ()) else : node = db.sap_cc.getnode (cc) if not node.valid : sap_cc = _ ('sap_cc') name = node.name raise Reject (_ ("Invalid %(sap_cc)s: %(name)s") % locals ()) if node.organisation != org : o1 = db.organisation.get (org, 'name') if not node.organisation : raise Reject (_ ("Organisation of CC/TC is empty")) o2 = db.organisation.get (node.organisation, 'name') raise Reject \ ( _("Organisation must be consistent with CC/TC: got %s expect %s") % (o1, o2) )
def _audit_update_active(db, c, nodeid, newvalues): new_status = newvalues.get('status') old_status = c.get(nodeid, 'status') if new_status == old_status: return # Prepare auxiliary data for id in db.cstatus.list(): title = db.cstatus.get(id, 'title') if title == 'open': s_open = id elif title == 'done': s_done = id elif title == 'n/a': s_na = id elif title == 'inactive': s_inactive = id else: raise Exception('title: %s' % title) closed_statuses = ( s_done, s_na, ) # Find reverse dependencies dependencies = {} all_ids = c.list() for id in all_ids: dependencies[id] = [] for id in all_ids: for dep_id in c.get(id, 'prereq'): dependencies[dep_id].append(id) # If activated, check it doesn't break dependencies if old_status == s_inactive: for id in c.get(nodeid, 'prereq'): if c.get(id, 'status') not in closed_statuses: raise Reject("Prerequisity checkpoint not yet completed: %s" % (c.get(id, 'title'), )) # If deactivated, check it doesn't break dependencies if new_status == s_inactive: for id in dependencies[nodeid]: if c.get(id, 'status') in closed_statuses: raise Reject("Dependent checkpoint already closed: %s" % (c.get(id, 'title'), )) # If deactivated or reopened, deactivate open dependants if new_status in ( s_inactive, s_open, ): for id in dependencies[nodeid]: if c.get(id, 'status') == s_open: c.set(id, status=s_inactive) # If closed, activate inactive dependants if new_status in closed_statuses and old_status not in closed_statuses: for id in dependencies[nodeid]: if c.get(id, 'status') == s_inactive: for dep_id in c.get(id, 'prereq'): if dep_id != nodeid and c.get( dep_id, 'status') not in closed_statuses: break else: c.set(id, status=s_open)
def find_time_records(db, cl, nodeid, new_values): """ Search for existing time records when start/end date changes. Reject if valid records other than public holidays are found. """ if 'valid_to' not in new_values and 'valid_from' not in new_values: return dyn = cl.getnode(nodeid) valid_to = new_values.get('valid_to') valid_from = new_values.get('valid_from') next = user_dynamic.next_user_dynamic(db, dyn) prev = user_dynamic.prev_user_dynamic(db, dyn) to = next and (next.valid_from - common.day) frm = prev and (prev.valid_to) ranges = dict \ ( valid_to = common.pretty_range (valid_to, to) , valid_from = common.pretty_range (frm, valid_from - common.day) ) gaps = dict \ ( valid_to = not next or next.valid_from > valid_to , valid_from = not prev or prev.valid_to < valid_from ) msgs = dict \ ( valid_to = _ ( "There are (non public holiday) " "time records at or after %s" ) , valid_from = _ ( "There are (non public holiday) " "time records before %s" ) ) for k in ('valid_to', 'valid_from'): value = new_values.get(k) if value is not None and gaps[k]: trs = db.time_record.filter \ ( None , { 'daily_record.user': dyn.user , 'daily_record.date': ranges [k] } ) # loop for checking if time recs are public holiday for id in trs: tr = db.time_record.getnode(id) # case where no wp was entered yet if tr.wp is None: raise Reject(msgs[k] % value.pretty(common.ymd)) # case where wp was set wp = db.time_wp.getnode(tr.wp) tc = db.time_project.getnode(wp.project) if not tc.is_public_holiday: raise Reject(msgs[k] % value.pretty(common.ymd)) # loop entirely for retiring public holidys for id in trs: tr = db.time_record.getnode(id) assert tr.wp wp = db.time_wp.getnode(tr.wp) tc = db.time_project.getnode(wp.project) assert tc.is_public_holiday db.time_record.retire(id)
def new_pr_approval (db, cl, nodeid, new_values) : common.require_attributes \ (_, cl, nodeid, new_values, 'purchase_request', 'order') if ( not new_values.get ('user', None) and not new_values.get ('role', None) ) : raise Reject (_ ("user or role required")) if 'role' in new_values and 'role_id' not in new_values : raise Reject (_ ("No role id")) new_values ['status'] = db.pr_approval_status.lookup ('undecided')
def check_wp(db, wp_id, user, first_day, last_day, comment): wp = db.time_wp.getnode(wp_id) tp = db.time_project.getnode(wp.project) if not tp.approval_required: raise Reject(_("No approval required for work package")) if not wp.is_public and user not in wp.bookers: raise Reject(_("User may not book on work package")) if first_day < wp.time_start or wp.time_end and last_day > wp.time_end: raise Reject(_("Work package not valid during vacation time")) if tp.is_special_leave and not comment: raise Reject(_("Comment is required for special leave"))
def audit_user(db, c, nodeid, newvalues): if newvalues.get('username') not in ( 'admin', 'anonymous', ): newvalues['roles'] = 'User' username = newvalues.get('username') if not username: Reject("Username may not be empty") if not re.match('^[a-z]+$', username): Reject("Only lowercase English letters allowed in username")
def _make_project (db, c, nodeid, newvalues): name = newvalues['project'] if not newvalues.get ('user'): raise Reject ("No project creator given") # Create project directory project_directory = os.path.join (os.path.dirname (db.config.HOME), name) try: os.mkdir (project_directory) except OSError: raise Reject ("Project name <em>%s</em> is already taken" % (name,)) # Create the project try: # Create project directory template = 'waassistant' template_directory = os.path.dirname (project_directory) templates = roundup.init.listTemplates (template_directory) if not templates.has_key (template): raise Exception ("Template `waassistant' unavailable") roundup.init.install (project_directory, templates[template]['path']) # Update config file url = os.path.dirname (os.path.dirname (db.config.TRACKER_WEB)) + '/' + name + '/' config_file = os.path.join (project_directory, 'config.ini') config_file_tmp = config_file + '.tmp' os.rename (config_file, config_file_tmp) infile, outfile = open (config_file_tmp), open (config_file, 'w') for line in infile: if re.match ('^#?web =', line): line = 'web = %s\n' % (url,) elif re.match ('name =', line): line = 'name = %s\n' % (name,) outfile.write (line) infile.close (), outfile.close () os.remove (config_file_tmp) # Initialize project f = open (os.path.join (os.path.join (db.config.TRACKER_HOME, 'db'), 'backend_name')) backend = f.read () f.close () try: tracker = roundup.instance.open (project_directory) if tracker.exists (): tracker.nuke () except: pass roundup.init.write_select_db (project_directory, backend) tracker = roundup.instance.open (project_directory) tracker.init (roundup.password.Password ('dummypassword')) except Exception, e: try: os.rmdir (project_directory) except: pass raise Reject ("Project creation failed: %s" % (e,))
def check_metadata (db, cl, nodeid, new_values) : """ The metadata field should be in json. This field should have the following format: { 'system_name' : 'jira' , 'levels' : [ { 'level' : 1 , 'level_name' : 'Project' , 'name' : 'Project-Name' , 'id' : '4711' , ... ] } Note that both, the top-level system_name and levels are required. In the levels array at least one member is required. The level is an integer value and levels must start with 1 and be tightly numbered (without jumps of the counter). The level_name and name of the respective item on that level depends on the remote system. The id is a string because some systems may use non-numeric ids here. The fields shown are all required, additional fields may be present. """ if 'metadata' not in new_values : return metadata = new_values ['metadata'] # Allow empty if not metadata : return obj = json.loads (metadata) if not isinstance (obj, type ({})) : raise Reject (_ ("Invalid metadata, object not a dict")) if 'system_name' not in obj or 'levels' not in obj : raise Reject (_ ("Invalid metadata, required fields missing")) if not isinstance (obj ['levels'], type ([])) : raise Reject (_ ("Invalid metadata, levels must be array")) for n, lvl in enumerate (obj ['levels']) : if not isinstance (lvl, type ({})) : raise Reject (_ ("Invalid metadata, level not a dict")) for k in 'level', 'level_name', 'name', 'id' : if k not in lvl : raise Reject \ (_ ('Invalid metadata, required field "%s" ' 'in level missing' ) % k ) if k != 'level' : if not isinstance (lvl ['k'], type (u'')) : raise Reject \ (_ ('Invalid metadata: %s: String expected') % k) if int (lvl ['level']) != n + 1 : raise Reject (_ ('Invalid metadata, level: expect: %d' % (n+1)))
def check_travel_flag (db, cl, nodeid, new_values) : """ Ensure that the travel flag cannot be set and that WPs with travel flag may not be resurrected (change the closed date) """ # Allow 'admin' to do this anyway, needed for regression tests that # use a WP with travel set. if db.getuid () == '1' : return if new_values.get ('travel', False) : raise Reject ("Travel flag must not be set") if nodeid and 'time_end' in new_values : wp = db.time_wp.getnode (nodeid) if wp.travel and wp.time_end : raise Reject ("Travel WP may not be resurrected")
def audit_register_user (db, c, nodeid, newvalues): configuration = UserConfig (os.path.join (os.path.dirname (db.dir), 'configwa.ini')) wausers_path = configuration.WAUSERS_HOME if wausers_path: if not nodeid and not newvalues.has_key ('wausername'): if newvalues.get ('username') not in ('admin', 'anonymous',): if configuration.WAUSERS_SAME_LOGIN: newvalues['wausername'] = newvalues.get ('username') else: raise Reject ("No WAusers name given") if wausers_path not in sys.path: sys.path.append (wausers_path) import waauth if newvalues.has_key ('wausername'): if not waauth.check_user (newvalues['wausername'], configuration.WAUSERS_HOME): raise Reject ("WAusers name `%s' does not exist" % (newvalues['wausername'],))
def auto_wp_check(db, cl, nodeid, new_values): """ Check auto_wp properties """ # These properties must not change: props = \ ( 'contract_type' , 'org_location' , 'time_project' ) if nodeid: for p in props: if p in new_values: raise Reject(_('Property "%s" must not change') % _(p)) else: common.require_attributes \ ( _, cl, nodeid, new_values , 'org_location' , 'time_project' , 'name' ) if 'durations_allowed' not in new_values: new_values['durations_allowed'] = False if 'is_valid' not in new_values: new_values['is_valid'] = False if 'all_in' not in new_values: new_values['all_in'] = True
def requester_chg (db, cl, nodeid, new_values) : if 'requester' in new_values : st_rej = db.pr_status.lookup ('rejected') st_open = db.pr_status.lookup ('open') ost = cl.get (nodeid, 'status') if ost != st_open and ost != st_rej : raise Reject (_ ("Requester may not be changed"))
def check_dyn_user_params(db, user, first_day, last_day): d = first_day ctype = -1 # contract_type is either None or a string, can't be numeric while d <= last_day: dyn = user_dynamic.get_user_dynamic(db, user, d) if not dyn: ymd = common.ymd raise Reject(_("No dynamic user data for %s") % d.pretty(ymd)) if dyn.vacation_yearly is None: raise Reject(_("No yearly vacation for this user")) if dyn.vacation_day is None or dyn.vacation_month is None: raise Reject(_("Vacation date setting is missing")) if ctype != dyn.contract_type and ctype != -1: raise Reject(_("Differing contract types in range")) ctype = dyn.contract_type d += common.day
def creator_resolution(db, cl, nodeid, newvalues): '''Catch attempts to set the status to "resolved" - if the assignedto user isn't the creator, then set the status to "in-progress" (try "confirm-done" first though, but "classic" Roundup doesn't have that status) ''' if 'status' not in newvalues: return # get the resolved state ID resolved_id = db.status.lookup('resolved') if newvalues['status'] != resolved_id: return # check the assignedto assignedto = newvalues.get('assignedto', cl.get(nodeid, 'assignedto')) creator = cl.get(nodeid, 'creator') if assignedto == creator: if db.getuid() != creator: name = db.user.get(creator, 'username') raise Reject('Only the creator (%s) may close this issue' % name) return # set the assignedto and status newvalues['assignedto'] = creator try: status = db.status.lookup('confirm-done') except KeyError: status = db.status.lookup('in-progress') newvalues['status'] = status
def check_correction(db, cl, nodeid, new_values): common.require_attributes \ (_, cl, nodeid, new_values, 'user', 'date', 'day') if nodeid: common.require_attributes \ (_, cl, nodeid, new_values, 'absolute') else: if 'absolute' not in new_values: new_values['absolute'] = False user = new_values.get('user') if user is None: user = cl.get(nodeid, 'user') if 'date' in new_values: new_values['date'] = common.fix_date(new_values['date']) date = new_values.get('date') if date is None: date = cl.get(nodeid, 'date') if freeze.frozen(db, user, date): # Allow admin to add (initial) absolute correction if (nodeid is not None or db.getuid() != '1' or not new_values.get('absolute')): raise Reject(_("Frozen")) # Check that vacation parameters exist in dyn. user records dyn = user_dynamic.act_or_latest_user_dynamic(db, user) if not dyn or dyn.valid_to and dyn.valid_to < date: username = db.user.get(user, 'username') raise Reject \ (_ ('No current dyn. user record for "%(username)s"') % locals ()) while dyn and (not dyn.valid_to or dyn.valid_to > date): if (dyn.vacation_yearly is None or not dyn.vacation_month or not dyn.vacation_day): raise Reject \ (_ ('Missing vacation parameters in dyn. user record(s)')) dyn = user_dynamic.prev_user_dynamic(db, dyn)
def check_retire (db, cl, nodeid, new_values) : assert not new_values uid = db.getuid () st_open = db.daily_record_status.lookup ('open') st_leave = db.daily_record_status.lookup ('leave') tr = cl.getnode (nodeid) dr = db.daily_record.getnode (tr.daily_record) if frozen (db, dr.user, dr.date) : raise Reject (_ ("Can't retire frozen time record")) tt_by = db.user.get (dr.user, 'timetracking_by') allowed = True if dr.status == st_open : if ( uid != dr.user and uid != tt_by and not common.user_has_role (db, uid, 'controlling', 'admin') ) : # Must have a leave submission in status accepted, then we # can retire existing records ac = db.leave_status.lookup ('accepted') vs = vacation.leave_submissions_on_date \ (db, dr.user, dr.date, filter = dict (status = ac)) if not vs : allowed = False else : if dr.status == st_leave : # All leave submissions must be in state cancelled or declined # At least one must be cancelled cn = db.leave_status.lookup ('cancelled') dc = db.leave_status.lookup ('declined') vs = vacation.leave_submissions_on_date (db, dr.user, dr.date) if not vs : allowed = False if allowed : allowed = False for v in vs : if v.status == dc : continue if v.status == cn : allowed = True if v.status != cn : allowed = False break else : allowed = False # Allow admin to retire any time_record (!) if not allowed and db.getuid () != '1' : raise Reject (_ ("Permission denied"))
def new_submission(db, cl, nodeid, new_values): """ Check that new leave submission is allowed and has sensible parameters """ common.reject_attributes(_, new_values, 'approval_hr', 'comment_cancel') uid = db.getuid() st_subm = db.leave_status.lookup('submitted') if 'user' not in new_values: user = new_values['user'] = uid else: user = new_values['user'] common.require_attributes \ (_, cl, nodeid, new_values, 'first_day', 'last_day', 'user') first_day = new_values['first_day'] last_day = new_values['last_day'] fix_dates(new_values) if 'time_wp' not in new_values: wps = vacation.valid_leave_wps \ ( db , user , last_day , [('-', 'project.is_vacation'), ('-', 'project.approval_hr')] ) if wps: new_values['time_wp'] = wps[0] common.require_attributes(_, cl, nodeid, new_values, 'time_wp') if freeze.frozen(db, user, first_day): raise Reject(_("Frozen")) comment = new_values.get('comment') check_range(db, None, user, first_day, last_day) check_wp(db, new_values['time_wp'], user, first_day, last_day, comment) is_admin = (uid == '1') if 'status' in new_values and new_values[ 'status'] != st_subm and not is_admin: raise Reject(_('Initial status must be "submitted"')) if 'status' not in new_values: new_values['status'] = st_subm if (user != uid and not (is_admin or common.user_has_role(db, uid, 'HR-vacation'))): raise Reject \ (_ ("Only special role may create submission for other user")) vacation.create_daily_recs(db, user, first_day, last_day) if vacation.leave_days(db, user, first_day, last_day) == 0: raise Reject(_("Vacation request for 0 days")) check_dr_status(db, user, first_day, last_day, 'open') check_dyn_user_params(db, user, first_day, last_day)
def audit_retire(db, c, nodeid, newvalues): for id in c.list(): if id == nodeid: continue if id in c.get(nodeid, 'prereq'): raise Reject( "Deletion prevented since another checkpoint depends on this one: %s" % (id, ))
def check_name (db, cl, nodeid, new_values) : """ Ensure that names do not contain certain characters """ forbidden = ',/"' if 'name' in new_values : name = new_values ['name'] for c in forbidden : if c in name : raise Reject (_ ("Name contains forbidden character %s") % c)
def _check_location_values(db, c, nodeid, newvalues): # Empty URL? url = newvalues.get('url') if url == '' or (url is None and nodeid is None): raise Reject, "No URL given" if url[:len('http://')] != 'http://' and url[:len('https://' )] != 'https://': raise Reject('URL does not start with http:// nor https://')
def check_epic_key (db, cl, nodeid, new_values) : """ Ensure that the epic_key matches the format of keys in Jira """ if 'epic_key' in new_values : r = re.compile (r'^[A-Z][0-9A-Z_]+[0-9A-Z]-[0-9]+$') k = new_values ['epic_key'] if k is not None and not r.search (k) : epickey = _ ('epic_key') raise Reject (_ ("Not a valid %(epickey)s: %(k)s") % locals ())
def check_pr_offer_item (db, cl, nodeid, new_values) : common.require_attributes \ (_, cl, nodeid, new_values, 'units', 'price_per_unit') units = new_values.get ('units', None) price = new_values.get ('price_per_unit', None) oi = None if nodeid : oi = cl.getnode (nodeid) if units is None : assert oi units = oi.units if price is None : assert oi price = oi.price_per_unit if units <= 0 : raise Reject ("Units must not be <= 0") if price <= 0 : raise Reject ("Price must not be <= 0")
def check_currency (db, cl, nodeid, new_values) : common.require_attributes \ (_, cl, nodeid, new_values, 'min_sum', 'order', 'exchange_rate') if new_values.get ('key_currency') : for id in db.pr_currency.getnodeids () : if id == nodeid : continue if cl.get (id, 'key_currency') : raise Reject (_ ("Duplicate key currency"))
def common_user_checks(db, cl, nodeid, new_values): ''' Make sure user properties are valid. - email address has no spaces in it - roles specified exist ''' if ('address' in new_values and new_values['address'] and ' ' in new_values['address']): raise ValueError, 'Email address must not contain spaces' common.check_roles(db, cl, nodeid, new_values) # automatic setting of realname if 'firstname' in cl.properties: n = 'firstname' fn = new_values.get(n, None) or cl.get(nodeid, n) or '' n = 'lastname' ln = new_values.get(n, None) or cl.get(nodeid, n) or '' if (new_values.has_key("firstname") or new_values.has_key("lastname")): realname = " ".join((fn, ln)) new_values["realname"] = realname if 'lunch_duration' in new_values: ld = new_values['lunch_duration'] if ld * 3600 % 900: raise Reject, _("Times must be given in quarters of an hour") new_values['lunch_duration'] = int(ld * 4) / 4. if ld > 8: raise Reject, _("Lunchbreak of more than 8 hours? Sure?") if ld < .5: raise Reject, _("Lunchbreak must be at least half an hour.") if 'lunch_start' in new_values: ls = new_values['lunch_start'] ls = Date(ls) # trigger date-spec error if this fails. if 'tt_lines' in new_values: ttl = new_values['tt_lines'] if ttl < 1: new_values['tt_lines'] = 1 if ttl > 5: new_values['tt_lines'] = 5 if 'supervisor' in new_values: common.check_loop \ (_, cl, nodeid, 'supervisor', new_values ['supervisor']) # Allow nickname to be empty # Nick must be unique and must not collide with a username # This is checked in both directions if 'nickname' in new_values and new_values['nickname']: v = new_values['nickname'] common.check_unique(_, cl, nodeid, nickname=v) common.check_unique(_, cl, nodeid, username=v) if 'nickname' in cl.properties and 'username' in new_values: common.check_unique(_, cl, nodeid, nickname=new_values['username']) for k in maxlen: if k in new_values: if new_values[k] is None: continue if len(new_values[k]) > maxlen[k]: fn = _(k) l = maxlen[k] raise Reject(_('%(fn)s too long: > %(l)s' % locals()))
def prjust (db, cl, nodeid, new_values) : """ Field pr_justification must be edited when signing """ pjn = 'pr_justification' fn = _ (pjn) pj = new_values.get (pjn, cl.get (nodeid, pjn)) if pj : for k, v in prlib.pr_justification : if v in pj : raise Reject (_ ("You must edit %(fn)s") % locals ())
def handle(self): ''' Perform some action. No return value is required. ''' if self.client.env['REQUEST_METHOD'] != 'POST': raise Reject(self._('Invalid request')) # parse the props from the form try: props, links = self.client.parsePropsFromForm(create=1) except (ValueError, KeyError) as message: self.client.add_error_message(self._('Error: %s') % str(message)) return print props print props[('project', self.form['projectid'].value)]['supplier'] try: message = self._editnodes(props, links) except (ValueError, KeyError, IndexError, Reject) as message: escape = not isinstance(message, RejectRaw) self.client.add_error_message(self._('Edit Error: %s') % str(message), escape=escape) return self.db.project.set(self.form['projectid'].value, status='5') # Set project status to 'in-progress' #insert task(s) for task in self.db.workflow.filter(None, filterspec={ 'workflowname': '1', 'trg_type': None, 'trg_state': None }): t = self.db.issue.create( project=self.form['projectid'].value, tasktype=self.db.workflow.get(task, 'new_type'), status='new', supplier=self.db.workflow.get(task, 'new_resp') if self.db.workflow.get(task, 'new_resp') else props[('project', self.form['projectid'].value)]['supplier']) # commit now that all the tricky stuff is done self.db.commit() # redirect to the item's edit page # redirect to finish off url = self.base + self.classname # note that this action might have been called by an index page, so # we will want to include index-page args in this URL too if self.nodeid is not None: url += self.nodeid url += '?@ok_message=%s&@template=%s' % (urllib_.quote( 'Project%s launched.' % (self.form['projectid'].value)), urllib_.quote(self.template)) if self.nodeid is None: req = templating.HTMLRequest(self.client) print self.form['projectid'].value url += '&' + req.indexargs_url('', {})[1:] raise exceptions.Redirect(url)
def check_issue_nums (db, cl, nodeid, new_values) : issue_ids = new_values.get ('issue_ids', None) # Allow empty value, also exits if not changed if issue_ids is None : return minl = int (getattr (db.config.ext, 'LINK_MINID', 0)) maxl = int (getattr (db.config.ext, 'LINK_MAXID', 100)) ids = [x.strip () for x in issue_ids.split (',')] for id in ids : if not (minl <= len (id) <= maxl) or not id.isdigit () : raise Reject (_ ("Invalid Issue-Number: %s") % id)
def approvalchange (db, cl, nodeid, new_values) : if 'special_approval' not in new_values : return status = new_values.get ('status', cl.get (nodeid, 'status')) # In state open we do nothing at this point, the special approvals # will be processed later, in other states change of approvals is no # longer possible. if status == db.pr_status.lookup ('open') : return if status != db.pr_status.lookup ('approving') : raise Reject (_ ("Approval change only in state open and approving")) sa = set (new_values ['special_approval']) osa = set (cl.get (nodeid, 'special_approval')) if osa - sa : raise Reject (_ ("Cannot remove users from approval list")) for uid in sa - osa : prlib.gen_pr_approval \ ( db, True , purchase_request = nodeid , user = uid , order = 15 , description = _ ("Special approval") )