org.entcore.registry.services.impl.DefaultExternalApplicationService.java Source code

Java tutorial

Introduction

Here is the source code for org.entcore.registry.services.impl.DefaultExternalApplicationService.java

Source

/*
 * Copyright  "Open Digital Education", 2016
 *
 * This program is published by "Open Digital Education".
 * You must indicate the name of the software and the company in any production /contribution
 * using the software and indicate on the home page of the software industry in question,
 * "powered by Open Digital Education" with a reference to the website: https://opendigitaleducation.com/.
 *
 * This program is free software, licensed under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation, version 3 of the License.
 *
 * You can redistribute this application and/or modify it since you respect the terms of the GNU Affero General Public License.
 * If you modify the source code and then use this modified source code in your creation, you must make available the source code of your modifications.
 *
 * You should have received a copy of the GNU Affero General Public License along with the software.
 * If not, please see : <http://www.gnu.org/licenses/>. Full compliance requires reading the terms of this license and following its directives.
    
 */

package org.entcore.registry.services.impl;

import static fr.wseduc.webutils.Utils.defaultValidationParamsNull;
import static org.entcore.common.neo4j.Neo4jResult.validEmptyHandler;
import static org.entcore.common.neo4j.Neo4jResult.validResultHandler;
import static org.entcore.common.neo4j.Neo4jResult.validUniqueResultHandler;

import java.util.List;
import java.util.UUID;

import org.entcore.common.neo4j.Neo4j;
import org.entcore.common.neo4j.StatementsBuilder;
import org.entcore.registry.services.ExternalApplicationService;
import io.vertx.core.Handler;
import io.vertx.core.eventbus.Message;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import fr.wseduc.webutils.Either;
import fr.wseduc.webutils.collections.Joiner;

public class DefaultExternalApplicationService implements ExternalApplicationService {

    private final Neo4j neo = Neo4j.getInstance();

    @Override
    public void listExternalApps(String structureId, final Handler<Either<String, JsonArray>> handler) {
        String filter = "";
        JsonObject params = null;
        if (structureId != null && !structureId.trim().isEmpty()) {
            filter = ", (s:Structure)-[:HAS_ATTACHMENT*0..]->(p:Structure) "
                    + "WHERE HAS(app.structureId) AND s.id = {structure} AND p.id = app.structureId AND r.structureId = app.structureId "
                    + "AND (app.inherits = true OR p = s) ";
            params = new JsonObject().put("structure", structureId);
        }
        String query = "MATCH (app:Application:External)-[:PROVIDE]->(act:Action)<-[:AUTHORIZE]-(r:Role) " + filter
                + "WITH app, r, collect(distinct act) as roleActions " + "MATCH (app)-[:PROVIDE]->(action:Action) "
                + "RETURN distinct app as application, collect(action) as actions, collect(distinct {role: r, actions: roleActions}) as roles";
        neo.execute(query, params, validResultHandler(new Handler<Either<String, JsonArray>>() {
            public void handle(Either<String, JsonArray> event) {
                if (event.isLeft()) {
                    handler.handle(event);
                    return;
                }
                JsonArray rows = event.right().getValue();
                for (Object objRow : rows) {
                    JsonObject row = (JsonObject) objRow;
                    JsonObject application = row.getJsonObject("application");
                    JsonArray actions = row.getJsonArray("actions");
                    JsonArray roles = row.getJsonArray("roles");

                    JsonObject appData = application.getJsonObject("data");
                    JsonArray scope = appData.getJsonArray("scope");
                    if (scope != null && scope.size() > 0) {
                        appData.put("scope", Joiner.on(" ").join(scope));
                    } else {
                        appData.put("scope", "");
                    }
                    row.put("data", appData);
                    row.remove("application");

                    JsonArray actionsCopy = new fr.wseduc.webutils.collections.JsonArray();
                    for (Object actionObj : actions) {
                        JsonObject action = (JsonObject) actionObj;
                        JsonObject data = action.getJsonObject("data");
                        actionsCopy.add(data);
                    }
                    row.put("actions", actionsCopy);

                    for (Object roleObj : roles) {
                        JsonObject role = (JsonObject) roleObj;
                        JsonObject data = role.getJsonObject("role").getJsonObject("data");
                        role.put("role", data);
                        JsonArray acts = role.getJsonArray("actions");
                        JsonArray actsCopy = new fr.wseduc.webutils.collections.JsonArray();
                        for (Object actionObj : acts) {
                            JsonObject action = (JsonObject) actionObj;
                            actsCopy.add(action.getJsonObject("data"));
                        }
                        role.put("actions", actsCopy);

                    }
                }

                handler.handle(event);
            }
        }));
    }

