class Database(object):
    databases = {}

    @classmethod
    def register(cls, name):
        if name not in cls.databases:
            cls.databases[name] = declarative_base(cls=_Base)
        return cls.databases[name]

    @classmethod
    def get(cls, name):
        return cls.databases[name] class SessionFactory(object):

    sessions = {}

    @classmethod
    def register(cls, name, scoped, engine):
        if scoped:
            cls.sessions[name] = scoped_session(sessionmaker(bind=engine))
            register(cls.sessions[name])
        else:
            cls.sessions[name] = sessionmaker(bind=engine)
        return cls.sessions[name]

    @classmethod
    def get(cls, name):
        return cls.sessions[name]

    @classmethod
    def get_object_session(cls, object_):
        try:
            return cls.sessions[object_.__database__].object_session(object_)
        except KeyError:
            return None class ModelError(Exception):

    def __init__(self, errors):
        super(ModelError, self).__init__('\n'.join(errors))
        self.errors = errors def create_engine(db_name, settings, prefix='sqlalchemy.', scoped=False):
    engine = engine_from_config(settings, prefix)

    DBSession = SessionFactory.register(db_name, scoped, engine)
    DBSession.configure(bind=engine)
    Database.get(db_name).metadata.bind = engine

    return engine def dispose_engine(db_name):
    Database.get(db_name).metadata.bind.dispose() class LdapCache(object):
    """ Ldap cache class singleton """
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            raise RuntimeError('Ldap is not initialized')

        return cls._instance

    @classmethod
    def configure(cls, settings):
        cls._instance = cls.from_config(settings)

    @classmethod
    def from_config(cls, config, **kwargs):
        """
        Return a Ldap client object configured from the given configuration.
        """
        return LdapWrapper(config) def translate(string, country):
    # hack to use en locale for us country
    if country == 'us':
        country = 'en'
    if country == 'zh':
        country = 'en'

    if country in localizers:
        localizer = localizers[country]
    else:
        here = os.path.dirname(__file__)
        local_path = os.path.join(here, '../locale')
        localizer = make_localizer(country, [local_path])
        localizers[country] = localizer

    return localizer.translate(trans(string)) def addToCal(url, date_from, date_end, summary):
    """ Add entry in calendar to period date_from, date_end """

    vcal_entry = """BEGIN:VCALENDAR
VERSION:2.0
PRODID:Pyvac Calendar
BEGIN:VEVENT
SUMMARY:%s
DTSTART;VALUE=DATE:%s
DTEND;VALUE=DATE:%s
END:VEVENT
END:VCALENDAR
"""

    client = caldav.DAVClient(url)
    # use url parameter to force calendar to use
    principal = caldav.Principal(client, url)
    calendars = principal.calendars()
    if not len(calendars):
        return False

    vcal_entry = vcal_entry % (summary,
                               date_from.strftime('%Y%m%d'),
                               (date_end + relativedelta(days=1)).strftime('%Y%m%d'))
    calendar = calendars[0]
    log.info('Using calendar %r' % calendar)
    log.info('Using entry: %s' % vcal_entry)

    event = caldav.Event(client, data=vcal_entry, parent=calendar).save()
    log.info('Event %s created' % event)

    url_obj = event.url
    url_obj = str(url_obj)
    url_obj = urllib.parse.quote(url_obj, safe='/:')
    return url_obj def daterange(start_date, end_date):
    for n in range(int((end_date - start_date).days + 1)):
        yield start_date + timedelta(n) def utcify(date):
    """ return an UTC datetime from a Date object """
    return calendar.timegm(date.timetuple()) * 1000 def get_holiday(user, year=None, use_datetime=False):
    """ return holidays for user country

    format is unixtime for javascript
    """
    klass = conv_table[user.country]

    cal = klass()
    current_year = year or datetime.now().year
    next_year = current_year + 1

    # retrieve Dates from workalendar
    holiday_current_raw = [dt for dt, _ in cal.holidays(current_year)]
    holiday_next_raw = [dt for dt, _ in cal.holidays(next_year)]

    if user.country in override and current_year in override[user.country]:
        holiday_current_raw = [datetime.strptime(dt, '%Y-%m-%d')
                               for dt in
                               override[user.country][current_year]]

    if user.country in override and next_year in override[user.country]:
        holiday_next_raw = [datetime.strptime(dt, '%Y-%m-%d')
                            for dt in
                            override[user.country][next_year]]

    if not use_datetime:
        # must cast to javascript timestamp
        holiday_current = [utcify(dt) for dt in holiday_current_raw]
        holiday_next = [utcify(dt) for dt in holiday_next_raw]
    else:
        # must cast to datetime as workalendar returns only Date objects
        holiday_current = [datetime(dt.year, dt.month, dt.day)
                           for dt in holiday_current_raw]
        holiday_next = [datetime(dt.year, dt.month, dt.day)
                        for dt in holiday_next_raw]

    return holiday_current + holiday_next
