# -*- coding: utf-8 -*-
#
# Copyright 2006 Waldemar Kornewald, wkornewald@haiku-os.org
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Waldemar Kornewald, wkornewald@haiku-os.org

from trac.core import *
from trac.config import *


class IUserStore(Interface):
    """
    Extension point interface for backends that store known users.
    """

    def supports_user_operation(self, operation):
        """
        Returns whether the operation (a method name) is supported.

        @return supported
        """
        return hasattr(self, operation)

    def create_user(self, username, password):
        """
        Creates a new user with the given username and password.

        @return success
        """

    def get_users(self):
        """
        Generator that yields an ordered list of known users.

        @return username
        """

    def has_user(self, username):
        """
        Returns whether the user exists.
        """
        return username in self.get_users()

    def check_password(self, username, password):
        """
        Checks if the password is correct for the given user.
        """

    def change_password(self, username, password):
        """
        Changes a user's password.

        @return success
        """

    def delete_user(self, username):
        """
        Deletes a user.

        @return success
            Returns False if the user didn't exist.
        """


class IUserAttributeProvider(Interface):
    """
    Extension point interface for backends that store user attributes.
    """

    def supports_attribute_operation(self, operation):
        """
        Returns whether the operation (a method name) is supported.

        @return supported
        """
        return hasattr(self, operation)

    def get_user_attribute(self, username, attribute):
        """
        Returns a user attribute.

        If the attribute is not set it returs an empty string.
        If the attribute is not supported None is returned.
        """

    def set_user_attribute(self, username, attribute, value):
        """
        Sets a user attribute. If value is None the attribute gets deleted.

        @return success
            Returns False if setting the attribute is not supported.
        """

    def delete_all_user_attributes(self, username):
        """
        Deletes all of the given user's attributes.

        @return success
        """


class UserManager(Component):
    """
    Component responsible for managing users and user attributes.
    """

    store = ExtensionOption('users',
        'store', IUserStore, 'SessionUserStore',
        doc="""The user store that should be used for authentication
            (''since 0.11'').""")
    attribute_providers = OrderedExtensionsOption('users',
        'attribute_providers', IUserAttributeProvider,
        doc="""Ordered list of user attribute providers (''since 0.11'').""")

    # general methods

    def supports_operation(self, operation):
        if store.supports_user_operation(operation):
            return True
        for provider in providers:
            if provider.supports_attribute_operation(operation):
                return True
        return False

    # IUserStore methods

    def create_user(self, username, password):
        if not store.supports_user_operation('create_user'):
            return False
        return self.store.create_user(username, password)

    def get_users(self):
        if not store.supports_user_operation('get_users'):
            return []
        return self.store.get_users()

    def has_user(self, username):
        if not store.supports_user_operation('has_user'):
            return False
        return self.store.has_user(username)

    def check_password(self, username, password):
        if not store.supports_user_operation('check_password'):
            return False
        return self.store.check_password(username, password)

    def change_password(self, username, password):
        if not store.supports_user_operation('change_password'):
            return False
        return self.store.change_password(username, password)

    def delete_user(self, username):
        if not store.supports_user_operation('delete_user'):
            return False
        return self.store.delete_user(username)

    # IUserAttributeProvider methods

    def get_user_attribute(self, username, attribute):
        for provider in self.attribute_providers:
            if not provider.supports_attribute_operation('get_user_attribute'):
                continue
            value = provider.get_user_attribute(username, attribute)
            if value is not None:
                return value
        return None

    def set_user_attribute(self, username, attribute, value):
        for provider in self.attribute_providers:
            if not provider.supports_attribute_operation('set_user_attribute'):
                continue
            result = provider.set_user_attribute(username, attribute, value)
            if result:
                return True
        return False

    def delete_all_user_attributes(self, username):
        for provider in self.attribute_providers:
            if not provider.supports_attribute_operation('delete_all_user_attributes'):
                continue
            result = provider.delete_all_user_attributes(username)
            if result:
                return True
        return False


class SessionUserStore(Component):
    """
    Component for managing authenticated users stored in sessions.
    """

    implements(IUserStore)

    def get_users(self):
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("SELECT sid FROM session "
                       "WHERE authenticated=1 "
                       "ORDER BY sid")
        for row in cursor:
            yield row[0]


class SessionUserAttributeProvider(Component):
    """
    Component for providing user attributes via Trac sessions.
    """

    implements(IUserAttributeProvider)
