<?php
/**
 * phpaga
 *
 * User management functionality.
 *
 * This file contains the necessary routines to manage users.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @version $Id: users.php 878 2007-10-31 22:11:00Z florian $
 *
 * Copyright (c) 2002, Florian Lanthaler <florian@phpaga.net>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in
 *      the documentation and/or other materials provided with the
 *      distribution.
 *
 *    * Neither the name of Florian Lanthaler nor the names of his
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


/**
 * Gets a user's information from the database.
 *
 * @param int     $userID    User ID
 *
 * @return array  $userInfo Array containing the results. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_user_getUserInfo($userID)
{

    $userInfo = array();
    $h_perm = array();

    if (!isset($userID) || !is_numeric($userID))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_USER_INVALIDID);

    $query = 'SELECT usr_login, users.pe_id, pe_lastname, pe_firstname,
        pe_email, persons.cpn_id, cpn_name,
        users.lng_id, lng_code, usr_skin, usr_perm
        FROM users
        LEFT JOIN persons ON users.pe_id = persons.pe_id
        LEFT JOIN companies ON persons.cpn_id = companies.cpn_id
        LEFT JOIN languages ON users.lng_id = languages.lng_id
        WHERE usr_id = ?';

    $d = new PhPagaDbData;

    $qrow = $d->queryRow($query, $userID);

    if (PhPagaError::isError($qrow))
        return $qrow;

    if (!is_array($qrow) || !count($qrow))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_USER_FIND);

    $userInfo['usr_id'] = $userID;
    $userInfo['usr_login'] = $qrow['usr_login'];
    $userInfo['pe_id'] = $qrow['pe_id'];
    $userInfo['usr_name'] = phpaga_persons_formatname($qrow['pe_lastname'], $qrow['pe_firstname']);
    $userInfo['usr_email'] = $qrow['pe_email'];
    $userInfo['cpn_id'] = $qrow['cpn_id'];
    $userInfo['cpn_name'] = $qrow['cpn_name'];
    $userInfo['lng_id'] = $qrow['lng_id'];
    $userInfo['lng_code'] = $qrow['lng_code'];
    $userInfo['skin'] = $qrow['usr_skin'];

    $userInfo['perm'] = array();

    if (strlen($qrow['usr_perm'])) {

        $h_perm = explode('|', trim($qrow['usr_perm']));

        foreach ($h_perm as $h_p)
            $userInfo['perm'][$h_p] = true;
    }

    return $userInfo;
}


/**
 * Loads all users matching search criteria into an array.
 *
 * @param int    $count        Number of records matching the query
 * @param array  $s_userInfo   User information (search criteria)
 * @param int    $offset       Offset
 * @param int    $limit        Limit
 *
 * @return array $userInfo     Array containing the results. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_user_search($s_userInfo = null, $offset = null, $limit = null)
{

    $userInfo = array();
    $where = array();
    $qparam = array();

    if (isset($s_userInfo) && !is_array($s_userInfo)) {
        $s_userInfo = array();
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_INVALIDSEARCHPARAM);
    }

    $query = 'SELECT usr_id, usr_login, users.pe_id, pe_lastname, pe_firstname,
        pe_email, persons.cpn_id, cpn_name,
        users.lng_id, lng_code, usr_skin
        FROM users
        LEFT JOIN persons ON users.pe_id = persons.pe_id
        LEFT JOIN companies ON persons.cpn_id = companies.cpn_id
        LEFT JOIN languages ON users.lng_id = languages.lng_id ';

    if (isset($s_userInfo['prj_id']) && is_numeric($s_userInfo['prj_id']))
        $query .= 'LEFT JOIN project_members pm ON ((pm.pe_id = persons.pe_id))';

    if (isset($s_userInfo['usr_id']) && is_numeric($s_userInfo['usr_id'])) {
        $where[] = 'usr_id = ?';
        $qparam[] = $s_userInfo['usr_id'];
    }

    if (isset($s_userInfo['usr_login']) && strlen($s_userInfo['usr_login'])) {
        $where[] = 'usr_login LIKE ?';
        $qparam[] = '%'.$s_userInfo['usr_login'].'%';
    }

    if (isset($s_userInfo['pe_lastname']) && strlen($s_userInfo['pe_lastname'])) {
        $where[] = 'pe_lastname LIKE ?';
        $qparam[] = '%'.$s_userInfo['pe_lastname'].'%';
    }

    if (isset($s_userInfo['prj_id']) && is_numeric($s_userInfo['prj_id'])) {
        $where[] = 'pm.prj_id = ?';
        $qparam[] = $s_userInfo['prj_id'];
    }

    if ((PHPAGA_DB_SYSTEM != 'mysql') && (isset($s_userInfo['notmemberof_prj_id'])
                                          && is_numeric($s_userInfo['notmemberof_prj_id']))) {

        $where[] = '(persons.pe_id NOT IN (SELECT pe_id FROM project_members WHERE prj_id = ?))';
        $qparam[] = $s_userInfo['notmemberof_prj_id'];
    }

    if (count($where))
        $query .= sprintf('WHERE %s ', implode(' AND ', $where));

    if (isset($s_userInfo['sort']) && ($s_userInfo['sort'] == 'person'))
        $query .= 'ORDER BY pe_lastname, pe_firstname ';
    else
        $query .= 'ORDER BY usr_login ';

    $d = new PhPagaDbData;
    $r = $d->queryAll($query, $qparam, $offset, $limit);

    if (PhPagaError::isError($r))
        return $r;

    foreach ($r as $qrow) {
        phpaga_sanitizeArray($qrow);
        $qrow['pe_name'] = phpaga_persons_formatname($qrow['pe_lastname'], $qrow['pe_firstname']);
        $userInfo[] = $qrow;
    }

    return $userInfo;
}


/**
 * Modifies an existing user profile in the database
 *
 * @param  array  $userInfo  Array with the values to be set
 *
 * @return bool   $result  True, or PhPagaError
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_user_update($userInfo)
{

    global $phpaga_languages;

    $fields = array();

    if (!isset($userInfo['usr_id']) || !is_numeric($userInfo['usr_id']) || !is_array($userInfo))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_USER_INVALIDID);

    if (isset($userInfo['pe_id']) && is_numeric($userInfo['pe_id']))
        $fields['pe_id'] = $userInfo['pe_id'];

    if (isset($userInfo['usr_pe_id']) && is_numeric($userInfo['usr_pe_id']))
        $fields['usr_pe_id'] = $userInfo['usr_pe_id'];

    if (isset($userInfo['lng_id']) && is_numeric($userInfo['lng_id']))
    {
        $fields['lng_id'] = $userInfo['lng_id'];

        /* Check whether the locales for the selected language are available */

        $current = setlocale(LC_COLLATE, NULL);
        $lng_code = phpaga_getLanguageCode($fields['lng_id']);

        $langname = setlocale(LC_ALL, $phpaga_languages[$lng_code]);

        if ($langname === false)
            return PhPagaError::raiseErrorByCode(PHPAGA_ERR_LOCALENOTAVAIL);

        if (strstr(PHP_OS, 'WIN'))
        {
            putenv('LANG='.$langname);
            putenv('LANGUAGE='.$langname);
        }

        setlocale(LC_ALL, $current);
    }

    if (isset($userInfo['usr_passwd']) && strlen($userInfo['usr_passwd']))
        $fields['usr_passwd'] = phpaga_password($userInfo['usr_passwd']);

    if (isset($userInfo['usr_skin']) && strlen($userInfo['usr_skin']))
        $fields['usr_skin'] = $userInfo['usr_skin'];

    if (isset($userInfo['perm']) && is_array($userInfo['perm']))
    {
        if (count($userInfo['perm']) == 0)
            $fields['usr_perm'] = null;
        else
            $fields['usr_perm'] = implode('|', $userInfo['perm']);
    }

    if (count($fields) == 0)
        return true;

    $d = new PhPagaDbData;

    $result = $d->update('users', $fields, 'usr_id = ?', $userInfo['usr_id']);

    if (PhPagaError::isError($result))
        return $result;

    /* Reload the auth_user information and set the session variables
     * accordingly if we're doing modifications on the current user
     */

    if ($_SESSION['auth_user']['usr_id'] == $userInfo['usr_id']) {
        $_SESSION['auth_user'] = phpaga_user_getUserInfo($userInfo['usr_id']);
    }

    return true;
}


