#!/bin/bash /usr/scripts/python.sh
# -*- encoding: utf-8 -*-

""" Pour détecter les gens en chambre invalide, les prévenir, et supprimer leurs
machines en l'absence de réponse. Récupérer des IPs, c'est cool.

Codé par b2moo, commenté par 20-100, cr{itiqu|on}é par Nit
<daniel.stan@crans.org>
<legallic@crans.org>
<samir@crans.org>
"""

import sys
import os
import datetime
import time
import re

import affichage
import lc_ldap.shortcuts
from lc_ldap.crans_utils import to_generalized_time_format as to_gtf

import mail as mail_module
from config import demenagement_delai as delai, \
    debut_periode_transitoire, periode_transitoire

ERASE_DAY = { 'second': 0, 'minute': 0, 'microsecond': 0, 'hour': 0, }
DAY = datetime.timedelta(days=1)
FORMAT_LDAP = '%Y%m%d%H%M%S%z'

RESP = 'respbats@crans.org'

FILTER = u'''(&
    (aid=*)
    (chbre=????)
    (finAdhesion>=%(date)s)
    (finConnexion>=%(date)s)
)'''

# On récupère ceux qui n'ont pas payé cette année
now = datetime.datetime.now().replace(**ERASE_DAY)

def get_kickout(adh):
    """Renvoie la date et la chambre de la dernière expulsion"""
    # On cherche la dernière fois qu'il s'est retrouvé en chambre ????
    for l in adh['historique'][::-1]:
        # On récupère la date du dernier changement de chambre
        #  (l'historique est enregistré par ordre chronologique)
        x = re.match("(.*),.* : chbre \((.*) -> \?\?\?\?\)", str(l))
        if x <> None:
            return (l.get_datetime(), x.group(2))
    raise IndexError('Adh jamais expulse')

def warn_or_delete(smtp, clandestin, fail, done):
    """Avertit l'adhérent ou supprime ses machines si nécessaire"""
    date, exchambre = get_kickout(clandestin)

    # Date de suppression prévue
    date_suppr = date + delai*DAY

    if date_suppr < now: # A expiré
        reason = u'Adhérent sans chambre valide depuis %d jours' % delai
        for m in clandestin.machines(mode='rw'):
            try:
                with m:
                    m.delete(reason)
                done.append(m)
            except Exception as e:
                fail.append((m, e))
    elif date_suppr < now + DAY or now - date < DAY:
        # Expire dans un jour ou vient tout juste de se faire virer
        mail_addr = clandestin.get_mail()
        if not clandestin.machines() or not mail_addr:
            return # Si pas de machine, on s'en fout. Si pas de mail, inutile
        try:
            data = {
                'dn': clandestin.dn.split(',')[0],
                'when': now.strftime('%Y/%M/%D %H:%m:%S:%s'),
                'chbre' : exchambre,
            }
            chbre_url = mail_module.validation_url('demenagement', data, True)
            chbre_url_error = u""
        except Exception as error:
            chbre_url_error = u"[[erreur de génération: %r]]" % error
            chbre_url = u""
        data = {
            "from" : RESP,
            "chambre" : exchambre,
            "jours" : (date_suppr - now).days+1,
            "to" : mail_addr,
            "adh": clandestin,
            "chbre_url" : chbre_url,
            "chbre_url_error" : chbre_url_error,
            "lang_info": "English version below",
        }
        smtp.send_template('demenagement', data)

def format_entry(m):
    """Renvoie une ligne de tableau, pour une machine"""
    return [
        unicode(m['host'][0]),
        unicode(' '.join(m.dn.split(',')[:2])),
    ]

def spaces(x):
    """Ajoute des espaces en plus sur un tableau de tableau de strings"""
    if type(x) == list:
        return map(spaces, x)
    else:
        return u' ' + unicode(x) + u' '

if __name__ == '__main__':
    conn = lc_ldap.shortcuts.lc_ldap_admin()

    if periode_transitoire:
        date = to_gtf(debut_periode_transitoire)
    else:
        date = now.strftime(FORMAT_LDAP) + 'Z'

    bad_boys_e_s = conn.search(FILTER % {'date': date})

    fail = []
    done = []
    with mail_module.ServerConnection() as smtp:
        for clandestin in bad_boys_e_s:
            warn_or_delete(smtp, clandestin, fail, done)

    if fail or done:
        done = spaces([format_entry(m) for m in done])
        fail = spaces([format_entry(m) + [e] for (m,e) in fail])
        data = {
            'from': RESP,
            'to': RESP,
            'delai': delai,
            'fail': fail,
            'done': done,
            'done_tab': affichage.tableau(
                done,
                titre=[u'Hôte', u'Référence'],
                alignement=['d', 'd'],
            ),
            'fail_tab': affichage.tableau(
                fail,
                titre=[u'Hôte', u'Référence', u'Erreurs'],
                alignement=['d', 'd', 'd'],
            ),
        }
        with mail_module.ServerConnection() as smtp:
            mail = mail_module.generate('demenagement_stats', data)
            smtp.sendmail(RESP, [RESP], mail.as_string())
