# -*- coding: utf-8 -*-
###########################################################################
# Eole NG - 2009
# Copyright Pole de Competence Eole  (Ministere Education - Academie Dijon)
# Licence CeCill  cf /root/LicenceEole.txt
# eole@ac-dijon.fr
#
###########################################################################
"""
    Classe de gestion des users 'Administrateur'
"""
from os import system, makedirs
from os.path import join, isdir
from ldap import MOD_REPLACE, modlist
from datetime import datetime
import time
from fichier.quota import set_quota
from fichier.acl import set_owner, clear_acl, set_user_acl, copy_default_acl
from scribe.ldapconf import SMB_SERVEUR, HOME_PATH, MAIL_DOMAIN, PROF_FILTER, \
AD_HOME_PATH, ADMIN_GROUPS, USER_FILTER, num_etab, BRANCHE_GROUP_ETAB
from scribe.eoletools import fixdate, create_ad_home, \
to_list, not_empty, format_current_date, replace_cars, format_old_date
from scribe.eoleuser import User, gen_common_attrs, send_first_mail, \
gen_profil, gen_common_devdir, gen_radius_attrs


class Enseignant(User):
    """
        classe pour la gestion des enseignants Scribe
    """
    _type = 'personnels'
    profil = 'enseignant'
    filtre = "(&%s)" % PROF_FILTER
    must_args = ['login', 'password', 'nom', 'prenom', 'date', 'civilite']
    may_args = dict(classe='',
                    mail='internet',
                    quota='0',
                    profil='1',
                    shell=False,
                    change_pwd=False,
                    patronyme='',
                    admin=False,
                    mail_acad='',
                    int_id='',
                    groups=[],
                    entlogin=True,
                    disciplines='',
                    entpersonjointure='',
                    syncpassword=True,
                   )
    has_samba = True
    has_ftp = True

    def get_smbldap_useradd_args(self, login,  profil, shell, etab, **args):
        """
            ajoute un utilisateur à l'aide /usr/sbin/smbldap-useradd
        """
        if shell:
            shell = "bash"
        else:
            shell = "false"
        groups = to_list(args['groups'])
        if args['admin']:
            groups.extend(ADMIN_GROUPS)
        groups.append('DomainUsers')
        if etab is not None:
            groups.append(etab)
            groups.append('profs-{}'.format(etab))
        useradd_args = ['-o', 'ou=local,ou=personnels',
                        '-s', '/bin/%s' % shell,
                        '-d', '/home/%s/%s' % (login[0], login),
                        '-C', '\\\\{0}\\{1}\\perso'.format(SMB_SERVEUR, login),
                        '-F', '%s' % gen_profil(profil, login),
                        '-g', 'professeurs',
                        '-G', ','.join(groups)]

        if "temporary" in args:
            unixdays = (datetime.utcnow() - datetime(1970,1,1)).days
            unixdays += int(args["temporary"]) - 1
            useradd_args.extend(["-Z", "shadowExpire=%s" % unixdays])
        useradd_args.append(login)
        return useradd_args

    def _add_scribe_user(self, login, **args):
        """
            ajout les attributs Scribe à un Prof
        """
        mail = args['mail']
        if '@' not in mail:
            if mail in ['internet', 'restreint']:
                mail = "{0}@{1}".format(login, MAIL_DOMAIN[mail])
                maildir = self.get_maildir(login)
            else:
                mail = ''
                maildir = ''
        else:
            maildir = ''
        # compatibilité : Divcod=autre -> Divcod=[]
        if args['classe'] == 'autre':
            args['classe'] = ''
        classe = to_list(args['classe'])
        # Rappel : 0-> prof normal, 1-> utilisateur admin, 2-> prof principal
        if args['admin']:
            typeadmin = '1'
        elif classe == []:
            typeadmin = '0'
        else:
            typeadmin = '2'
        datas = []
        user_dn = self.get_user_dn(login) #USER_DN % dict(uid=login, _type=self._type)
        objectclass = self._get_attr(login, 'objectClass')
        objectclass.extend(['administrateur', 'ENTPerson', 'ENTAuxEnseignant', 'radiusprofile'])
        datas.append((MOD_REPLACE, 'objectClass', objectclass))
        datas.extend(gen_common_attrs(login, entprofil=self.profil, **args))
        datas.extend(gen_radius_attrs())
        if mail != '':
            datas.append((MOD_REPLACE, 'mail', mail))
        if maildir != '':
            datas.append((MOD_REPLACE, 'mailHost', 'localhost'))
            datas.append((MOD_REPLACE, 'mailDir', maildir))
        datas.append((MOD_REPLACE, 'typeadmin', typeadmin))
        datas.append((MOD_REPLACE, 'Divcod', classe))
        if not_empty(args, 'mail_acad'):
            datas.append((MOD_REPLACE, 'FederationKey',
                          args['mail_acad'].lower()))
        if not_empty(args, 'disciplines') and args['disciplines'] != []:
            datas.append((MOD_REPLACE, 'ENTAuxEnsCategoDiscipline',
                          args['disciplines']))
        # FIXME : remplissage d'autres attributs provenant de ENTAuxEnseignant
        self.ldap_admin._modify(user_dn, datas)
        if maildir != '':
            send_first_mail(mail)

    def _add_perso(self, login, **args):
        """
            Crée les différents répertoires de l'utilisateur
        """
        abc = join(HOME_PATH, login[0])
        rep = join(abc, login)
        perso = join(rep, 'perso')
        # Eole-AD
        create_ad_home(login, rep)
        if not isdir(perso):
            makedirs(perso, 0o700)
        rep = join(AD_HOME_PATH, login)
        # répertoire supérieur
        clear_acl(rep)
        set_user_acl(rep, login, 'rwx')
        copy_default_acl(rep)
        # chown pour la prise en compte des quotas
        set_owner(perso, login)
        if 'quota' in args:
            set_quota(login, args['quota'])

    def _change_etab(self, user, old_etab, new_etab):
        old_dn = self.get_user_dn(user)
        new_dn = self.get_user_dn(user, force_etab=new_etab)
        #copie de l'utilisateur + suppression
        uidfilter = "(&%s(uid=%s))" % (USER_FILTER, user)
        cur_ldif = self.ldap_admin._search_one(uidfilter)
        self._desinscription(user, old_etab, sync=False)
        self._desinscription(user, 'profs-' + old_etab, sync=False)
        for grp in self._get_user_groups(user, old_etab):
            self._desinscription(user, grp, sync=False)
        self.ldap_admin._delete(old_dn)
        #Suppression du cache
        self.cache_etab['login'].pop(user)
        self.ldap_admin._add(new_dn, modlist.addModlist(cur_ldif))
        #inscription dans le groupe du nouvel etablissement
        self._inscription(user, new_etab, sync=False, etab=num_etab)
        self._inscription(user, 'profs-' + new_etab, sync=False, etab=new_etab)


    def _update(self, login, **args):
        """
            Mise à niveau Enseignant via l'extraction
        """
        if 'etab' in args:
            user_dn = self.get_user_dn(login, force_etab=args.get('etab')) #USER_DN % dict(uid=login, _type=self._type)
        else:
            user_dn = self.get_user_dn(login) #USER_DN % dict(uid=login, _type=self._type)
        datas = []
        if not_empty(args, 'mail_acad'):
            datas.append((MOD_REPLACE, 'FederationKey',
                          args['mail_acad'].lower()))
        if not_empty(args, 'int_id'):
            datas.append((MOD_REPLACE, 'intid', args['int_id'] ))
        if not_empty(args, 'entpersonjointure'):
            datas.append((MOD_REPLACE, 'ENTPersonJointure', args['entpersonjointure']))
        if not_empty(args, 'classe'):
            principal = self._get_attr(login, 'Divcod')
            principal.extend(to_list(args['classe']))
            datas.append((MOD_REPLACE, 'Divcod', to_list(principal)))
            datas.append((MOD_REPLACE, 'typeadmin', '2'))
        if not_empty(args, 'disciplines') and args['disciplines'] != []:
            datas.append((MOD_REPLACE, 'ENTAuxEnsCategoDiscipline', args['disciplines']))
        datas.append((MOD_REPLACE, 'sn', args['nom']))
        datas.append((MOD_REPLACE, 'givenName', args['prenom']))
        datas.append((MOD_REPLACE, 'cn', "%(prenom)s %(nom)s" % args ))
        datas.append((MOD_REPLACE, 'displayName', "%(prenom)s %(nom)s" % args ))
        datas.append((MOD_REPLACE, 'gecos', replace_cars("%(prenom)s %(nom)s" % args) ))
        datas.append((MOD_REPLACE, 'LastUpdate', format_current_date()))
        self.ldap_admin._modify(user_dn, datas)
        if not_empty(args, 'groups'):
            groups = to_list(args['groups'])
            old_groups = self._get_user_groups(login)
            for group in groups:
                if group not in old_groups:
                    self._inscription(login, group, sync=False)
        self._gen_ftpdir(login)
        self._gen_groupesdir(login)

    def _Upgrade(self, login):
        """
            Mise à niveau d'un compte enseignant
        """
        user_dn = self.get_user_dn(login) #USER_DN % dict(uid=login, _type=self._type)
        datas = []
        obj = self._get_attr(login, 'objectClass')
        obj.extend(['ENTPerson', 'ENTAuxEnseignant'])
        datas.append((MOD_REPLACE, 'objectClass', obj))
        datas.extend(self._gen_upgrade_attrs(login))
        if 'radiusprofile' not in obj:
            obj.append('radiusprofile')
            datas.extend(gen_radius_attrs())
        self.ldap_admin._modify(user_dn, datas)

    def _gen_upgrade_attrs(self, login):
        """
        Gestion des nouveaux attributs enseignant
        """
        infos = self._get_attrs(login, ['givenName', 'sn', 'Divcod',
                                'codecivilite', 'dateNaissance'])
        prenom = infos['givenName'][0]
        nom = infos['sn'][0]
        civilite = infos['codecivilite'][0]
        attrs = []
        yesterday = format_old_date()
        attrs.append((MOD_REPLACE, 'LastUpdate', yesterday))
        attrs.append((MOD_REPLACE, 'gecos', replace_cars("%s %s" % (prenom, nom)) ))
        attrs.append((MOD_REPLACE, 'ENTPersonLogin', login))
        attrs.append((MOD_REPLACE, 'ENTPersonJointure', 'ENT'))
        attrs.append((MOD_REPLACE, 'ENTPersonProfils', self.profil))
        attrs.append((MOD_REPLACE, 'ENTPersonNomPatro', nom))
        if civilite == '3':
            sexe = 'F'
            titre = 'Mlle'
        elif civilite == '2':
            sexe = 'F'
            titre = 'Mme'
        else:
            titre = 'M.'
            sexe = 'M'
        attrs.append((MOD_REPLACE, 'ENTPersonSexe', sexe))
        attrs.append((MOD_REPLACE, 'personalTitle', titre))
        if 'dateNaissance' in infos:
            date = fixdate(infos['dateNaissance'][0])
            attrs.append((MOD_REPLACE, 'ENTPersonDateNaissance', date))
        if infos['Divcod'] == ['autre']:
            attrs.append((MOD_REPLACE, 'Divcod', []))
        return attrs



    def _get_enseignants(self, attrs=['uid']):
        """
            Renvoie les users 'enseignants'
        """
        return self._get_users(filtre=self.filtre, attrs=attrs)

    def _gen_devdir(self, login, homedir=None):
        """
            Génération du répertoire "devoirs" pour les enseignants
        """
        if homedir is None:
            homedir = self._get_attr(login, 'homeDirectory')[0].strip()
        gen_common_devdir(login, homedir)
        # dossier contenant les devoirs et les données à distribuer du prof
        # U:\devoirs\.distribues ou \\scribe\devoirs\.distribues
        dev_dist_dir = join(HOME_PATH, 'workgroups/devoirs', login)
        if not isdir(dev_dist_dir):
            system('mkdir -p %s' % dev_dist_dir)
        system('setfacl -PRbk %s' % dev_dist_dir)
        system('chmod -R 0755 %s' % dev_dist_dir)
        system('setfacl -PRm u:%s:rwx %s' % (login, dev_dist_dir))
        system('setfacl -dPRm u:%s:rwx %s' % (login, dev_dist_dir))
        dev_part = join(homedir, 'devoirs')
        dev_perso = join(homedir, 'perso', 'devoirs')
        for rep in [dev_part, dev_perso]:
            link = join(rep, '.distribues') # le cacher avec un "."
            system('ln -nsf %s %s' % (dev_dist_dir, link))


    def _purge_classes_admin(self, divcod='*', etab=None):
        """
            Suppression de toutes les nomminations
            sur une ou toutes les classes
        """
        if etab is None:
            suffix = None
        else:
            suffix = BRANCHE_GROUP_ETAB % {'etab': etab}
        res = self.ldap_admin._search("(&%s(Divcod=%s))" % (
            self.filtre, divcod), 'uid', suffix=suffix)
        for ens in res:
            login = ens[1]['uid'][0]
            if divcod == '*':
                # on vide sans se poser de question
                self._set_attr(login, 'Divcod', [])
                self._set_attr(login, 'typeadmin', '0')
            else:
                classes = self._get_attr(login, 'Divcod')
                classes.remove(divcod)
                self._set_attr(login, 'Divcod', classes)
                if not classes:
                    self._set_attr(login, 'typeadmin', '0')

    def is_enseignant(self, uid):
        """
            test si l'utilisateur existe dans l'annuaire
            (mode déconnecté)
        """
        self.ldap_admin.connect()
        res = self._is_enseignant(uid)
        self.ldap_admin.close()
        return res

    def _is_enseignant(self, uid):
        """
            test si l'utilisateur existe dans l'annuaire
        """
        uidfilter = "(&%s(uid=%s))" % (PROF_FILTER, uid)
        if self.ldap_admin._search_one(uidfilter):
            return True
        return False
