Add ability to generate a meeting index
Adding optional parameters -t and -w used to generate an index of meetings using a Jinja2 template. Refactor output file/dir preparation so that index generation can make use of it. Expose UTC time in the Schedule object and human-friendly description of the recurrence in the Recurrence objects, so that they are directly usable in the templates. Change-Id: I103ac552f43a02a0b6e2e3ad6e5f52a6877efa68
This commit is contained in:
parent
f14a9b4736
commit
8bc6cf87c5
|
@ -0,0 +1,18 @@
|
|||
<h1>IRC meetings</h1>
|
||||
|
||||
{% for meeting in meetings %}
|
||||
<h3>{{ meeting.project }}</h3>
|
||||
|
||||
<ul>
|
||||
{% for schedule in meeting.schedules %}
|
||||
<li>{{ schedule.recurrence }} on {{ schedule.day }} at
|
||||
<a href="http://www.timeanddate.com/worldclock/fixedtime.html?hour={{ schedule.utc[:2] }}&min={{ schedule.utc[2:] }}&sec=0">{{ schedule.utc }} UTC</a>
|
||||
in #{{ schedule.irc }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
Chair (to contact for more information): {{ meeting.chair }}</p>
|
||||
|
||||
{{ meeting.description|urlize }}
|
||||
|
||||
{% endfor %}
|
|
@ -1,4 +1,5 @@
|
|||
pbr>=0.6,!=0.7,<1.0
|
||||
argparse
|
||||
icalendar
|
||||
jinja2
|
||||
pyyaml
|
||||
|
|
|
@ -15,6 +15,8 @@ import logging
|
|||
import os
|
||||
|
||||
from yaml2ical import ical
|
||||
from yaml2ical import index
|
||||
from yaml2ical import meeting
|
||||
|
||||
|
||||
# logging settings
|
||||
|
@ -45,48 +47,79 @@ project infrastructure.
|
|||
outputtype.add_argument("-o", "--output",
|
||||
dest="icalfile",
|
||||
help="output file (one file for all meetings)")
|
||||
parser.add_argument("-t", "--indextemplate",
|
||||
dest="index_template",
|
||||
help="generate an index from selected meetings")
|
||||
parser.add_argument("-w", "--indexoutput",
|
||||
dest="index_output",
|
||||
help="output index file")
|
||||
parser.add_argument("-f", "--force",
|
||||
dest="force",
|
||||
action='store_true',
|
||||
help="forcefully remove/overwrite previous .ics "
|
||||
"output files")
|
||||
help="remove/overwrite previous output files")
|
||||
|
||||
# parse arguments:
|
||||
return parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
|
||||
if ((args.index_template and not args.index_output) or
|
||||
(args.index_output and not args.index_template)):
|
||||
parser.error("You need to provide both -t and "
|
||||
"-w if you want to output an index.")
|
||||
return args
|
||||
|
||||
|
||||
def _check_if_location_exists(location):
|
||||
if not os.path.isdir(location):
|
||||
raise ValueError("Invalid location %s" % location)
|
||||
def _check_if_location_exists(location, style='f'):
|
||||
if style == 'd' and not os.path.isdir(location):
|
||||
raise ValueError("Directory %s does not exist" % location)
|
||||
if style == 'f' and not os.path.isfile(location):
|
||||
raise ValueError("File %s does not exist" % location)
|
||||
|
||||
|
||||
def _prepare_output(output, style='f', force=False):
|
||||
location = os.path.abspath(output)
|
||||
if style == 'd':
|
||||
_check_if_location_exists(location, style=style)
|
||||
if os.listdir(location) != []:
|
||||
if force:
|
||||
for f in os.listdir(location):
|
||||
file_path = os.path.join(location, f)
|
||||
os.remove(file_path)
|
||||
else:
|
||||
raise Exception("Directory for storing iCals is not empty, "
|
||||
"suggest running with -f to remove old files.")
|
||||
else:
|
||||
if os.path.exists(location):
|
||||
if force:
|
||||
os.remove(location)
|
||||
else:
|
||||
raise Exception("Output file already exists, suggest running "
|
||||
"with -f to overwrite previous file.")
|
||||
return location
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
yaml_dir = os.path.abspath(args.yaml_dir)
|
||||
_check_if_location_exists(yaml_dir)
|
||||
if args.ical_dir:
|
||||
ical_dir = os.path.abspath(args.ical_dir)
|
||||
_check_if_location_exists(ical_dir)
|
||||
_check_if_location_exists(yaml_dir, style='d')
|
||||
|
||||
if os.listdir(ical_dir) != []:
|
||||
if args.force:
|
||||
for f in os.listdir(ical_dir):
|
||||
file_path = os.path.join(ical_dir, f)
|
||||
os.remove(file_path)
|
||||
else:
|
||||
raise Exception("Directory for storing iCals is not empty, "
|
||||
"suggest running with -f to remove old files.")
|
||||
ical.convert_yaml_to_ical(yaml_dir, outputdir=ical_dir)
|
||||
meetings = meeting.load_meetings(yaml_dir)
|
||||
# Check uniqueness and conflicts here before writing out to .ics
|
||||
meeting.check_for_meeting_conflicts(meetings)
|
||||
|
||||
if args.ical_dir:
|
||||
ical_dir = _prepare_output(args.ical_dir, style='d', force=args.force)
|
||||
ical.convert_meetings_to_ical(meetings, outputdir=ical_dir)
|
||||
else:
|
||||
icalfile = os.path.abspath(args.icalfile)
|
||||
if os.path.exists(icalfile):
|
||||
if args.force:
|
||||
os.remove(icalfile)
|
||||
else:
|
||||
raise Exception("Output file already exists, suggest running "
|
||||
"with -f to overwrite previous file.")
|
||||
ical.convert_yaml_to_ical(yaml_dir, outputfile=icalfile)
|
||||
icalfile = _prepare_output(args.icalfile, force=args.force)
|
||||
ical.convert_meetings_to_ical(meetings, outputfile=icalfile)
|
||||
|
||||
if args.index_template and args.index_output:
|
||||
index_template = os.path.abspath(args.index_template)
|
||||
_check_if_location_exists(index_template)
|
||||
index_output = _prepare_output(args.index_output, force=args.force)
|
||||
index.convert_meetings_to_index(
|
||||
meetings, index_template, index_output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -17,8 +17,6 @@ import os
|
|||
import os.path
|
||||
import pytz
|
||||
|
||||
from yaml2ical import meeting
|
||||
|
||||
|
||||
class Yaml2IcalCalendar(icalendar.Calendar):
|
||||
"""A calendar in ics format."""
|
||||
|
@ -78,22 +76,14 @@ class Yaml2IcalCalendar(icalendar.Calendar):
|
|||
ics.write(self.to_ical())
|
||||
|
||||
|
||||
def convert_yaml_to_ical(yaml_dir, outputdir=None, outputfile=None):
|
||||
"""Convert meeting YAML files to iCal.
|
||||
def convert_meetings_to_ical(meetings, outputdir=None, outputfile=None):
|
||||
"""Converts a meeting list to iCal.
|
||||
|
||||
If meeting_list is specified, only those meetings in yaml_dir with
|
||||
filenames contained in meeting_list are converted; otherwise,
|
||||
all meeting in yaml_dir are converted.
|
||||
|
||||
:param yaml_dir: directory where meeting.yaml files are stored
|
||||
:param meetings: list of meetings to convert
|
||||
:param outputdir: location to store iCal files (one file per meeting)
|
||||
:param outputfile: output iCal file (one single file for all meetings)
|
||||
|
||||
"""
|
||||
meetings = meeting.load_meetings(yaml_dir)
|
||||
|
||||
# Check uniqueness and conflicts here before writing out to .ics
|
||||
meeting.check_for_meeting_conflicts(meetings)
|
||||
|
||||
# convert meetings to a list of ical
|
||||
if outputdir:
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import jinja2
|
||||
import logging
|
||||
import os
|
||||
import os.path
|
||||
|
||||
|
||||
def convert_meetings_to_index(meetings, template, output_file):
|
||||
"""Creates index file from list of meetings.
|
||||
|
||||
:param meetings: list of meetings to convert
|
||||
:param template: jinja2 template to use
|
||||
:param output_file: output index file
|
||||
|
||||
"""
|
||||
|
||||
(template_dir, template_file) = os.path.split(template)
|
||||
loader = jinja2.FileSystemLoader(template_dir)
|
||||
env = jinja2.environment.Environment(trim_blocks=True, loader=loader)
|
||||
template = env.get_template(template_file)
|
||||
|
||||
with open(output_file, "w") as out:
|
||||
out.write(template.render(meetings=meetings))
|
||||
|
||||
logging.info('Wrote %d meetings to index.' % (len(meetings)))
|
|
@ -29,6 +29,7 @@ class Schedule(object):
|
|||
self.project = meeting.project
|
||||
self.filefrom = meeting.filefrom
|
||||
try:
|
||||
self.utc = sched_yaml['time']
|
||||
self.time = datetime.datetime.strptime(sched_yaml['time'], '%H%M')
|
||||
self.day = sched_yaml['day']
|
||||
self.irc = sched_yaml['irc']
|
||||
|
|
|
@ -40,6 +40,9 @@ class WeeklyRecurrence(object):
|
|||
def rrule(self):
|
||||
return {'freq': 'weekly'}
|
||||
|
||||
def __str__(self):
|
||||
return "Weekly"
|
||||
|
||||
|
||||
class BiWeeklyRecurrence(object):
|
||||
"""Meetings occuring on alternate weeks.
|
||||
|
@ -71,6 +74,9 @@ class BiWeeklyRecurrence(object):
|
|||
def rrule(self):
|
||||
return {'freq': 'weekly', 'interval': 2}
|
||||
|
||||
def __str__(self):
|
||||
return "Every two weeks (on %s weeks)" % self.style
|
||||
|
||||
|
||||
supported_recurrences = {
|
||||
'weekly': WeeklyRecurrence(),
|
||||
|
|
Loading…
Reference in New Issue