"""
$URL: svn+ssh://svn.mems-exchange.org/repos/trunk/dulcinea/lib/user.py $
$Id: user.py 28836 2006-09-21 17:08:38Z dbinger $
"""
from dulcinea.common import get_site_name, get_publisher, is_qp, get_users
from qp.lib.spec import add_getters_and_setters, specify
from qp.lib.spec import spec, pattern
from qp.pub.user import User
from qp.lib.util import randbytes
import sha, binascii


def hash_password(password):
    """Apply a one way hash function to a password and return the result."""
    return sha.new(password).hexdigest()

def get_realm():
    return get_site_name()

class DulcineaUser (User):
    """
    a registered user.
    """
    global_permissions = {
        "act-as":
            "Allow to act as another user.",
        "create-users":
            "Allow the creation of other users.",
        "manage-permissions":
            "Allow changing of permissions.",
        "staff":
            ("Is a member of the staff, with all of the privileges and "
             "responsibilities thereunto appertaining."),
        "system":
            "Allow to do things normally done by the software system.",
        }

    id_is = spec(
        pattern('^[-A-Za-z0-9_@. ]*$'),
        "unique among users here, spaces allowed")

    def __str__(self):
        return self.id or '*no id*'

    format = __str__ # subclasses should override

    def get_key(self):
        """ used for forming component representing this user in URLs
        """
        return self.get_id()

    def set_id(self, user_id):
        assert self.id == None
        specify(self, id=user_id)

    def set_password(self, new_password, realm=None, check=True):
        """Set the user's password to 'new_password'."""
        if check and self.check_new_password(new_password) != "":
            raise ValueError, 'invalid password'
        if is_qp():
            User.set_password(self, new_password, realm=realm)
        else:
            digester = self.get_digester()
            if not new_password:
                digester.discard_digest(realm or get_realm())
            else:
                digester.set_digest(realm or get_realm(),
                                    hash_password(new_password))

    def has_password(self, password, realm=None):
        """Return true if the provided password is correct."""
        digester = self.get_digester()
        if realm is None:
            realm = get_realm()
        digest = digester.get_digest(realm)
        if is_qp():
            if User.has_password(self, password, realm=realm):
                return True
            elif digest == hash_password(password):
                # If the digest uses the older Dulcinea hash, set
                # a new digest using the QP hash.
                User.set_password(self, password, realm=realm)
                return True
            else:
                return False
        else:
            return digest == hash_password(password)

    def generate_password (self, realm=None, length=6):
        """Set the password to a random value and return the new password."""
        password = binascii.b2a_base64(binascii.unhexlify(randbytes(length)))
        password = password[:length]
        self.set_password(password, realm=realm)
        return password

    def check_new_password(self, new_password):
        """(string) -> string
        Check if a new password is valid.  Returns the empty string if the
        password is okay otherwise returns a string that describes what is
        wrong with the entered password.
        """
        return ""

    def format_realname(self):
        return ''

    def is_null(self):
        return not self

    def is_disabled(self, realm=None):
        return not bool(self.get_digester().get_digest(realm or get_realm()))

    def is_system(self):
        return self.id == 'SYSTEM'

    def is_admin(self):
        return self.is_granted('staff')

    def is_granted(self, permission, granter=True):
        return self.get_permissions().is_granted(permission, granter)

    def can_manage_permissions(self):
        return self.is_granted('manage-permissions')

    def get_email_realname_pair(self):
        return self.get_email(), self.format_realname() or ''

add_getters_and_setters(DulcineaUser)

def list_users():
    return [user for user in get_users().itervalues()
           if not (user.is_null() or
                   user.is_system() or
                   user.is_disabled())]

def gen_users_granted(permission, granter=True):
    for user in get_users().itervalues():
        if user.is_granted(permission, granter):
            yield user

def get_matching_user(identifier):
    """(identifier : string) -> DulcineaUser | None

    Return a user with matching id or email address, or None
    if no such user is found.
    """
    return lookup_user(id=identifier, email=identifier)

def add_user(user):
    return get_publisher().add_user(user)

def lookup_user(id=None, email=None, **kwargs):
    return get_publisher().lookup_user(id=id, email=email, **kwargs)

