163 lines
4.9 KiB
Python
163 lines
4.9 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
"""This module globally bundles some utility functions for my ctdo plugins"""
|
||
|
|
||
|
|
||
|
from sys import maxint
|
||
|
from datetime import datetime, date, time
|
||
|
from trac.util.datefmt import utc, timezone
|
||
|
from re import match
|
||
|
from trac.wiki import WikiPage
|
||
|
from trac.web.chrome import ITemplateProvider
|
||
|
from trac.core import Component, implements, TracError
|
||
|
|
||
|
class CTDOTools(Component):
|
||
|
implements(ITemplateProvider)
|
||
|
|
||
|
# ITemplateProvider methods
|
||
|
def get_templates_dirs(self):
|
||
|
from pkg_resources import resource_filename
|
||
|
return [resource_filename(__name__, 'templates')]
|
||
|
|
||
|
def get_htdocs_dirs(self):
|
||
|
"""Return a list of directories with static resources (such as style
|
||
|
sheets, images, etc.)
|
||
|
|
||
|
Each item in the list must be a `(prefix, abspath)` tuple. The
|
||
|
`prefix` part defines the path in the URL that requests to these
|
||
|
resources are prefixed with.
|
||
|
|
||
|
The `abspath` is the absolute path to the directory containing the
|
||
|
resources on the local file system.
|
||
|
"""
|
||
|
from pkg_resources import resource_filename
|
||
|
return [('hw', resource_filename(__name__, 'htdocs'))]
|
||
|
|
||
|
|
||
|
class ValidationError(ValueError):
|
||
|
"""simple exception class"""
|
||
|
def __str__(self):
|
||
|
return "ValidationError: value out of bounds!"
|
||
|
|
||
|
def validate_id(value):
|
||
|
"""type and range check"""
|
||
|
if (0 > int(value) > maxint):
|
||
|
raise ValidationError("invalid argument")
|
||
|
|
||
|
def validate_email(addr):
|
||
|
"""validates email against rfc822"""
|
||
|
rfc822_specials = '()<>@,;:\\"[]'
|
||
|
# First we validate the name portion (name@domain)
|
||
|
mychar = 0
|
||
|
while mychar < len(addr):
|
||
|
if addr[mychar] == '"' and (
|
||
|
not mychar or addr[mychar - 1] == '.' or addr[mychar - 1] == '"'):
|
||
|
mychar = mychar + 1
|
||
|
while mychar < len(addr):
|
||
|
if addr[mychar] == '"':
|
||
|
break
|
||
|
if addr[mychar] == '\\' and addr[mychar + 1] == ' ':
|
||
|
mychar += 2
|
||
|
continue
|
||
|
if ord(addr[mychar]) < 32 or ord(addr[mychar]) >= 127:
|
||
|
return 0
|
||
|
mychar += 1
|
||
|
else:
|
||
|
return False
|
||
|
if addr[mychar] == '@':
|
||
|
break
|
||
|
if addr[mychar] != '.':
|
||
|
return False
|
||
|
mychar += 1
|
||
|
continue
|
||
|
if addr[mychar] == '@':
|
||
|
break
|
||
|
if ord(addr[mychar]) <= 32 or ord(addr[mychar]) >= 127:
|
||
|
return False
|
||
|
if addr[mychar] in rfc822_specials:
|
||
|
return False
|
||
|
mychar += 1
|
||
|
if not mychar or addr[mychar - 1] == '.':
|
||
|
return False
|
||
|
# Next we validate the domain portion (name@domain)
|
||
|
domain = mychar = mychar + 1
|
||
|
if domain >= len(addr):
|
||
|
return False
|
||
|
count = 0
|
||
|
while mychar < len(addr):
|
||
|
if addr[mychar] == '.':
|
||
|
if mychar == domain or addr[mychar - 1] == '.':
|
||
|
return False
|
||
|
count += 1
|
||
|
if ord(addr[mychar]) <= 32 or ord(addr[mychar]) >= 127:
|
||
|
return False
|
||
|
if addr[mychar] in rfc822_specials:
|
||
|
return False
|
||
|
mychar += 1
|
||
|
return count >= 1
|
||
|
|
||
|
|
||
|
def gen_wiki_page(env, authname, page_name, content, remote_addr):
|
||
|
"""programatically creates a wiki page"""
|
||
|
|
||
|
page = WikiPage(env)
|
||
|
page.name = page_name
|
||
|
page.version = 1
|
||
|
page.text = content
|
||
|
page.save(authname,
|
||
|
'initially created by TracRendezVous',
|
||
|
remote_addr)
|
||
|
|
||
|
|
||
|
def date_cmp(left, right):
|
||
|
"""compares two dates"""
|
||
|
|
||
|
if left.time_begin < right.time_begin:
|
||
|
return -1
|
||
|
elif left.time_begin > right.time_begin:
|
||
|
return 1
|
||
|
else:
|
||
|
return 0
|
||
|
|
||
|
|
||
|
def date_parse(arg):
|
||
|
"""converts a date string of form dd.mm.yyyy into a datetime.date obj"""
|
||
|
groups = match("^(\d{1,2}).(\d{1,2}).(\d{4})$", arg).groups()
|
||
|
return date(int(groups[2]), int(groups[1]), int(groups[0]))
|
||
|
|
||
|
|
||
|
def time_parse(arg):
|
||
|
"""converts a time string of form MM:HH into a datetime.time obj"""
|
||
|
matched = match("^(\d{1,2}):(\d{1,2})$", arg).groups()
|
||
|
return time(int(matched[0]), int(matched[1]))
|
||
|
|
||
|
|
||
|
def datetime_parse(arg, tzinfo=utc):
|
||
|
"""converts a datetime string of form dd.mm.yyyy MM:HH into a
|
||
|
datetime.datetime obj"""
|
||
|
|
||
|
# get real tzinfo for the date taking dst into account
|
||
|
arg = datetime.strptime(arg, "%d.%m.%Y %H:%M").replace(tzinfo=tzinfo)
|
||
|
return local_to_utc(arg, tzinfo)
|
||
|
|
||
|
|
||
|
def local_to_utc(arg, tzinfo=utc):
|
||
|
"""converts local datetime to utc datetime"""
|
||
|
|
||
|
real_tz = tzinfo.fromutc(arg).tzinfo
|
||
|
return datetime(arg.year, arg.month, arg.day, arg.hour, arg.minute,
|
||
|
arg.second, tzinfo=real_tz).astimezone(utc)
|
||
|
|
||
|
|
||
|
def get_tz(session_tzname):
|
||
|
"""returns the timezone name and the timezone of the actual trac session"""
|
||
|
|
||
|
if session_tzname == 'UTC':
|
||
|
selected_tz = utc
|
||
|
else:
|
||
|
try:
|
||
|
selected_tz = timezone(session_tzname)
|
||
|
except Exception:
|
||
|
selected_tz = utc
|
||
|
return session_tzname, selected_tz
|