<?PHP
#
#   FILE:  DrupalSync.php
#
#   Part of the Collection Workflow Integration System (CWIS)
#   Copyright 2002-2013 Edward Almasy and Internet Scout Research Group
#   http://scout.wisc.edu/cwis/
#

require_once("sync_common.php");

/**
* Plugin to synchronize logins between a CWIS and Drupal installation.
*
* A companion cwis_user plugin must also be installed on the target drupal site.
*/
final class DrupalSync extends Plugin
{
    /**
    * Register the DrupalSync plugin.
    * @see Plugin::Register
    */
    function Register()
    {
        $this->Name = "Drupal Login Synchronization";
        $this->Version = "1.0.2";
        $this->Description = "Allows users to register or log in"
            ." on CWIS or an associated Drupal installation "
            ." and be registered or logged in on the other package as well.  "
            ." An included companion module (<i>cwis_user</i>) must"
            ." be loaded on the Drupal site for this plugin to work";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/cwis/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array(
            "CWISCore" => "2.0.0"
            );
    }

    /**
    * Install the DrupalSync plugin.
    * @see Plugin::Install
    */
    function Install()
    {
        $DB = new Database();
        $DB->Query("CREATE TABLE DrupalSync_DtoC ( "
                   ."UserName TEXT, "
                   ."Command TEXT,"
                   ."Password TEXT, "
                   ."Email TEXT, "
                   ."Token INT );");
        $DB->Query("CREATE TABLE DrupalSync_CtoD ( "
                   ."UserName TEXT, "
                   ."Command TEXT,"
                   ."Password TEXT, "
                   ."Email TEXT, "
                   ."Token INT );");
        $DB->Query("CREATE TABLE DrupalSync_UserNameMap ( "
                   ."CwisName TEXT, "
                   ."DrupalName TEXT)");
    }

    /**
    * Uninstall the DrupalSync plugin.
    * @see Plugin::Uninstall
    */
    function Uninstall()
    {
        $DB = new Database();
        foreach ( array("DrupalSync_DtoC" => "Drupal to CWIS login synchronization",
                        "DrupalSync_CtoD" => "CWIS to Drupal login synchronization",
                        "DrupalSync_UserNameMap" => "CWIS/Drupal username mapping"
                      ) as $Table => $Desc )
        {
            if (FALSE === $DB->Query("DROP TABLE ".$Table) )
            { return "Could not remove the ".$Desc." table"; }
        }
    }

    /**
    * Upgrade the DrupalSync plugin.
    * @see Plugin::Upgrade
    */
    function Upgrade($PreviousVersion)
    {
        $DB = new Database();
        if (version_compare($PreviousVersion, "1.0.2", "<"))
        {
            foreach (array("DrupalToCwisUserSync" => "DrupalSync_DtoC",
                           "CwisToDrupalUserSync" => "DrupalSync_CtoD",
                           "UserNameMap"          => "DrupalSync_UserNameMap"
                         ) as $OldName => $NewName )
            {
                $DB->Query("ALTER TABLE ".$OldName
                           ." RENAME TO ".$NewName);
            }
        }
    }

    /**
    * Hook the DrupalSync plugin into the event system.
    * @see Plugin::HookEvents
    */
    function HookEvents()
    {
        return array(
            "EVENT_PAGE_LOAD"             => "CheckLoginCookie",
            "EVENT_USER_ADDED"            => "DrupalMirrorUserAdd",
            "EVENT_USER_DELETED"          => "DrupalMirrorUserDel",
            "EVENT_USER_PASSWORD_CHANGED" => "DrupalMirrorUserUpdate",
            "EVENT_USER_LOGIN"            => "DrupalMirrorUserLogin",
            "EVENT_USER_LOGOUT"           => "DrupalMirrorUserLogout"
            );
    }

