def test_iteration_creation(self): docs.add_iteration('testiter') rt = docs.add_task('testiter',parent=None,params={'summary':'1st test task'},tags=['chuckacha']) tf = docs.get_fns(iteration='testiter',flush=True) assert len(tf)==1 for i in range(5): rt2 = docs.add_task(iteration=None,parent=rt['id'],params={'summary':'1st subtask'},tags=['subtask']) print rt2 tf = docs.get_fns(iteration='testiter',recurse=True,flush=True) assert len(tf)==i+2 t1 = docs.get_task(rt['id'],read=True) assert t1['id']==rt['id'] assert t1['summary']=='1st test task' assert 'chuckacha' in t1['tags'] t2 = docs.get_task(rt2['id'],read=True) assert t2['summary']=='1st subtask' assert 'subtask' in t2['tags']
def test_iteration_creation(self): docs.add_iteration('testiter') rt = docs.add_task('testiter',parent=None,params={'summary':'1st test task'},tags=['chuckacha']) tf = docs.get_fns(iteration='testiter',flush=True) assert len(tf)==1 for i in range(5): rt2 = docs.add_task(iteration=None,parent=rt['id'],params={'summary':'1st subtask'},tags=['subtask']) print(rt2) tf = docs.get_fns(iteration='testiter',recurse=True,flush=True) assert len(tf)==i+2 t1 = docs.get_task(rt['id'],read=True) assert t1['id']==rt['id'] assert t1['summary']=='1st test task' assert 'chuckacha' in t1['tags'] t2 = docs.get_task(rt2['id'],read=True) assert t2['summary']=='1st subtask' assert 'subtask' in t2['tags']
def iteration_commits(request,iteration,branch): gwu = cfg.GITWEB_URL its = get_iterations() it = [it for it in its if it[1]['name']==iteration][0] start_date = it[1]['start date'] end_date = it[1]['end date'] #print('commits on iteration %s to branch %s'%(iteration,branch)) tf = get_fns(recurse=True) metas = [os.path.join(os.path.dirname(t),'meta.json') for t in tf] agg={} ; repos=[] ; task_data={} ; lastcommits={} for m in metas: tid = '/'.join(os.path.dirname(m).split('/')[2:]) if not os.path.exists(m): continue md = loadmeta(m) if 'branchlastcommits' not in md: continue blc = md['branchlastcommits'] for br,stmp in blc.items(): if '/' not in br: #print "%s has no /"%(br) continue try: repo,br = br.split('/') except ValueError: #print '%s has too many /'%(br) continue stmp = parsegitdate(stmp) if not (stmp.date()>=start_date.date() and stmp.date()<=end_date.date()): #print 'bad commit date %s'%stmp continue if not (branch=='all' or branch==br): #print 'branch mismatch %s<>%s'%(branch,br) continue if tid not in agg: agg[tid]={} if repo not in agg[tid]: agg[tid][repo]=[] agg[tid][repo].append(br) if tid not in task_data: t = get_task(tid) task_data[tid]=t if tid not in lastcommits: lastcommits[tid]=stmp if stmp>=lastcommits[tid]: lastcommits[tid]=stmp if repo not in repos: repos.append(repo) #print(tid,repo,br,stmp) agg = list(agg.items()) def lcsort(i1,i2): return cmp(lastcommits[i1[0]],lastcommits[i2[0]]) agg.sort(lcsort,reverse=True) return {'agg':agg,'it':it,'branch':branch,'repos':repos,'gwu':gwu,'task_data':task_data,'lastcommits':lastcommits,'request':request}
def metastate_set(request): k = request.params.get('k') v = request.params.get('v') spl = k.split('-') tid = spl[1] msk = '-'.join(spl[2:]) #_,tid,msk = adm = get_admin(request,'unknown') #special case if msk=='work estimate': t = get_task(tid) #print '%s = %s + %s'%(msk,t['total_hours'],v) #v = "%4.2f"%(float(t.get('total_hours',0))+float(v)) else: t = get_task(tid) print 'setting %s.%s = %s'%(tid,msk,v) append_journal_entry(t,adm,'',{msk:v}) return {'status':'ok'}
def history(request,task): t = get_task(task) st,op = gso('git log --follow -- %s'%(os.path.join(cfg.DATADIR,task,'task.org'))) ; assert st==0 commitsi = cre.finditer(op) for c in commitsi: cid = c.group(1) url = '%(gitweb_url)s/?p=%(docs_reponame)s;a=commitdiff;h=%(cid)s'%{'cid':cid,'gitweb_url':cfg.GITWEB_URL,'docs_reponame':cfg.DOCS_REPONAME} op = op.replace(cid,"<a href='%(url)s'>%(cid)s</a>"%{'cid':cid,'url':url}) t['summary'] = '' rt = {'op':op,'task':t,'request':request} return rt
def rpr(request,task,journal=False,render_only=False): t= get_task(task) if journal: vn = 'jpath' else: vn = 'path' cmd = 'emacs -batch --visit="%s" --funcall org-export-as-html-batch'%(t[vn]) st,op = gso(cmd) ; assert st==0,"%s returned %s\n%s"%(cmd,st,op) rt = open(t[vn].replace('.org','.html'),'r').read() if render_only: return rt r = Response() r.body = rt return r
def global_journal(request,creator=None,day=None,groupby=None,state=None): adm = get_admin(request,'unknown') ai = [] if day=='current': daya=datetime.datetime.now().date() #strftime('%Y-%m-%d') day = [daya,daya] elif day: if ':' in day: days = day.split(':') daya = datetime.datetime.strptime(days[0],'%Y-%m-%d').date() dayb = datetime.datetime.strptime(days[1],'%Y-%m-%d').date() day = [daya,dayb] else: daya = datetime.datetime.strptime(day,'%Y-%m-%d').date() day = [daya,daya] print 'obtaining journals' gaj = get_all_journals(day) print 'obtained; reading %s journals'%len(gaj) for jt in gaj: if hasattr(jt,'tid'): ji = [jt] jt = get_task(jt.tid) else: ji = jt.journal if creator: ji = [i for i in ji if i['creator']==creator] if state: sk,sv = state.split('=') ji = [i for i in ji if dict(i)['attrs'].get(sk)==sv] for jii in ji: jii['tid']=jt._id ai+=ji print 'finished reading. sorting' ai.sort(lambda x1,x2: cmp(x1['created_at'],x2['created_at'])) print 'sorted' if groupby: rt={} for i in ai: assert groupby in i k = 'entries for %s'%i[groupby] if k not in rt: rt[k]=[] rt[k].append(i) return {'j':rt,'task':None,'groupby':groupby,'user':adm} else: return {'j':{'all':ai},'task':None,'grouby':None,'user':adm}
def journal_edit(request,task,jid): adm = get_admin(request,'unknown') t = get_task(task) if request.method=='POST': metastates={} for ms,msvals in METASTATES.items(): msv = request.params.get(ms) if msv and msv in msvals: metastates[ms]=msv append_journal_entry(t,adm,request.params.get('content'),metastates) redir = '/'+URL_PREFIX+task+'/j' rd = Redirect(redir) return rd j = rpr(request,task,journal=True,render_only=True) return {'t':t,'j':j,'metastates':METASTATES}
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}
trow = c3.fetchone() if not trow: break tsum,tcomplete,tassignee = trow ptasks.append({'summary':tsum,'complete':tcomplete,'assignee':(tassignee and usermap[tassignee] or None)}) r['stasks']=ptasks iterdir = os.path.join(cfg.DATADIR,r['iteration']) if not os.path.exists(iterdir): os.mkdir(iterdir) iterfn = os.path.join(iterdir,'iteration.org') render('iteration',iterinfo[r['iteration']],iterfn) assert r['story_id'] #make sure we are not overwriting if 'force' not in sys.argv: t = get_task(r['story_id'],exc=False) if t: continue storydir = os.path.join(iterdir,str(r['story_id'])) if not os.path.exists(storydir): os.mkdir(storydir) print 'rendering story %s'%r['story_id'] try: r['detail'] = r['detail'].decode('utf-8') #raise Exception(type(r['detail'])) except UnicodeDecodeError: r['detail']= r['detail'].decode('cp1251') r['tags']=storytags #r['detail'] = r['detail'].decode('utf-8') storyfn = os.path.join(storydir,cfg.TASKFN)
#external_ids_msg_ids = [i['value'] for i in list(Task.view('task/external_msg_ids',key=md['mid']))] # we are a reply if the thread exists in the db and our id is not that of the top level task (already created) # here we are ABSOLUTELY RELYING ON THE FACT that tasks are fed to us in per thread, chronological order! is_reply = len(thread_task_ids) and not len(external_ids_task_ids) force_id = None tres = tre.search(md['orig_subj']) if tres: force_id = tres.group(1) is_reply = True print('DETERMINED TID FROM SUBJECT', force_id) if len(external_ids_task_ids): ext = get_task(external_ids_task_ids[0]) else: ext = None if not is_reply: print('NOT A REPLY, commencing, unq key %s' % md['unq_key']) # do we have an existing task with that unique key? if not force_id: if len(external_ids_task_ids): force_id = external_ids_task_ids[0] print('FORCING UPDATE ON ID %s' % force_id) else: force_id = None print('CREATING NEW') uns = "** Email contents\n"
def journal(request,task): t = get_task(task) jitems = read_journal(t) return {'task':t,'j':{'%s existing entries'%t._id:jitems},'metastates':METASTATES}
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, }