def get_session(self, url, stypes): sessions = self.db.openid_session.filter(None, {'url': url}) for session_id in sessions: # Match may not have been exact if self.db.openid_session.get(session_id, 'url') != url: continue expires = self.db.openid_session.get(session_id, 'expires') if expires > date.Date('.') + date.Interval("1:00"): # valid for another hour return self.db.openid_session.getnode(session_id) now = date.Date('.') session_data = openid2rp.associate(stypes, url) # check whether a session has expired a day ago sessions = self.db.openid_session.filter(None, {'expires': 'to -1d'}) if sessions: session = self.db.openid_session.getnode(sessions[0]) session.assoc_handle = session_data['assoc_handle'] else: session_id = self.db.openid_session.create( assoc_handle=session_data['assoc_handle']) session = self.db.openid_session.getnode(session_id) session.url = url session.mac_key = session_data['mac_key'] session.expires = now + date.Interval(int(session_data['expires_in'])) self.db.commit() return session
def confirm_registration(self, otk): props = self.getOTKManager().getall(otk) for propname, proptype in self.user.getprops().items(): value = props.get(propname, None) if value is None: pass elif isinstance(proptype, hyperdb.Date): props[propname] = date.Date(value) elif isinstance(proptype, hyperdb.Interval): props[propname] = date.Interval(value) elif isinstance(proptype, hyperdb.Password): props[propname] = password.Password(encrypted=value) # tag new user creation with 'admin' self.journaltag = 'admin' # create the new user cl = self.user props['roles'] = self.config.NEW_WEB_USER_ROLES userid = cl.create(**props) # clear the props from the otk database self.getOTKManager().destroy(otk) self.commit() return userid
def totalTimeSpent(times): ''' Call me with a list of timelog items (which have an Interval "period" property) ''' total = date.Interval('0d') for time in times: total += time.period._value return total
def __init__ (self, opt) : self.opt = opt tracker = instance.open (opt.dir) self.db = tracker.open ('admin') now = date.Date ('.') exp = now + date.Interval ('%s days' % opt.days) wps = self.db.time_wp.filter \ ( None , dict (time_end = '.;%s' % exp.pretty ('%Y-%m-%d')) , sort=[('+', 'responsible')] ) self.wps = [self.db.time_wp.getnode (i) for i in wps] self.messages = {} self.build_mails ()
def pending_approval (db, userid, itemid) : """ Users are allowed to edit message if a pending approval from them is linked to the PR. """ if not linked_pr (db, userid, itemid) : return False if open_or_approving (db, userid, itemid) : return True # Also allow for reject because message is tried to attach twice # We allow this only for some time (5 min after last change) st_reject = db.pr_status.lookup ('rejected') pr = db.purchase_request.getnode (itemid) if pr.status != st_reject : return False now = date.Date ('.') if pr.activity + date.Interval ('00:05:00') > now : return True return False
def confirm_registration(self, otk): props = self.getOTKManager().getall(otk) for propname, proptype in self.user.getprops().items(): value = props.get(propname, None) if value is None: pass elif isinstance(proptype, hyperdb.Date): props[propname] = date.Date(value) elif isinstance(proptype, hyperdb.Interval): props[propname] = date.Interval(value) elif isinstance(proptype, hyperdb.Password): props[propname] = password.Password(encrypted=value) # tag new user creation with 'admin' self.journaltag = 'admin' # create the new user cl = self.user props['roles'] = self.config.NEW_WEB_USER_ROLES try: # ASSUME:: ValueError raised during create due to key value # conflict. I an use message in exception to determine # when I should intercept the exception with a more # friendly error message. If i18n is used to translate # original exception message this will fail and translated # text (probably unfriendly) will be used. userid = cl.create(**props) except ValueError as e: username = props['username'] # Try to make error message less cryptic to the user. if str(e) == 'node with key "%s" exists' % username: raise ValueError(_("Username '%s' already exists." % username)) else: raise # clear the props from the otk database self.getOTKManager().destroy(otk) # commit cl.create (and otk changes) self.commit() return userid
def add_milestones(db, cl, nodeid, new_values): """auditor on release.create XXX: not sure if this should be in an auditor ??? - creates the milestones and attaches them to the newly created release. - set release's `status` to M000 """ milestones = \ [ ("M000", "+ 0d", "Release Planning has started") , ("M100", "+ 2m 15d", "Release Planning completed, Feature Freeze") , ("M200", "+ 3m 20d", "Design completed") , ("M210", "+ 3m 30d", "Check for Customer Appslications to be " "used as Testcases") , ("M300", "+ 6m 20d", "Implementation completed") , ("M310", "+ 7m ", "TC Spec & TC Implementation completed") , ("M400", "+ 8m 15d", "Integration Test completed; Beta Release") , ("M410", "+ 8m 20d", "Documentation Completed") , ("M490", "+ 9m ", "Bugfixing completed") , ("M500", "+ 9m 10d", "Test by Services completed; Production " "Release") , ("M600", "+10m" , "Shipment completed") ] order = 1 ms_ids = [] today = date.Date(".").pretty(format="%Y-%m-%d") today = date.Date(today) # to start today at 00:00 and not somewhere in # the day for name, interval, desc in milestones: planned = today + date.Interval(interval) ms = db.milestone.create(name=name, description=desc, order=order, planned=planned, release=nodeid) ms_ids.append(ms) order += 1 new_values["milestones"] = ms_ids # set status to M0 new_values["status"] = ms_ids[0]
def handle(self): """Performs an edit of all of a class' items in one go. The "rows" CGI var defines the CSV-formatted entries for the class. New nodes are identified by the ID 'X' (or any other non-existent ID) and removed lines are retired. """ cl = self.db.classes[self.classname] idlessprops = cl.getprops(protected=0).keys() idlessprops.sort() props = ['id'] + idlessprops # do the edit rows = StringIO.StringIO(self.form['rows'].value) reader = csv.reader(rows) found = {} line = 0 for values in reader: line += 1 if line == 1: continue # skip property names header if values == props: continue # extract the nodeid nodeid, values = values[0], values[1:] found[nodeid] = 1 # see if the node exists if nodeid in ('x', 'X') or not cl.hasnode(nodeid): exists = 0 else: exists = 1 # confirm correct weight if len(idlessprops) != len(values): self.client.error_message.append( self._('Not enough values on line %(line)s') % {'line': line}) return # extract the new values d = {} for name, value in zip(idlessprops, values): prop = cl.properties[name] value = value.strip() # only add the property if it has a value if value: # if it's a multilink, split it if isinstance(prop, hyperdb.Multilink): value = value.split(':') elif isinstance(prop, hyperdb.Password): value = password.Password(value) elif isinstance(prop, hyperdb.Interval): value = date.Interval(value) elif isinstance(prop, hyperdb.Date): value = date.Date(value) elif isinstance(prop, hyperdb.Boolean): value = value.lower() in ('yes', 'true', 'on', '1') elif isinstance(prop, hyperdb.Number): value = float(value) d[name] = value elif exists: # nuke the existing value if isinstance(prop, hyperdb.Multilink): d[name] = [] else: d[name] = None # perform the edit if exists: # edit existing cl.set(nodeid, **d) else: # new node found[cl.create(**d)] = 1 # retire the removed entries for nodeid in cl.list(): if not found.has_key(nodeid): cl.retire(nodeid) # all OK self.db.commit() self.client.ok_message.append(self._('Items edited OK'))
def add_new_columns_v2(self): '''While we're adding the actor column, we need to update the tables to have the correct datatypes.''' for klass in self.classes.values(): cn = klass.classname properties = klass.getprops() old_spec = self.database_schema['tables'][cn] # figure the non-Multilink properties to copy over propnames = ['activity', 'creation', 'creator'] # figure actions based on data type for name, s_prop in old_spec[1]: # s_prop is a repr() string of a hyperdb type object if s_prop.find('Multilink') == -1: if name in properties: propnames.append(name) continue tn = '%s_%s'%(cn, name) if name in properties: # grabe the current values sql = 'select linkid, nodeid from %s'%tn self.sql(sql) rows = self.cursor.fetchall() # drop the old table self.drop_multilink_table_indexes(cn, name) sql = 'drop table %s'%tn self.sql(sql) if name in properties: # re-create and populate the new table self.create_multilink_table(klass, name) sql = '''insert into %s (linkid, nodeid) values (%s, %s)'''%(tn, self.arg, self.arg) for linkid, nodeid in rows: self.sql(sql, (int(linkid), int(nodeid))) # figure the column names to fetch fetch = ['_%s'%name for name in propnames] # select the data out of the old table fetch.append('id') fetch.append('__retired__') fetchcols = ','.join(fetch) sql = 'select %s from _%s'%(fetchcols, cn) self.sql(sql) # unserialise the old data olddata = [] propnames = propnames + ['id', '__retired__'] cols = [] first = 1 for entry in self.cursor.fetchall(): l = [] olddata.append(l) for i in range(len(propnames)): name = propnames[i] v = entry[i] if name in ('id', '__retired__'): if first: cols.append(name) l.append(int(v)) continue if first: cols.append('_' + name) prop = properties[name] if isinstance(prop, hyperdb.Date) and v is not None: v = date.Date(v) elif isinstance(prop, hyperdb.Interval) and v is not None: v = date.Interval(v) elif isinstance(prop, hyperdb.Password) and v is not None: v = password.Password(encrypted=v) elif isinstance(prop, hyperdb.Integer) and v is not None: v = int(v) elif (isinstance(prop, hyperdb.Boolean) or isinstance(prop, hyperdb.Number)) and v is not None: v = float(v) # convert to new MySQL data type prop = properties[name] if v is not None: e = self.to_sql_value(prop.__class__)(v) else: e = None l.append(e) # Intervals store the seconds value too if isinstance(prop, hyperdb.Interval): if first: cols.append('__' + name + '_int__') if v is not None: l.append(v.as_seconds()) else: l.append(e) first = 0 self.drop_class_table_indexes(cn, old_spec[0]) # drop the old table self.sql('drop table _%s'%cn) # create the new table self.create_class_table(klass) # do the insert of the old data args = ','.join([self.arg for x in cols]) cols = ','.join(cols) sql = 'insert into _%s (%s) values (%s)'%(cn, cols, args) for entry in olddata: self.sql(sql, tuple(entry)) # now load up the old journal data to migrate it cols = ','.join('nodeid date tag action params'.split()) sql = 'select %s from %s__journal'%(cols, cn) self.sql(sql) # data conversions olddata = [] for nodeid, journaldate, journaltag, action, params in \ self.cursor.fetchall(): #nodeid = int(nodeid) journaldate = date.Date(journaldate) #params = eval(params) olddata.append((nodeid, journaldate, journaltag, action, params)) # drop journal table and indexes self.drop_journal_table_indexes(cn) sql = 'drop table %s__journal'%cn self.sql(sql) # re-create journal table self.create_journal_table(klass) dc = self.to_sql_value(hyperdb.Date) for nodeid, journaldate, journaltag, action, params in olddata: self.save_journal(cn, cols, nodeid, dc(journaldate), journaltag, action, params) # make sure the normal schema update code doesn't try to # change things self.database_schema['tables'][cn] = klass.schema()
def handle(self): """Performs an edit of all of a class' items in one go. The "rows" CGI var defines the CSV-formatted entries for the class. New nodes are identified by the ID 'X' (or any other non-existent ID) and removed lines are retired. """ # ensure modification comes via POST if self.client.env['REQUEST_METHOD'] != 'POST': raise roundup.exceptions.Reject(self._('Invalid request')) # figure the properties list for the class cl = self.db.classes[self.classname] props_without_id = list(cl.getprops(protected=0)) # the incoming CSV data will always have the properties in colums # sorted and starting with the "id" column props_without_id.sort() props = ['id'] + props_without_id # do the edit rows = io_.BytesIO(self.form['rows'].value) reader = csv.reader(rows) found = {} line = 0 for values in reader: line += 1 if line == 1: continue # skip property names header if values == props: continue # extract the itemid itemid, values = values[0], values[1:] found[itemid] = 1 # see if the node exists if itemid in ('x', 'X') or not cl.hasnode(itemid): exists = 0 # check permission to create this item if not self.hasPermission('Create', classname=self.classname): raise exceptions.Unauthorised( self._( 'You do not have permission to create %(class)s') % {'class': self.classname}) elif cl.hasnode(itemid) and cl.is_retired(itemid): # If a CSV line just mentions an id and the corresponding # item is retired, then the item is restored. cl.restore(itemid) continue else: exists = 1 # confirm correct weight if len(props_without_id) != len(values): self.client.add_error_message( self._('Not enough values on line %(line)s') % {'line': line}) return # extract the new values d = {} for name, value in zip(props_without_id, values): # check permission to edit this property on this item if exists and not self.hasPermission('Edit', itemid=itemid, classname=self.classname, property=name): raise exceptions.Unauthorised( self._('You do not have permission to edit %(class)s') % {'class': self.classname}) prop = cl.properties[name] value = value.strip() # only add the property if it has a value if value: # if it's a multilink, split it if isinstance(prop, hyperdb.Multilink): value = value.split(':') elif isinstance(prop, hyperdb.Password): value = password.Password(value, config=self.db.config) elif isinstance(prop, hyperdb.Interval): value = date.Interval(value) elif isinstance(prop, hyperdb.Date): value = date.Date(value) elif isinstance(prop, hyperdb.Boolean): value = value.lower() in ('yes', 'true', 'on', '1') elif isinstance(prop, hyperdb.Number): value = float(value) d[name] = value elif exists: # nuke the existing value if isinstance(prop, hyperdb.Multilink): d[name] = [] else: d[name] = None # perform the edit if exists: # edit existing cl.set(itemid, **d) else: # new node found[cl.create(**d)] = 1 # retire the removed entries for itemid in cl.list(): if itemid not in found: # check permission to retire this item if not self.hasPermission( 'Retire', itemid=itemid, classname=self.classname): raise exceptions.Unauthorised( self._( 'You do not have permission to retire %(class)s') % {'class': self.classname}) cl.retire(itemid) # all OK self.db.commit() self.client.add_ok_message(self._('Items edited OK'))