    /**
    * Determine if there are any user synchronization actions to
    * perform.  When a user is logged in to the Drupal site, it sets a
    * cookie for us.  Also, check if there are pending user
    * creation/deletion/update requests having to do with some other
    * user.  Handle those as well, if there are any.
    */
    function CheckLoginCookie($PageName)
    {
        global $G_User;

        $Helper = new DrupalSync_Helper();

        $UserFactory = new CWUserFactory();

        # Handle pending user creation requested by Drupal
        $UsersToCreate = $Helper->UsersToCreate();
        foreach ($UsersToCreate as $UserData)
        {
            $TmpUser = new SPTUser($UserData["UserName"]);
            if ($TmpUser->Status() == U_NOSUCHUSER)
            {
                # If we've gotten this far, then the user has already
                # passed Drupal's password strength and email format
                # requirements. We don't want to fail to mirrow a
                # user that's valid on the Drupal side because they
                # have different PW/Email format requirements than we
                # do. Therefore, ignore format errors.
                $TmpUser = $UserFactory->CreateNewUser(
                    $UserData["UserName"],
                    $UserData["Password"], $UserData["Password"],
                    $UserData["Email"], $UserData["Email"],
                    array(U_ILLEGALPASSWORD, U_ILLEGALPASSWORDAGAIN,
                          U_ILLEGALEMAIL, U_ILLEGALEMAILAGAIN));
                if (is_object($TmpUser) && $TmpUser->Status()==U_OKAY)
                {
                    $TmpUser->GivePriv(PRIV_POSTTOFORUMS);
                    $TmpUser->GivePriv(PRIV_POSTCOMMENTS);
                }
            }

            # If user was successfully created, or if they already existed,
            # then mark them as done:
            if (is_object($TmpUser) && $TmpUser->Status() == U_OKAY)
            {
                $Helper->UserCreated($UserData["UserName"]);
            }
        }

        # Handle pending user deletions requested by Drupal
        $UsersToDelete = $Helper->UsersToDelete();
        foreach ($UsersToDelete as $UserData)
        {
            $TmpUser = new SPTUser($UserData["UserName"]);
            if (is_object($TmpUser) && $TmpUser->Status()==U_OKAY)
            {
                $TmpUser->Delete();
                $Helper->UserDeleted($UserData["UserName"]);
            }
        }

        # Handle pending user update requests by Drupal
        $UsersToUpdate = $Helper->UsersToUpdate();
        foreach ($UsersToUpdate as $UserData)
        {
            $TmpUser = new SPTUser($UserData["UserName"]);
            if (is_object($TmpUser) && $TmpUser->Status()==U_OKAY )
            {
                if (strlen($UserData["Password"]))
                {
                    $TmpUser->SetPassword($UserData["Password"]);
                }

                if (strlen($UserData["Email"]))
                {
                    $TmpUser->Set("EMail",$UserData["Email"]);
                }

                $Helper->UserUpdated($UserData["UserName"]);
            }
        }

        # Check for requests dealing with this user
        $Cmd = $Helper->CheckForCommand( $G_User->Name() );

        if ($Cmd["Command"]==="Login")
        {
            if ($G_User->Login($Cmd["UserName"],$Cmd["Password"])==U_OKAY)
            {
                $Helper->UserLoggedIn($Cmd["UserName"]);
            }
        }
        else if ($Cmd["Command"]==="Logout")
        {
            $G_User->Logout();
            $Helper->UserLoggedOut($Cmd["UserName"]);
        }
    }

    /**
    * Tell the Druapl site about user creations.
    */
    function DrupalMirrorUserAdd($UserId, $Password)
    {
        $Helper = new DrupalSync_Helper();
        $User = new SPTUser($UserId);
        if (is_object($User) && $User->Status()==U_OKAY)
        {
            $Helper->SignalCommand(
                "Create", $User->Name(), $Password, $User->Get("EMail"));
        }
    }

    /**
    * Tell the Druapl site about user deletions.
    */
    function DrupalMirrorUserDel($UserId)
    {
        $Helper = new DrupalSync_Helper();
        $User = new SPTUser($UserId);
        if (is_object($User) && $User->Status()==U_OKAY)
        {
            $Helper->SignalCommand("Delete", $User->Name());
        }
    }

    /**
    * Tell the Druapl site about updates to user Email or passwords.
    */
    function DrupalMirrorUserUpdate($UserId,$OldPass,$NewPass)
    {
        $Helper = new DrupalSync_Helper();
        $User = new SPTUser($UserId);
        if (is_object($User) && $User->Status()==U_OKAY)
        {
            $Helper->SignalCommand(
                "Update",$User->Name(), $NewPass, $User->Get("EMail"));
        }
    }

    /**
    * Tell the Drupal site when users log in.
    */
    function DrupalMirrorUserLogin($UserId, $Password)
    {
        $Helper = new DrupalSync_Helper();
        $User = new SPTUser($UserId);
        if (is_object($User) && $User->Status()==U_OKAY)
        {
            $Helper->SignalCommand(
                "Login", $User->Name(), $Password, $User->Get("EMail"));
        }
    }

    /**
    * Tell the Druapl site when users log out.
    */
    function DrupalMirrorUserLogout($UserId)
    {
        $Helper = new DrupalSync_Helper();
        $User = new SPTUser($UserId);
        if (is_object($User) && $User->Status()==U_OKAY)
        {
            $Helper->SignalCommand("Logout", $User->Name());
        }
    }
};
?>