/**
 * Adds a new user.
 *
 * @param  array  $user     Array containing user information.
 *
 * @return int    $result   ID of the freshly inserted user. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.1
 */

function phpaga_user_add($user)
{

    /* make sure login and password have at least more than 0 length */
    if (!isset($user['usr_login']) || !strlen($user['usr_login']))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_AUTH_LOGINLENGTH);
    elseif (!isset($user['usr_passwd']) || !strlen($user['usr_passwd']))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_AUTH_PASSWDLENGTH);
    elseif (!isset($user['pe_id']) || !is_numeric($user['pe_id']))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_USR_NOPEASSOC);

    if (!isset($user['lng_id']) || !is_numeric($user['lng_id']))
        $user['lng_id'] = PhPagaError::raiseErrorByCode(PHPAGA_DEFAULTLANGUAGE);

    if (!isset($user['usr_skin']) || !strlen($user['usr_skin']))
        $user['usr_skin'] = PhPagaError::raiseErrorByCode(PHPAGA_DEFAULT_SKIN);

    if (!isset($user['usr_pe_id']) || !is_numeric($user['usr_pe_id']))
        $user['usr_pe_id'] = 1;

    $d = new PhPagaDbData;

    $id = $d->nextId('users_usr_id');

    $fields = array('usr_id'=> $id,
                    'pe_id' => $user['pe_id'],
                    'lng_id' => $user['lng_id'],
                    'usr_login' => $user['usr_login'],
                    'usr_passwd' => phpaga_password($user['usr_passwd']),
                    'usr_pe_id' => $user['usr_pe_id'],
                    'usr_skin' => $user['usr_skin']
        );

    if (isset($user['perm']) && is_array($user['perm']))
    {
        if (count($user['perm']) == 0)
            $fields['usr_perm'] = NULL;
        else
            $fields['usr_perm'] = implode('|', $user['perm']);
    }

    $r = $d->insert('users', $fields);

    if (PhPagaError::isError($r))
        return $r;

    return $id;
}


/**
 * Deletes a user and his settings from the database.
 *
 * @param int    $userID    Users's ID
 *
 * @return bool  $result    True if successfull, PhPagaError otherwise.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_user_delete($userID)
{

    if (!isset($userID) || !is_numeric($userID))
        return PhPagaError::raiseErrorByCode(PHPAGA_ERR_USER_INVALIDID);

    $d = new PhPagaDbData;

    $result = $d->execute('DELETE FROM userconfig WHERE usr_id = ?', $userID);

    if (PhPagaError::isError($result))
        return $result;

    $result = $d->execute('DELETE FROM users WHERE usr_id = ?', $userID);

    if (PhPagaError::isError($result))
        return $result;

    return true;
}


/**
 * Checks whether a user has a determined permission. If no user id
 * is given then take the user from the current session.
 *
 * @param  int    $perm       Permission ID
 * @param  int    $uid        User ID (optional)
 *
 * @return bool   $hasperm    true if user has permission, false otherwise
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_user_hasperm($perm, $uid = null)
{

    if (!strlen($uid) || !is_numeric($uid)) {

        return(is_numeric($perm) && isset($_SESSION['auth_user'])
               && isset($_SESSION['auth_user']['perm'])
               && isset($_SESSION['auth_user']['perm'][$perm]));

    } else {

        $user = phpaga_user_getUserInfo($uid);

        if (PhPagaError::isError($user))
            return false;
        else
            return(is_numeric($perm) && isset($user['perm']) && isset($user['perm'][$perm]));
    }
}


/**
 * Checks whether the current user has a determined permission or one
 * of a series of permissions (in an array).
 * Outputs an error message and stop the program if the permission is
 * missing.
 *
 * @param  int    $perm       Permission ID
 *
 * @return void
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_user_pageperm($perm)
{

    if (is_array($perm)) {

        foreach($perm as $p)
            if (phpaga_user_hasperm($p))
                return;

    } else if (phpaga_user_hasperm($perm))
        return;

    phpaga_header();
    phpaga_message(_('No access'), _("You don't have the necessary rights to access this page."));
    phpaga_footer();
    die();
}


/**
 * Gets the count of available users. This routine is used
 * to determine whether phpaga has been set up and configured
 * properly.
 *
 * @return int  $n  Number of available users. A PhPagaError object on failure.
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @since phpaga 0.3
 */

function phpaga_user_getNumUsers()
{

    $numusers = null;

    $d = new PhPagaDbData;
    $n = $d->queryOneVal('SELECT COUNT(usr_id) FROM users');

    return $n;
}

?>