########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/Xslt/User.py,v 1.21 2005/04/06 23:05:46 jkloth Exp $
"""
XSLT extension elements and functions supporting the 4SS User API

Copyright 2004 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

import sha

from Ft.Lib import boolean
from Ft.Server import FTSERVER_NAMESPACE
from Ft.Server.Server import FtServerServerException, Error
from Ft.Server.Common import ResourceTypes
from Ft.Xml.XPath import Conversions
from Ft.Xml.Xslt import XsltElement, ContentInfo, AttributeInfo

from Ns import SCORE_NS
import FtssXsltBase


def GetUserName(context, path):
    """
    Get the user name given the path to a user resource.
    If the path is invalid or does not give a user object, '' is returned.
    """
    path = Conversions.StringValue(path)
    try:
        username = FtssXsltBase.FetchBaseObject(context.processor, path).getUsername()
    except (FtServerServerException, AttributeError):
        username = u''
    return username


class SetUserNameElement(XsltElement):
    """
    Set the username of a user resource.
    """
    content = ContentInfo.Empty

    legalAttrs = {
        'path' : AttributeInfo.UriReferenceAvt(
            required=1, description='The path of the user'),
        'new-name' : AttributeInfo.StringAvt(
            required=1, description='The new name'),
        }

    def instantiate(self, context, processor):
        context.setProcessState(self)

        path = self._path.evaluate(context)
        name = self._new_name.evaluate(context)

        user = FtssXsltBase.FetchBaseObject(processor, path)
        user.setUsername(name)
        return


def SetUserData(context, key, value, path=None):
    """
    Sets property data associated with a user
    """
    key = Conversions.StringValue(key)
    value = Conversions.StringValue(value)
    repo = context.processor._repository
    if path:
        user = FtssXsltBase.FetchBaseObject(context.processor,
                                            Conversions.StringValue(path))
    else:
        user = repo.getCurrentUser()
    if user is not None:
        if user.has_key(key):
            print "Xslt/User: Value '" + value + "' replaces value '" + user[key] + "' for key '" + key + "' in user data."
        user[key] = value
        context.processor.extensionParams[(FTSERVER_NAMESPACE,'commit')]=1
        return boolean.true
    else:
        print "Xslt/User: set-user-data() called but there is no current repo user."
        return boolean.false


def GetUserData(context, key, path=None):
    """
    Gets property data associated with a user
    """
    key = Conversions.StringValue(key)
    repo = context.processor._repository

    if path:
        user = FtssXsltBase.FetchBaseObject(context.processor,Conversions.StringValue(path))
    else:
        user = repo.getCurrentUser()

    if user is not None:
        if user.has_key(key):
           return user[key]
        else:
            print "Xslt/User: Key '" + key + "' not found in user data."
    else:
        print "Xslt/User: get-user-data() called but there is no current repo user."
    return ''


def GetUserDataKeys(context, path=None):
    """
    Gets the names of properties associated with a user
    """
    if path:
        user = FtssXsltBase.FetchBaseObject(context.processor,Conversions.StringValue(path))
    else:
        user = repo.getCurrentUser()
    doc = context.node.rootNode
    return map(doc.createTextNode, user.keys())


def RemoveUserData(context, key, path=None):
    """
    Erases property data associated with a user
    """
    key = Conversions.StringValue(key)
    repo = context.processor._repository
    if path:
        user = FtssXsltBase.FetchBaseObject(context.processor,Conversions.StringValue(path))
    else:
        user = repo.getCurrentUser()
    if user is not None:
        if user.has_key(key):
            print "Xslt/User: Key '" + key + "' with value '" + user[key] + "' removed from user data."
            del user[key]
            return boolean.true
        else:
            print "Xslt/User: Key '" + key + "not found in user data."
    else:
        print "Xslt/User: remove-user-data() called but there is no current repo user."
    return boolean.false


class ChangeUserPasswordElement(XsltElement):
    """
    Changes the password of the specified user resource.
    """

    content = ContentInfo.Empty

    legalAttrs = {
        'path' : AttributeInfo.UriReferenceAvt(
            required=1, description='The path of the user'),
        'new-password' : AttributeInfo.StringAvt(
            description=('The new password. If not specified, will remove the '
                         'password for this user.')),
        }

    def instantiate(self, context, processor):
        context.setProcessState(self)

        path = self._path.evaluate(context)
        password = self._new_password.evaluate(context) or ''

        hashedPW = sha.new(password).hexdigest()

        user = FtssXsltBase.FetchBaseObject(processor, path)
        user.setPassword(hashedPW)
        return


ExtFunctions = {
    (SCORE_NS, 'get-username'):     GetUserName,
    (SCORE_NS, 'get-user-data'):     GetUserData,
    (SCORE_NS, 'get-user-data-keys'):     GetUserDataKeys,
    (SCORE_NS, 'set-user-data'):     SetUserData,
    (SCORE_NS, 'remove-user-data'):  RemoveUserData,
}

ExtElements = {
    (SCORE_NS, 'change-password'): ChangeUserPasswordElement,
    (SCORE_NS, 'set-username'): SetUserNameElement,
}

