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

/**
* Automatically prunes user accounts that have never been activated and that are
* not referred to within resource metdata.
*/
class AccountPruner extends Plugin {

    # ---- STANDARD PLUGIN INTERFACE -----------------------------------------

    /**
    * Register information about this plugin.
    */
    function Register()
    {
        $this->Name = "User Account Pruner";
        $this->Version = "1.0.3";
        $this->Description = "Automatically prunes user accounts"
                ." that have never been activated and that are not"
                ." referred to within resource metadata.";
        $this->Author = "Internet Scout";
        $this->Url = "http://scout.wisc.edu/cwis/";
        $this->Email = "scout@scout.wisc.edu";
        $this->Requires = array(
                "CWISCore" => "2.2.2");
        $this->EnabledByDefault = FALSE;

        $this->CfgSetup["UnactivatedFrequency"] = array(
                "Type" => "Option",
                "Label" => "Prune Unactivated Accounts Every",
                "Default" => "Never",
                "Help" => "How often to prune accounts that have never"
                        ." been activated and/or used.",
                "Options" => array(
                        "Never" => "Never",
                        "Daily" => "Daily",
                        "Weekly" => "Weekly",
                        "Monthly" => "Monthly",
                        "Once" => "Once",
                        ),
                );
        $this->CfgSetup["UnactivatedDays"] = array(
                "Type" => "Number",
                "Label" => "Prune Unactivated Accounts After",
                "Size" => 4,
                "Units" => "days",
                "Default" => 30,
                "Help" => "Number of days that must have elapsed since creation"
                        ." before accounts that have never been activated and/or"
                        ." used are pruned.",
                );
    }

    /**
    * Initialize default settings.
    */
    function Install()
    {
        $this->ConfigSetting("UnactivatedDays", 30);
    }

    /**
    * Declare events defined by this plugin.  This is used when a plugin defines
    * new events that it signals or responds to.  Names of these events should
    * begin with the plugin base name, followed by "_EVENT_" and the event name
    * in all caps (for example "MyPlugin_EVENT_MY_EVENT").
    * @return Array with event names for the index and event types for the values.
    */
    function DeclareEvents()
    {
        return array(
                "AccountPruner_EVENT_DO_NOT_PRUNE_USER"
                        => ApplicationFramework::EVENTTYPE_NAMED,
                );
    }

    /**
    * Hook the events into the application framework.
    * @return Returns an array of events to be hooked into the application
    *      framework.
    */
    function HookEvents()
    {
        if ($this->ConfigSetting("UnactivatedFrequency") == "Daily")
            return array("EVENT_DAILY" => "PruneUnactivatedAccounts");
        elseif ($this->ConfigSetting("UnactivatedFrequency") == "Weekly")
            return array("EVENT_WEEKLY" => "PruneUnactivatedAccounts");
        elseif ($this->ConfigSetting("UnactivatedFrequency") == "Monthly")
            return array("EVENT_MONTHLY" => "PruneUnactivatedAccounts");
        elseif ($this->ConfigSetting("UnactivatedFrequency") == "Once")
            return array("EVENT_PERIODIC" => "PruneUnactivatedAccounts");
        else
            return array();
    }


    # ---- HOOKED METHODS ----------------------------------------------------

    /**
    * Remove user accounts that have never been activated and are not referred
    * to within resource metadata.
    * @param string $LastRunAt Date this method was last called by the
    *      application framework.
    */
    function PruneUnactivatedAccounts($LastRunAt)
    {
        # bail out if no number of days specified
        if (!strlen(trim($this->ConfigSetting("UnactivatedDays")))) {  return;  }

        # turn off pruning if we are set to only run once
        if ($this->ConfigSetting("UnactivatedFrequency") == "Once")
        {
            $this->ConfigSetting("UnactivatedFrequency", "Never");
        }

        # find all accounts unactivated and older than specified number of days
        $DB = new Database();
        $DB->Query("SELECT UserId FROM APUsers"
                ." WHERE LastLoginDate = '0000-00-00 00:00:00'"
                ." AND CreationDate < DATE_SUB(NOW(), INTERVAL "
                        .intval($this->ConfigSetting("UnactivatedDays"))." DAY)");
        $UserIds = $DB->FetchColumn("UserId");

        # for each account
        $Schema = new MetadataSchema();
        $Fields = $Schema->GetFields(MetadataSchema::MDFTYPE_USER);
        foreach ($UserIds as $Id)
        {
            # skip account if currently referred to within resource metadata
            $UseCount = 0;
            foreach ($Fields as $Field)
            {
                $UseCount += $Field->ValueUseCount($Id);
            }
            if ($UseCount > 0) {  continue;  }

            # skip account if hooked method asks us to
            $SignalResult = $GLOBALS["AF"]->SignalEvent(
                    "AccountPruner_EVENT_DO_NOT_PRUNE_USER",
                    array("UserId" => $Id));
            if (is_array($SignalResult))
            {
                foreach ($SignalResult as $HandlerName => $Result)
                {
                    if ($Result) {  continue 2;  }
                }
            }

            # delete account
            $User = new CWUser(intval($Id));
            $User->Delete();
        }
    }

}
