Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat wb 3801 adapt legacy visibles #613

Merged
merged 5 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.entcore.common.conversation;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class LegacySearchVisibleRequest {
private final String userId;
private final String search;
private final String language;
private final String parentMessageId;

@JsonCreator
public LegacySearchVisibleRequest(@JsonProperty("userId") final String userId,
@JsonProperty("search") final String search,
@JsonProperty("language") final String language,
@JsonProperty("parentMessageId") final String parentMessageId) {
this.userId = userId;
this.search = search;
this.language = language;
this.parentMessageId = parentMessageId;
}

public String getUserId() {
return userId;
}

public String getSearch() {
return search;
}

public String getLanguage() {
return language;
}

public String getParentMessageId() {
return parentMessageId;
}
}
125 changes: 118 additions & 7 deletions common/src/main/java/org/entcore/common/user/UserUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,10 @@
package org.entcore.common.user;

import com.fasterxml.jackson.databind.ObjectMapper;

import fr.wseduc.mongodb.MongoDb;
import fr.wseduc.webutils.I18n;
import fr.wseduc.webutils.Utils;
import static fr.wseduc.webutils.Utils.getOrElse;
import static fr.wseduc.webutils.Utils.handlerToAsyncHandler;
import static fr.wseduc.webutils.Utils.isEmpty;
import static fr.wseduc.webutils.Utils.isNotEmpty;
import fr.wseduc.webutils.http.Renders;
import static fr.wseduc.webutils.http.Renders.unauthorized;
import fr.wseduc.webutils.request.CookieHelper;
import fr.wseduc.webutils.security.JWT;
import fr.wseduc.webutils.security.SecureHttpServerRequest;
Expand All @@ -49,7 +43,6 @@
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import static org.entcore.common.http.filter.AppOAuthResourceProvider.getTokenId;

import io.vertx.core.shareddata.LocalMap;
import org.entcore.common.neo4j.Neo4j;
Expand All @@ -58,6 +51,9 @@
import org.entcore.common.utils.StringUtils;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
Expand All @@ -66,6 +62,13 @@
import java.util.Set;
import java.util.stream.Collectors;

import static fr.wseduc.webutils.Utils.getOrElse;
import static fr.wseduc.webutils.Utils.handlerToAsyncHandler;
import static fr.wseduc.webutils.Utils.isEmpty;
import static fr.wseduc.webutils.Utils.isNotEmpty;
import static fr.wseduc.webutils.http.Renders.unauthorized;
import static org.entcore.common.http.filter.AppOAuthResourceProvider.getTokenId;

