<?PHP

$GLOBALS["G_ErrMsgs"] = SiteUpgrade310_PerformUpgrade();

/**
* Perform all of the site upgrades for 3.1.0.
* @return Returns NULL on success and an eror message if an error occurs.
*/
function SiteUpgrade310_PerformUpgrade()
{
    try
    {
        Msg(1, "Updating resource schema permissions...");
        SiteUpgrade310_UpdateResourceSchemaPermissions();

        Msg(1, "Updating user schema permissions...");
        SiteUpgrade310_UpdateUserSchemaPermissions();
    }

    catch (Exception $Exception)
    {
        return array($Exception->getMessage(),
                "Exception Trace:<br/><pre>"
                        .$Exception->getTraceAsString()."</pre>");
    }
}

/**
* Update permissions for the resource schema.
*/
function SiteUpgrade310_UpdateResourceSchemaPermissions()
{
    $Schema = new MetadataSchema();

    # This business gets a little annoying.  We introduced the new
    # permissions system in CWIS 300, and included migration code that
    # set some weird permissions from 241 -> 300. These migrated
    # permissions were actually different from those on a fresh install.

    # First, work through the schema permissions.  For these, the
    # freshly installed perms are mostly correct and we're just working
    # to correct the wacky migrated permissions.

    #
    # SCHEMA VIEWING PRIVILEGES
    #

    # reconstruct what freshly installed schema viewing privs would
    # be, as these need to be updated
    $InstalledVPrivs = new PrivilegeSet();
    $InstalledVPrivs->AddCondition($Schema->GetFieldIdByName("Release Flag"), 1);
    $InstalledVPrivs->AddPrivilege(PRIV_RESOURCEADMIN);
    $Subgroup = new PrivilegeSet();
    $Subgroup->AllRequired(TRUE);
    $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
    $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
    $InstalledVPrivs->AddSet( $Subgroup );

    # reconstruct what the migrated schema viewing privs would be
    $MigratedVPrivs = new PrivilegeSet();
    $MigratedVPrivs->AddCondition( $Schema->GetFieldIdByName("Release Flag"), 1);
    $MigratedVPrivs->AddPrivilege(PRIV_RESOURCEADMIN);
    $Subgroup = new PrivilegeSet();
    $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
    $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
    $MigratedVPrivs->AddSet( $Subgroup );

    # if our viewing privs are equal to the migrated ones, update them
    # to the new defaults
    $SerialVPrivs = serialize($Schema->ViewingPrivileges()->GetPrivilegeInfo());
    if ( $SerialVPrivs == serialize($MigratedVPrivs->GetPrivilegeInfo()) ||
         $SerialVPrivs == serialize($InstalledVPrivs->GetPrivilegeInfo()) )
    {
        $VPrivs = new PrivilegeSet();
        $VPrivs->AddCondition( $Schema->GetFieldIdByName("Release Flag"), 1);
        $VPrivs->AddCondition(PrivilegeSet::HAVE_RESOURCE, FALSE, "==");
        $VPrivs->AddPrivilege(PRIV_RESOURCEADMIN);
        $Subgroup = new PrivilegeSet();
        $Subgroup->AllRequired(TRUE);
        $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
        $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
        $VPrivs->AddSet( $Subgroup );

        $Schema->ViewingPrivileges( $VPrivs );
    }

    #
    # SCHEMA AUTHORING PRIVILEGES
    #

    # reconstruct what the migrated schema authoring privs would be
    $MigratedAPrivs = new PrivilegeSet();
    $MigratedAPrivs->AddPrivilege( PRIV_RESOURCEADMIN );
    $MigratedAPrivs->AddCondition( $Schema->GetFieldIdByName("Added By Id") );

    # reconstruct what newly installed schema authoring privs would be
    $InstalledAPrivs = new PrivilegeSet();
    $InstalledAPrivs->AddPrivilege( PRIV_RESOURCEADMIN );

    # if our current schema authoring privs are equal to either the
    # migrated or installed authoring privs update them to the new defaults
    if (serialize($Schema->AuthoringPrivileges()->GetPrivilegeInfo()) ==
        serialize($MigratedAPrivs->GetPrivilegeInfo())  ||
        serialize($Schema->AuthoringPrivileges()->GetPrivilegeInfo()) ==
        serialize($InstalledAPrivs->GetPrivilegeInfo()) )
    {
        $APrivs = new PrivilegeSet();
        $APrivs->AddPrivilege( PRIV_RESOURCEADMIN );
        $APrivs->AddPrivilege( PRIV_MYRESOURCEADMIN );

        $Schema->AuthoringPrivileges( $APrivs );
    }

    #
    # SCHEMA EDITING PRIVILEGES
    #

    # reconstruct what the migrated schema editing privs would be
    $MigratedEPrivs = new PrivilegeSet();
    $MigratedEPrivs->AddPrivilege(PRIV_RESOURCEADMIN);
    $MigratedEPrivs->AddPrivilege(PRIV_RELEASEADMIN);
    $Subgroup = new PrivilegeSet();
    $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
    $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
    $MigratedEPrivs->AddSet( $Subgroup );

    # if our current schema editing privs are equal to the migrated
    # schema editing privs, then update them to the new defaults
    if (serialize($Schema->EditingPrivileges()->GetPrivilegeInfo()) ==
        serialize($MigratedEPrivs->GetPrivilegeInfo()) )
    {
        $EPrivs = new PrivilegeSet();
        $EPrivs->AddPrivilege( PRIV_RESOURCEADMIN );
        $EPrivs->AddPrivilege( PRIV_RELEASEADMIN );
        $Subgroup = new PrivilegeSet();
        $Subgroup->AllRequired(TRUE);
        $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
        $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
        $EPrivs->AddSet( $Subgroup );

        $Schema->EditingPrivileges( $EPrivs );
    }

    # The schema permissions are now happy.  Next on to the field
    # permissions, which get a bit hairier.  A bug in MetadataField
    # caused fresh installs not to have any field permissions set in
    # 300, 301, and 302.  However, the migration from 241 to 300
    # splatted some rather odd permissions into all of the fields in
    # the resource schema.

    #
    # FIELD VIEWING PRIVILEGES
    #

    # both migrated and installed viewing privileges are empty,
    # so reconstructing those is easy. :)

    # create arrays to store the serialized versions of migrated privs
    # that we check for
    $SerialMVP = array();
    $SerialMAP = array();
    $SerialMEP = array();

    # Reconstruct field viewing privs that we want to migrate from
    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_MYRESOURCEADMIN );
    $SerialMVP["Added By Id"]  = serialize($MP->GetPrivilegeInfo());
    $SerialMVP["Last Modified By Id"] = serialize($MP->GetPrivilegeInfo());
    $SerialMVP["Release Flag"] = serialize($MP->GetPrivilegeInfo());


    # Reconstruct field authoring privs that we want to migrate from
    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_MYRESOURCEADMIN );
    $SerialMAP["XX-DEFAULT-XX"] = serialize($MP->GetPrivilegeInfo());

    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_SYSADMIN );
    $SerialMAP["Added By Id"] = serialize($MP->GetPrivilegeInfo());

    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_RELEASEADMIN );
    $SerialMAP["Release Flag"] = serialize($MP->GetPrivilegeInfo());


    # Reconstruct field editing privs that we want to migrate from
    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_RESOURCEADMIN );
    $SerialMEP["XX-DEFAULT-XX"] = serialize($MP->GetPrivilegeInfo());

    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_RELEASEADMIN );
    $SerialMEP["Release Flag"] = serialize($MP->GetPrivilegeInfo());

    $MP = new PrivilegeSet();
    $MP->AddPrivilege( PRIV_SYSADMIN );
    $SerialMEP["Added By Id"] = serialize($MP->GetPrivilegeInfo());


    # make a list of fields used for workflow that should not be viewable to the public
    $WorkflowFields = array(
        "Added By Id", "Last Modified By Id", "Date Record Checked", "Release Flag");

    # iterate over the fields, updating their permissions
    foreach ($Schema->GetFields(NULL, NULL, TRUE) as $Field)
    {
        $VPInfo = $Field->ViewingPrivileges()->GetPrivilegeInfo();
        $APInfo = $Field->AuthoringPrivileges()->GetPrivilegeInfo();
        $EPInfo = $Field->EditingPrivileges()->GetPrivilegeInfo();

        # ViewingPrivileges was empty in clean installs and migrated installations,
        # so fill in the desired values for empty privsets
        # (an empty privset will have one element, Logic, in the PrivilegeInfo array)
        if (count($VPInfo)==1 ||
               (isset($SerialMVP[$Field->Name()]) &&
                    serialize($VPInfo) == $SerialMVP[$Field->Name()]) )
        {
            $VPrivs = new PrivilegeSet();

            if (in_array($Field->Name(), $WorkflowFields))
            {
                $VPrivs->AddPrivilege( PRIV_RESOURCEADMIN );
                $Subgroup = new PrivilegeSet();
                $Subgroup->AllRequired(TRUE);
                $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
                $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
                $VPrivs->AddSet( $Subgroup );
            }

            $Field->ViewingPrivileges( $VPrivs );
        }

        # Look for migrated authoring privileges and clear them out.
        # Default privs for a new install were empty, which is what we
        # want, so we don't need to do anything in that case.
        $MPToCheck = isset ($SerialMAP[$Field->Name()]) ?
            $SerialMAP[$Field->Name()] : $SerialMAP["XX-DEFAULT-XX"];
        if (serialize($APInfo) == $MPToCheck)
        {
            $APrivs = new PrivilegeSet();

            if ($Field->Name() == "Date Of Record Creation" ||
                $Field->Name() == "Added By Id" ||
                $Field->Name() == "Last Modified By Id")
            {
                $APrivs->AddPrivilege(PRIV_COLLECTIONADMIN);
            }

            $Field->AuthoringPrivileges( $APrivs );
        }

        $MPToCheck = isset ($SerialMEP[$Field->Name()]) ?
            $SerialMEP[$Field->Name()] : $SerialMEP["XX-DEFAULT-XX"];
        if (serialize($EPInfo) == $MPToCheck || count($EPInfo) == 1)
        {
            $EPrivs = new PrivilegeSet();

            if ($Field->Name() == "Date Of Record Creation" ||
                $Field->Name() == "Added By Id" ||
                $Field->Name() == "Last Modified By Id")
            {
                $EPrivs->AddPrivilege( PRIV_COLLECTIONADMIN );
            }
            elseif ($Field->Name() != "Release Flag")
            {
                $EPrivs->AddPrivilege( PRIV_RESOURCEADMIN );
                $Subgroup = new PrivilegeSet();
                $Subgroup->AllRequired(TRUE);
                $Subgroup->AddPrivilege( PRIV_MYRESOURCEADMIN );
                $Subgroup->AddCondition( $Schema->GetFieldIdByName("Added By Id") );
                $EPrivs->AddSet( $Subgroup );
            }

            $Field->EditingPrivileges( $EPrivs );
        }
    }
}