import re
import logging
import json
import math
import cryptacular.bcrypt
import yaml
from datetime import datetime, timedelta
from pyramid.settings import asbool, aslist
from dateutil.relativedelta import relativedelta
from sqlalchemy import (Table, Column, ForeignKey, Enum,
                        Integer, Float, Boolean, Unicode, DateTime,
                        UnicodeText, Index, UniqueConstraint)
from sqlalchemy import or_, and_, func
from sqlalchemy.orm import relationship, synonym, backref
from sqlalchemy.ext.declarative import declared_attr
    from yaml import CSafeLoader as YAMLLoader
    from yaml import SafeLoader as YAMLLoader
from .helpers.sqla import (Database, SessionFactory, ModelError,
                           create_engine as create_engine_base,
                           dispose_engine as dispose_engine_base
                           )
from pyvac.helpers.ldap import LdapCache
from pyvac.helpers.i18n import translate as _
from pyvac.helpers.calendar import addToCal
from pyvac.helpers.util import daterange
from pyvac.helpers.holiday import utcify, get_holiday
        from calendar import monthrange
        from datetime import datetime
        from datetime import datetime
    def pool(self):
        """Retrieve pool status stored in json."""
        if self.pool_status:
            return json.loads(self.pool_status)
        return {}

    @property
    def pool_left(self):
        """Retrieve pool left status."""
        if self.pool:
            pool = self.pool
            if self.type == 'CP':
                if 'acquis' in pool:
                    return pool.get('n_1', {}).get('left', 0) + pool['restant']['left'] + pool['acquis']['left'] # noqa
                else:
                    # new pool format
                    # {u'CP acquis': 12.48, u'CP restant': 25.0, u'RTT': 12.0}
                    return pool.get('CP acquis', 0) + pool.get('CP restant', 0)
            else:
                # RTT
                if 'left' in pool:
                    return pool['left']
                else:
                    # new pool format
                    return pool.get('RTT', 0)
        return {}

    def refund_userpool(self, session):
        """refund userpool amount in case of CANCEL/DENIED."""
        UserPool.increment_request(session, self)

    @property
    def sudoed(self):
        """Retrieve is request was sudoed."""
        if self.status == 'APPROVED_ADMIN':
            if len(self.history) == 1:
                for entry in self.history:
                    if entry.sudo_user_id:
                        return entry.sudo_user

    @property
    def summary(self):
        """Get a short string representation of a request, for tooltip."""
        return ('%s: %s - %s' %
                (self.user.name,
                 self.date_from.strftime('%d/%m/%Y'),
                 self.date_to.strftime('%d/%m/%Y')))

    @property
    def summarycal(self):
        """Get a short string representation of a request.

        for calendar summary.
        """
        label = ' %s' % self.label if self.label else ''
        return ('%s - %.1f %s%s' %
                (self.user.name, self.days, self.type, label))

    @property
    def summarycsv(self):
        """Get a string representation in csv format of a request."""
        # name, datefrom, dateto, number of days, type of days, label, message
        label = '%s' % self.label if self.label else ''
        message = '%s' % self.message if self.message else ''
        days = self.days
        # XXX: must convert CPLU vacation to hours until 2017 cycle
        if self.user.country == 'lu':
            if self.type == 'CP':
                if self.created_at < datetime(2016, 7, 26):
                    days = CPLUVacation.convert_days(days)
            if self.type == 'Maladie':
                days = CPLUVacation.convert_days(days)
            if self.type == 'Compensatoire':
                days = CPLUVacation.convert_days(days)
            if self.type == 'Exceptionnel':
                days = CPLUVacation.convert_days(days)

        return ('%s,%s,%s,%s,%s,%.1f,%s,%s,%s' %
                (self.user.registration_number or '',
                 self.user.lastname,
                 self.user.firstname,
                 self.date_from.strftime('%d/%m/%Y'),
                 self.date_to.strftime('%d/%m/%Y'),
                 days,
                 self.type,
                 label,
                 message))

    @property
    def summarymail(self):
        """Get a short string representation of a request.

        for mail summary.
        """
        label = ' %s' % self.label if self.label else ''
        return ('%s: %s - %s (%.1f %s%s)' %
                (self.user.name,
                 self.date_from.strftime('%d/%m/%Y'),
                 self.date_to.strftime('%d/%m/%Y'),
                 self.days,
                 self.type,
                 label))

    @property
    def is_oldcplu(self):
        # XXX: must convert CPLU vacation to hours until 2017 cycle
        if (self.user.country == 'lu' and self.type == 'CP' and
                (self.created_at < datetime(2016, 7, 26))):
            return True

        return False

    @property
    def timestamps(self):
        """
        Return request dates as list of timestamps.

        timestamp are in javascript format
        """
        return [utcify(date)

                for date in daterange(self.date_from, self.date_to)