public class UserUtils {

private static final Vertx vertx = Vertx.currentContext().owner();
Expand Down Expand Up @@ -235,6 +238,7 @@ public static void findVisibles(EventBus eb, String userId, String customReturn,
public void handle(AsyncResult<Message<JsonArray>> res) {
if (res.succeeded()) {
JsonArray r = res.result().body();
log.info("UserUtils.findVisibles - r.size = " + r.size()); // TODO JBER : exposer métrique
if (acceptLanguage != null) {
translateGroupsNames(r, acceptLanguage);
}
Expand Down Expand Up @@ -348,6 +352,106 @@ private static void formatPositions(JsonObject dbResult) {
dbResult.put("positions", positions);
}

public static JsonArray mapObjectToContact(final String profile, final JsonArray shareBookmarks, final JsonArray visible, final String acceptLanguage) {
final List<String> usedInAll = Arrays.asList("TO", "CC", "CCI");
final List<String> usedInCCI = Collections.singletonList("CCI");

/*
final JsonArray sb = new JsonArray();
if (shareBookmarks != null) {
for (String id: shareBookmarks.fieldNames()) {
final JsonArray value = shareBookmarks.getJsonArray(id);
if (value == null || value.size() < 2) {
continue;
}
final JsonObject r = new fr.wseduc.webutils.collections.JsonObject();
r.put("id", id);
r.put("displayName", value.remove(0));
r.put("type", "ShareBookmark");
sb.add(r);
}
}

final JsonArray res = !sb.isEmpty() ? sortShareBookmarksByName(sb) : new JsonArray();
*/

final JsonArray res = new JsonArray();
for (Object o: shareBookmarks) {
if (!(o instanceof JsonObject)) continue;
JsonObject j = (JsonObject) o;
j.put("type", "ShareBookmark");
j.put("usedIn", usedInAll);
res.add(j);
}

for (Object o: visible) {
if (!(o instanceof JsonObject)) continue;
JsonObject j = (JsonObject) o;
if (j.getString("name") != null) {
j.remove("profile");
j.remove("children");
j.remove("classrooms");
j.remove("disciplines");
j.remove("functions");
j.remove("relatives");

Object gt = j.remove("groupType");
Object gp = j.remove("groupProfile");
if (gt instanceof Iterable) {
for (Object gti: (Iterable) gt) {
if (gti != null && !"Group".equals(gti) && gti.toString().endsWith("Group")) {
j.put("groupType", gti);
if ("ProfileGroup".equals(gti)) {
j.put("profile", gp);
}
break;
}
}
}

UserUtils.groupDisplayName(j, acceptLanguage);
j.put("displayName", j.getString("name"));

if ("ManualGroup".equals(j.getString("groupType")) && "BroadcastGroup".equals(j.getString("subType"))) {
j.put("type", "BroadcastGroup");
j.put("usedIn", usedInCCI);
} else {
j.put("type", "Group");
j.put("usedIn", usedInAll);
}
} else {
j.put("type", "User");
j.put("usedIn", usedInAll);
j.remove("groupProfile");
j.remove("groupType");
j.remove("nbUsers");
if (profile.equals("Student")) {
j.remove("relatives");
}
}

j.remove("name");
j.remove("groupDisplayName");
j.remove("sortDisplayName");
j.remove("sortWeight");
j.remove("subjects");
j.remove("subType");
j.remove("sorted_children_names");
j.remove("sorted_functions");
j.remove("sorted_disciplines");

res.add(j);
}
return res;
}

private static JsonArray sortShareBookmarksByName(JsonArray sb) {
List<JsonObject> list = sb.getList();
list.sort(Comparator.comparing(o -> o.getString("displayName")));

return new JsonArray(list);
}

public static void findUsersCanSeeMe(final EventBus eb, HttpServerRequest request,
final Handler<JsonArray> handler) {
JsonObject m = new JsonObject()
Expand Down Expand Up @@ -667,6 +771,13 @@ public void handle(JsonObject session) {
});
}

/**
* Fetch the user's session information and return an unauthorized response if the user has no session. Therefore,
* <b>there is no need to handle a failure of the returned Future</b>.
* @param eb Event bus to be used to fetch the user's session
* @param request Caller's request
* @return The user's session information
*/
public static Future<UserInfos> getAuthenticatedUserInfos(EventBus eb, HttpServerRequest request) {
final Promise<UserInfos> promise = Promise.promise();
getSession(eb, request, session -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void start(final Promise<Void> startPromise) throws Exception {
TimelineHelper helper = new TimelineHelper(vertx, vertx.eventBus(), config);
CommunicationController communicationController = new CommunicationController();

communicationController.setCommunicationService(new DefaultCommunicationService(helper, config.getJsonArray("discoverVisibleExpectedProfile", new JsonArray())));
communicationController.setCommunicationService(new DefaultCommunicationService(vertx, helper, config));

addController(communicationController);
setDefaultResourceFilter(new CommunicationFilter());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,31 @@
import fr.wseduc.webutils.http.BaseController;
import fr.wseduc.webutils.http.Renders;
import fr.wseduc.webutils.request.RequestUtils;
import io.vertx.core.CompositeFuture;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.eventbus.Message;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.entcore.common.http.filter.AdminFilter;
import org.entcore.common.http.filter.ResourceFilter;
import org.entcore.common.neo4j.Neo4j;
import org.entcore.common.user.UserUtils;
import org.entcore.common.utils.StringUtils;
import org.entcore.common.validation.StringValidation;
import org.entcore.communication.filters.CommunicationDiscoverVisibleFilter;
import org.entcore.communication.services.CommunicationService;
import org.entcore.communication.services.impl.DefaultCommunicationService;

import java.util.List;

import static fr.wseduc.webutils.Utils.getOrElse;
import static fr.wseduc.webutils.Utils.isNotEmpty;
import static org.entcore.common.http.response.DefaultResponseHandler.*;
import static org.entcore.common.neo4j.Neo4jResult.fullNodeMergeHandler;
import static org.entcore.common.neo4j.Neo4jResult.validResultHandler;

public class CommunicationController extends BaseController {

Expand Down Expand Up @@ -269,7 +277,7 @@ public void searchVisible(HttpServerRequest request) {
"visibles.displayName as displayName, visibles.groupDisplayName as groupDisplayName, " +
"HEAD(visibles.profiles) as profile, subjects" + nbUsers + groupTypes;
communicationService.visibleUsers(user.getUserId(), null, expectedTypes, true, true, false,
preFilter, customReturn, params, user.getType(), visibles -> {
preFilter, customReturn, params, user.getType(), false, visibles -> {
if (visibles.isRight()) {
renderJson(request,
UserUtils.translateAndGroupVisible(visibles.right().getValue(),
Expand Down Expand Up @@ -875,4 +883,22 @@ public void addDiscoverVisibleGroupUsers(HttpServerRequest request) {
});
}

/**
* Search entities (users, groups) visible by the requester.
* This endpoint can serve 2 different types of results based on the configuration :
* - the old format that used to be served by the module conversation
* - the new format which returns more data
* @param request Caller's HTTP request
*/
@Get("/visible/search")
@SecuredAction(value = "", type = ActionType.AUTHENTICATED)
public void searchVisibleContacts(HttpServerRequest request) {
UserUtils.getAuthenticatedUserInfos(eb, request)
.onSuccess(userInfos -> {
final String query = request.params().get("query");
communicationService.searchVisibles(userInfos, query, I18n.acceptLanguage(request))
.onSuccess(visibles -> renderJson(request, visibles))
.onFailure(th -> renderError(request, new JsonObject().put("error", th.getMessage())));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import fr.wseduc.webutils.Either;

import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.json.JsonArray;
Expand Down Expand Up @@ -106,11 +107,12 @@ void applyDefaultRules(JsonArray structureIds, final Integer transactionId, fina
void removeRules(String structureId, Handler<Either<String, JsonObject>> handler);

void visibleUsers(String userId, String structureId, JsonArray expectedTypes, boolean itSelf, boolean myGroup,
boolean profile, String preFilter, String customReturn, JsonObject additionnalParams,
boolean profile, String preFilter, String customReturn, JsonObject additionalParams,
Handler<Either<String, JsonArray>> handler);

void visibleUsers(String userId, String structureId, JsonArray expectedTypes, boolean itSelf, boolean myGroup,
boolean profile, String preFilter, String customReturn, JsonObject additionnalParams, String userProfile,
boolean profile, String preFilter, String customReturn, JsonObject additionalParams, String userProfile,
boolean reverseUnion,
Handler<Either<String, JsonArray>> handler);

void usersCanSeeMe(String userId, final Handler<Either<String, JsonArray>> handler);
Expand Down Expand Up @@ -167,5 +169,15 @@ void visibleManualGroups(String userId, String customReturn, JsonObject addition
void addDiscoverVisibleGroupUsers(UserInfos user, String groupId, JsonObject body, HttpServerRequest request, Handler<Either<String, JsonObject>> handler);

void getDiscoverVisibleAcceptedProfile(Handler<Either<String, JsonArray>> handler);


/**
* Search visible users.
* @param user Requester
* @param search Keyword to filter the search results
* @param language User's language
*/
Future<JsonArray> searchVisibles(UserInfos user, String search, String language);

}

Loading