Skip to content

Instantly share code, notes, and snippets.

@jamespan
Created October 5, 2016 04:46
Show Gist options
  • Save jamespan/cb364331daeb10682cde4b535fa1a7e9 to your computer and use it in GitHub Desktop.
Save jamespan/cb364331daeb10682cde4b535fa1a7e9 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# coding=utf-8
import datetime
import dateutil.parser
import pytz
import argparse
from collections import OrderedDict
import frontmatter
class Task(object):
def __init__(self, name):
self.name = name
self.completed = False
self.complete_date = None
self.due_date = None
self.defer_date = None
self.estimated_minutes = None
self._note = ''
self.note_metadata = None
self.note_body = None
@property
def note(self):
return self._note
@note.setter
def note(self, value):
self._note = value
metadata, content = frontmatter.parse(value)
self.note_metadata = metadata
self.note_body = content
class Project(object):
status_map = {
1178816616: 'ONHOLD',
1178816609: 'ACTIVE',
}
def __init__(self, name):
self.name = name
self._status = None
self.tasks = []
def add_task(self, task):
self.tasks.append(task)
@property
def status(self):
return self._status
@status.setter
def status(self, value):
if value in Project.status_map:
self._status = Project.status_map[value]
else:
self._status = str(value)
def completed_tasks(self):
return filter(lambda x: x.completed, self.tasks)
def incomplete_tasks(self):
return filter(lambda x: not x.completed, self.tasks)
def working_tasks(self):
return filter(lambda x: not x.completed and 'progress' in x.note_metadata, self.tasks)
class Workload(object):
def __init__(self, projects=None):
if projects is None:
projects = OrderedDict()
self.projects = projects
def add_project(self, project):
self.projects[project.name] = project
def get_project(self, name):
return self.projects[name]
def has_project(self, name):
return name in self.projects
def report(self):
rpt = ''
for name, project in self.projects.iteritems():
indent_level = 0
rpt += ' ' * indent_level + '+ ' + name + '\n'
indent_level += 2
for task in project.tasks:
if task.complete_date is not None:
rpt += ' ' * indent_level + '+ ' + task.name + '\n'
return rpt
def build_workload(workload, filters):
# from Foundation import *
from ScriptingBridge import SBApplication
omniFocus = SBApplication.applicationWithBundleIdentifier_("com.omnigroup.OmniFocus2")
omniFocusDocument = omniFocus.defaultDocument()
for omniFocusProject in omniFocusDocument.flattenedProjects():
folder = omniFocusProject.folder().get()
if folder is not None:
folder = folder.name()
if 'folder' in filters and filters['folder'] and folder not in filters['folder']:
continue
project = Project(omniFocusProject.name())
project.status = omniFocusProject.status()
for omniFocusTask in omniFocusProject.rootTask().flattenedTasks():
t = Task(omniFocusTask.name())
if omniFocusTask.completed():
complete_date = dateutil.parser.parse(str(omniFocusTask.completionDate().get()))
if 'start' in filters and complete_date < filters['start']:
continue
t.complete_date = complete_date
t.completed = True
defer_date = str(omniFocusTask.deferDate().get())
if defer_date is not None and defer_date.strip() != 'None':
t.defer_date = dateutil.parser.parse(defer_date)
due_date = str(omniFocusTask.dueDate().get())
if due_date is not None and due_date.strip() != 'None':
t.due_date = dateutil.parser.parse(due_date)
estimated = omniFocusTask.estimatedMinutes().get()
if estimated is not None:
t.estimated_minutes = int(estimated)
t.note = omniFocusTask.note().text()
project.add_task(t)
if len(project.tasks) > 0:
workload.add_project(project)
parser = argparse.ArgumentParser('Omni Weekly')
parser.add_argument('--folder', dest='folders', default=[], action='append',
help='project folders to scan and generate report')
args = parser.parse_args()
filter_folder = args.folders
filter_deadline = datetime.datetime.now(pytz.timezone('Asia/Shanghai'))
filter_period_days = 7
filter_start = filter_deadline - datetime.timedelta(days=filter_period_days)
class JinjaReportWorkload(Workload):
def __init__(self, projects=None):
super(JinjaReportWorkload, self).__init__(projects)
self.template = u"""
1. 已经完成:
{%- for name, project in workload.projects.iteritems() %}
{%- if project.completed_tasks() %}
+ {{ name }}
{%- for task in project.tasks %}
{%- if task.completed %}
+ {{ task.name }}{%- if task.note_body -%}:{{ task.note_body }}{%- endif %}
{%- if task.estimated_minutes or task.note_metadata.issue %}
{% if task.estimated_minutes -%}[{{ task.estimated_minutes//25 }}🍅]{%- endif -%}
{%- if task.note_metadata.issue -%}[[Aone]({{ task.note_metadata.issue }})]{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- endfor %}
2. 仍在进行:
{%- for name, project in workload.projects.iteritems() %}
{%- if project.working_tasks() %}
+ {{ name }}
{%- for task in project.tasks %}
{%- if not task.completed and task.note_metadata.progress %}
+ {{ task.name }}{%- if task.note_body -%}:{{ task.note_body }} {% else %} {% endif %}
[估计进度 {{ task.note_metadata.progress }}]
{%- if task.note_metadata.issue -%}[[Aone]({{ task.note_metadata.issue }})]{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- endfor %}
3. 下周计划:
{%- for name, project in workload.projects.iteritems() %}
{%- if project.status == 'ACTIVE' and project.incomplete_tasks() %}
+ {{ name }}
{%- for task in project.tasks %}
{%- if not task.completed %}
+ {{ task.name }}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- endfor -%}
"""
def report(self):
from jinja2 import Environment
return Environment().from_string(self.template).render({'workload': self})
Workload = JinjaReportWorkload
workload = Workload()
build_workload(workload, {
'folder': filter_folder,
'start': filter_start
})
print workload.report().encode('utf-8')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment