<?php
/**
 * @desc this program will add or edit a logaholic user account
 * for more information please read:
 * http://www.logaholic.com/manual/LogaholicManual/APIDocumentationForServiceProviderEditions
 */

class LogaholicDBUser
{

    var $logaholicuser;
    var $logaholicpass;
    var $logaholicname;
    var $logaholicemail;
    var $logaholic_newusername; // when editing a user, a new_username must be supplied (may be the same as the old username)
    var $usersubscriptionid;
    var $usersubscriptionname;
    var $accessEditProfile;
    var $accessAddProfile;
    var $accessUpdateLogs;
    var $changeAccountInfo;
    var $active;
    var $expires;
    var $metadata;
    var $profiles;

    # this will run when the program starts
    function __construct()
    {
        global $db;

        #set some default values
        $this->accessEditProfile = "1";
        $this->accessAddProfile = "0";
        $this->accessUpdateLogs = "0";
        $this->active = "1";
        $this->expires = "0";
        $this->usersubscriptionid = 0;
        $this->usersubscriptionname = "";
        $this->isAdmin = 0;
        $this->changeAccountInfo = 0;
        $this->accessBasicEditProfile = 0;
        $this->profiles = '';
        $this->metadata = array(
            "changeAccountInfo" => $this->changeAccountInfo
        ,
            "profileLimit" => 0
        ,
            "trackermode_0" => 0
        ,
            "trackermode_1" => 0
        ,
            "trackermode_2" => 0
        ,
            "trackermode_3" => 0
        ,
            "allProfiles" => 0
        ,
            "accessBasicEditProfile" => $this->accessBasicEditProfile
        );

        # first check the variables we need to execute this program
        $this->CheckVars();

        # now connect to the database
        $this->dbConnect();

        return;
    }

