# Path: kittystore/events.py
# def subscribe(target, eventclass):
# def notify(event):
# def subscribe_to(eventclass):
#     def wrapper(f):
# def reset():
# 
# Path: kittystore/utils.py
# def get_message_id_hash(msg_id):
#     """
#     Returns the X-Message-ID-Hash header for the provided Message-ID header.
# 
#     See <http://wiki.list.org/display/DEV/Stable+URLs#StableURLs-Headers> for
#     details. Example:
# 
#     >>> get_message_id_hash('<87myycy5eh.fsf@uwakimon.sk.tsukuba.ac.jp>')
#     'JJIGKPKB6CVDX6B2CUG4IHAJRIQIOUTP'
# 
#     """
#     msg_id = email.utils.unquote(msg_id)
#     return unicode(b32encode(sha1(msg_id).digest()))
# 
# Path: kittystore/storm/utils.py
# def get_participants_count_between(store, list_name, begin_date, end_date):
#         from .model import Email
#         # We filter on emails dates instead of threads dates because that would
#         # also include last month's participants when threads carry from one
#         # month to the next
#         result = store.find(Email.sender_email, And(
#                         Email.list_name == list_name,
#                         Email.date >= begin_date,
#                         Email.date < end_date,
#                         )).config(distinct=True)
#         #return result.count() # generates a sub-query
#         return len(list(result))
# 
# def get_threads_between(store, list_name, begin_date, end_date):
#         from .model import Thread
#         return store.find(Thread, And(
#                     Thread.list_name == list_name,
#                     Thread.date_active >= begin_date,
#                     Thread.date_active < end_date,
#                 ))
# 
# Path: kittystore/storm/hack_datetime.py
# class DateTime(DateTime):
#     # Overwrite DateTime in Storm's locals
#     # pylint: disable-msg=E0102
#     variable_class = DateTimeVariableHack


import datetime
from collections import namedtuple
from zope.interface import implements
from storm.locals import Unicode, RawStr, Int, ReferenceSet, Reference, Proxy
from storm.locals import Storm, Store, And
from storm.expr import Desc
from mailman.interfaces.messages import IMessage
from mailman.interfaces.archiver import ArchivePolicy
from mailman.database.types import Enum
from kittystore import events
from kittystore.utils import get_message_id_hash
from .utils import get_participants_count_between, get_threads_between
from .hack_datetime import DateTime
    __storm_table__ = "list"

    # The following properties are mirrored from Mailman's MailingList instance
    mailman_props = ("display_name", "description", "subject_prefix",
                     "archive_policy", "created_at")

    name = Unicode(primary=True)
    display_name = Unicode()
    description = Unicode()
    subject_prefix = Unicode()
    archive_policy = Enum(ArchivePolicy)
    created_at = DateTime()

    def __init__(self, name):
        self.name = unicode(name)

    def get_recent_dates(self):
        today = datetime.datetime.utcnow()
        #today -= datetime.timedelta(days=400) #debug
        # the upper boundary is excluded in the search, add one day
        end_date = today + datetime.timedelta(days=1)
        begin_date = end_date - datetime.timedelta(days=32)
        return begin_date, end_date

    @property
    def recent_participants_count(self):
        store = Store.of(self)
        begin_date, end_date = self.get_recent_dates()
        return store.cache.get_or_create(
            str("list:%s:recent_participants_count" % self.name),

# Path: kittystore/events.py
# def subscribe(target, eventclass):
# def notify(event):
# def subscribe_to(eventclass):
#     def wrapper(f):
# def reset():
# 
# Path: kittystore/utils.py
# def get_message_id_hash(msg_id):
#     """
#     Returns the X-Message-ID-Hash header for the provided Message-ID header.
# 
#     See <http://wiki.list.org/display/DEV/Stable+URLs#StableURLs-Headers> for
#     details. Example:
# 
#     >>> get_message_id_hash('<87myycy5eh.fsf@uwakimon.sk.tsukuba.ac.jp>')
#     'JJIGKPKB6CVDX6B2CUG4IHAJRIQIOUTP'
# 
#     """
#     msg_id = email.utils.unquote(msg_id)
#     return unicode(b32encode(sha1(msg_id).digest()))
# 
# Path: kittystore/storm/utils.py
# def get_participants_count_between(store, list_name, begin_date, end_date):
#         from .model import Email
#         # We filter on emails dates instead of threads dates because that would
#         # also include last month's participants when threads carry from one
#         # month to the next
#         result = store.find(Email.sender_email, And(
#                         Email.list_name == list_name,
#                         Email.date >= begin_date,
#                         Email.date < end_date,
#                         )).config(distinct=True)
#         #return result.count() # generates a sub-query
#         return len(list(result))
# 
# def get_threads_between(store, list_name, begin_date, end_date):
#         from .model import Thread
#         return store.find(Thread, And(
#                     Thread.list_name == list_name,
#                     Thread.date_active >= begin_date,
#                     Thread.date_active < end_date,
#                 ))
# 
# Path: kittystore/storm/hack_datetime.py
# class DateTime(DateTime):
#     # Overwrite DateTime in Storm's locals
#     # pylint: disable-msg=E0102
#     variable_class = DateTimeVariableHack


# Path: kittystore/storm/model.py
import datetime
from collections import namedtuple
from zope.interface import implements
from storm.locals import Unicode, RawStr, Int, ReferenceSet, Reference, Proxy
from storm.locals import Storm, Store, And
from storm.expr import Desc
from mailman.interfaces.messages import IMessage
from mailman.interfaces.archiver import ArchivePolicy
from mailman.database.types import Enum
from kittystore import events
from kittystore.utils import get_message_id_hash
from .utils import get_participants_count_between, get_threads_between
from .hack_datetime import DateTime

    __storm_table__ = "list"

    # The following properties are mirrored from Mailman's MailingList instance
    mailman_props = ("display_name", "description", "subject_prefix",
                     "archive_policy", "created_at")

    name = Unicode(primary=True)
    display_name = Unicode()
    description = Unicode()
    subject_prefix = Unicode()
    archive_policy = Enum(ArchivePolicy)
    created_at = DateTime()

    def __init__(self, name):
        self.name = unicode(name)

    def get_recent_dates(self):
        today = datetime.datetime.utcnow()
        #today -= datetime.timedelta(days=400) #debug
        # the upper boundary is excluded in the search, add one day
        end_date = today + datetime.timedelta(days=1)
        begin_date = end_date - datetime.timedelta(days=32)
        return begin_date, end_date

    @property
    def recent_participants_count(self):
        store = Store.of(self)
        begin_date, end_date = self.get_recent_dates()
        return store.cache.get_or_create(
            str("list:%s:recent_participants_count" % self.name),

            lambda: get_participants_count_between(store, self.name,