def tracking(request,rng): frto = rng.split(':') ; narr=[] for tel in frto: otel = tel if tel=='lastmonth': tel = (datetime.datetime.now()-datetime.timedelta(days=30)).strftime('%Y-%m-%d') if tel=='lastweek': tel = (datetime.datetime.now()-datetime.timedelta(days=7)).strftime('%Y-%m-%d') if tel=='yesterday': tel = (datetime.datetime.now()-datetime.timedelta(days=1)).strftime('%Y-%m-%d') if tel=='today': tel = (datetime.datetime.now()).strftime('%Y-%m-%d') narr.append(tel) frto = narr st,op = gso("find %s -type f -iname 'hours.json'"%cfg.DATADIR) ; assert st==0 fnames = op.split("\n") sums={} ; tasksums={} ; tdescrs = {} ; testimates = {} for fn in fnames: tid = os.path.dirname(fn).replace(cfg.DATADIR+'/','') with open(fn,'r') as f: j = json.loads(f.read()) matching = filter(lambda x: x[0]>=frto[0] and x[0]<=frto[1],j.items()) for dt,data in matching: for person,hrs in data.items(): sums[person] = sums.get(person,0)+hrs if person not in tasksums: tasksums[person]={} tasksums[person][tid] = tasksums[person].get(tid,0)+hrs t = get_task(tid) if tid not in tdescrs: tdescrs[tid] = t['summary'] metastates,content = read_current_metastates(t,True) if t.get('total_hours') and metastates.get('work estimate'): remaining_hours = '%4.2f'%(float(metastates.get('work estimate')['value']) - float(t.get('total_hours'))) else: remaining_hours = '--' testimates[tid]=remaining_hours sums = sums.items() sums.sort(lambda x,y: cmp(x[1],y[1]),reverse=True) return {'fr':frto[0],'to':frto[1],'tracked':sums,'tasksums':tasksums,'tdescrs':tdescrs,'testimates':testimates}
def task(request,P,C,task,rev=None): # fetch_stamp is a hidden form input used to protect task updates against overwrite by older forms of the task submitted fstamp = request.params.get('changed_at') if fstamp and fstamp!='None': fstamp = datetime.datetime.strptime( fstamp, "%Y-%m-%d %H:%M:%S.%f" ) else: fstamp=None now = datetime.datetime.now() if task.endswith('/'): task=task[0:-1] gwu = cfg.GITWEB_URL if task.startswith('new/'): under='/'.join(task.split('/')[1:]) task='new' else: under=None msg=None adm = get_admin(request,'unknown') repos = get_repos(C) usernames = get_usernames(C) tags=[] ; links=[] ; informed=[] ; branches=[] ; cross_links_raw = get_cross_links(C,task) cross_links=[] dependencies=[] for k,v in list(request.params.items()): if k.startswith('tag-'): tn = k.replace('tag-','') if tn=='new': for nt in [nt.strip() for nt in v.split(',') if nt.strip()!='']: tags.append(nt) else: tags.append(tn) if k.startswith('link-'): tn = k.replace('link-','') if tn in ['new-url','new-anchor']: continue #raise Exception('newlink') else: links.append({'url':v,'anchor':tn}) if k.startswith('informed-'): tn = k.replace('informed-','') if tn=='new': continue informed.append(tn) if k.startswith('branches-'): tn = k.replace('branches-','') if tn in ['new-repo','new-branch']: continue branches.append(tn) if k.startswith('cross_link-'): cln = k.replace('cross_link-','') cross_links.append(cln) #print('adding cross_link',cln,'due to',k,v) if k.startswith('dependency-'): dln = k.replace('dependency-','') dependencies.append(dln) lna = request.params.get('link-new-anchor') lnu = request.params.get('link-new-url') ncl = request.params.get('add-cross_link') ndl = request.params.get('add-dependency') if task and task!='new': karma = getattr(get_task(C,task),'karma',{}) else: karma = {} nkarma = request.params.get('karma-new') if nkarma: kdt = datetime.datetime.now().date().strftime('%Y-%m-%d') nkarmaval = request.params.get('karma-plus') and 1 or -1 # find out what's our expense for today mykarma = sum([k['value'][1] for k in get_karma(C,kdt,adm)]) if (nkarmaval>0 and mykarma<cfg.KARMA_POINTS_PER_DAY) or nkarmaval<0: if kdt not in karma: karma[kdt]={} if adm not in karma[kdt]: karma[kdt][adm]={} if nkarma not in karma[kdt][adm]: karma[kdt][adm][nkarma]=0 newval = karma[kdt][adm][nkarma]+nkarmaval if newval>=0: karma[kdt][adm][nkarma]=newval if ncl: for ncli in ncl.split(','): cross_links.append(ncli) if ndl: for ndli in ndl.split(','): dependencies.append(ndli) if lna and lnu: links.append({'anchor':lna,'url':lnu}) inn = request.params.get('informed-new') if inn and inn not in informed: informed.append(inn) nrb = request.params.get('branches-new-branch','') assert '/' not in nrb,"branch name may not contain '/'" if nrb: branches.append(request.params.get('branches-new-repo')+'/'+nrb) tags = list(set([tag for tag in tags if tag!=''])) uns = request.params.get('unstructured','').strip() if len(uns) and not uns.startswith('**'): uns='** Details\n'+uns assignees=[request.params.get('assignee')] if request.params.get('id') and request.params.get('id')!='None': t = get_task(C,request.params.get('id')) assignees.append(t.assignee) tid = request.params.get('id') o_params = {'summary':request.params.get('summary'), 'karma':dict(karma), 'tags':tags, 'status':request.params.get('status'), 'assignee':request.params.get('assignee'), 'handled_by':request.params.get('handled_by'), 'unstructured':uns, 'links':links, 'cross_links_raw':request.params.get('cross_links'), 'cross_links':cross_links, 'dependencies':dependencies, 'informed':informed, 'branches':branches} print(o_params) rewrite(P,C,tid,o_params,safe=False,user=adm,fetch_stamp=fstamp) t = get_task(C,tid) cross_links_raw = get_cross_links(C,tid) if request.params.get('content-journal'): tj = get_task(C,task) metastates={} append_journal_entry(P,C,tj,adm,request.params.get('content-journal'),metastates) assert request.params.get('id') if request.params.get('create'): o_params = {'summary':request.params.get('summary'), 'status':request.params.get('status'), 'assignee':request.params.get('assignee'), 'creator':get_admin(request,'unknown'), 'handled_by':request.params.get('handled_by'), 'unstructured':uns, 'links':links, 'informed':informed, 'branches':branches} if request.params.get('under'): parent = request.params.get('under') else: parent=None rt = add_task(P,C,parent=parent,params=o_params,tags=tags,user=adm) redir = '/'+URL_PREFIX+rt._id print('redircting to %s'%redir) rd = Redirect(redir) return rd if task=='new': ch=[] else: #raise Exception('eff off',task) #print('getting children') ch = get_children(C,task) sortmode = request.params.get('sortby','default') ch.sort(key=cmp_to_key(sortmodes[sortmode]),reverse=True) print(('got',len(ch),'kids')) if task=='new': t = Task(created_at=None, summary='', unstructured='', status='TODO', assignee=adm, creator=adm, tags=[], links=[], branches=[], karma={}, journal=[]) opar=[] gantt_labels={} ; gantt={} changed_at=None else: gantt_labels,gantt = gantt_info(C,task) C.execute("select changed_at from tasks where id=%s",(task,)) fo = C.fetchone() if fo: changed_at = fo['changed_at'] else: changed_at = None if rev: t = Task.get_rev(C,task,rev) else: t = get_task(C,task) par = task ; parents=[] parents = task.split('/') opar = [] for i in range(len(parents)-1): opar.append('/'.join(parents[:i+1])) parents = [(pid,get_task(C,pid)['summary']) for pid in opar] prt = get_usernames(C) metastates,content = read_current_metastates(t,True) zerodelta = datetime.timedelta(seconds=0) if gantt.get('t') and gantt.get('we'): remaining_hours = gantt.get('we')-gantt.get('t') else: remaining_hours=zerodelta #journal jitems = t.journal dependencies = getattr(t,'dependencies',[]) branchtargets=[(re.compile("pre"),"preproduction"), (re.compile("prod"),"production"), (re.compile(".*"),"staging")] btgts={} for br in t.branches: for ptn,tgt in branchtargets: ptnres = ptn.search(br.split("/")[1]) #print 'ptnres of',br,'in',tgt,'is',ptnres if ptnres: if tgt not in btgts: btgts[tgt]=[] btgts[tgt].append(br) break C.execute("select * from tasks_pri_comb_lean where id=%s",(task,)) pri = C.fetchall() if len(pri): pr = pri[0] pri = pr['tot_pri'] dep_pri = pr['dep_pri'] else: pri=0 dep_pri=0 C.execute("select depid,path_info from tasks_deps_hierarchy where tid=%s",(t._id,)) fulldeps = [d for d in C.fetchall() if d['depid'] not in dependencies] C.execute("select tid,path_info from tasks_deps_hierarchy where depid=%s",(t._id,)) dependants = [d for d in C.fetchall()] tup = tuple(cross_links_raw+ [d['tid'] for d in dependants]+ [d for d in dependencies]+ [fd['depid'] for fd in fulldeps]) if len(tup): C.execute("select id id,contents->>'summary' summary from tasks where id in %s",(tup,)) summaries = dict([(r['id'],r['summary']) for r in C.fetchall()]) else: summaries={} return basevars(request,P,C,{'task':t, 'rev':rev, 'changed_at':changed_at, 'pri':pri, 'dep_pri':dep_pri, 'gantt':gantt, 'gantt_labels':gantt_labels, 'zerodelta':zerodelta, 'branches_by_target':btgts, 'summaries':summaries, 'cross_links':cross_links_raw, 'dependencies':dependencies, 'fulldeps':fulldeps, 'dependants':dependants, 'remaining_hours':remaining_hours, 'total_hours':0, 'j':{'%s existing entries'%t._id:jitems}, 'gwu':gwu, 'url':RENDER_URL, 'statuses':STATUSES, 'participants':prt, 'usernames':usernames, 'msg':msg, 'children':ch, 'repos':repos, 'parents':parents, 'request':request, 'metastates':metastates, 'possible_metastates':cfg.METASTATES, 'colors':cfg.METASTATES_COLORS, 'overrides':cfg.METASTATES_OVERRIDES, 'karma_per_day':cfg.KARMA_POINTS_PER_DAY, 'diff_branches':cfg.DIFF_BRANCHES, 'under':under, 'humanize':humanize, 'now':now, 'reduce':reduce, })
def queue(request,P,C,assignee=None,archive=False,metastate_group='merge'): #print('queue()') if assignee=='me': assignee=get_admin(request,'unknown') queue={} #print('get_journals()') gj = get_journals(P,C, assignee=assignee, metastate_group=metastate_group, archive=archive ) for tj in gj: t = tj['contents'] tid = t['_id'] #print('going over task',tid) cm,content = read_current_metastates(tj['contents'],True) #skip this task if has no metastates relevant to us relevant_metastates=False for cmk in cm: if cmk in cfg.METASTATES[metastate_group]: relevant_metastates=True break if not relevant_metastates: continue #print 'reading journal' jitems = read_journal(t) lupd = sorted(list(cm.values()),key=lambda x:x['updated'],reverse=True) if len(lupd): lupd=lupd[0]['updated'] else: lupd=None #any journal update takes precedence if len(jitems): try: jlupd = jitems[-1]['created_at'] except: raise Exception(jitems[-1]) if not lupd or jlupd >=lupd: lupd = jlupd #assert t.get('total_hours')!='None' #print 'adding to queue' queue[tid]={'states':dict([(cmk,cmv['value']) for cmk,cmv in list(cm.items())]), #'total_hours':t.get('total_hours',0), 'fullstates':cm, 'last updated':lupd, 'status':t['status'], 'summary':t['summary'], 'last entry':content, 'tags':t['tags'], 'assignee':t['assignee'], 'merge':[l['url'] for l in t['links'] if l['anchor']=='merge doc'], 'job':[l['url'] for l in t['links'] if l['anchor']=='job'], 'specs':[l['url'] for l in t['links'] if l['anchor']=='specs']} queue = list(queue.items()) qsort = cmp_to_key( lambda x1,x2: cmp((x1[1]['last updated'] and datetime.datetime.strptime(x1[1]['last updated'].split('.')[0],iso_dfmt) or datetime.datetime(year=1970,day=1,month=1)), (x2[1]['last updated'] and datetime.datetime.strptime(x2[1]['last updated'].split('.')[0],iso_dfmt) or datetime.datetime(year=1970,day=1,month=1)))) queue.sort(key=qsort,reverse=True) metastate_url_prefix = dict (list(zip(list(cfg.METASTATE_URLS.values()),list(cfg.METASTATE_URLS.keys()))))[metastate_group] #print('rendering') return basevars(request,P,C,{'queue':queue, 'metastate_group':metastate_group, 'metastate_url_prefix':metastate_url_prefix, 'metastates':METASTATES, 'colors':cfg.METASTATES_COLORS, 'overrides':cfg.METASTATES_OVERRIDES})
def queue(request,assignee=None,archive=False,metastate_group='merge'): if assignee=='me': assignee=get_admin(request,'unknown') queue={} print 'cycling journals' for t in get_journals(): if assignee and t.assignee!=assignee: continue if metastate_group!='production': if not archive and t['status'] in cfg.DONESTATES: continue elif archive and t['status'] not in cfg.DONESTATES: continue tid = t._id #print t assert t.status,"could not get status for %s"%tid #print 'reading metastates' cm,content = read_current_metastates(t,True) #skip this task if has no metastates relevant to us relevant_metastates=False for cmk in cm: if cmk in cfg.METASTATES[metastate_group]: relevant_metastates=True break if not relevant_metastates: continue print 'reading journal' jitems = read_journal(t) lupd = sorted(cm.values(),lambda x1,x2: cmp(x1['updated'],x2['updated']),reverse=True) if len(lupd): lupd=lupd[0]['updated'] else: lupd=None #any journal update takes precedence if len(jitems): try: jlupd = jitems[-1]['created_at'] except: raise Exception(jitems[-1]) if not lupd or jlupd >=lupd: lupd = jlupd #assert t.get('total_hours')!='None' print 'adding to queue' queue[tid]={'states':dict([(cmk,cmv['value']) for cmk,cmv in cm.items()]), #'total_hours':t.get('total_hours',0), 'fullstates':cm, 'last updated':lupd, 'status':t['status'], 'summary':t['summary'], 'last entry':content, 'tags':t['tags'], 'assignee':t.assignee, 'merge':[l['url'] for l in t.links if l['anchor']=='merge doc'], 'job':[l['url'] for l in t.links if l['anchor']=='job'], 'specs':[l['url'] for l in t.links if l['anchor']=='specs']} print 'done. itemizing' queue = queue.items() print 'sorting' queue.sort(lambda x1,x2: cmp((x1[1]['last updated'] and x1[1]['last updated'] or datetime.datetime(year=1970,day=1,month=1)),(x2[1]['last updated'] and x2[1]['last updated'] or datetime.datetime(year=1970,day=1,month=1))),reverse=True) metastate_url_prefix = dict (zip(cfg.METASTATE_URLS.values(),cfg.METASTATE_URLS.keys()))[metastate_group] print 'rendering' return {'queue':queue, 'metastate_group':metastate_group, 'metastate_url_prefix':metastate_url_prefix, 'metastates':METASTATES, 'colors':cfg.METASTATES_COLORS, 'overrides':cfg.METASTATES_OVERRIDES}
def task(request,task): if task.endswith('/'): task=task[0:-1] gwu = cfg.GITWEB_URL if task.startswith('new/'): under='/'.join(task.split('/')[1:]) task='new' else: under=None msg=None adm = get_admin(request,'unknown') repos = [r['Name'] for r in get_table_contents(os.path.join(cfg.DATADIR,'repos.org')) if r.get('Name')] tags=[] ; links=[] ; informed=[] ; branches=[] for k,v in request.params.items(): if k.startswith('tag-'): tn = k.replace('tag-','') if tn=='new': for nt in [nt.strip() for nt in v.split(',') if nt.strip()!='']: tags.append(nt) else: tags.append(tn) if k.startswith('link-'): tn = k.replace('link-','') if tn in ['new-url','new-anchor']: continue #raise Exception('newlink') else: links.append({'url':v,'anchor':unicode(tn,'utf-8')}) if k.startswith('informed-'): tn = k.replace('informed-','') if tn=='new': continue informed.append(tn) if k.startswith('branches-'): tn = k.replace('branches-','') if tn in ['new-repo','new-branch']: continue branches.append(tn) lna = request.params.get('link-new-anchor') lnu = request.params.get('link-new-url') if lna and lnu: links.append({'anchor':lna,'url':lnu}) inn = request.params.get('informed-new') if inn and inn not in informed: informed.append(inn) nrb = request.params.get('branches-new-branch','') assert '/' not in nrb,"branch name may not contain '/'" if nrb: branches.append(request.params.get('branches-new-repo')+'/'+nrb) tags = list(set([tag for tag in tags if tag!=''])) uns = request.params.get('unstructured','').strip() if len(uns) and not uns.startswith('**'): uns='** Details\n'+uns assignees=[request.params.get('assignee')] if request.params.get('id') and request.params.get('id')!='None': t = get_task(request.params.get('id')) assignees.append(t.assignee) tid = request.params.get('id') o_params = {'summary':request.params.get('summary'), 'tags':tags, 'status':request.params.get('status'), 'assignee':request.params.get('assignee'), 'unstructured':uns, 'links':links, 'informed':informed, 'branches':branches} print o_params rewrite(tid,o_params,safe=False,user=adm) t = get_task(tid) if request.params.get('content-journal'): tj = get_task(task) metastates={} append_journal_entry(tj,adm,request.params.get('content-journal'),metastates) assert request.params.get('id') if request.params.get('create'): o_params = {'summary':request.params.get('summary'), 'status':request.params.get('status'), 'assignee':request.params.get('assignee'), 'creator':get_admin(request,'unknown'), 'unstructured':uns, 'links':links, 'informed':informed, 'branches':branches} if request.params.get('under'): parent = request.params.get('under') else: parent=None rt = add_task(parent=parent,params=o_params,tags=tags,user=adm) redir = '/'+URL_PREFIX+rt._id print 'redircting to %s'%redir rd = Redirect(redir) return rd if task=='new': ch=[] else: ch = get_children(task) if task=='new': t = Task(created_at=None, summary='', unstructured='', status='TODO', assignee=adm, creator=adm, tags=[], links=[], branches=[], journal=[]) opar=[] else: t = get_task(task) par = task ; parents=[] parents = task.split('/') opar = [] for i in xrange(len(parents)-1): opar.append('/'.join(parents[:i+1])) parents = [(pid,get_task(pid)['summary']) for pid in opar] prt = [r[0] for r in get_participants(sort=True)] metastates,content = read_current_metastates(t,True) # if t.get('total_hours') and metastates.get('work estimate'): # remaining_hours = float(metastates.get('work estimate')['value']) - float(t.get('total_hours')) # elif t.get('total_hours'): # remaining_hours = -1 * float(t.get('total_hours')) # else: # remaining_hours = None remaining_hours=None #journal jitems = t.journal return {'task':t, 'remaining_hours':remaining_hours, 'total_hours':0, 'j':{'%s existing entries'%t._id:jitems}, 'gwu':gwu, 'url':RENDER_URL, 'statuses':STATUSES, 'participants':prt, 'msg':msg, 'children':ch, 'repos':repos, 'parents':parents, 'request':request, 'metastates':metastates, 'possible_metastates':cfg.METASTATES, 'colors':cfg.METASTATES_COLORS, 'overrides':cfg.METASTATES_OVERRIDES, 'diff_branches':cfg.DIFF_BRANCHES, 'under':under, }