    @Override
    public void listExternalApplicationRolesWithGroups(String structureId, String connectorId,
            Handler<Either<String, JsonArray>> handler) {
        String query = "MATCH (e:External{id: {connectorId}})-[:PROVIDE]->()<-[:AUTHORIZE]-(r:Role) "
                + "OPTIONAL MATCH (r)<-[:AUTHORIZED]-(g:Group)-[:DEPENDS*1..2]->(s:Structure {id: {structureId}}) "
                + "OPTIONAL MATCH (s)<-[:HAS_ATTACHMENT]-(subStruct:Structure)<-[:DEPENDS]-()-[:AUTHORIZED]-(r) "
                + "WITH r,e,subStruct, COLLECT(DISTINCT{id: g.id, name: g.name}) as groups "
                + "RETURN r.id as id, r.name as name, e.id as connectorId, "
                + "COLLECT(DISTINCT subStruct.name) as subStructures, e.structureId as owner, "
                + "CASE WHEN any(x in groups where x <> {name: null, id: null}) THEN groups ELSE [] END as groups";

        JsonObject params = new JsonObject().put("connectorId", connectorId).put("structureId", structureId);
        neo.execute(query, params, validResultHandler(handler));
    }

    @Override
    public void deleteExternalApplication(String applicationId, Handler<Either<String, JsonObject>> handler) {
        String query = "MATCH (n:Application:External {id : {id}}) " + "WHERE coalesce(n.locked, false) = false "
                + "MATCH n-[r1:PROVIDE]->(a:Action) " + "OPTIONAL MATCH a<-[r2:AUTHORIZE]-(r:Role) "
                + "OPTIONAL MATCH r<-[r3:AUTHORIZED]-(g:Group) " + "WHERE r.structureId = n.structureId "
                + "DELETE r1, r2, r3, n, a, r ";
        JsonObject params = new JsonObject().put("id", applicationId);
        neo.execute(query, params, validEmptyHandler(handler));
    }

    @Override
    public void createExternalApplication(String structureId, final JsonObject application,
            final Handler<Either<String, JsonObject>> handler) {
        if (defaultValidationParamsNull(handler, application, application.getString("name"), structureId,
                application.getString("address")))
            return;

        final String applicationName = application.getString("name");
        final String id = UUID.randomUUID().toString();
        application.put("scope", new fr.wseduc.webutils.collections.JsonArray(
                "[\"" + application.getString("scope", "").replaceAll("\\s", "\",\"") + "\"]"));
        application.put("id", id);
        application.put("structureId", structureId);

        /* App creation query */
        final String createApplicationQuery = "MATCH (n:Application) " + "WHERE n.name = {applicationName} "
                + "WITH count(*) AS exists " + "WHERE exists=0 " + "CREATE (m:Application:External {props}) "
                + "RETURN m.id as id";

        final StatementsBuilder b = new StatementsBuilder().add(createApplicationQuery,
                new JsonObject().put("applicationName", applicationName).put("props", application));

        /* Underlying action & role creation query */
        String createActionsAndRolesQuery = "MATCH (n:Application) " + "WHERE n.id = {id} "
                + "CREATE UNIQUE n-[r:PROVIDE]->(a:Action:WorkflowAction {type: {type}, "
                + "name:{name}, displayName:{displayName}}) " + "WITH a "
                + "CREATE UNIQUE (r:Role {id: {roleId}, name: {roleName}, structureId: {structureId}})-[:AUTHORIZE]->(a) "
                + "RETURN r.id as roleId";
        b.add(createActionsAndRolesQuery,
                new JsonObject().put("id", id).put("roleId", UUID.randomUUID().toString())
                        .put("type", "SECURED_ACTION_WORKFLOW").put("name", applicationName + "|address")
                        .put("roleName", applicationName + "- ACCESS ").put("structureId", structureId)
                        .put("displayName", applicationName + ".address"));

        neo.executeTransaction(b.build(), null, true, new Handler<Message<JsonObject>>() {
            @Override
            public void handle(Message<JsonObject> m) {
                JsonArray results = m.body().getJsonArray("results");
                if ("ok".equals(m.body().getString("status")) && results != null) {
                    JsonArray appRes = results.getJsonArray(0);
                    JsonArray roleRes = results.getJsonArray(1);
                    JsonObject j = new JsonObject()
                            .mergeIn(appRes.size() > 0 ? appRes.getJsonObject(0) : new JsonObject())
                            .mergeIn(roleRes.size() > 0 ? roleRes.getJsonObject(0) : new JsonObject());
                    handler.handle(new Either.Right<String, JsonObject>(j));
                } else {
                    handler.handle(new Either.Left<String, JsonObject>(m.body().getString("message")));
                }
            }
        });
    }

    @Override
    public void toggleLock(String structureId, Handler<Either<String, JsonObject>> handler) {
        if (defaultValidationParamsNull(handler, structureId))
            return;
        String query = "MATCH (app:Application:External) WHERE app.id = {structureId} "
                + "SET app.locked = NOT coalesce(app.locked, false) " + "RETURN app.locked as locked";
        neo.execute(query, new JsonObject().put("structureId", structureId), validUniqueResultHandler(handler));
    }

    @Override
    public void massAuthorize(String appId, List<String> profiles,
            final Handler<Either<String, JsonObject>> handler) {
        String query = "MATCH (app:Application:External {id: {appId}})-[:PROVIDE]->(act:Action)<-[:AUTHORIZE]-(r:Role), "
                + "(appStruct:Structure)<-[:HAS_ATTACHMENT*0..]-(s:Structure)<-[:DEPENDS]-(pg:ProfileGroup)-[:HAS_PROFILE]->(p:Profile) "
                + "WHERE coalesce(app.locked, false) = false AND appStruct.id = app.structureId AND r.structureId = app.structureId "
                + "AND p.name IN {profiles} AND NOT((pg)-[:AUTHORIZED]->(r)) "
                + "CREATE UNIQUE (pg)-[:AUTHORIZED]->(r) ";
        JsonObject params = new JsonObject().put("appId", appId).put("profiles",
                new fr.wseduc.webutils.collections.JsonArray(profiles));

        neo.execute(query, params, validEmptyHandler(handler));
    }

    @Override
    public void massUnauthorize(String appId, List<String> profiles,
            final Handler<Either<String, JsonObject>> handler) {
        String query = "MATCH (app:Application:External {id: {appId}})-[:PROVIDE]->(act:Action)<-[:AUTHORIZE]-(r:Role), "
                + "(appStruct:Structure)<-[:HAS_ATTACHMENT*0..]-(s:Structure)<-[:DEPENDS]-(pg:ProfileGroup)-[:HAS_PROFILE]->(p:Profile) "
                + "WHERE coalesce(app.locked, false) = false AND appStruct.id = app.structureId AND r.structureId = app.structureId "
                + "AND p.name IN {profiles} " + "MATCH (r)<-[auth:AUTHORIZED]-(pg) " + "DELETE auth ";
        JsonObject params = new JsonObject().put("appId", appId).put("profiles",
                new fr.wseduc.webutils.collections.JsonArray(profiles));

        neo.execute(query, params, validEmptyHandler(handler));
    }

}