PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/visual/views.py

https://github.com/danohuiginn/yak
Python | 190 lines | 174 code | 7 blank | 9 comment | 1 complexity | 8e4ecbb44f51aa50df12b3b7afa648c3 MD5 | raw file
  1. # Create your views here.
  2. from django.http import HttpResponse
  3. from django.shortcuts import render_to_response
  4. from django.core.exceptions import ObjectDoesNotExist
  5. from django.contrib.auth.decorators import login_required
  6. import glob, json, re
  7. from collections import defaultdict
  8. from markdown import markdown
  9. from datetime import datetime, timedelta
  10. import dateutil
  11. from models import RecurringTask, RecurringTaskResult
  12. import string
  13. PROJECT_FILES = '/home/src/notes/todo/p*txt' #glob
  14. project_sortorder = (
  15. 'active', 'fading', 'inactive', 'on hold', 'paused',
  16. 'unknown', 'completed', 'abandoned')
  17. project_sortdict = dict(zip(project_sortorder, string.letters))
  18. def asciiffs(brokenstring):
  19. """
  20. Like UnicodeDammit, but actually works. And breaks any non-ascii input.
  21. """
  22. return ''.join(x for x in brokenstring if ord(x) < 128)
  23. def findjson(text):
  24. """
  25. input is a string possibly containing a json string somewhere within it
  26. look for it, parse the json. return the parsed json, or {} if it doesn't exist
  27. """
  28. match = re.search('({.*?})', text, re.DOTALL)
  29. if match is None:
  30. return {}
  31. try:
  32. return json.loads(match.group(1))
  33. except ValueError:
  34. return {}
  35. def parselists(body):
  36. headings = ('TODO', 'NEXT', 'DONE')
  37. @login_required
  38. def do_task(request):
  39. date = request.GET.get('date', None)
  40. task_id = request.GET.get('task_id', None)
  41. result = request.GET.get('result', None)
  42. if not (date and result):
  43. return HttpResponse('Bad data')
  44. try:
  45. task = RecurringTask.objects.get(id = task_id)
  46. except ObjectDoesNotExist:
  47. return HttpResponse('No such task')
  48. try: #delete existing row
  49. dbrow = RecurringTaskResult.objects.get(date = date, task = task)
  50. dbrow.delete()
  51. return HttpResponse('Undone')
  52. except ObjectDoesNotExist:
  53. dbrow = RecurringTaskResult(date = date, task = task, result = task.max)
  54. dbrow.save()
  55. return HttpResponse(dbrow.result)
  56. @login_required
  57. def vimsaves(day = None):
  58. if day:
  59. try:
  60. day = dateutil.parser.parse(day)
  61. except ValueError:
  62. day = None
  63. if day is None:
  64. day = datetime.now()
  65. data = {
  66. 'day' : day,
  67. 'saves' : checkins_per_day(day),
  68. }
  69. return render_to_response('saves.html', data)
  70. def todolist(body, howmany = 3):
  71. """XXX: this needs to also incorporate details from non-vim
  72. sources. i.e. probably will need to operate with a wider set
  73. of inputs
  74. Output is a list of todo items
  75. """
  76. parts = re.split('TODO', body, 1)
  77. if len(parts) < 2:
  78. return []
  79. results = []
  80. for line in parts[1].split('\n'):
  81. line = line.strip()
  82. if line:
  83. results.append(line)
  84. if len(results) >= howmany:
  85. break
  86. return results
  87. def parse_textfile(filename):
  88. """handle the markup-plus thing, to get a usable object
  89. out of a plain text file"""
  90. data = defaultdict(str)
  91. textfile = open(filename, 'r')
  92. data.update({
  93. 'filename' : filename,
  94. 'title' : textfile.readline().strip(),
  95. 'status' : 'unknown',})
  96. body = textfile.read()
  97. data['body_plain'] = body
  98. data['body_markdown'] = markdown(asciiffs(body))
  99. data['todoitems'] = todolist(body)
  100. data.update(findjson(body))
  101. data['sortorder'] = project_sortdict.get(data['status'], 'z')
  102. #XXX json should probably be removed from the remainder of the body
  103. return data
  104. def get_projects():
  105. """XXX: probably want to bolt on some todo-list parsing here"""
  106. return [parse_textfile(x) for x in glob.glob(PROJECT_FILES)]
  107. @login_required
  108. def index(request):
  109. data = {'projects' : get_projects()}
  110. data.update(recurring_tasks())
  111. return render_to_response('dashboard.html', data)
  112. def dateify(predate):
  113. """
  114. turn a string containing a date into a datetime object
  115. if it is already a datetime object, return it unmodified
  116. return None for data we can't handle
  117. XXX: generalise this so it can handle all kinds of dates
  118. and get the strptime headache away from me
  119. """
  120. assert(isinstance(predate, (str, unicode, datetime)))
  121. if isinstance(predate, datetime):
  122. return predate
  123. formatstrings = ('%Y-%m-%d', '%Y')
  124. for formatstring in formatstrings:
  125. try:
  126. return datetime.strptime(predate, formatstring)
  127. except ValueError:
  128. continue
  129. return None
  130. def daterange(startdate, enddate, step = None):
  131. """
  132. XXX: this should be in a utils library somewhere
  133. Return a list of dates between startdate and enddate, exclusively
  134. step is one day by default, but can be specified otherwise
  135. dates can be supplied as datetime.datetime or datetime.date
  136. """
  137. startdate, enddate = map(dateify, (startdate, enddate))
  138. if step is None:
  139. step = timedelta(days = 1)
  140. dates = []
  141. while startdate <= enddate:
  142. dates.append(startdate)
  143. startdate += step
  144. return dates
  145. def recurring_tasks(request = None, startdate = None, enddate = None):
  146. enddate = enddate or datetime.now()
  147. startdate = startdate or (enddate - timedelta(days = 14))
  148. dates = daterange(startdate, enddate)
  149. dates.reverse()
  150. results = dict((x, []) for x in RecurringTask.objects.all())
  151. for date in dates:
  152. for result in results.keys():
  153. try:
  154. results[result].append(result.recurringtaskresult_set.get(date = date).result)
  155. except ObjectDoesNotExist:
  156. results[result].append('')
  157. return {
  158. 'recur_dates' : [x.strftime('%F') for x in dates],
  159. 'recur_tasks' : results}