<?xml version="1.0"?>
<component>
<?component error="true" debug="true"?>
<registration
	description="scimgroups"
	progid="flexwhere.WSC"
	version="1.00"
	classid="{6D817B6F-9D08-4636-AAD9-8BD7C5EFF56A}"
>
</registration>

<public>

<!-- properties -->

<!-- methods -->
	<method name="initialize">
		<PARAMETER name="params"/>
	</method>
	<method name="error_handler">
		<PARAMETER name="code"/>
		<PARAMETER name="msg"/>
		<PARAMETER name="orgHandler"/>
	</method>
	<method name="transform_filter">
		<PARAMETER name="filter"/>
	</method>
	<method name="transform_outgoing">
		<PARAMETER name="params"/>
		<PARAMETER name="data"/>
	</method>
	<method name="transform_incoming">
		<PARAMETER name="params"/>
		<PARAMETER name="data"/>
	</method>
	<method name="get_eTag">
		<PARAMETER name="params"/>
		<PARAMETER name="data"/>
	</method>
</public>

<script language="javascript">
<![CDATA[

/*	properties	*/


/*	methods	*/
/*
/*
    $Id$

    File:   scimgroups.wsc
*/
/* Globals */
var FCLT;


function initialize(params)
{
    FCLT = params;
}

function error_handler(code, msg, orgHandler)
{
    code = code || 500;
    var data = {
        "schemas" : ["urn:ietf:params:scim:api:messages:2.0:Error"],
        "scimType": "invalidValue",
        "detail"  : msg,
        "status"  : code
    };

    FCLT.DEZE.Response.ContentType = "application/json";
    FCLT.DEZE.Response.Write(FCLT.DEZE.JSON.stringify(data, null, 2));
    var codestr = String(code);
    if (typeof code == "number")
    {
        var codestr = { 400: "Bad request",
                        403: "Forbidden",
                        404: "Not Found",
                        422: "Unprocessable Entity" }[code];
        if (codestr)
            code = code + " " + codestr;
    }
    FCLT.DEZE.Response.Status = code;

    FCLT.DEZE.__Log("Aborting with status: " + code);
    FCLT.DEZE.__Log(data);

    FCLT.DEZE.Response.End;
}

function transform_filter(filter)
{
    if ("count" in filter)
        filter.limit = filter.count;
    if ("startindex" in filter)
        filter.offset = filter.startindex - 1;
    if ("filter" in filter)
    {
        if (filter.filter.match(/^id/)) // Ontvangen filter: "filter": "id eq \"KFSG_authorizationgroup_703\""
        {
            var v_filter = filter.filter.replace ("id eq \"" + FCLT.DEZE.customerId + "_authorizationgroup_", "");
            v_filter = v_filter.replace("\"", "");
            filter.id = v_filter;
        }
        else if (filter.filter.match(/^displayName/)) // Azure, filter=displayName+eq+"Vastgoed%2c+Gronden+en+Duurzaamheid"
        {
            var v_filter = filter.filter.replace ("displayName eq \"", "");
            v_filter = v_filter.replace("\"", "");
            filter.name = v_filter;
        }
    }
    filter.nointernal = 1;
    return filter;
}

function get_eTag(params, data)
{
    if (data && typeof data == "object" && "meta" in data)
        return data.meta.version;
    return null;
}

function transform_incoming(params, data)
{
    FCLT.DEZE.__Log(data);
    FCLT.DEZE.__Log(params);

    if ("id" in data) // uit transform_filter
    {
        var groep_key = data["id"].replace (FCLT.DEZE.customerId + "_authorizationgroup_", "");
    }
    else
        groep_key = params.filter.id; // door APPL/FAC/fac_rewrite.config

    if (params.method == "PATCH" && groep_key > 0)
    {
        /* PATCH vanuit Azure
            {
                "schemas": [
                    "urn:ietf:params:scim:api:messages:2.0:PatchOp"
                ],
                "Operations": [
                    {
                        "op": "Add",
                        "path": "members",
                        "value": [
                            {
                                "value": "LOGC_person_9502"
                            }
                        ]
                    }
                ]
            }
            of
            {
                "schemas": [
                    "urn:ietf:params:scim:api:messages:2.0:PatchOp"
                ],
                "Operations": [
                    {
                        "op": "Replace",
                        "path": "externalId",
                        "value": "e1871df3-6798-49c2-81cc-97ceb766647a"
                    },
                    {
                        "op": "Replace",
                        "path": "displayName",
                        "value": "AareonTest"
                    }
                ]
            }
        */
        if (!("schemas" in data) || data.schemas[0] != "urn:ietf:params:scim:api:messages:2.0:PatchOp")
            FCLT.DEZE.api2.error(400, "Missing or bad schema");

        var newdata = {};
        // Ik weet niet of Azure meerdere operation 'Add' kan sturen met telkens een enkele value
        // of een enkele operation met een multi-value. We kunnen beide aan.
        for (var i = 0; i < data.Operations.length; i++)
        {
            var oper = data.Operations[i];
            if (oper.path == 'externalId') 
            {
                newdata['externalId'] = oper.value;
            }
            if (oper.path == 'displayName')
            {
                newdata['displayName'] = oper.value;
            }
            if (oper.path == 'members') // Die passen we on the fly aan
            {
                for (var j = 0; j < oper.value.length; j++)
                {
                    var member = oper.value[j].value;
                    var member_id = member.replace (FCLT.DEZE.customerId + "_person_", "");
                    var prs_key = parseInt(member_id, 10);
                    if (isNaN(prs_key))
                    {
                        error_handler(500, "Invalid user", "");
                    }
                    switch (oper.op.toLowerCase())
                    {
                        case "add":
                            var sql = "INSERT INTO fac_gebruikersgroep"
                                    + "    (fac_groep_key, prs_perslid_key)"
                                    + " SELECT " + groep_key + ", " + prs_key
                                    + "   FROM DUAL"
                                    + " WHERE (" + groep_key + ", " + prs_key + ")"
                                    + "   NOT IN (SELECT fac_groep_key, prs_perslid_key"
                                    + "             FROM fac_gebruikersgroep)";
                            FCLT.DEZE.Oracle.Execute(sql);
                            break;
                        case "remove":
                            var sql = "DELETE FROM fac_gebruikersgroep"
                                    + " WHERE fac_groep_key = " + groep_key
                                    + "   AND prs_perslid_key = " + prs_key;
                            FCLT.DEZE.Oracle.Execute(sql);
                            break;
                        case "replace":
                            // unsupported, ignore
                            break;
                        default:
                            // unknown op?
                    }
                }
            }
        }
        data = newdata;
    }

    var authorizationgroup = {};
    if ("displayName" in data)
        authorizationgroup["name"] = data["displayName"];
    if ("externalId" in data)
        authorizationgroup["externalid"] = data["externalId"];

    // Hieronder de code voor als een SCIM-client alle members tegelijk bij een PUT/POST stuurt
    // Ik weet niet of iemand dat doet
    if (data["members"] && groep_key > 0)
    {
        var sql = "DELETE fac_rapport WHERE fac_rapport_node = 'SCIMGROUPS'"; // omweg omdat het enorm veel data kan zijn?
        FCLT.DEZE.Oracle.Execute(sql);

        var oRs;
        var member_id;
        for (var j = 0; j < data["members"].length; j++)
        {
            if (data["members"][j].value)
            {
                member = data["members"][j].value;
                member_id = member.replace (FCLT.DEZE.customerId + "_person_", "");
                if (isNaN(member_id)) {
                    error_handler(500, "Ongeldige gebruiker", "");
                }
                sql = "INSERT INTO fac_rapport (fac_rapport_node, fac_rapport_regel, fac_rapport_volgnr) "
                    + " VALUES('SCIMGROUPS', " + groep_key + ", " + FCLT.DEZE.safe.quoted_sql(member_id) + ")";
                oRs = FCLT.DEZE.Oracle.Execute(sql);
            }
        }
        // We slaan de groep key tijdelijk op in fac_rapport_regel
        // en de perslid_key in het volgnummer omdat deze uniek moet zijn.
        sql = "INSERT INTO fac_gebruikersgroep ( fac_groep_key, prs_perslid_key) "
            + "SELECT fac_rapport_regel, fac_rapport_volgnr FROM fac_rapport r "
            + " WHERE NOT EXISTS (SELECT fac_gebruikersgroep_key "
            + "                     FROM fac_gebruikersgroep gg WHERE gg.prs_perslid_key = fac_rapport_volgnr AND gg.fac_groep_key = r.fac_rapport_regel)";
        FCLT.DEZE.Oracle.Execute(sql);

        sql = "DELETE fac_gebruikersgroep gg "
            + " WHERE fac_groep_key = " + groep_key
            + "   AND NOT EXISTS (SELECT fac_rapport_volgnr "
            + "                     FROM fac_rapport r WHERE gg.prs_perslid_key = fac_rapport_volgnr AND gg.fac_groep_key = r.fac_rapport_regel)";
        FCLT.DEZE.Oracle.Execute(sql);
    }

    //FCLT.DEZE.__DoLog(authorizationgroup);

    return { authorizationgroup: authorizationgroup };
}

function transform_one_group(params, authorizationgroup)
{
    FCLT.DEZE.__Log(authorizationgroup);
    var unique = FCLT.DEZE.customerId + "_authorizationgroup_" + String(authorizationgroup.id);
    var onegroup = {
           "displayName":authorizationgroup.name,
           "externalId":authorizationgroup.externalid,
           "id":unique,
           "schemas":[
              "urn:ietf:params:scim:schemas:core:2.0:Group",
              "urn:ietf:params:scim:schemas:extension:enterprise:2.0:Group"
           ],
           "members":[],
           "meta":{
              "created":authorizationgroup.created,
              "lastModified":authorizationgroup.lastchange?authorizationgroup.lastchange:authorizationgroup.created,
              "location":FCLT.DEZE.HTTP.urlzelf() + "/appl/SCIM/Groups/" + unique,
              "resourceType":"Group"
           }
        }

    if (FCLT.DEZE.getQParam("excludedAttributes", "") == "members")
    {
        delete onegroup["members"];
    }
    else
    {
        for (var j = 0; j < authorizationgroup.users.length; j++)
        {
            var user = authorizationgroup.users[j];
            var unique = FCLT.DEZE.customerId + "_person_" + String(user.person.id);
            onegroup.members.push({
                     "value":unique,
                     "type":"User",
                     "$ref":FCLT.DEZE.HTTP.urlzelf() + "/appl/SCIM/Users/" + unique,
                     "display":user.person.name
                  })
        }
    }
    var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
    var eTag = '"' + oCrypto.hex_sha1(FCLT.DEZE.JSON.stringify(onegroup)).toLowerCase() + '"';
    onegroup.meta["version"] = "W/" + eTag; // Weak eTag?
    return onegroup;
}

function transform_outgoing(params, data)
{
    if ("authorizationgroup" in data)
    {
        var oneauthorizationgroup = transform_one_group(params, data.authorizationgroup);
        return oneauthorizationgroup;
    }
    if ("authorizationgroups" in data)
    {
        var allgroups = [];
        for (var i = 0; i < data.authorizationgroups.length; i++)
        {
            var authorizationgroup = data.authorizationgroups[i];
            allgroups.push(transform_one_group(params, authorizationgroup));
        }

        return {
        	"totalResults": data.total_count,
        	"itemsPerPage": allgroups.length,
        	"startIndex": 1,
        	"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
        	"Resources": allgroups
        };
    }
}

]]>
</script>
</component>
