#!/usr/bin/python
#
# 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 Library 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.
#
# Copyright 2005 Dan Williams <dcbw@redhat.com> and Red Hat, Inc.


import sys, os


# Note: We probably want to port to psqlite2.dbapi2 and sqlite3.dbapi2 and
# remove support for the original sqlite python bindings.
try:
    import pysqlite2._sqlite as sqlite
except ImportError:
    try:
        import _sqlite3 as sqlite
    except ImportError:
        import sqlite
sys.path.append('/usr/share/plague/server')
from DBManager import ResultSet

def print_usage(prog):
    print "Usage:\n"
    print "   %s <dbfile> <command ...>\n\n" % prog
    print "      Commands:"
    print "         add <email> [own_jobs] [job_admin] [user_admin] [server_admin]"
    print "         del <email>"
    print "         mod <email> [+/-own_jobs] [+/-job_admin] [+/-user_admin] [+/-server_admin]"
    print "         find <search string>"


class UserManagerException:
    def __init__(self, message):
        self.message = message


class UserManager:
    def __init__(self, dbfile):
        self.dbcx = sqlite.connect(dbfile, timeout=2)
        self.curs = self.dbcx.cursor()

        # Ensure the table exists in the database
        create = False
        try:
            self.curs.execute('SELECT * FROM users')
            self.dbcx.commit()
        except sqlite.DatabaseError, e:
            create = True

        if create:
            self.curs.execute('CREATE TABLE users (email VARCHAR(50), ' \
                    'own_jobs BOOLEAN, job_admin BOOLEAN, ' \
                    'user_admin BOOLEAN, server_admin BOOLEAN)')
            self.dbcx.commit()

    def __del__(self):
        self.dbcx.close()

    def dispatch(self, prog, command, args):
        if command == 'add':
            self.add_user(args)
        elif command == 'del':
            self.del_user(args)
        elif command == 'mod':
            self.mod_user(args)
        elif command == 'find':
            self.find_user(args)
        else:
            print_usage(prog)

    def add_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email="%s"' % email)
        self.dbcx.commit()
        item = self.curs.fetchone()
        if item:
            raise UserManagerException("User %s already exists." % email)

        own_jobs = 0
        job_admin = 0
        user_admin = 0
        server_admin = 0
        for arg in args[1:]:
            if arg == 'own_jobs':
                own_jobs = 1
            elif arg == 'job_admin':
                job_admin = 1
            elif arg == 'user_admin':
                user_admin = 1
            elif arg == 'server_admin':
                server_admin = 1
            else:
                raise UserManagerException("The user privilege '%s' is unknown." % arg)

        self.curs.execute('INSERT INTO users (email, own_jobs, job_admin,' \
                ' user_admin, server_admin) VALUES ("%s", %d, %d, %d, %d)' \
                % (email, own_jobs, job_admin, user_admin, server_admin))
        self.dbcx.commit()
        print "User %s added." % email

    def del_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email="%s"' % email)
        self.dbcx.commit()
        item = self.curs.fetchone()
        if not item:
            raise UserManagerException("User %s doesn't exist." % email)

        sys.stdout.write("Really delete %s? (y/n): " % email)
        resp = sys.stdin.readline()
        resp = resp.lower().strip()
        if resp == 'y' or resp == 'yes':
            self.curs.execute('DELETE FROM users WHERE email="%s"' % email)
            self.dbcx.commit()
            print "User %s deleted." % email
        else:
            print "User %s not deleted." % email

    def _cap_to_num(self, cap):
        if cap == '-':
            return 0
        elif cap == '+':
            return 1
        else:
            raise UserManagerException("Invalid format '%s', privileges must begin with + or -." % cap)

    def mod_user(self, args):
        if len(args) < 1:
            raise UserManagerException("Invalid command, too few options.")

        email = args[0]
        self.curs.execute('SELECT * FROM users WHERE email="%s"' % email)
        self.dbcx.commit()
        item = self.curs.fetchone()
        if not item:
            raise UserManagerException("User %s doesn't exist." % email)

        item = ResultSet(item, self.curs.description)
        own_jobs = item['own_jobs']
        job_admin = item['job_admin']
        user_admin = item['user_admin']
        server_admin = item['server_admin']
        for opt in args[1:]:
            if opt[0] != '+' and opt[0] != '-':
                raise UserManagerException("Invalid format '%s', privileges must begin with + or -." % opt)
            priv = opt[1:]
            if priv == 'own_jobs':
                own_jobs = self._cap_to_num(opt[0])
            elif priv == 'job_admin':
                job_admin = self._cap_to_num(opt[0])
            elif priv == 'user_admin':
                user_admin = self._cap_to_num(opt[0])
            elif priv == 'server_admin':
                server_admin = self._cap_to_num(opt[0])
            else:
                raise UserManagerException("The privilege '%s' is unknown." % priv)

        self.curs.execute('UPDATE users SET own_jobs=%d, job_admin=%d, user_admin=%d, server_admin=%d' \
                    ' WHERE email="%s"' % (own_jobs, job_admin, user_admin, server_admin, email))
        self.dbcx.commit()
        print "User privileges updated: own_jobs=%d, job_admin=%d, user_admin=%d, server_admin=%d" % (
                    own_jobs, job_admin, user_admin, server_admin)

    def find_user(self, args):
        sql = "SELECT * FROM users"

        if len(args) > 0:
            sql = sql + ' WHERE email LIKE "%%%s%%"' % args[0]

        self.curs.execute(sql)
        self.dbcx.commit()
        data = [ResultSet(row,self.curs.description) for row in self.curs.fetchall()]
        if not len(data):
            raise UserManagerException("No matching users found.")

        print "\nResults:"
        print "-" * 100
        for row in data:
            string = "%s" % row['email'] + " " * (40 - len(row['email']))
            string = string + "own_jobs:%d  " % row['own_jobs']
            string = string + "job_admin:%d  " % row['job_admin']
            string = string + "user_admin:%d  " % row['user_admin']
            string = string + "server_admin:%d  " % row['server_admin']
            print string
        print ""


if __name__ == '__main__':
    if len(sys.argv) < 3:
        print_usage(sys.argv[0])
        sys.exit(1)

    dbfile = sys.argv[1]
    if not os.access(dbfile, os.R_OK):
        print "The user database '%s' does not exist or is not readable." % dbfile
        sys.exit(1)

    um = UserManager(dbfile)
    try:
        um.dispatch(sys.argv[0], sys.argv[2], sys.argv[3:])
    except UserManagerException, e:
        print e.message
        sys.exit(1)

    sys.exit(0)