/**
* Update permissions for the user schema.
*/
function SiteUpgrade310_UpdateUserSchemaPermissions()
{
    # This business is slightly less annoying. Because the permissions
    # we set for the user schema were so weird, we will just nuke them
    # without regard for their current values.

    # get the user metadata schema
    $UserSchema = new MetadataSchema(MetadataSchema::SCHEMAID_USER);

    # get the user ID metadata field
    $UserIdField = $UserSchema->GetFieldByName("UserId");

    #
    # SCHEMA PRIVILEGES
    #

    # We only want system administrators, user administrators,
    # and the corresponding user to be able to view the
    # fields in this schema.

    # set the schema viewing privileges
    $ViewingPrivileges = new PrivilegeSet();
    $ViewingPrivileges->AddCondition($UserIdField);
    $ViewingPrivileges->AddPrivilege(PRIV_USERADMIN);
    $ViewingPrivileges->AddPrivilege(PRIV_SYSADMIN);
    $UserSchema->ViewingPrivileges($ViewingPrivileges);

    # These fields are authored during user creation; since
    # the new user has no privileges, we don't want to set
    # any permissions on authoring.

    # set the schema authoring privileges
    $AuthoringPrivileges = new PrivilegeSet();
    $UserSchema->AuthoringPrivileges($AuthoringPrivileges);

    # The schema level editing permissions are the same as
    # the schema level viewing permissions.

    # set the schema editing privileges
    $EditingPrivileges = new PrivilegeSet();
    $EditingPrivileges->AddCondition($UserIdField);
    $EditingPrivileges->AddPrivilege(PRIV_USERADMIN);
    $EditingPrivileges->AddPrivilege(PRIV_SYSADMIN);
    $UserSchema->EditingPrivileges($EditingPrivileges);

    #
    # FIELD PRIVILEGES
    #

    # We will also nuke the field permissions for consistency.

    # make a blank privilege set to use for all the privileges
    $Privileges = new PrivilegeSet();

    # iterate over all the fields in the schema
    foreach ($UserSchema->GetFields() as $Field)
    {
        # All of the fields will use the schema level permissions.
        # The only difference will be that the UserId field
        # will not be editable or optional. Since this field is the only
        # link from the resource to the APUsers table, we don't
        # want anyone to be able to change it.

        # set up the user id field editable and optional attributes
        if ($Field->Name() == "UserId")
        {
            $Field->Editable(FALSE);
            $Field->Optional(FALSE);
        }
        # set up the attributes for the other fields
        else
        {
            $Field->Editable(TRUE);
            $Field->Optional(TRUE);
        }

        # set up the field viewing privileges
        $Field->ViewingPrivileges($Privileges);

        # set up the field authoring privileges
        $Field->AuthoringPrivileges($Privileges);

        # set up the field editing privileges
        $Field->EditingPrivileges($Privileges);
    }
}