    /**
     * @desc This function checks the required variables
     */
    function CheckVars()
    {
        global $action;

        $help = "Required variables:<br>\n";
        $help .= " - username (adduser, edituser, deleteuser, getdbsize)<br>\n";
        $help .= " - password (adduser, edituser)<br>\n";
        $help .= " - new_username (edituser) <br><br>\n\n";
        $help .= "Optional variables:<br>\n";
        $help .= " - fullname <br>\n";
        $help .= " - email <br>\n";
        $help .= " - accessEditProfile <br>\n";
        $help .= " - accessBasicEditProfile <br>\n";
        $help .= " - accessAddProfile <br>\n";
        $help .= " - accessUpdateLogs <br>\n";
        $help .= " - active <br>\n";
        $help .= " - expires <br>\n";
        $help .= " - subscriptionid (The id of the subscription. NOT the name.) <br>\n";
        $help .= " - subscriptionname (The name of the subscription. NOT the id.) <br>\n";

        $standalone_actions = array("listusers", "cloudusersinfo");

        if (in_array($action, $standalone_actions)) {
            return; # no need for checks these guys can handle themselves.
        }

        if ($action == "deleteuser") {
            if (!empty($_GET["username"])) {
                $this->logaholicuser = $_GET["username"];
                return;
            }
        }

        if ($action == "listuserprofiles" || $action == "getuserprofileinfo") {
            if (!empty($_GET["username"])) {
                $this->logaholicuser = $_GET["username"];
                return;
            }
        }

        if ($action == "edituser") {
            if (empty($_GET["new_username"])) {
                Output("When editing users, variable new_username is required <br><br>\n\n" . $help, true);
                exit();
            }
        }

        if ($action == 'fetchuser' || $action == 'getuser') {
            if (!empty($_GET['username'])) {
                $this->logaholicuser = $_GET["username"];
                return;
            }
        }

        if ($action == 'getdbsize') {
            if (!empty($_GET['username'])) {
                $this->logaholicuser = $_GET["username"];
                return;
            }
        }

        if (isset($_GET["username"])) {
            $this->logaholicuser = $_GET["username"];
            if (isset($_GET['password'])) {
                if ($this->isValidMd5($_GET['password'])) {
                    $this->logaholicpass = $_GET["password"];
                } else {
                    $this->logaholicpass = md5($_GET["password"]);
                }

                # for cpanel, just do it!
                //$this->logaholicpass = $_GET["password"];

            }
            if (isset($_GET['fullname'])) {
                $this->logaholicname = $_GET["fullname"];
            }
            if (isset($_GET['email']) && filter_var($_GET['email'], FILTER_VALIDATE_EMAIL)) {
                $this->logaholicemail = $_GET["email"];
            }
            if (isset($_GET['new_username'])) {
                $this->logaholic_newusername = $_GET["new_username"];
            }
            if (isset($_GET["accessEditProfile"]) && ($_GET["accessEditProfile"] == 1 || $_GET["accessEditProfile"] == 0)) {
                $this->accessEditProfile = $_GET["accessEditProfile"];
            }
            if (isset($_GET["accessBasicEditProfile"]) && ($_GET["accessBasicEditProfile"] == 1 || $_GET["accessBasicEditProfile"] == 0)) {
                $this->accessBasicEditProfile = $_GET["accessBasicEditProfile"];
            }
            if (isset($_GET["accessAddProfile"]) && ($_GET["accessAddProfile"] == 1 || $_GET["accessAddProfile"] == 0)) {
                $this->accessAddProfile = $_GET["accessAddProfile"];
            }
            if (isset($_GET["accessUpdateLogs"]) && ($_GET["accessUpdateLogs"] == 1 || $_GET["accessUpdateLogs"] == 0)) {
                $this->accessUpdateLogs = $_GET["accessUpdateLogs"];
            }

            if (isset($_GET["changeAccountInfo"]) && ($_GET["changeAccountInfo"] == 1 || $_GET["changeAccountInfo"] == 0)) {
                $this->changeAccountInfo = $_GET["changeAccountInfo"];
            }

            if (isset($_GET["active"]) && ($_GET["active"] == 1 || $_GET["active"] == 0)) {
                $this->active = $_GET["active"];
            }
            if (isset($_GET["expires"]) && is_numeric($_GET["expires"])) {
                $this->expires = $_GET["expires"];
            }
            if (isset($_GET["subscriptionid"]) && is_numeric($_GET["subscriptionid"])) {
                $this->usersubscriptionid = $_GET["subscriptionid"];
            }
            if (isset($_GET["subscriptionname"])) {
                $this->usersubscriptionname = $_GET["subscriptionname"];
            }
            if (isset($_GET["isAdmin"]) && ($_GET["isAdmin"] == 1 || $_GET["isAdmin"] == 0)) {
                $this->isAdmin = $_GET["isAdmin"];
            }

            if ((!empty($this->logaholicpass) && !empty($this->logaholicuser))
                || ($action == 'edituser' && !empty($this->logaholicuser))
            ) {
                return;
            } else {
                Output("We need a valid username and password <br><br>\n\n" . $help, true);
            }
        } else {
            Output($help, true);
        }
    }

    function isValidMd5($md5)
    {
        if (strlen($md5) > 32) {
            return true;
        }

        return !empty($md5) && preg_match('/^[a-f0-9]{32}$/', $md5);
    }

    function dbConnect()
    {
        global $db, $config;
        require_once($config['path'] . "/common.inc.php");
    }

    function LogaholicDBUser()
    {
        __construct();
    }

