Nantes Université

Skip to content
Extraits de code Groupes Projets
Non vérifiée Valider ba8c7760 rédigé par Féry Mathieu (Mathius)'s avatar Féry Mathieu (Mathius)
Parcourir les fichiers

feat(db): Add management of OrderBy and add Post created OrderBy

parent a52b0f54
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Pipeline #34201 réussi
......@@ -25,6 +25,7 @@ import fr.univnantes.webandcloud.api.services.DBService;
import fr.univnantes.webandcloud.api.services.TokenService;
import fr.univnantes.webandcloud.api.services.WithCursor;
import fr.univnantes.webandcloud.api.services.WithIdentifierService;
import fr.univnantes.webandcloud.api.services.db.DBPost;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
......@@ -36,7 +37,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
public class Posts extends BaseController {
@Autowired
DBService<Post> postDB;
DBPost postDB;
@Autowired
DBService<User> userDB;
@Autowired
......@@ -52,7 +53,7 @@ public class Posts extends BaseController {
public WithCursor<List<Post>> posts(
@Parameter(description = "Limit for request", example = "2") @RequestParam @Nullable Integer limit,
@Parameter(description = "Cursor for next entity", example = "CgA=") @RequestParam @Nullable String cursor) {
return postDB.getAll(limit, cursor != null ? Cursor.fromUrlSafe(cursor) : null);
return postDB.getAllCreatedDesc(limit, cursor != null ? Cursor.fromUrlSafe(cursor) : null);
}
@CrossOrigin
......
......@@ -11,13 +11,13 @@ import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreException;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.Entity.Builder;
import com.google.cloud.datastore.EntityQuery;
import com.google.cloud.datastore.Key;
import com.google.cloud.datastore.KeyQuery;
import com.google.cloud.datastore.Query;
import com.google.cloud.datastore.QueryResults;
import com.google.cloud.datastore.StructuredQuery;
import com.google.cloud.datastore.StructuredQuery.CompositeFilter;
import com.google.cloud.datastore.StructuredQuery.Filter;
import com.google.cloud.datastore.StructuredQuery.OrderBy;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -65,51 +65,76 @@ public class DBService<EntityUsed extends WithIdentifier> extends ServiceUsingDa
}
public WithCursor<Set<Key>> searchKeyWith(EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(null, null, entity, filterFieldOfs);
return searchKeyWith(null, null, null, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(limit, getFieldOf(entity, filterFieldOfs));
return searchKeyWith(limit, null, null, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(Cursor lastCursor,
EntityUsed entity,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(null, lastCursor, null, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(OrderBy[] orders, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(lastCursor, getFieldOf(entity, filterFieldOfs));
return searchKeyWith(null, null, orders, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, Cursor lastCursor,
EntityUsed entity,
public WithCursor<Set<Key>> searchKeyWith(Integer limit, Cursor lastCursor, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(limit, lastCursor, getFieldOf(entity, filterFieldOfs));
return searchKeyWith(limit, lastCursor, null, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, OrderBy[] orders,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(limit, null, null, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(Cursor lastCursor,
OrderBy[] orders, EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(null, lastCursor, orders, entity, filterFieldOfs);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, Cursor lastCursor,
OrderBy[] orders, EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchKeyWith(limit, lastCursor, orders, getFieldOf(entity, filterFieldOfs));
}
public WithCursor<Set<Key>> searchKeyWith(Filter... filters) {
return searchKeyWith(null, null, filters);
return searchKeyWith(null, null, null, filters);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, Filter... filters) {
return searchKeyWith(limit, null, filters);
return searchKeyWith(limit, null, null, filters);
}
public WithCursor<Set<Key>> searchKeyWith(Cursor lastCursor, Filter... filters) {
return searchKeyWith(null, lastCursor, filters);
return searchKeyWith(null, lastCursor, null, filters);
}
public WithCursor<Set<Key>> searchKeyWith(OrderBy[] orders, Filter... filters) {
return searchKeyWith(null, null, orders, filters);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, Cursor lastCursor, Filter... filters) {
KeyQuery.Builder builder = Query.newKeyQueryBuilder().setKind(utils.getKindValue());
if (limit != null)
builder = builder.setLimit(limit);
if (lastCursor != null)
builder.setStartCursor(lastCursor);
Filter currentFilter = null;
for (Filter filter : filters)
currentFilter = currentFilter != null ? CompositeFilter.and(currentFilter, filter) : filter;
if (currentFilter != null)
builder = builder.setFilter(currentFilter);
return searchKeyWith(limit, lastCursor, null, filters);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, OrderBy[] orders, Filter... filters) {
return searchKeyWith(limit, null, orders, filters);
}
public WithCursor<Set<Key>> searchKeyWith(Cursor lastCursor, OrderBy[] orders, Filter... filters) {
return searchKeyWith(null, lastCursor, orders, filters);
}
public WithCursor<Set<Key>> searchKeyWith(Integer limit, Cursor lastCursor, OrderBy[] orders, Filter... filters) {
Set<Key> keys = new HashSet<>();
QueryResults<Key> queryResult = getDatastore().run(builder.build());
QueryResults<Key> queryResult = getDatastore().run(
buildQuery(Query.newKeyQueryBuilder(), limit, lastCursor, orders, filters));
while (queryResult.hasNext()) {
keys.add(queryResult.next());
}
......@@ -117,85 +142,182 @@ public class DBService<EntityUsed extends WithIdentifier> extends ServiceUsingDa
}
public WithCursor<Set<String>> searchIdWith(EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(null, null, entity, filterFieldOfs);
return searchIdWith(null, null, null, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(Integer limit,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(limit, null, entity, filterFieldOfs);
return searchIdWith(limit, null, null, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(Cursor lastCursor, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(null, lastCursor, entity, filterFieldOfs);
return searchIdWith(null, lastCursor, null, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(OrderBy[] orders,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(null, null, orders, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, Cursor lastCursor,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(limit, lastCursor, getFieldOf(entity, filterFieldOfs));
return searchIdWith(limit, lastCursor, null, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, OrderBy[] orders,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(limit, null, orders, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(Cursor lastCursor, OrderBy[] orders, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(null, lastCursor, orders, entity, filterFieldOfs);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, Cursor lastCursor, OrderBy[] orders,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchIdWith(limit, lastCursor, orders, getFieldOf(entity, filterFieldOfs));
}
public WithCursor<Set<String>> searchIdWith(Filter... filters) {
return searchIdWith(null, null, filters);
return searchIdWith(null, null, null, filters);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, Filter... filters) {
return searchIdWith(limit, null, filters);
return searchIdWith(limit, null, null, filters);
}
public WithCursor<Set<String>> searchIdWith(Cursor lastCursor, Filter... filters) {
return searchIdWith(null, lastCursor, filters);
return searchIdWith(null, lastCursor, null, filters);
}
public WithCursor<Set<String>> searchIdWith(OrderBy[] orders, Filter... filters) {
return searchIdWith(null, null, orders, filters);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, Cursor lastCursor, Filter... filters) {
WithCursor<Set<Key>> baseCursor = searchKeyWith(limit, lastCursor, filters);
return searchIdWith(limit, lastCursor, null, filters);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, OrderBy[] orders, Filter... filters) {
return searchIdWith(limit, null, orders, filters);
}
public WithCursor<Set<String>> searchIdWith(Cursor lastCursor, OrderBy[] orders, Filter... filters) {
return searchIdWith(null, lastCursor, orders, filters);
}
public WithCursor<Set<String>> searchIdWith(Integer limit, Cursor lastCursor, OrderBy[] orders, Filter... filters) {
WithCursor<Set<Key>> baseCursor = searchKeyWith(limit, lastCursor, orders, filters);
return new WithCursor<>(getIdsFromKey(baseCursor.data), baseCursor.cursor);
}
public WithCursor<List<EntityUsed>> searchWith(EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(null, null, entity, filterFieldOfs);
return searchWith(null, null, null, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(limit, null, entity, filterFieldOfs);
return searchWith(limit, null, null, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(Cursor lastCursor, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(null, lastCursor, entity, filterFieldOfs);
return searchWith(null, lastCursor, null, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(OrderBy[] orders, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(null, null, orders, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, Cursor lastCursor,
public WithCursor<List<EntityUsed>> searchWith(Integer limit, Cursor lastCursor, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(limit, lastCursor, null, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, OrderBy[] orders, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(limit, null, orders, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(Cursor lastCursor, OrderBy[] orders, EntityUsed entity,
FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(null, lastCursor, orders, entity, filterFieldOfs);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, Cursor lastCursor, OrderBy[] orders,
EntityUsed entity, FilterFieldOf<EntityUsed>... filterFieldOfs) {
return searchWith(limit, lastCursor, getFieldOf(entity, filterFieldOfs));
return searchWith(limit, lastCursor, orders, getFieldOf(entity, filterFieldOfs));
}
public WithCursor<List<EntityUsed>> searchWith(Filter... filters) {
return searchWith(null, null, filters);
return searchWith(null, null, null, filters);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, Filter... filters) {
return searchWith(limit, null, filters);
return searchWith(limit, null, null, filters);
}
public WithCursor<List<EntityUsed>> searchWith(Cursor lastCursor, Filter... filters) {
return searchWith(null, lastCursor, filters);
return searchWith(null, lastCursor, null, filters);
}
public WithCursor<List<EntityUsed>> searchWith(OrderBy[] orders, Filter... filters) {
return searchWith(null, null, orders, filters);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, Cursor lastCursor, Filter... filters) {
EntityQuery.Builder builder = Query.newEntityQueryBuilder().setKind(utils.getKindValue());
return searchWith(limit, lastCursor, null, filters);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, OrderBy[] orders, Filter... filters) {
return searchWith(limit, null, orders, filters);
}
public WithCursor<List<EntityUsed>> searchWith(Cursor lastCursor, OrderBy[] orders, Filter... filters) {
return searchWith(null, lastCursor, orders, filters);
}
protected static <V> StructuredQuery.Builder<V> buildBuilderOfQuery(StructuredQuery.Builder<V> builder,
String kind, Integer limit, Cursor lastCursor, OrderBy[] orders, Filter... filters) {
builder.setKind(kind);
if (limit != null)
builder = builder.setLimit(limit);
if (lastCursor != null)
builder.setStartCursor(lastCursor);
if (orders != null && orders.length > 0)
for (OrderBy orderBy : orders)
builder.addOrderBy(orderBy);
Filter currentFilter = null;
for (Filter filter : filters)
currentFilter = currentFilter != null ? CompositeFilter.and(currentFilter, filter) : filter;
if (currentFilter != null)
builder = builder.setFilter(currentFilter);
return builder;
}
protected <V> StructuredQuery.Builder<V> buildBuilderOfQuery(StructuredQuery.Builder<V> builder,
Integer limit, Cursor lastCursor, OrderBy[] orders, Filter... filters) {
return buildBuilderOfQuery(builder, utils.getKindValue(), limit, lastCursor, orders, filters);
}
protected static <V> StructuredQuery<V> buildQuery(StructuredQuery.Builder<V> builder,
String kind, Integer limit, Cursor lastCursor, OrderBy[] orders, Filter... filters) {
return buildBuilderOfQuery(builder, kind, limit, lastCursor, orders, filters).build();
}
protected <V> StructuredQuery<V> buildQuery(StructuredQuery.Builder<V> builder,
Integer limit, Cursor lastCursor, OrderBy[] orders, Filter... filters) {
return buildQuery(builder, utils.getKindValue(), limit, lastCursor, orders, filters);
}
public WithCursor<List<EntityUsed>> searchWith(Integer limit, Cursor lastCursor, OrderBy[] orders,
Filter... filters) {
List<EntityUsed> entities = new ArrayList<>();
QueryResults<Entity> queryResult = getDatastore().run(builder.build());
QueryResults<Entity> queryResult = getDatastore().run(
buildQuery(Query.newEntityQueryBuilder(), limit, lastCursor, orders, filters));
while (queryResult.hasNext()) {
entities.add(utils.createFromEntity(queryResult.next()));
}
......@@ -251,30 +373,35 @@ public class DBService<EntityUsed extends WithIdentifier> extends ServiceUsingDa
}
public WithCursor<Set<Key>> retrieveKeys() {
return retrieveKeys(null, null);
return retrieveKeys(null, null, null);
}
public WithCursor<Set<Key>> retrieveKeys(Integer limit) {
return retrieveKeys(limit, null);
return retrieveKeys(limit, null, null);
}
public WithCursor<Set<Key>> retrieveKeys(Cursor lastCursor) {
return retrieveKeys(null, lastCursor);
return retrieveKeys(null, lastCursor, null);
}
public WithCursor<Set<Key>> retrieveKeys(OrderBy[] orders) {
return retrieveKeys(null, null, orders);
}
public WithCursor<Set<Key>> retrieveKeys(Integer limit, Cursor lastCursor) {
KeyQuery.Builder builder = Query.newKeyQueryBuilder().setKind(utils.getKindValue());
if (limit != null)
builder.setLimit(limit);
if (lastCursor != null)
builder.setStartCursor(lastCursor);
Query<Key> query = builder.build();
Set<Key> keys = new HashSet<>();
QueryResults<Key> queryResult = getDatastore().run(query);
while (queryResult.hasNext()) {
keys.add(queryResult.next());
}
return new WithCursor<>(keys, queryResult.getCursorAfter());
return retrieveKeys(limit, lastCursor, null);
}
public WithCursor<Set<Key>> retrieveKeys(Integer limit, OrderBy[] orders) {
return retrieveKeys(limit, null, orders);
}
public WithCursor<Set<Key>> retrieveKeys(Cursor lastCursor, OrderBy[] orders) {
return retrieveKeys(null, lastCursor, orders);
}
public WithCursor<Set<Key>> retrieveKeys(Integer limit, Cursor lastCursor, OrderBy[] orders) {
return searchKeyWith(limit, lastCursor, orders);
}
protected Set<String> getIdsFromKey(Set<Key> keys) {
......@@ -300,21 +427,34 @@ public class DBService<EntityUsed extends WithIdentifier> extends ServiceUsingDa
}
public WithCursor<List<EntityUsed>> getAll() {
return getAll(null, null);
return getAll(null, (Cursor) null);
}
public WithCursor<List<EntityUsed>> getAll(Integer limit) {
WithCursor<Set<Key>> baseCursor = retrieveKeys(limit);
return new WithCursor<>(getAllOf(baseCursor.data), baseCursor.cursor);
return getAll(limit, (Cursor) null);
}
public WithCursor<List<EntityUsed>> getAll(Cursor lastCursor) {
WithCursor<Set<Key>> baseCursor = retrieveKeys(lastCursor);
return new WithCursor<>(getAllOf(baseCursor.data), baseCursor.cursor);
return getAll(null, lastCursor);
}
public WithCursor<List<EntityUsed>> getAll(OrderBy... orders) {
return getAll(null, null, orders);
}
public WithCursor<List<EntityUsed>> getAll(Integer limit, Cursor lastCursor) {
WithCursor<Set<Key>> baseCursor = retrieveKeys(limit, lastCursor);
return new WithCursor<>(getAllOf(baseCursor.data), baseCursor.cursor);
return getAll(limit, lastCursor, new OrderBy[0]);
}
public WithCursor<List<EntityUsed>> getAll(Integer limit, OrderBy... orders) {
return getAll(limit, null, orders);
}
public WithCursor<List<EntityUsed>> getAll(Cursor lastCursor, OrderBy... orders) {
return getAll(null, lastCursor, orders);
}
public WithCursor<List<EntityUsed>> getAll(Integer limit, Cursor lastCursor, OrderBy... orders) {
return searchWith(limit, lastCursor, orders);
}
}
package fr.univnantes.webandcloud.api.services.db;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.cloud.datastore.Cursor;
import com.google.cloud.datastore.StructuredQuery.OrderBy;
import org.springframework.stereotype.Service;
import fr.univnantes.webandcloud.api.core.Post;
import fr.univnantes.webandcloud.api.core.User;
import fr.univnantes.webandcloud.api.services.DBAncestorService;
import fr.univnantes.webandcloud.api.services.WithCursor;
@Service
public class DBPost extends DBAncestorService<Post, User> {
OrderBy createdDesc = OrderBy.desc("postTime");
public WithCursor<List<Post>> getAllCreatedDesc() {
return getAllCreatedDesc(null, (Cursor) null);
}
public WithCursor<List<Post>> getAllCreatedDesc(Integer limit) {
return getAllCreatedDesc(limit, (Cursor) null);
}
public WithCursor<List<Post>> getAllCreatedDesc(Cursor lastCursor) {
return getAllCreatedDesc(null, lastCursor);
}
public WithCursor<List<Post>> getAllCreatedDesc(OrderBy... orders) {
return getAllCreatedDesc(null, null, orders);
}
public WithCursor<List<Post>> getAllCreatedDesc(Integer limit, Cursor lastCursor) {
return getAllCreatedDesc(limit, lastCursor, new OrderBy[0]);
}
public WithCursor<List<Post>> getAllCreatedDesc(Integer limit, OrderBy... orders) {
return getAllCreatedDesc(limit, null, orders);
}
public WithCursor<List<Post>> getAllCreatedDesc(Cursor lastCursor, OrderBy... orders) {
return getAllCreatedDesc(null, lastCursor, orders);
}
public WithCursor<List<Post>> getAllCreatedDesc(Integer limit, Cursor lastCursor, OrderBy... orders) {
List<OrderBy> ordersList = new ArrayList<>(Arrays.asList(orders));
ordersList.add(createdDesc);
return getAll(limit, lastCursor, ordersList.toArray(new OrderBy[ordersList.size()]));
}
}
......@@ -3,6 +3,7 @@ package fr.univnantes.webandcloud.api.services.db;
import java.util.List;
import com.google.cloud.datastore.Cursor;
import com.google.cloud.datastore.StructuredQuery.OrderBy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -30,15 +31,32 @@ public class DBUser extends DBService<User> {
}
public WithCursor<List<User>> searchWithUserNameStartsWith(Integer limit, String userName) {
return searchWithUserNameStartsWith(limit, null, userName);
return searchWithUserNameStartsWith(limit, null, null, userName);
}
public WithCursor<List<User>> searchWithUserNameStartsWith(Cursor lastCursor, String userName) {
return searchWithUserNameStartsWith(null, lastCursor, userName);
return searchWithUserNameStartsWith(null, lastCursor, null, userName);
}
public WithCursor<List<User>> searchWithUserNameStartsWith(OrderBy[] orders, String userName) {
return searchWithUserNameStartsWith(null, null, orders, userName);
}
public WithCursor<List<User>> searchWithUserNameStartsWith(Integer limit, Cursor lastCursor, String userName) {
return searchWith(limit, lastCursor, new User(null, userName, null, null, null, null, null),
return searchWithUserNameStartsWith(limit, lastCursor, null, userName);
}
public WithCursor<List<User>> searchWithUserNameStartsWith(Integer limit, OrderBy[] orders, String userName) {
return searchWithUserNameStartsWith(limit, null, orders, userName);
}
public WithCursor<List<User>> searchWithUserNameStartsWith(Cursor lastCursor, OrderBy[] orders, String userName) {
return searchWithUserNameStartsWith(null, lastCursor, orders, userName);
}
public WithCursor<List<User>> searchWithUserNameStartsWith(Integer limit, Cursor lastCursor, OrderBy[] orders,
String userName) {
return searchWith(limit, lastCursor, orders, new User(null, userName, null, null, null, null, null),
userNameStartsWith);
}
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter