# -*- coding: iso-8859-15 -*-


# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
#     Romain Chantereau <rchantereau@entrouvert.com>
#     Nicolas Clapiès <nclapies@easter-eggs.org>
#     Pierre-Antoine Dejace <padejace@entrouvert.be>
#     Thierry Dulieu <tdulieu@easter-eggs.com>
#     Florent Monnier <monnier@codelutin.com>
#     Cédric Musso <cmusso@easter-eggs.org>
#     Frédéric Péters <fpeters@entrouvert.be>
#     Benjamin Poussin <poussin@codelutin.com>
#     Emmanuel Raviart <eraviart@entrouvert.com>
#     Sébastien Régnier <regnier@codelutin.com>
#     Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
#     Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
#     Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
#     Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
#     Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


__doc__ = """Glasnost Password Accounts Web"""

__version__ = '$Revision$'[11:-2]


import glasnost.common.context as context
import glasnost.common.faults as faults
import glasnost.common.ObjectsCommon as commonObjects
import glasnost.common.tools_new as commonTools
import glasnost.common.xhtmlgenerator as X

import glasnost.proxy.PasswordAccountsProxy as proxyPasswordAccounts

import ObjectsWeb as objects
from tools import *


class AdminPasswordAccounts(objects.AdminMixin,
                            proxyPasswordAccounts.AdminPasswordAccounts):
    pass
objects.register(AdminPasswordAccounts)


class Login(objects.ObjectWebMixin, commonObjects.ObjectCommon):
    id_kindName = None
    language_kindName = None
    version_kindName = None

    login = None
    class login_kindClass:
        _kindName = 'String'
        balloonHelp = N_('Enter the username you use on this site.')
        isRequired = 1
        isTranslatable = 0
        label = N_('Username')
        textMaxLength = 40
        widget_size = 15

    password = None
    class password_kindClass:
        _kindName = 'Password'
        balloonHelp = N_('Enter your secret password.')
        isRequired = 1
        label = N_('Password')
        textMaxLength = 15
        widget_size = 15

    def getOrderedLayoutSlotNames(self, parentSlot = None):
        slotNames = commonObjects.ObjectCommon.getOrderedLayoutSlotNames(
                self, parentSlot = parentSlot)
        slotNames += ['login', 'password']
        return slotNames


class PasswordChange(objects.ObjectWebMixin, commonObjects.ObjectCommon):
    id_kindName = None
    language_kindName = None
    version_kindName = None

    currentPassword = None
    class currentPassword_kindClass:
        _kindName = 'Password'
        balloonHelp = N_('Enter your current password.')
        isRequired = 1
        isTranslatable = 0
        label = N_('Current Password')

    newPassword = None
    class newPassword_kindClass:
        _kindName = 'Password'
        balloonHelp = N_('Enter your new password.')
        isRequired = 1
        isTranslatable = 0
        label  = N_('New Password')

    newPasswordConfirmation = None
    class newPasswordConfirmation_kindClass:
        _kindName = 'Password'
        balloonHelp = N_('Enter your new password a second time '
                         'for confirmation.')
        isRequired = 1
        isTranslatable = 0
        label  = N_('New Password (confirmation)')

    def getOrderedLayoutSlotNames(self, parentSlot = None):
        slotNames = commonObjects.ObjectCommon.getOrderedLayoutSlotNames(
                self, parentSlot = parentSlot)
        slotNames += ['currentPassword', 'newPassword',
                      'newPasswordConfirmation']
        return slotNames

        


class PasswordAccount(objects.ObjectWebMixin,
                      proxyPasswordAccounts.PasswordAccount):
    def getEditLayoutSlotNames(self, fields, parentSlot = None):
        slotNames = objects.ObjectWebMixin.getEditLayoutSlotNames(self,
                fields, parentSlot = parentSlot)
        if not self.getWeb().canChangePassword():
            slotNames.remove('password')
        return slotNames
objects.register(PasswordAccount)


class PasswordAccountsWeb(objects.ObjectsWebMixin,
                          proxyPasswordAccounts.PasswordAccountsProxy):
    def login(self):
        object = Login()
        return self.loginObject(object)
    login.isPublicForWeb = 1

    def loginObject(self, object):
        req = context.getVar('req')
        req.headers_out['Cache-Control'] = 'no-cache, must-revalidate'

        context.push(_level = 'loginObject', layoutMode = 'edit')
        try:
            layout = X.array()

            if context.getVar('error'):
                layout += object.getErrorLayout()

            # The instruction submitUrl = X.actionUrl('loginSubmit')
            # doesn't work because the login method can be called from
            # IdentitiesWeb.
            submitUrl = X.roleUrl(self.serverRole, action = 'loginSubmit')
            if context.getVar('virtualHost').useHTTPS:
                hostNameAndPort = commonTools.makeHttpHostNameAndPort(
                        context.getVar('httpHostName'),
                        context.getVar('httpPort'))
                submitUrl = 'https://%s%s' % (hostNameAndPort, submitUrl)

            form = X.form(action = submitUrl, enctype = 'multipart/form-data',
                          method = 'post')
            layout += form

            if context.getVar('nextUri'):
                form += X.div(X.input(name = 'nextUri', type = 'hidden',
                                      value = context.getVar('nextUri')))

            form += object.getEditLayout(fields = None)

            buttonsBar = X.div(_class = 'buttons-bar')
            form += buttonsBar
            buttonsBar += X.buttonInForm('login', 'loginButton')
            if 1: # TODO: check if emailPassword is available
                buttonsBar += X.buttonInForm(
                        'send-password-by-email', 'sendButton')
            return writePageLayout(layout, _('Login'))
        finally:
            context.pull(_level = 'loginObject')

    def loginSubmit(self, **keywords):
        if keywords is None:
            keywords = {}

        object = Login()
        object.submitFields(keywords)

        if isButtonSelected('sendButton', keywords) and object.login:
            try:
                self.emailPassword(object.login)
            except:
                return failure(_('An error occured while sending the password.'),
                        X.rootUrl())
            return success(_('The password has been sent successfully.'), X.rootUrl())

        if context.getVar('again'):
            return self.loginObject(object)

        try:
            userToken, authenticationMethod = self.checkObjectAuthentication(
                    object.login, object.password)
        except faults.WrongLogin, fault:
            context.setVar('error', 1)
            object.setError('self.login', fault)
            return self.loginObject(object)
        except faults.WrongPassword, fault:
            context.setVar('error', 1)
            object.setError('self.password', fault)
            return self.loginObject(object)
        except:
            if context.getVar('debug'):
                raise
            return accessForbidden()
        identitiesWeb = getWebForServerRole('identities')
        return identitiesWeb.loginSucceeded(userToken, authenticationMethod)
    loginSubmit.isPublicForWeb = 1

    def changePassword(self):
        if not context.getVar('userToken'):
            return failure(_('You are not logged in'))

        # TODO: what if user logged with a smartcard ?
        
        if not self.canChangePassword():
            return failure(
                    _('You are not authorized to change your password'))
        object = PasswordChange()
        return self.changePasswordObject(object)
    changePassword.isPublicForWeb = 1

    def changePasswordObject(self, object):
        layout = X.array()
        
        object.currentPassword = '' # no default

        if context.getVar('error'):
            layout += object.getErrorLayout()

        form = X.form(action = X.actionUrl('changePasswordSubmit'),
                      enctype = 'multipart/form-data', method = 'post')
        layout += form
        form += object.getEditLayout()

        buttonsBar = X.div(_class = 'buttons-bar')
        form += buttonsBar
        buttonsBar += X.buttonInForm(_('Change the password'), 'button')
        return writePageLayout(layout, _('Changing password'))

    def changePasswordSubmit(self, **keywords):
        if not self.canChangePassword():
            return accessForbidden()

        if keywords is None:
            keywords = {}

        object = PasswordChange()
        object.submitFields(keywords)

        if context.getVar('again'):
            return self.changePasswordObject(object)

        if object.newPassword != object.newPasswordConfirmation:
            context.setVar('error', 1)
            object.setError('self.newPasswordConfirmation',
                    faults.WrongPassword(''))
            return self.changePasswordObject(object)

        try:
            proxyPasswordAccounts.PasswordAccountsProxy.changePassword(
                self, object.currentPassword, object.newPassword)
        except faults.WrongPassword, e:
            context.setVar('error', 1)
            object.setError('self.currentPassword', e)
            return self.changePasswordObject(object)

        return success(_('Password changed successfully'), X.rootUrl())
    changePasswordSubmit.isPublicForWeb = 1