    /**
     * @desc This function will add the user to the user table
     */
    function AddUser()
    {
        global $db;
        # Before setting the id in the query check if we need to convert a name to an id
        if (!empty($this->usersubscriptionname) && empty($this->usersubscriptionid)) {
            $this->SetSubscriptionIdByName();
        }

        $this->metadata = json_encode(array(
                                          "changeAccountInfo" => $this->changeAccountInfo
                                      ,
                                          "profileLimit" => 0
                                      ,
                                          "trackermode_0" => 0
                                      ,
                                          "trackermode_1" => 0
                                      ,
                                          "trackermode_2" => 0
                                      ,
                                          "trackermode_3" => 0
                                      ,
                                          "allProfiles" => 0
                                      ,
                                          "accessBasicEditProfile" => $this->accessBasicEditProfile
                                      ));


        $fields = array(
            'username',
            'name',
            'password',
            'email',
            'created',
            'isAdmin',
            'active',
            'accessUpdateLogs',
            'accessAddProfile',
            'accessEditProfile',
            'expires',
            'metadata',
            'subscriptionid'
        );
        $values = array(
            $db->Quote($this->logaholicuser)
        ,
            $db->Quote($this->logaholicname)
        ,
            $db->Quote($this->logaholicpass)
        ,
            $db->Quote($this->logaholicemail)
        ,
            "UNIX_TIMESTAMP(NOW())"
        ,
            $db->Quote($this->isAdmin)
        ,
            $db->Quote($this->active)
        ,
            $db->Quote($this->accessUpdateLogs)
        ,
            $db->Quote($this->accessAddProfile)
        ,
            $db->Quote($this->accessEditProfile)
        ,
            $db->Quote($this->expires)
        ,
            $db->Quote($this->metadata)
        ,
            $db->Quote($this->usersubscriptionid)
        );
        if (!empty($this->profiles)) {
            $fields[] = 'profiles';
            $values[] = $db->Quote($this->profiles);
        }

        $query = "INSERT INTO " . TBL_USERS . " (" . implode(",", $fields) . ") VALUES (" . implode(",", $values) . ")";

        @$db->Execute($query) or Output("An error occurred: " . $db->ErrorMsg(), true);

        Output("Success: Added user $this->logaholicuser<br>\n");
    }

    function SetSubscriptionIdByName()
    {
        global $db;
        $r = $db->Execute(
            "SELECT `id` FROM " . TBL_SUBSCRIPTIONS . " WHERE `name`=" . $db->Quote(
                $this->usersubscriptionname
            ) . " LIMIT 1"
        );
        $row = $r->fetchRow();
        if (empty($row)) {
            Output("Invalid Subscription Name\n", true);
        } else {
            $this->usersubscriptionid = $row['id'];
        }
    }

    /**
     * @desc This function will edit an existing user
     */
    function EditUser()
    {
        global $db;

        $query = "UPDATE " . TBL_USERS . " SET username=" . $db->Quote($this->logaholic_newusername);

        /**
         *  if these values are null, the they were never passed in the request
         *  so don't attempt to update them: it could nullify an existing value
         */
        if ($this->logaholicpass !== null) {
            $query .= ", password=" . $db->Quote($this->logaholicpass);
        }

        if ($this->logaholicname !== null) {
            $query .= ", name=" . $db->Quote($this->logaholicname);
        }

        if ($this->logaholicemail !== null) {
            $query .= ", email=" . $db->Quote($this->logaholicemail);
        }

        if (!empty($this->profiles)) {
            $query .= ", profiles=" . $db->Quote($this->profiles);
        }

        if ($this->accessUpdateLogs !== null) {
            $query .= ", accessUpdateLogs=" . $db->Quote($this->accessUpdateLogs);
        }

        if ($this->accessAddProfile !== null) {
            $query .= ", accessAddProfile=" . $db->Quote($this->accessAddProfile);
        }

        if ($this->accessEditProfile !== null) {
            $query .= ", accessEditProfile=" . $db->Quote($this->accessEditProfile);
        }
        if ($this->accessBasicEditProfile !== null) {
            $res = $db->Execute(
                "select metadata from " . TBL_USERS . " where username=" . $db->Quote($this->logaholicuser)
            );
            $md = $res->fetchRow();
            $md = json_decode($md["metadata"], true);
            $md['accessBasicEditProfile'] = $this->accessBasicEditProfile;
            $query .= ", metadata=" . $db->Quote(json_encode($md));
        }

        # Before setting the id in the query check if we need to convert a name to an id
        if (!empty($this->usersubscriptionname) && empty($this->usersubscriptionid)) {
            $this->SetSubscriptionIdByName();
        }
        if (!empty($this->usersubscriptionid)) {
            $query .= ", subscriptionid=" . $db->Quote($this->usersubscriptionid);
            $this->ChangeSubscriptionId();
        }

        if ($this->isAdmin !== null) {
            $query .= ", isAdmin=" . $db->Quote($this->isAdmin);
        }

        $query .= " where username=" . $db->Quote($this->logaholicuser);
        @$db->Execute($query) or Output("An error occurred " . $db->ErrorMsg(), true);

        Output("Edited User $this->logaholic_newusername<br>\n");
    }

    function ChangeSubscriptionId()
    {
        global $db;

        # Does this even exists?
        if (!CheckIfTableExists(TBL__SUBSCRIPTIONS_USERLOG)) {
            return false;
        }

        $r = $db->Execute("SELECT * FROM " . TBL_SUBSCRIPTIONS . " WHERE id = {$this->usersubscriptionid}");
        $row = $r->fetchRow();
        if ($row === false) {
            Output("Invalid subscription Id given", true);
            return false;
        }

        $vals = json_decode($row['value'], true);

        if (empty($vals["Price"])) {
            return false;
        }

        $nowd = date("Y-m-d H:i:s", time());
        NewSubscriptionLogEntry(
            "On $nowd Changed to {$row['name']}",
            $row['name'],
            $vals["Price"]['value'],
            $this->logaholic_newusername
        );
    }

    /**
     * @desc This function will delete a user and all profiles that belong to that user
     */
    function DeleteUser()
    {
        global $db;

        # first, get the list of profiles for this user
        $profile_list = getProfileList($this->logaholicuser);
        //dump($profile_list);
        $return = "";
        # next, delete each profile from the system
        if (!empty($profile_list)) {
            $profiles = explode(",", $profile_list);
            foreach ($profiles as $profile) {
                $_GET['profile_name'] = $profile;
                # do the delete action using the LogaholicDBprofile class    
                // $s = $this->getSiteFromProfilename($profile);
                // if(empty($s)){
                // } else {
                //     $_GET['site'] = $s;
                // }
                $site = new LogaholicDBProfile();
                $return .= $site->DeleteProfile();
            }
        }

        # finally, delete the user record
        @$db->Execute(
            "delete from " . TBL_USERS . " where username=" . $db->Quote($this->logaholicuser) . " limit 1"
        ) or Output("An error occurred:" . $db->ErrorMsg(), true);

        Output($return . "Deleted user $this->logaholicuser<br>\n");
    }

    function FetchUser()
    {
        global $db;

        $query = @$db->Execute(
            "SELECT * from " . TBL_USERS . " where username=" . $db->Quote($this->logaholicuser)
        ) or Output("An error occurred:" . $db->ErrorMsg(), true);
        $data = array();
        if ($query->NumRows() != 0) {
            foreach ($query->FetchRow() as $key => $value) {
                if (!is_numeric($key)) {
                    $data[$key] = $value;
                }
            }
        }

        return $data;
    }

    function getSiteFromProfilename($profilename)
    {
        global $db;

        $query = $db->Execute(
            "select confdomain from " . TBL_PROFILES . " where profilename=" . $db->Quote($profilename)
        ) or Output("An error occurred:" . $db->ErrorMsg(), true);
        if ($query->NumRows() == 0) {
            Output("An error occurred: Profilename $profilename not found", true, false);
        }
        $q = $query->FetchRow();
        return $q['confdomain'];
    }

    function ListUserProfiles()
    {
        global $db;
        $profile_list = getProfileList($this->logaholicuser);
        $profile_list = explode(",", $profile_list);
        if (!empty($profile_list)) {
            Output($profile_list);
        } else {
            Output(array());
        }
        return;
    }

    function getUserProfileInfo()
    {
        global $db;
        $profile_list = getProfileList($this->logaholicuser);
        $profile_list = explode(",", $profile_list);
        $in = "'" . implode("','", $profile_list) . "'";
        $query = "select profilename, activated, lastused, sessioncounter, update_status, other_settings, stats 
                from " . TBL_PROFILES . " where profilename IN ($in)";

        $q = $db->Execute($query);
        $data = array();
        while ($row = $q->fetchRow()) {
            $os = json_decode($row['other_settings'], true);
            $has_email_alerts = false;
            foreach ($os as $setting => $val) {
                if (strpos($setting, 'emailalerts') !== false) {
                    $has_email_alerts = true;
                }
            }
            $data[] = array(
                'profilename' => $row["profilename"],
                'activated' => $row["activated"],
                'lastused' => $row['lastused'],
                'sessioncounter' => $row['sessioncounter'],
                'update_status' => $row['update_status'],
                'has_email_alerts' => $has_email_alerts,
                'stats' => json_decode($row['stats'])
            );
        }
        return Output($data);
    }

    /**
     * @desc This function will return the database size of all profiles that belongs to this user
     */
    function getUserDBSize()
    {
        global $db;
        $profile_list = getProfileList($this->logaholicuser);
        if (empty($profile_list)) {
            Output("No profiles found for this user", true);
        }
        $size = 0;
        $p = explode(",", $profile_list);
        foreach ($p as $profile) {
            $dbp = new LogaholicDBProfile($profile);
            $size = $size + $dbp->getProfileDBSize($profile);
        }
        return $size;
    }

    /**
     * @desc This function gives a list with the full data the CloudCron needs to update a Cloud Database
     */
    function GetCloudUsersInfo()
    {
        global $db;
        $result = array();
        $profiles = array();
        $backup_profiles = array();

        # Get users
        $users = $this->ListUsers();

        # Get profiles
        $r = $db->Execute("SELECT profilename, sessioncounter FROM " . TBL_PROFILES);
        while ($row = $r->fetchRow()) {
            $profiles[trim($row['profilename'])] = $row['sessioncounter'];
        }

        # Set a double array which is needed to see which profiles are missing a user
        $backup_profiles = $profiles;

        # Prepare result set
        foreach ($users as $user) {
            $user_profiles = array();

            # only if this users has profiles
            if (!empty($user['profiles'])) {
                $p = explode(",", $user['profiles']);
                foreach ($p as $k => $v) {
                    $v = trim($v);
                    if (isset($profiles[$v])) {
                        $user_profiles[$v] = $profiles[$v];

                        # If the profile is still in the array remove it
                        if (isset($backup_profiles[$v])) {
                            unset($backup_profiles[$v]);
                        }
                    }
                }
            }

            $result[] = array(
                "Created" => $user['created'],
                "Username" => $user['username'],
                "Password" => $user['password'],
                "Subscription" => $user['subscription'],
                "Lastlogin" => $user['lastlogin'],
                "Profiles" => $user_profiles
            );
        }

        # add version number to ignore the other call
        return array(
            "Version" => LOGAHOLIC_BASE_EDITION . " " . LOGAHOLIC_VERSION_NUMBER,
            "Users" => $result,
            "NoUser" => $backup_profiles
        );
    }

    function ListUsers()
    {
        global $db;
        if (CheckIfTableExists(TBL_SUBSCRIPTIONS)) {
            $query = "SELECT u.username,u.password,s.`name` , profiles, created , lastlogin from " . TBL_USERS . " as u LEFT JOIN " . TBL_SUBSCRIPTIONS . " as s ON u.subscriptionid = s.id WHERE u.isAdmin != 1";
        } else {
            $query = "SELECT username, password, '' as name , profiles, created , lastlogin from " . TBL_USERS . " WHERE isAdmin != 1";
        }
        $q = $db->Execute($query);
        $data = array();
        while ($row = $q->fetchRow()) {
            $data[] = array(
                'username' => $row["username"],
                'password' => $row["password"],
                'subscription' => $row['name'],
                'created' => $row['created'],
                'lastlogin' => $row['lastlogin'],
                'profiles' => $row['profiles']
            );
        }
        return $data;
    }

}