From 7f5982734f895bb9ca7c62498e0a06f4120ebbd1 Mon Sep 17 00:00:00 2001
From: spoonman01
Date: Mon, 30 Sep 2024 12:22:11 +0200
Subject: [PATCH 1/5] feat(get-domain-from-backend) Use new Helium API to fetch
backend domain
* Update Helium to 1.4.1
* Add assertions to major tests
* Remove Consts.java from tests
---
pom.xml | 3 +-
.../wire/bots/hold/HoldMessageResource.java | 2 +-
.../com/wire/bots/hold/MessageHandler.java | 71 ++++++++-------
.../wire/bots/hold/NotificationProcessor.java | 2 +-
src/main/java/com/wire/bots/hold/Service.java | 18 +++-
.../bots/hold/healthchecks/SanityCheck.java | 6 +-
.../hold/resource/ConversationResource.java | 8 +-
.../java/com/wire/bots/hold/utils/Cache.java | 9 +-
.../com/wire/bots/hold/utils/Collector.java | 9 +-
.../java/com/wire/bots/hold/utils/Helper.java | 7 +-
.../wire/bots/hold/utils/HoldClientRepo.java | 7 +-
.../wire/bots/hold/utils/HoldWireClient.java | 11 +--
src/test/java/com/wire/bots/hold/Consts.java | 8 --
.../java/com/wire/bots/hold/DatabaseTest.java | 24 ++---
.../wire/bots/hold/MessageTemplateTest.java | 87 ++++++++++---------
...ialization.java => SerializationTest.java} | 6 +-
.../com/wire/bots/hold/utils/TestCache.java | 17 ++--
17 files changed, 162 insertions(+), 133 deletions(-)
delete mode 100644 src/test/java/com/wire/bots/hold/Consts.java
rename src/test/java/com/wire/bots/hold/{Serialization.java => SerializationTest.java} (94%)
diff --git a/pom.xml b/pom.xml
index 7eba379..b5e93dc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,6 @@
2.1.2
1.0.10
0.16.0
- 1.3.0
@@ -68,7 +67,7 @@
com.wire
helium
- ${helium.version}
+ 1.4.1
com.github.smoketurner
diff --git a/src/main/java/com/wire/bots/hold/HoldMessageResource.java b/src/main/java/com/wire/bots/hold/HoldMessageResource.java
index d03271f..3e455fd 100644
--- a/src/main/java/com/wire/bots/hold/HoldMessageResource.java
+++ b/src/main/java/com/wire/bots/hold/HoldMessageResource.java
@@ -20,7 +20,7 @@ public HoldMessageResource(MessageHandlerBase handler, HoldClientRepo repo) {
}
protected WireClient getWireClient(UUID userId, Payload payload) throws CryptoException {
- return repo.getClient(userId, payload.data.recipient, payload.convId);
+ return repo.getClient(userId, payload.data.recipient, payload.conversation);
}
public boolean onNewMessage(UUID userId, UUID id, Payload payload) {
diff --git a/src/main/java/com/wire/bots/hold/MessageHandler.java b/src/main/java/com/wire/bots/hold/MessageHandler.java
index 1d8b854..bf6a0a0 100644
--- a/src/main/java/com/wire/bots/hold/MessageHandler.java
+++ b/src/main/java/com/wire/bots/hold/MessageHandler.java
@@ -5,6 +5,7 @@
import com.wire.bots.hold.DAO.EventsDAO;
import com.wire.xenon.MessageHandlerBase;
import com.wire.xenon.WireClient;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.SystemMessage;
import com.wire.xenon.models.*;
import com.wire.xenon.tools.Logger;
@@ -26,81 +27,81 @@ public class MessageHandler extends MessageHandlerBase {
@Override
public void onNewConversation(WireClient client, SystemMessage msg) {
UUID eventId = msg.id;
- UUID convId = msg.convId;
+ QualifiedId conversationId = msg.conversation.id;
UUID userId = client.getId();
String type = msg.type;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onConversationRename(WireClient client, SystemMessage msg) {
UUID eventId = msg.id;
- UUID convId = msg.convId;
+ QualifiedId conversationId = msg.conversation.id;
UUID userId = client.getId();
String type = Const.CONVERSATION_RENAME;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onMemberJoin(WireClient client, SystemMessage msg) {
UUID eventId = msg.id;
- UUID convId = msg.convId;
+ QualifiedId conversationId = msg.conversation.id;
UUID userId = client.getId();
String type = msg.type;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onMemberLeave(WireClient client, SystemMessage msg) {
UUID eventId = msg.id;
- UUID convId = msg.convId;
+ QualifiedId conversationId = msg.conversation.id;
UUID userId = client.getId();
String type = msg.type;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onText(WireClient client, TextMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_NEW_TEXT;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onText(WireClient client, EphemeralTextMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_NEW_TEXT;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onEditText(WireClient client, EditedTextMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_EDIT_TEXT;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onPhotoPreview(WireClient client, PhotoPreviewMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_IMAGE_PREVIEW;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
assetsDAO.insert(msg.getMessageId(), msg.getMimeType());
}
@@ -108,11 +109,11 @@ public void onPhotoPreview(WireClient client, PhotoPreviewMessage msg) {
@Override
public void onFilePreview(WireClient client, FilePreviewMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_FILE_PREVIEW;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
assetsDAO.insert(msg.getMessageId(), msg.getMimeType());
}
@@ -120,11 +121,11 @@ public void onFilePreview(WireClient client, FilePreviewMessage msg) {
@Override
public void onAudioPreview(WireClient client, AudioPreviewMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_AUDIO_PREVIEW;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
assetsDAO.insert(msg.getMessageId(), msg.getMimeType());
}
@@ -132,11 +133,11 @@ public void onAudioPreview(WireClient client, AudioPreviewMessage msg) {
@Override
public void onVideoPreview(WireClient client, VideoPreviewMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_VIDEO_PREVIEW;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
assetsDAO.insert(msg.getMessageId(), msg.getMimeType());
}
@@ -144,14 +145,20 @@ public void onVideoPreview(WireClient client, VideoPreviewMessage msg) {
@Override
public void onAssetData(WireClient client, RemoteMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_ASSET_DATA;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
try {
- final byte[] assetData = client.downloadAsset(msg.getAssetId(), msg.getAssetToken(), msg.getSha256(), msg.getOtrKey());
+ final byte[] assetData = client.downloadAsset(
+ msg.getAssetId(),
+ null, // TODO(WPB-11287): Change null to default domain
+ msg.getAssetToken(),
+ msg.getSha256(),
+ msg.getOtrKey()
+ );
assetsDAO.insert(msg.getMessageId(), assetData);
} catch (Exception e) {
Logger.exception(e, "onAssetData");
@@ -161,34 +168,34 @@ public void onAssetData(WireClient client, RemoteMessage msg) {
@Override
public void onDelete(WireClient client, DeletedTextMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_DELETE_TEXT;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
public void onCalling(WireClient client, CallingMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_CALL;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
public void onReaction(WireClient client, ReactionMessage msg) {
UUID eventId = msg.getEventId();
- UUID convId = msg.getConversationId();
+ QualifiedId conversationId = msg.getConversationId();
UUID userId = client.getId();
String type = Const.CONVERSATION_OTR_MESSAGE_ADD_REACTION;
- persist(eventId, convId, userId, type, msg);
+ persist(eventId, conversationId.id, userId, type, msg);
}
@Override
- public boolean onConnectRequest(WireClient client, UUID from, UUID to, String status) {
+ public boolean onConnectRequest(WireClient client, QualifiedId from, QualifiedId to, String status) {
return false;
}
diff --git a/src/main/java/com/wire/bots/hold/NotificationProcessor.java b/src/main/java/com/wire/bots/hold/NotificationProcessor.java
index 2303919..3cf36c2 100644
--- a/src/main/java/com/wire/bots/hold/NotificationProcessor.java
+++ b/src/main/java/com/wire/bots/hold/NotificationProcessor.java
@@ -103,7 +103,7 @@ private void process(UUID userId, NotificationList notificationList) {
} else {
Logger.debug("Processed: `%s` conv: %s, user: %s, notifId: %s",
payload.type,
- payload.convId,
+ payload.conversation,
userId,
notif.id);
}
diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java
index 2563e8a..568fdf7 100644
--- a/src/main/java/com/wire/bots/hold/Service.java
+++ b/src/main/java/com/wire/bots/hold/Service.java
@@ -29,7 +29,9 @@
import com.wire.bots.hold.resource.*;
import com.wire.bots.hold.utils.HoldClientRepo;
import com.wire.bots.hold.utils.ImagesBundle;
+import com.wire.helium.LoginClient;
import com.wire.xenon.Const;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.crypto.CryptoDatabase;
import com.wire.xenon.crypto.storage.JdbiStorage;
import com.wire.xenon.factories.CryptoFactory;
@@ -44,12 +46,12 @@
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import io.prometheus.client.CollectorRegistry;
+import io.prometheus.client.dropwizard.DropwizardExports;
+import io.prometheus.client.exporter.MetricsServlet;
import org.flywaydb.core.Flyway;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
-import io.prometheus.client.dropwizard.DropwizardExports;
-import io.prometheus.client.exporter.MetricsServlet;
import javax.ws.rs.client.Client;
import java.util.concurrent.TimeUnit;
@@ -57,6 +59,7 @@
public class Service extends Application {
public static Service instance;
public static MetricRegistry metrics;
+ public static String API_DOMAIN;
protected Config config;
protected Environment environment;
protected Jdbi jdbi;
@@ -128,6 +131,8 @@ public void run(Config config, Environment environment) {
environment.healthChecks().register("SanityCheck", new SanityCheck(accessDAO, httpClient));
final HoldClientRepo repo = new HoldClientRepo(jdbi, cf, httpClient);
+ final LoginClient loginClient = new LoginClient(httpClient);
+
final HoldMessageResource holdMessageResource = new HoldMessageResource(new MessageHandler(jdbi), repo);
final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, config, holdMessageResource);
@@ -139,6 +144,10 @@ public void run(Config config, Environment environment) {
CollectorRegistry.defaultRegistry.register(new DropwizardExports(metrics));
environment.getApplicationContext().addServlet(MetricsServlet.class, "/metrics");
+
+ // todo here
+ // String res = loginClient.getBackendConfiguration();
+ // handle res ^
}
public Config getConfig() {
@@ -177,6 +186,9 @@ protected void setupDatabase(Config.Database database) {
}
public CryptoFactory getCryptoFactory(Jdbi jdbi) {
- return (botId) -> new CryptoDatabase(botId, new JdbiStorage(jdbi));
+ return (botId) -> new CryptoDatabase(
+ new QualifiedId(botId, null), // TODO(WPB-11287): Change null to default domain
+ new JdbiStorage(jdbi)
+ );
}
}
diff --git a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
index 4a42742..80df73a 100644
--- a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
+++ b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
@@ -4,6 +4,7 @@
import com.wire.bots.hold.DAO.AccessDAO;
import com.wire.bots.hold.model.LHAccess;
import com.wire.helium.API;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.tools.Logger;
import javax.ws.rs.client.Client;
@@ -35,7 +36,10 @@ protected Result check() {
while (!accessList.isEmpty()) {
Logger.info("SanityCheck: checking %d devices, created: %s", accessList.size(), created);
for (LHAccess access : accessList) {
- boolean hasDevice = api.hasDevice(access.userId, access.clientId);
+ boolean hasDevice = api.hasDevice(
+ new QualifiedId(access.userId, null), // TODO(WPB-11287): Change null to default domain
+ access.clientId
+ );
if (!access.enabled && hasDevice)
return Result.unhealthy("User %s is NOT tracked in LH", access.userId);
diff --git a/src/main/java/com/wire/bots/hold/resource/ConversationResource.java b/src/main/java/com/wire/bots/hold/resource/ConversationResource.java
index f126ec6..6a7c649 100644
--- a/src/main/java/com/wire/bots/hold/resource/ConversationResource.java
+++ b/src/main/java/com/wire/bots/hold/resource/ConversationResource.java
@@ -18,6 +18,7 @@
import com.wire.helium.API;
import com.wire.xenon.backend.models.Conversation;
import com.wire.xenon.backend.models.Member;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.SystemMessage;
import com.wire.xenon.models.*;
import com.wire.xenon.tools.Logger;
@@ -229,7 +230,7 @@ private void onVideoPreview(Collector collector, Event event) {
private void onMember(Collector collector, Event event, String label) {
try {
SystemMessage msg = mapper.readValue(event.payload, SystemMessage.class);
- for (UUID userId : msg.users) {
+ for (QualifiedId userId : msg.users) {
String format = String.format("**%s** %s **%s**",
getUserName(msg.from),
label,
@@ -297,8 +298,9 @@ private API getLHApi() {
private String formatConversation(Conversation conversation) {
StringBuilder sb = new StringBuilder();
+ QualifiedId creatorId = new QualifiedId(conversation.creator, null); // TODO(WPB-11287): Change null to default domain
sb.append(String.format("**%s** created conversation **%s** with: \n",
- getUserName(conversation.creator),
+ getUserName(creatorId),
conversation.name));
for (Member member : conversation.members) {
sb.append(String.format("- **%s** \n", getUserName(member.id)));
@@ -316,7 +318,7 @@ private String getText(UUID msgId) throws IOException {
}
@Nullable
- private String getUserName(UUID userId) {
+ private String getUserName(QualifiedId userId) {
Cache cache = new Cache(api, assetsDAO);
return cache.getUser(userId).name;
}
diff --git a/src/main/java/com/wire/bots/hold/utils/Cache.java b/src/main/java/com/wire/bots/hold/utils/Cache.java
index 619b63c..e0e55c2 100644
--- a/src/main/java/com/wire/bots/hold/utils/Cache.java
+++ b/src/main/java/com/wire/bots/hold/utils/Cache.java
@@ -2,6 +2,7 @@
import com.wire.bots.hold.DAO.AssetsDAO;
import com.wire.helium.API;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.tools.Logger;
@@ -12,9 +13,10 @@
import java.util.concurrent.ConcurrentHashMap;
public class Cache {
+ // TODO(WPB-11287): Add default domain here
private static final ConcurrentHashMap assets = new ConcurrentHashMap<>();//
- private static final ConcurrentHashMap users = new ConcurrentHashMap<>();//
- private static final ConcurrentHashMap profiles = new ConcurrentHashMap<>();//
+ private static final ConcurrentHashMap users = new ConcurrentHashMap<>();//
+ private static final ConcurrentHashMap profiles = new ConcurrentHashMap<>();//
private final API api;
private final AssetsDAO assetsDAO;
@@ -54,7 +56,8 @@ public File getProfileImage(User user) {
return file;
}
- public User getUser(UUID userId) {
+ public User getUser(QualifiedId userId) {
+ // TODO(WPB-11287): Fetch first in map then check API
return users.computeIfAbsent(userId, k -> {
try {
return api.getUser(userId);
diff --git a/src/main/java/com/wire/bots/hold/utils/Collector.java b/src/main/java/com/wire/bots/hold/utils/Collector.java
index c3370f5..3ab7814 100644
--- a/src/main/java/com/wire/bots/hold/utils/Collector.java
+++ b/src/main/java/com/wire/bots/hold/utils/Collector.java
@@ -1,5 +1,6 @@
package com.wire.bots.hold.utils;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
import com.wire.xenon.models.OriginMessage;
import com.wire.xenon.models.TextMessage;
@@ -25,7 +26,7 @@ public void add(TextMessage event) throws ParseException {
message.text = Helper.markdown2Html(event.getText(), true);
message.time = toTime(event.getTime());
- UUID senderId = event.getUserId();
+ QualifiedId senderId = event.getUserId();
String dateTime = event.getTime();
User user = cache.getUser(senderId);
@@ -48,7 +49,7 @@ public void add(OriginMessage event) throws ParseException {
message.text = Helper.markdown2Html(url, false);
}
- UUID senderId = event.getUserId();
+ QualifiedId senderId = event.getUserId();
User user = cache.getUser(senderId);
Sender sender = sender(user, message);
@@ -78,7 +79,7 @@ private Sender sender(User user, Message message) {
private Sender system(Message message, String type) {
Sender sender = new Sender();
sender.system = "system";
- sender.senderId = UUID.randomUUID();
+ sender.senderId = new QualifiedId(UUID.randomUUID(), null); // TODO(WPB-11287): Change null to default domain
sender.avatar = systemIcon(type);
sender.messages.add(message);
return sender;
@@ -212,7 +213,7 @@ public static class Message {
}
public static class Sender {
- UUID senderId;
+ QualifiedId senderId;
String avatar;
String name;
String accent;
diff --git a/src/main/java/com/wire/bots/hold/utils/Helper.java b/src/main/java/com/wire/bots/hold/utils/Helper.java
index fc70891..893384b 100644
--- a/src/main/java/com/wire/bots/hold/utils/Helper.java
+++ b/src/main/java/com/wire/bots/hold/utils/Helper.java
@@ -2,6 +2,7 @@
import com.wire.helium.API;
import com.wire.xenon.backend.models.Asset;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
import com.wire.xenon.exceptions.HttpException;
import org.commonmark.Extension;
@@ -28,7 +29,7 @@ static File getProfile(API api, User user) throws IOException, HttpException {
for (Asset asset : user.assets) {
if (asset.size.equals("preview")) {
- byte[] profile = api.downloadAsset(asset.key, null);
+ byte[] profile = api.downloadAsset(asset.key, user.id.domain, null);
save(profile, file);
break;
}
@@ -54,8 +55,8 @@ static String getExtension(String mimeType) {
return split.length == 1 ? split[0] : split[1];
}
- static String avatarFile(UUID senderId) {
- return String.format("avatars/%s.png", senderId);
+ static String avatarFile(QualifiedId senderId) {
+ return String.format("avatars/%s.png", senderId.id);
}
static String markdown2Html(String text, Boolean escape) {
diff --git a/src/main/java/com/wire/bots/hold/utils/HoldClientRepo.java b/src/main/java/com/wire/bots/hold/utils/HoldClientRepo.java
index b03f1b3..f808e2a 100644
--- a/src/main/java/com/wire/bots/hold/utils/HoldClientRepo.java
+++ b/src/main/java/com/wire/bots/hold/utils/HoldClientRepo.java
@@ -5,6 +5,7 @@
import com.wire.bots.hold.model.LHAccess;
import com.wire.helium.API;
import com.wire.xenon.WireClient;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.crypto.Crypto;
import com.wire.xenon.factories.CryptoFactory;
import org.jdbi.v3.core.Jdbi;
@@ -24,10 +25,10 @@ public HoldClientRepo(Jdbi jdbi, CryptoFactory cf, Client httpClient) {
this.httpClient = httpClient;
}
- public WireClient getClient(UUID userId, String deviceId, UUID convId) throws CryptoException {
+ public WireClient getClient(UUID userId, String deviceId, QualifiedId conversationId) throws CryptoException {
Crypto crypto = cf.create(userId);
final LHAccess single = jdbi.onDemand(AccessDAO.class).get(userId);
- final API api = new API(httpClient, convId, single.token);
- return new HoldWireClient(userId, deviceId, convId, crypto, api);
+ final API api = new API(httpClient, conversationId, single.token);
+ return new HoldWireClient(userId, deviceId, conversationId, crypto, api);
}
}
diff --git a/src/main/java/com/wire/bots/hold/utils/HoldWireClient.java b/src/main/java/com/wire/bots/hold/utils/HoldWireClient.java
index dfd2a05..2ad4701 100644
--- a/src/main/java/com/wire/bots/hold/utils/HoldWireClient.java
+++ b/src/main/java/com/wire/bots/hold/utils/HoldWireClient.java
@@ -4,6 +4,7 @@
import com.wire.xenon.WireClient;
import com.wire.xenon.WireClientBase;
import com.wire.xenon.assets.IAsset;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
import com.wire.xenon.crypto.Crypto;
import com.wire.xenon.models.AssetKey;
@@ -15,10 +16,10 @@
public class HoldWireClient extends WireClientBase implements WireClient {
private final UUID userId;
- private final UUID convId;
+ private final QualifiedId convId;
private final String deviceId;
- public HoldWireClient(UUID userId, String deviceId, UUID convId, Crypto crypto, API api) {
+ HoldWireClient(UUID userId, String deviceId, QualifiedId convId, Crypto crypto, API api) {
super(api, crypto, null);
this.userId = userId;
this.convId = convId;
@@ -36,7 +37,7 @@ public String getDeviceId() {
}
@Override
- public UUID getConversationId() {
+ public QualifiedId getConversationId() {
return convId;
}
@@ -48,7 +49,7 @@ public User getSelf() {
}
@Override
- public void acceptConnection(UUID user) {
+ public void acceptConnection(QualifiedId user) {
}
@@ -63,7 +64,7 @@ public ArrayList getAvailablePrekeys() {
}
@Override
- public byte[] downloadProfilePicture(String assetKey) {
+ public byte[] downloadProfilePicture(String assetKey, String domain) {
return new byte[0];
}
diff --git a/src/test/java/com/wire/bots/hold/Consts.java b/src/test/java/com/wire/bots/hold/Consts.java
deleted file mode 100644
index b45ce0e..0000000
--- a/src/test/java/com/wire/bots/hold/Consts.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.wire.bots.hold;
-
-import java.util.UUID;
-
-public class Consts {
- public static final UUID dejan = UUID.fromString("40b96378-951d-11e9-bc42-526af7764f64");
- public static final UUID lipis = UUID.fromString("40b96896-951d-11e9-bc42-526af7764f64");
-}
diff --git a/src/test/java/com/wire/bots/hold/DatabaseTest.java b/src/test/java/com/wire/bots/hold/DatabaseTest.java
index c6c05d4..8ee64b9 100644
--- a/src/test/java/com/wire/bots/hold/DatabaseTest.java
+++ b/src/test/java/com/wire/bots/hold/DatabaseTest.java
@@ -8,6 +8,7 @@
import com.wire.bots.hold.model.Config;
import com.wire.bots.hold.model.Event;
import com.wire.bots.hold.model.LHAccess;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.models.TextMessage;
import io.dropwizard.testing.ConfigOverride;
import io.dropwizard.testing.DropwizardTestSupport;
@@ -48,20 +49,20 @@ public void eventsTextMessageTest() throws JsonProcessingException {
final String type = "conversation.otr-message-add.new-text";
final UUID eventId = UUID.randomUUID();
final UUID messageId = UUID.randomUUID();
- final UUID convId = UUID.randomUUID();
+ final QualifiedId convId = new QualifiedId(UUID.randomUUID(), null);
final String clientId = UUID.randomUUID().toString();
- final UUID userId = UUID.randomUUID();
+ final QualifiedId userId = new QualifiedId(UUID.randomUUID(), null);
final String time = new Date().toString();
final TextMessage textMessage = new TextMessage(eventId, messageId, convId, clientId, userId, time);
- textMessage.addMention(UUID.randomUUID().toString(), 0, 5);
+ textMessage.addMention(new QualifiedId(UUID.randomUUID(), null), 0, 5);
textMessage.setText("Some text");
String payload = mapper.writeValueAsString(textMessage);
- int insert = eventsDAO.insert(eventId, convId, userId, type, payload);
+ int insert = eventsDAO.insert(eventId, convId.id, userId.id, type, payload);
assert insert == 1;
- insert = eventsDAO.insert(UUID.randomUUID(), convId, userId, type, payload);
+ insert = eventsDAO.insert(UUID.randomUUID(), convId.id, userId.id, type, payload);
assert insert == 1;
final Event event = eventsDAO.get(eventId);
@@ -70,7 +71,7 @@ public void eventsTextMessageTest() throws JsonProcessingException {
assert textMessage.getMessageId().equals(message.getMessageId());
- List events = eventsDAO.listAll(convId);
+ List events = eventsDAO.listAll(convId.id);
assert events.size() == 2;
}
@@ -86,9 +87,9 @@ public void assetsTest() {
assetsDAO.insert(messageId, image);
final AssetsDAO.Asset asset = assetsDAO.get(messageId);
- final boolean deepEquals = Objects.deepEquals(image, asset.data);
- final boolean equals = Objects.equals(messageId, asset.messageId);
- final boolean equals1 = Objects.equals(mimetype, asset.mimeType);
+ assert Objects.deepEquals(image, asset.data);
+ assert Objects.equals(messageId, asset.messageId);
+ assert Objects.equals(mimetype, asset.mimeType);
}
@Test
@@ -105,11 +106,14 @@ public void accessTests() {
accessDAO.update(userId, token, cookie2);
final LHAccess lhAccess = accessDAO.get(userId);
+ assert lhAccess != null;
+ assert lhAccess.userId.equals(userId);
accessDAO.disable(userId);
final int insert2 = accessDAO.insert(userId, clientId, cookie);
final LHAccess lhAccess2 = accessDAO.get(userId);
-
+ assert lhAccess2 != null;
+ assert lhAccess2.created.equals(lhAccess.created);
}
}
diff --git a/src/test/java/com/wire/bots/hold/MessageTemplateTest.java b/src/test/java/com/wire/bots/hold/MessageTemplateTest.java
index ee541af..9306a11 100644
--- a/src/test/java/com/wire/bots/hold/MessageTemplateTest.java
+++ b/src/test/java/com/wire/bots/hold/MessageTemplateTest.java
@@ -6,6 +6,7 @@
import com.wire.bots.hold.utils.Collector;
import com.wire.bots.hold.utils.PdfGenerator;
import com.wire.bots.hold.utils.TestCache;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.models.OriginMessage;
import com.wire.xenon.models.PhotoPreviewMessage;
import com.wire.xenon.models.TextMessage;
@@ -18,35 +19,33 @@
import java.text.ParseException;
import java.util.UUID;
-import static com.wire.bots.hold.Consts.dejan;
-import static com.wire.bots.hold.Consts.lipis;
-
public class MessageTemplateTest {
- private static TextMessage txt(UUID userId, String time, String text) {
+ private static TextMessage txt(QualifiedId userId, String time, String text) {
TextMessage msg = new TextMessage(UUID.randomUUID(),
- UUID.randomUUID(),
- UUID.randomUUID(),
- UUID.randomUUID().toString(),
- userId, time);
+ UUID.randomUUID(),
+ new QualifiedId(UUID.randomUUID(), UUID.randomUUID().toString()),
+ UUID.randomUUID().toString(),
+ userId,
+ time);
msg.setText(text);
return msg;
}
- private static OriginMessage asset(UUID userId, String time, String name, String mime) {
+ private static OriginMessage asset(QualifiedId userId, String time, String name, String mime) {
return new PhotoPreviewMessage(
- UUID.randomUUID(),
- UUID.randomUUID(),
- UUID.randomUUID(),
- UUID.randomUUID().toString(),
- userId,
- time,
- mime, 0, name, 0, 0);
+ UUID.randomUUID(),
+ UUID.randomUUID(),
+ new QualifiedId(UUID.randomUUID(), UUID.randomUUID().toString()),
+ UUID.randomUUID().toString(),
+ userId,
+ time,
+ mime, 0, name, 0, 0);
}
@Before
public void makeDirs() {
File f = new File("src/test/output");
- boolean mkdir = f.mkdir();
+ f.mkdir();
}
@Test
@@ -96,62 +95,64 @@ private Collector.Conversation getConversation() throws ParseException {
final String thursday = "2019-07-08T08:35:21.348Z";
final String friday = "2019-07-09T18:21:17.548Z";
final String saturday = "2019-07-10T21:11:47.149Z";
+ final QualifiedId user1 = new QualifiedId(UUID.randomUUID(), UUID.randomUUID().toString());
+ final QualifiedId user2 = new QualifiedId(UUID.randomUUID(), UUID.randomUUID().toString());
Collector collector = new Collector(new TestCache());
String name = "Message Template Test";
collector.setConvName(name);
final String format = String.format("**Dejan** created conversation **%s** with: \n- **Lipis**", name);
collector.addSystem(format, thursday, "conversation.create");
- collector.add(txt(dejan, thursday, "Privet! Kak dela?"));
- collector.add(txt(lipis, thursday, "Ladna"));
- collector.add(asset(lipis, thursday, "i_know", "video/mp4"));
- collector.add(txt(dejan, thursday, "ππ π΄π€§βοΈππ¨βππ¨βπ«π©βπ¦π¨βπ§βπ¦π₯π§πΎππππ²π"));
- collector.add(txt(dejan, thursday, "4"));
- collector.add(txt(lipis, thursday, "5 π"));
- collector.add(txt(lipis, thursday, "πLorem ipsum **dolor** sit amet, consectetur adipiscing elit, sed " +
+ collector.add(txt(user1, thursday, "Privet! Kak dela?"));
+ collector.add(txt(user2, thursday, "Ladna"));
+ collector.add(asset(user2, thursday, "i_know", "video/mp4"));
+ collector.add(txt(user1, thursday, "ππ π΄π€§βοΈππ¨βππ¨βπ«π©βπ¦π¨βπ§βπ¦π₯π§πΎππππ²π"));
+ collector.add(txt(user1, thursday, "4"));
+ collector.add(txt(user2, thursday, "5 π"));
+ collector.add(txt(user2, thursday, "πLorem ipsum **dolor** sit amet, consectetur adipiscing elit, sed " +
"do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam," +
" quis nostrud exercitation ullamco _laboris_ nisi ut aliquip ex ea commodo consequat. " +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum"));
- collector.add(txt(dejan, friday, "7"));
- collector.add(txt(lipis, saturday, "8"));
- collector.add(asset(lipis, saturday, "ognjiste2", "image/png"));
- collector.add(asset(lipis, saturday, "small", "image/png"));
- collector.add(txt(dejan, saturday, "9"));
- collector.add(txt(dejan, saturday, "10"));
- collector.add(txt(lipis, saturday, "```collector.addSystem(img(dejan, friday," +
+ collector.add(txt(user1, friday, "7"));
+ collector.add(txt(user2, saturday, "8"));
+ collector.add(asset(user2, saturday, "ognjiste2", "image/png"));
+ collector.add(asset(user2, saturday, "small", "image/png"));
+ collector.add(txt(user1, saturday, "9"));
+ collector.add(txt(user1, saturday, "10"));
+ collector.add(txt(user2, saturday, "```collector.addSystem(img(dejan, friday," +
" \"SP\", \"image/jpeg\"));\n" +
" collector.addSystem(txt(dejan, friday, \"7\"));\n" +
" collector.addSystem(txt(lipis, saturday, \"8\"));\n" +
" collector.addSystem(img(lipis, saturday, \"ognjiste2\", \"image/png\"));\n" +
" collector.addSystem(img(lipis, saturday, \"small\", \"image/png\"));\n" +
"```"));
- collector.add(txt(dejan, saturday, "12"));
- collector.add(txt(lipis, saturday, "13"));
- collector.add(asset(dejan, saturday, "ognjiste", "image/png"));
- collector.add(txt(lipis, saturday, "14"));
- collector.add(txt(lipis, saturday, "15"));
- collector.add(txt(dejan, saturday, "Lorem ipsum **dolor** sit amet, consectetur adipiscing elit, sed " +
+ collector.add(txt(user1, saturday, "12"));
+ collector.add(txt(user2, saturday, "13"));
+ collector.add(asset(user1, saturday, "ognjiste", "image/png"));
+ collector.add(txt(user2, saturday, "14"));
+ collector.add(txt(user2, saturday, "15"));
+ collector.add(txt(user1, saturday, "Lorem ipsum **dolor** sit amet, consectetur adipiscing elit, sed " +
"do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam," +
" quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
"Excepteur sint occaecat cupidatat non _proident_, sunt in culpa qui officia deserunt mollit anim id est" +
" laborum."));
- collector.add(txt(lipis, saturday, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " +
+ collector.add(txt(user2, saturday, "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " +
"do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam," +
" quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " +
"Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est" +
" laborum."));
- collector.add(txt(dejan, saturday, "This is some url [google](https://google.com)"));
- collector.add(txt(dejan, saturday, "https://google.com"));
- collector.add(txt(lipis, saturday, "This is some url https://google.com and some text"));
- collector.add(txt(dejan, saturday, "These two urls https://google.com https://wire.com"));
+ collector.add(txt(user1, saturday, "This is some url [google](https://google.com)"));
+ collector.add(txt(user1, saturday, "https://google.com"));
+ collector.add(txt(user2, saturday, "This is some url https://google.com and some text"));
+ collector.add(txt(user1, saturday, "These two urls https://google.com https://wire.com"));
collector.addSystem("**Lipis** left the conversation", saturday, "conversation.member-leave");
collector.addSystem("**Tiago** joined the conversation", saturday, "conversation.member-join");
collector.addSystem("**Tiago** deleted text: 'some text'", saturday, "conversation.otr-message-add.delete-text");
collector.addSystem("**Tiago** called", saturday, "conversation.otr-message-add.call");
- collector.add(asset(dejan, saturday, "ognjiste2", "image/png"));
+ collector.add(asset(user1, saturday, "ognjiste2", "image/png"));
return collector.getConversation();
}
diff --git a/src/test/java/com/wire/bots/hold/Serialization.java b/src/test/java/com/wire/bots/hold/SerializationTest.java
similarity index 94%
rename from src/test/java/com/wire/bots/hold/Serialization.java
rename to src/test/java/com/wire/bots/hold/SerializationTest.java
index 81f6906..2a0689f 100644
--- a/src/test/java/com/wire/bots/hold/Serialization.java
+++ b/src/test/java/com/wire/bots/hold/SerializationTest.java
@@ -1,13 +1,13 @@
package com.wire.bots.hold;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.wire.xenon.models.ImageMessage;
+import com.wire.xenon.models.PhotoPreviewMessage;
import com.wire.xenon.models.TextMessage;
import org.junit.Test;
import java.io.IOException;
-public class Serialization {
+public class SerializationTest {
@Test
public void imageMessage() throws IOException {
String payload = "{" +
@@ -28,7 +28,7 @@ public void imageMessage() throws IOException {
"\"tag\":null" +
"}";
ObjectMapper mapper = new ObjectMapper();
- ImageMessage message = mapper.readValue(payload, ImageMessage.class);
+ PhotoPreviewMessage message = mapper.readValue(payload, PhotoPreviewMessage.class);
}
@Test
diff --git a/src/test/java/com/wire/bots/hold/utils/TestCache.java b/src/test/java/com/wire/bots/hold/utils/TestCache.java
index 86f78bb..0c36fb2 100644
--- a/src/test/java/com/wire/bots/hold/utils/TestCache.java
+++ b/src/test/java/com/wire/bots/hold/utils/TestCache.java
@@ -1,12 +1,11 @@
package com.wire.bots.hold.utils;
+import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
import java.io.File;
import java.util.UUID;
-import static com.wire.bots.hold.Consts.dejan;
-
public class TestCache extends Cache {
public TestCache() {
super(null, null);
@@ -24,11 +23,13 @@ public File getProfileImage(User user) {
}
@Override
- public User getUser(UUID userId) {
- User user = new User();
- user.id = userId;
- user.name = userId.equals(dejan) ? "Dejan" : "Lipis";
- user.accent = userId.equals(dejan) ? 3 : 5;
- return user;
+ public User getUser(QualifiedId userId) {
+ User dummyUser = new User();
+
+ dummyUser.id = userId;
+ dummyUser.name = userId.toString();
+ dummyUser.accent = 3;
+
+ return dummyUser;
}
}
From a051559b43840cc56c936e8420a2d6c54147ad67 Mon Sep 17 00:00:00 2001
From: alexandreferris
Date: Tue, 1 Oct 2024 16:46:37 +0200
Subject: [PATCH 2/5] feat(get-domain-from-backend) Use new Helium API to fetch
backend domain * Update Helium to 1.4.1 * Add assertions to major tests *
Remove Consts.java from tests * Add call to get api version and default
domain
---
.../wire/bots/hold/NotificationProcessor.java | 80 ++++++-------------
src/main/java/com/wire/bots/hold/Service.java | 11 ++-
.../bots/hold/healthchecks/SanityCheck.java | 21 ++++-
.../wire/bots/hold/model/Notification.java | 20 -----
.../bots/hold/model/NotificationList.java | 18 -----
.../bots/hold/resource/ConfirmResource.java | 10 ++-
.../hold/resource/ConversationResource.java | 2 +
.../java/com/wire/bots/hold/utils/Cache.java | 20 +++--
.../com/wire/bots/hold/utils/TestCache.java | 19 +++++
9 files changed, 93 insertions(+), 108 deletions(-)
delete mode 100644 src/main/java/com/wire/bots/hold/model/Notification.java
delete mode 100644 src/main/java/com/wire/bots/hold/model/NotificationList.java
diff --git a/src/main/java/com/wire/bots/hold/NotificationProcessor.java b/src/main/java/com/wire/bots/hold/NotificationProcessor.java
index 3cf36c2..b9fc760 100644
--- a/src/main/java/com/wire/bots/hold/NotificationProcessor.java
+++ b/src/main/java/com/wire/bots/hold/NotificationProcessor.java
@@ -3,39 +3,34 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wire.bots.hold.DAO.AccessDAO;
-import com.wire.bots.hold.model.Config;
import com.wire.bots.hold.model.LHAccess;
-import com.wire.bots.hold.model.Notification;
-import com.wire.bots.hold.model.NotificationList;
+import com.wire.helium.API;
import com.wire.helium.LoginClient;
import com.wire.helium.models.Access;
+import com.wire.helium.models.Event;
+import com.wire.helium.models.NotificationList;
import com.wire.xenon.backend.models.Payload;
import com.wire.xenon.exceptions.AuthException;
import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.tools.Logger;
import javax.ws.rs.client.Client;
-import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Cookie;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class NotificationProcessor implements Runnable {
+ private static final int DEFAULT_NOTIFICATION_SIZE = 100;
+
private final Client client;
private final AccessDAO accessDAO;
private final HoldMessageResource messageResource;
- private final WebTarget api;
- NotificationProcessor(Client client, AccessDAO accessDAO, Config config, HoldMessageResource messageResource) {
+ NotificationProcessor(Client client, AccessDAO accessDAO, HoldMessageResource messageResource) {
this.client = client;
this.accessDAO = accessDAO;
this.messageResource = messageResource;
-
- api = client.target(config.apiHost);
}
@Override
@@ -59,7 +54,11 @@ private Access getAccess(Cookie cookie) throws HttpException {
private void process(LHAccess device) {
UUID userId = device.userId;
+
try {
+ // todo get exception
+ final API api = new API(client, null, device.token);
+
Logger.debug("`GET /notifications`: user: %s, last: %s", userId, device.last);
String cookieValue = device.cookie;
@@ -77,10 +76,13 @@ private void process(LHAccess device) {
device.token = access.getAccessToken();
- NotificationList notificationList = retrieveNotifications(device);
+ NotificationList notificationList = api.retrieveNotifications(
+ device.clientId,
+ device.last,
+ DEFAULT_NOTIFICATION_SIZE
+ );
process(userId, notificationList);
-
} catch (AuthException e) {
accessDAO.disable(userId);
Logger.info("Disabled LH device for user: %s, error: %s", userId, e.getMessage());
@@ -89,27 +91,21 @@ private void process(LHAccess device) {
}
}
- private static String bearer(String token) {
- return token == null ? null : String.format("Bearer %s", token);
- }
-
private void process(UUID userId, NotificationList notificationList) {
-
- for (Notification notif : notificationList.notifications) {
- for (Payload payload : notif.payload) {
- if (!process(userId, payload, notif.id)) {
- Logger.error("Failed to process: user: %s, notif: %s", userId, notif.id);
- //return;
+ for (Event event : notificationList.notifications) {
+ for (Payload payload : event.payload) {
+ if (!process(userId, payload, event.id)) {
+ Logger.error("Failed to process: user: %s, event: %s", userId, event.id);
} else {
- Logger.debug("Processed: `%s` conv: %s, user: %s, notifId: %s",
+ Logger.debug("Processed: `%s` conv: %s, user: %s, eventId: %s",
payload.type,
payload.conversation,
userId,
- notif.id);
+ event.id);
}
}
- accessDAO.updateLast(userId, notif.id);
+ accessDAO.updateLast(userId, event.id);
}
}
@@ -123,13 +119,13 @@ private boolean process(UUID userId, Payload payload, UUID id) {
if (payload.from == null || payload.data == null) return true;
- final boolean b = messageResource.onNewMessage(userId, id, payload);
+ final boolean wasMessageSent = messageResource.onNewMessage(userId, id, payload);
- if (!b) {
+ if (!wasMessageSent) {
Logger.error("process: `%s` user: %s, from: %s:%s, error: %s", payload.type, userId, payload.from, payload.data.sender);
}
- return b;
+ return wasMessageSent;
}
private void trace(Payload payload) {
@@ -142,30 +138,4 @@ private void trace(Payload payload) {
}
}
}
-
- //TODO remove this and use retrieveNotifications provided by Helium
- private NotificationList retrieveNotifications(LHAccess access) throws HttpException {
- Response response = api.path("notifications").queryParam("client", access.clientId).queryParam("since", access.last).queryParam("size", 100).request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).header(HttpHeaders.AUTHORIZATION, bearer(access.token)).get();
-
- int status = response.getStatus();
-
- if (status == 200) {
- return response.readEntity(NotificationList.class);
- }
-
- if (status == 404) { //todo what???
- return response.readEntity(NotificationList.class);
- }
-
- if (status == 401) { //todo nginx returns text/html for 401. Cannot deserialize as json
- response.readEntity(String.class);
- throw new AuthException(status);
- }
-
- if (status == 403) {
- throw response.readEntity(AuthException.class);
- }
-
- throw response.readEntity(HttpException.class);
- }
}
diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java
index 568fdf7..5075545 100644
--- a/src/main/java/com/wire/bots/hold/Service.java
+++ b/src/main/java/com/wire/bots/hold/Service.java
@@ -27,14 +27,18 @@
import com.wire.bots.hold.monitoring.RequestMdcFactoryFilter;
import com.wire.bots.hold.monitoring.StatusResource;
import com.wire.bots.hold.resource.*;
+import com.wire.bots.hold.utils.Cache;
import com.wire.bots.hold.utils.HoldClientRepo;
import com.wire.bots.hold.utils.ImagesBundle;
import com.wire.helium.LoginClient;
+import com.wire.helium.models.BackendConfiguration;
import com.wire.xenon.Const;
import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.crypto.CryptoDatabase;
import com.wire.xenon.crypto.storage.JdbiStorage;
+import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.factories.CryptoFactory;
+import com.wire.xenon.tools.Logger;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.client.JerseyClientBuilder;
@@ -131,10 +135,9 @@ public void run(Config config, Environment environment) {
environment.healthChecks().register("SanityCheck", new SanityCheck(accessDAO, httpClient));
final HoldClientRepo repo = new HoldClientRepo(jdbi, cf, httpClient);
- final LoginClient loginClient = new LoginClient(httpClient);
final HoldMessageResource holdMessageResource = new HoldMessageResource(new MessageHandler(jdbi), repo);
- final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, config, holdMessageResource);
+ final NotificationProcessor notificationProcessor = new NotificationProcessor(httpClient, accessDAO, holdMessageResource);
environment.lifecycle()
.scheduledExecutorService("notifications")
@@ -144,10 +147,6 @@ public void run(Config config, Environment environment) {
CollectorRegistry.defaultRegistry.register(new DropwizardExports(metrics));
environment.getApplicationContext().addServlet(MetricsServlet.class, "/metrics");
-
- // todo here
- // String res = loginClient.getBackendConfiguration();
- // handle res ^
}
public Config getConfig() {
diff --git a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
index 80df73a..eb8afeb 100644
--- a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
+++ b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
@@ -3,8 +3,11 @@
import com.codahale.metrics.health.HealthCheck;
import com.wire.bots.hold.DAO.AccessDAO;
import com.wire.bots.hold.model.LHAccess;
+import com.wire.bots.hold.utils.Cache;
import com.wire.helium.API;
+import com.wire.helium.models.BackendConfiguration;
import com.wire.xenon.backend.models.QualifiedId;
+import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.tools.Logger;
import javax.ws.rs.client.Client;
@@ -30,14 +33,18 @@ protected Result check() {
API api = new API(client, null, single.token);
+ fetchAndStoreApiVersion(api);
+
String created = single.created;
List accessList = accessDAO.list(100, created);
while (!accessList.isEmpty()) {
Logger.info("SanityCheck: checking %d devices, created: %s", accessList.size(), created);
for (LHAccess access : accessList) {
+ // TODO(WPB-11287): Use user domain if exists, otherwise default
+ // TODO: String domain = (access.domain != null) ? access.domain : Cache.DEFAULT_DOMAIN;
boolean hasDevice = api.hasDevice(
- new QualifiedId(access.userId, null), // TODO(WPB-11287): Change null to default domain
+ new QualifiedId(access.userId, Cache.getDefaultDomain()), // TODO(WPB-11287): Change null to default domain
access.clientId
);
@@ -61,4 +68,16 @@ protected Result check() {
Logger.debug("Finished SanityCheck");
}
}
+
+ private void fetchAndStoreApiVersion(API api) {
+ if (Cache.getDefaultDomain() != null) { return; }
+
+ try {
+ BackendConfiguration apiVersionResponse = api.getBackendConfiguration();
+
+ Cache.setDefaultDomain(apiVersionResponse.domain);
+ } catch (HttpException exception) {
+ Logger.exception(exception, "Service.getApiVersion, exception: %s", exception.getMessage());
+ }
+ }
}
diff --git a/src/main/java/com/wire/bots/hold/model/Notification.java b/src/main/java/com/wire/bots/hold/model/Notification.java
deleted file mode 100644
index 5bfba19..0000000
--- a/src/main/java/com/wire/bots/hold/model/Notification.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.wire.bots.hold.model;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.wire.xenon.backend.models.Payload;
-
-import javax.validation.constraints.NotNull;
-import java.util.List;
-import java.util.UUID;
-
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class Notification {
- @JsonProperty
- @NotNull
- public List payload;
-
- @JsonProperty
- @NotNull
- public UUID id;
-}
diff --git a/src/main/java/com/wire/bots/hold/model/NotificationList.java b/src/main/java/com/wire/bots/hold/model/NotificationList.java
deleted file mode 100644
index 76a31f8..0000000
--- a/src/main/java/com/wire/bots/hold/model/NotificationList.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.wire.bots.hold.model;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import javax.validation.constraints.NotNull;
-import java.util.ArrayList;
-
-@JsonIgnoreProperties(ignoreUnknown = true)
-public class NotificationList {
- @JsonProperty("has_more")
- @NotNull
- public Boolean hasMore;
-
- @JsonProperty
- @NotNull
- public ArrayList notifications;
-}
diff --git a/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java b/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java
index 352f489..9cea782 100644
--- a/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java
+++ b/src/main/java/com/wire/bots/hold/resource/ConfirmResource.java
@@ -33,9 +33,13 @@ public ConfirmResource(AccessDAO accessDAO) {
@ApiResponse(code = 200, message = "Legal Hold Device enabled")})
public Response confirm(@ApiParam @Valid @NotNull ConfirmPayload payload) {
try {
- int insert = accessDAO.insert(payload.userId,
- payload.clientId,
- payload.refreshToken);
+ int insert = accessDAO.insert(
+ // TODO(WPB-11287): Add new column in DB for domain
+ // TODO(WPB-11287): + Use default domain for v0
+ payload.userId,
+ payload.clientId,
+ payload.refreshToken
+ );
if (0 == insert) {
Logger.error("ConfirmResource: Failed to insert Access %s:%s",
diff --git a/src/main/java/com/wire/bots/hold/resource/ConversationResource.java b/src/main/java/com/wire/bots/hold/resource/ConversationResource.java
index 6a7c649..ed226e3 100644
--- a/src/main/java/com/wire/bots/hold/resource/ConversationResource.java
+++ b/src/main/java/com/wire/bots/hold/resource/ConversationResource.java
@@ -67,6 +67,8 @@ public Response list(@ApiParam @PathParam("conversationId") UUID conversationId,
try {
List events = eventsDAO.listAllAsc(conversationId);
+ // TODO(WPB-11287) Verify default domain
+
testAPI();
Cache cache = new Cache(api, assetsDAO);
diff --git a/src/main/java/com/wire/bots/hold/utils/Cache.java b/src/main/java/com/wire/bots/hold/utils/Cache.java
index e0e55c2..b41101a 100644
--- a/src/main/java/com/wire/bots/hold/utils/Cache.java
+++ b/src/main/java/com/wire/bots/hold/utils/Cache.java
@@ -13,10 +13,11 @@
import java.util.concurrent.ConcurrentHashMap;
public class Cache {
- // TODO(WPB-11287): Add default domain here
- private static final ConcurrentHashMap assets = new ConcurrentHashMap<>();//
- private static final ConcurrentHashMap users = new ConcurrentHashMap<>();//
- private static final ConcurrentHashMap profiles = new ConcurrentHashMap<>();//
+ private static String DEFAULT_DOMAIN = null;
+
+ private static final ConcurrentHashMap assets = new ConcurrentHashMap<>(); //
+ private static final ConcurrentHashMap users = new ConcurrentHashMap<>(); //
+ private static final ConcurrentHashMap profiles = new ConcurrentHashMap<>(); //
private final API api;
private final AssetsDAO assetsDAO;
@@ -25,6 +26,16 @@ public Cache(API api, AssetsDAO assetsDAO) {
this.assetsDAO = assetsDAO;
}
+ public static void setDefaultDomain(String domain) {
+ if (DEFAULT_DOMAIN == null) {
+ DEFAULT_DOMAIN = domain;
+ }
+ }
+
+ public static String getDefaultDomain() {
+ return DEFAULT_DOMAIN;
+ }
+
@Nullable
public File getAssetFile(UUID messageId) {
@@ -57,7 +68,6 @@ public File getProfileImage(User user) {
}
public User getUser(QualifiedId userId) {
- // TODO(WPB-11287): Fetch first in map then check API
return users.computeIfAbsent(userId, k -> {
try {
return api.getUser(userId);
diff --git a/src/test/java/com/wire/bots/hold/utils/TestCache.java b/src/test/java/com/wire/bots/hold/utils/TestCache.java
index 0c36fb2..1ea23e8 100644
--- a/src/test/java/com/wire/bots/hold/utils/TestCache.java
+++ b/src/test/java/com/wire/bots/hold/utils/TestCache.java
@@ -2,6 +2,7 @@
import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.backend.models.User;
+import org.junit.Test;
import java.io.File;
import java.util.UUID;
@@ -32,4 +33,22 @@ public User getUser(QualifiedId userId) {
return dummyUser;
}
+
+ @Test
+ public void verifyDefaultDomainIsSetCorrectly() {
+ String firstDomain = Cache.getDefaultDomain();
+ assert firstDomain == null;
+
+ Cache.setDefaultDomain("dummy_domain");
+ String secondDomain = Cache.getDefaultDomain();
+
+ assert secondDomain != null;
+ assert secondDomain.equals("dummy_domain");
+
+ Cache.setDefaultDomain("dummy_domain_3");
+ String thirdDomain = Cache.getDefaultDomain();
+
+ assert thirdDomain != null;
+ assert thirdDomain.equals("dummy_domain");
+ }
}
From 84673c0bd947fde6d01b95455e17a2c04e892d8e Mon Sep 17 00:00:00 2001
From: alexandreferris
Date: Mon, 7 Oct 2024 12:29:05 +0200
Subject: [PATCH 3/5] feat(get-domain-from-backend) Use new Helium API to fetch
backend domain * Update Helium to 1.4.1 * Add assertions to major tests *
Remove Consts.java from tests * Add call to get api version and default
domain * Persist fallback domain to database * Add FallbackDomainFetcher to
handle fetch from cache, database and API
---
pom.xml | 6 ++
.../com/wire/bots/hold/DAO/MetadataDAO.java | 20 ++++
.../hold/DAO/MetadataResultSetMapper.java | 19 ++++
.../wire/bots/hold/FallbackDomainFetcher.java | 59 ++++++++++
.../wire/bots/hold/NotificationProcessor.java | 3 +-
src/main/java/com/wire/bots/hold/Service.java | 23 ++--
.../bots/hold/healthchecks/SanityCheck.java | 18 +---
.../com/wire/bots/hold/model/Metadata.java | 11 ++
.../java/com/wire/bots/hold/utils/Cache.java | 12 +--
.../db/migration/V107__add_metadata_table.sql | 4 +
.../java/com/wire/bots/hold/DatabaseTest.java | 18 ++++
.../bots/hold/FallbackDomainFetcherTest.java | 102 ++++++++++++++++++
.../com/wire/bots/hold/utils/CacheTest.java | 38 +++++++
.../com/wire/bots/hold/utils/TestCache.java | 18 ----
14 files changed, 302 insertions(+), 49 deletions(-)
create mode 100644 src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java
create mode 100644 src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java
create mode 100644 src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
create mode 100644 src/main/java/com/wire/bots/hold/model/Metadata.java
create mode 100644 src/main/resources/db/migration/V107__add_metadata_table.sql
create mode 100644 src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
create mode 100644 src/test/java/com/wire/bots/hold/utils/CacheTest.java
diff --git a/pom.xml b/pom.xml
index b5e93dc..c255d0e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -135,6 +135,12 @@
simpleclient_servlet
${prometheus.version}
+
+ org.mockito
+ mockito-all
+ 1.10.19
+ test
+
diff --git a/src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java b/src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java
new file mode 100644
index 0000000..933d83e
--- /dev/null
+++ b/src/main/java/com/wire/bots/hold/DAO/MetadataDAO.java
@@ -0,0 +1,20 @@
+package com.wire.bots.hold.DAO;
+
+import com.wire.bots.hold.model.Metadata;
+import org.jdbi.v3.sqlobject.config.RegisterColumnMapper;
+import org.jdbi.v3.sqlobject.customizer.Bind;
+import org.jdbi.v3.sqlobject.statement.SqlQuery;
+import org.jdbi.v3.sqlobject.statement.SqlUpdate;
+
+public interface MetadataDAO {
+ String FALLBACK_DOMAIN_KEY = "FALLBACK_DOMAIN_KEY";
+
+ @SqlUpdate("INSERT INTO Metadata (key, value)" +
+ "VALUES (:key, :value)" +
+ "ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value")
+ int insert(@Bind("key") String key, @Bind("value") String value);
+
+ @SqlQuery("SELECT key, value FROM Metadata WHERE key = :key LIMIT 1")
+ @RegisterColumnMapper(MetadataResultSetMapper.class)
+ Metadata get(@Bind("key") String key);
+}
diff --git a/src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java b/src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java
new file mode 100644
index 0000000..526985e
--- /dev/null
+++ b/src/main/java/com/wire/bots/hold/DAO/MetadataResultSetMapper.java
@@ -0,0 +1,19 @@
+package com.wire.bots.hold.DAO;
+
+import com.wire.bots.hold.model.Metadata;
+import org.jdbi.v3.core.mapper.ColumnMapper;
+import org.jdbi.v3.core.statement.StatementContext;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class MetadataResultSetMapper implements ColumnMapper {
+
+ @Override
+ public Metadata map(ResultSet rs, int columnNumber, StatementContext ctx) throws SQLException {
+ return new Metadata(
+ rs.getString("key"),
+ rs.getString("value")
+ );
+ }
+}
diff --git a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
new file mode 100644
index 0000000..58e7a40
--- /dev/null
+++ b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
@@ -0,0 +1,59 @@
+package com.wire.bots.hold;
+
+import com.wire.bots.hold.DAO.MetadataDAO;
+import com.wire.bots.hold.model.Metadata;
+import com.wire.bots.hold.utils.Cache;
+import com.wire.helium.LoginClient;
+import com.wire.helium.models.BackendConfiguration;
+import com.wire.xenon.exceptions.HttpException;
+import com.wire.xenon.tools.Logger;
+
+public class FallbackDomainFetcher implements Runnable {
+
+ private final LoginClient loginClient;
+ private final MetadataDAO metadataDAO;
+
+ /**
+ * Fetcher and handler for fallback domain.
+ *
+ * Fetches from API and compares against database value (if any), then inserts into database and updates cache value.
+ * If value received from the API is different from what is saved in the database, a [RuntimeException] is thrown.
+ *
+ * @param loginClient [{@link LoginClient}] as API to get backend configuration containing default domain.
+ * @param metadataDAO [{@link MetadataDAO}] as DAO to get/insert default domain to database.
+ *
+ * @throws RuntimeException if received domain from API is different from the one saved in the database.
+ */
+ FallbackDomainFetcher(LoginClient loginClient, MetadataDAO metadataDAO) {
+ this.loginClient = loginClient;
+ this.metadataDAO = metadataDAO;
+ }
+
+ @Override
+ public void run() {
+ if (Cache.getFallbackDomain() != null) { return; }
+
+ Metadata metadata = metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY);
+ try {
+ BackendConfiguration apiVersionResponse = loginClient.getBackendConfiguration();
+
+ if (metadata == null) {
+ metadataDAO.insert(MetadataDAO.FALLBACK_DOMAIN_KEY, apiVersionResponse.domain);
+ Cache.setFallbackDomain(apiVersionResponse.domain);
+ } else {
+ if (metadata.value.equals(apiVersionResponse.domain)) {
+ Cache.setFallbackDomain(apiVersionResponse.domain);
+ } else {
+ String formattedExceptionMessage = String.format(
+ "Database already has a default domain as %s and instead we got %s from the Backend API.",
+ metadata.value,
+ apiVersionResponse.domain
+ );
+ throw new RuntimeException(formattedExceptionMessage);
+ }
+ }
+ } catch (HttpException exception) {
+ Logger.exception(exception, "FallbackDomainFetcher.run, exception: %s", exception.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/com/wire/bots/hold/NotificationProcessor.java b/src/main/java/com/wire/bots/hold/NotificationProcessor.java
index b9fc760..1f504cf 100644
--- a/src/main/java/com/wire/bots/hold/NotificationProcessor.java
+++ b/src/main/java/com/wire/bots/hold/NotificationProcessor.java
@@ -56,7 +56,6 @@ private void process(LHAccess device) {
UUID userId = device.userId;
try {
- // todo get exception
final API api = new API(client, null, device.token);
Logger.debug("`GET /notifications`: user: %s, last: %s", userId, device.last);
@@ -86,6 +85,8 @@ private void process(LHAccess device) {
} catch (AuthException e) {
accessDAO.disable(userId);
Logger.info("Disabled LH device for user: %s, error: %s", userId, e.getMessage());
+ } catch (HttpException e) {
+ Logger.exception(e, "NotificationProcessor: Couldn't retrieve notifications, error: %s", e.getMessage());
} catch (Exception e) {
Logger.exception(e, "NotificationProcessor: user: %s, last: %s, error: %s", userId, device.last, e.getMessage());
}
diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java
index 5075545..4b2615f 100644
--- a/src/main/java/com/wire/bots/hold/Service.java
+++ b/src/main/java/com/wire/bots/hold/Service.java
@@ -21,24 +21,21 @@
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.wire.bots.hold.DAO.AccessDAO;
import com.wire.bots.hold.DAO.EventsDAO;
+import com.wire.bots.hold.DAO.MetadataDAO;
import com.wire.bots.hold.filters.ServiceAuthenticationFilter;
import com.wire.bots.hold.healthchecks.SanityCheck;
import com.wire.bots.hold.model.Config;
import com.wire.bots.hold.monitoring.RequestMdcFactoryFilter;
import com.wire.bots.hold.monitoring.StatusResource;
import com.wire.bots.hold.resource.*;
-import com.wire.bots.hold.utils.Cache;
import com.wire.bots.hold.utils.HoldClientRepo;
import com.wire.bots.hold.utils.ImagesBundle;
import com.wire.helium.LoginClient;
-import com.wire.helium.models.BackendConfiguration;
import com.wire.xenon.Const;
import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.crypto.CryptoDatabase;
import com.wire.xenon.crypto.storage.JdbiStorage;
-import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.factories.CryptoFactory;
-import com.wire.xenon.tools.Logger;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.client.JerseyClientBuilder;
@@ -63,7 +60,6 @@
public class Service extends Application {
public static Service instance;
public static MetricRegistry metrics;
- public static String API_DOMAIN;
protected Config config;
protected Environment environment;
protected Jdbi jdbi;
@@ -113,6 +109,7 @@ public void run(Config config, Environment environment) {
final AccessDAO accessDAO = jdbi.onDemand(AccessDAO.class);
final EventsDAO eventsDAO = jdbi.onDemand(EventsDAO.class);
+ final MetadataDAO metadataDAO = jdbi.onDemand(MetadataDAO.class);
// Monitoring resources
addResource(new StatusResource());
@@ -132,7 +129,21 @@ public void run(Config config, Environment environment) {
addResource(ServiceAuthenticationFilter.ServiceAuthenticationFeature.class);
- environment.healthChecks().register("SanityCheck", new SanityCheck(accessDAO, httpClient));
+ environment
+ .lifecycle()
+ .executorService("fallback_domain_fetcher")
+ .build()
+ .execute(
+ new FallbackDomainFetcher(
+ new LoginClient(httpClient),
+ metadataDAO
+ )
+ );
+
+ environment.healthChecks().register(
+ "SanityCheck",
+ new SanityCheck(accessDAO, httpClient)
+ );
final HoldClientRepo repo = new HoldClientRepo(jdbi, cf, httpClient);
diff --git a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
index eb8afeb..94df99a 100644
--- a/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
+++ b/src/main/java/com/wire/bots/hold/healthchecks/SanityCheck.java
@@ -5,9 +5,7 @@
import com.wire.bots.hold.model.LHAccess;
import com.wire.bots.hold.utils.Cache;
import com.wire.helium.API;
-import com.wire.helium.models.BackendConfiguration;
import com.wire.xenon.backend.models.QualifiedId;
-import com.wire.xenon.exceptions.HttpException;
import com.wire.xenon.tools.Logger;
import javax.ws.rs.client.Client;
@@ -33,8 +31,6 @@ protected Result check() {
API api = new API(client, null, single.token);
- fetchAndStoreApiVersion(api);
-
String created = single.created;
List accessList = accessDAO.list(100, created);
@@ -44,7 +40,7 @@ protected Result check() {
// TODO(WPB-11287): Use user domain if exists, otherwise default
// TODO: String domain = (access.domain != null) ? access.domain : Cache.DEFAULT_DOMAIN;
boolean hasDevice = api.hasDevice(
- new QualifiedId(access.userId, Cache.getDefaultDomain()), // TODO(WPB-11287): Change null to default domain
+ new QualifiedId(access.userId, Cache.getFallbackDomain()), // TODO(WPB-11287): Change null to default domain
access.clientId
);
@@ -68,16 +64,4 @@ protected Result check() {
Logger.debug("Finished SanityCheck");
}
}
-
- private void fetchAndStoreApiVersion(API api) {
- if (Cache.getDefaultDomain() != null) { return; }
-
- try {
- BackendConfiguration apiVersionResponse = api.getBackendConfiguration();
-
- Cache.setDefaultDomain(apiVersionResponse.domain);
- } catch (HttpException exception) {
- Logger.exception(exception, "Service.getApiVersion, exception: %s", exception.getMessage());
- }
- }
}
diff --git a/src/main/java/com/wire/bots/hold/model/Metadata.java b/src/main/java/com/wire/bots/hold/model/Metadata.java
new file mode 100644
index 0000000..f145827
--- /dev/null
+++ b/src/main/java/com/wire/bots/hold/model/Metadata.java
@@ -0,0 +1,11 @@
+package com.wire.bots.hold.model;
+
+public class Metadata {
+ public String key;
+ public String value;
+
+ public Metadata(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+}
diff --git a/src/main/java/com/wire/bots/hold/utils/Cache.java b/src/main/java/com/wire/bots/hold/utils/Cache.java
index b41101a..95b4ee4 100644
--- a/src/main/java/com/wire/bots/hold/utils/Cache.java
+++ b/src/main/java/com/wire/bots/hold/utils/Cache.java
@@ -13,7 +13,7 @@
import java.util.concurrent.ConcurrentHashMap;
public class Cache {
- private static String DEFAULT_DOMAIN = null;
+ private static String FALLBACK_DOMAIN = null;
private static final ConcurrentHashMap assets = new ConcurrentHashMap<>(); //
private static final ConcurrentHashMap users = new ConcurrentHashMap<>(); //
@@ -26,14 +26,12 @@ public Cache(API api, AssetsDAO assetsDAO) {
this.assetsDAO = assetsDAO;
}
- public static void setDefaultDomain(String domain) {
- if (DEFAULT_DOMAIN == null) {
- DEFAULT_DOMAIN = domain;
- }
+ public static void setFallbackDomain(String domain) {
+ FALLBACK_DOMAIN = domain;
}
- public static String getDefaultDomain() {
- return DEFAULT_DOMAIN;
+ public static String getFallbackDomain() {
+ return FALLBACK_DOMAIN;
}
@Nullable
diff --git a/src/main/resources/db/migration/V107__add_metadata_table.sql b/src/main/resources/db/migration/V107__add_metadata_table.sql
new file mode 100644
index 0000000..86e2406
--- /dev/null
+++ b/src/main/resources/db/migration/V107__add_metadata_table.sql
@@ -0,0 +1,4 @@
+CREATE TABLE Metadata (
+ key VARCHAR NOT NULL UNIQUE,
+ value VARCHAR NOT NULL
+);
diff --git a/src/test/java/com/wire/bots/hold/DatabaseTest.java b/src/test/java/com/wire/bots/hold/DatabaseTest.java
index 8ee64b9..833b28f 100644
--- a/src/test/java/com/wire/bots/hold/DatabaseTest.java
+++ b/src/test/java/com/wire/bots/hold/DatabaseTest.java
@@ -5,9 +5,11 @@
import com.wire.bots.hold.DAO.AccessDAO;
import com.wire.bots.hold.DAO.AssetsDAO;
import com.wire.bots.hold.DAO.EventsDAO;
+import com.wire.bots.hold.DAO.MetadataDAO;
import com.wire.bots.hold.model.Config;
import com.wire.bots.hold.model.Event;
import com.wire.bots.hold.model.LHAccess;
+import com.wire.bots.hold.model.Metadata;
import com.wire.xenon.backend.models.QualifiedId;
import com.wire.xenon.models.TextMessage;
import io.dropwizard.testing.ConfigOverride;
@@ -28,6 +30,7 @@ public class DatabaseTest {
private static AssetsDAO assetsDAO;
private static EventsDAO eventsDAO;
private static AccessDAO accessDAO;
+ private static MetadataDAO metadataDAO;
@BeforeClass
public static void init() throws Exception {
@@ -37,6 +40,7 @@ public static void init() throws Exception {
eventsDAO = app.getJdbi().onDemand(EventsDAO.class);
assetsDAO = app.getJdbi().onDemand(AssetsDAO.class);
accessDAO = app.getJdbi().onDemand(AccessDAO.class);
+ metadataDAO = app.getJdbi().onDemand(MetadataDAO.class);
}
@AfterClass
@@ -116,4 +120,18 @@ public void accessTests() {
assert lhAccess2 != null;
assert lhAccess2.created.equals(lhAccess.created);
}
+
+ @Test
+ public void metadataTests() {
+ String dummyKey = MetadataDAO.FALLBACK_DOMAIN_KEY + UUID.randomUUID();
+
+ Metadata nullMetadata = metadataDAO.get(dummyKey);
+ assert nullMetadata == null;
+
+ int insert = metadataDAO.insert(dummyKey, "dummy_domain");
+ Metadata metadata = metadataDAO.get(dummyKey);
+
+ assert metadata != null;
+ assert metadata.value.equals("dummy_domain");
+ }
}
diff --git a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
new file mode 100644
index 0000000..0b83ffe
--- /dev/null
+++ b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
@@ -0,0 +1,102 @@
+package com.wire.bots.hold;
+
+import com.wire.bots.hold.DAO.MetadataDAO;
+import com.wire.bots.hold.model.Metadata;
+import com.wire.bots.hold.utils.Cache;
+import com.wire.helium.LoginClient;
+import com.wire.helium.models.BackendConfiguration;
+import com.wire.xenon.exceptions.HttpException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.times;
+
+public class FallbackDomainFetcherTest {
+
+ private MetadataDAO metadataDAO;
+ private LoginClient loginClient;
+ private FallbackDomainFetcher fallbackDomainFetcher;
+
+ @Before
+ public void before() {
+ // Clears cached domain
+ Cache.setFallbackDomain(null);
+ metadataDAO = mock(MetadataDAO.class);
+ loginClient = mock(LoginClient.class);
+ fallbackDomainFetcher = new FallbackDomainFetcher(loginClient, metadataDAO);
+ }
+
+ @After
+ public void after() {
+ // Clears cached domain
+ Cache.setFallbackDomain(null);
+ }
+
+ @Test
+ public void givenNoFallbackDomainInCacheAndDatabase_whenExecuting_thenFetchFromApiAndStoreInCacheAndDatabase() throws HttpException {
+ // given
+ BackendConfiguration backendConfiguration = new BackendConfiguration();
+ backendConfiguration.domain = "dummy_domain_3";
+
+ when(metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY)).thenReturn(null);
+ when(metadataDAO.insert(any(), any())).thenReturn(1);
+ when(loginClient.getBackendConfiguration()).thenReturn(backendConfiguration);
+
+ // when
+ fallbackDomainFetcher.run();
+
+ // then
+ assert Cache.getFallbackDomain().equals("dummy_domain_3");
+ verify(metadataDAO, times(1)).insert(MetadataDAO.FALLBACK_DOMAIN_KEY, backendConfiguration.domain);
+ }
+
+ @Test
+ public void givenNoFallbackDomainInCache_whenExecuting_thenFetchFromAPIAndCompareWithDatabase() throws HttpException {
+ // given
+ BackendConfiguration backendConfiguration = new BackendConfiguration();
+ backendConfiguration.domain = "dummy_domain_2";
+
+ Metadata metadata = new Metadata(MetadataDAO.FALLBACK_DOMAIN_KEY, "dummy_domain_2");
+
+ when(metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY)).thenReturn(metadata);
+ when(loginClient.getBackendConfiguration()).thenReturn(backendConfiguration);
+
+ // when
+ fallbackDomainFetcher.run();
+
+ // then
+ assert Cache.getFallbackDomain().equals("dummy_domain_2");
+ }
+
+ @Test(expected=RuntimeException.class)
+ public void givenNoFallbackDomainInCache_whenExecutingAndApiReturnsDifferentDomainFromDatabase_thenThrowRuntimeException() throws HttpException, RuntimeException {
+ // given
+ BackendConfiguration backendConfiguration = new BackendConfiguration();
+ backendConfiguration.domain = "dummy_domain_1";
+
+ Metadata metadata = new Metadata(MetadataDAO.FALLBACK_DOMAIN_KEY, "dummy_domain_2");
+
+ when(metadataDAO.get(MetadataDAO.FALLBACK_DOMAIN_KEY)).thenReturn(metadata);
+ when(loginClient.getBackendConfiguration()).thenReturn(backendConfiguration);
+
+ // when
+ fallbackDomainFetcher.run();
+ }
+
+ @Test
+ public void givenFallbackDomainInCache_whenExecuting_thenReturnAndIgnoreDatabaseAndApiCalls() {
+ // given
+ Cache.setFallbackDomain("dummy_domain_0");
+
+ // when
+ fallbackDomainFetcher.run();
+
+ // then
+ assert Cache.getFallbackDomain().equals("dummy_domain_0");
+ }
+}
diff --git a/src/test/java/com/wire/bots/hold/utils/CacheTest.java b/src/test/java/com/wire/bots/hold/utils/CacheTest.java
new file mode 100644
index 0000000..ddbf2dd
--- /dev/null
+++ b/src/test/java/com/wire/bots/hold/utils/CacheTest.java
@@ -0,0 +1,38 @@
+package com.wire.bots.hold.utils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CacheTest {
+
+ @Before
+ public void before() {
+ // Clears cached domain
+ Cache.setFallbackDomain(null);
+ }
+
+ @After
+ public void after() {
+ // Clears cached domain
+ Cache.setFallbackDomain(null);
+ }
+
+ @Test
+ public void verifyDefaultDomainIsSetCorrectly() {
+ String firstDomain = Cache.getFallbackDomain();
+ assert firstDomain == null;
+
+ Cache.setFallbackDomain("dummy_domain");
+ String secondDomain = Cache.getFallbackDomain();
+
+ assert secondDomain != null;
+ assert secondDomain.equals("dummy_domain");
+
+ Cache.setFallbackDomain("dummy_domain_3");
+ String thirdDomain = Cache.getFallbackDomain();
+
+ assert thirdDomain != null;
+ assert thirdDomain.equals("dummy_domain_3");
+ }
+}
diff --git a/src/test/java/com/wire/bots/hold/utils/TestCache.java b/src/test/java/com/wire/bots/hold/utils/TestCache.java
index 1ea23e8..3a16723 100644
--- a/src/test/java/com/wire/bots/hold/utils/TestCache.java
+++ b/src/test/java/com/wire/bots/hold/utils/TestCache.java
@@ -33,22 +33,4 @@ public User getUser(QualifiedId userId) {
return dummyUser;
}
-
- @Test
- public void verifyDefaultDomainIsSetCorrectly() {
- String firstDomain = Cache.getDefaultDomain();
- assert firstDomain == null;
-
- Cache.setDefaultDomain("dummy_domain");
- String secondDomain = Cache.getDefaultDomain();
-
- assert secondDomain != null;
- assert secondDomain.equals("dummy_domain");
-
- Cache.setDefaultDomain("dummy_domain_3");
- String thirdDomain = Cache.getDefaultDomain();
-
- assert thirdDomain != null;
- assert thirdDomain.equals("dummy_domain");
- }
}
From b2137d607415eb451b23ff39b95cfd2a9fd9617a Mon Sep 17 00:00:00 2001
From: alexandreferris
Date: Mon, 7 Oct 2024 14:59:51 +0200
Subject: [PATCH 4/5] feat(get-domain-from-backend) Use new Helium API to fetch
backend domain * Update Helium to 1.4.1 * Add assertions to major tests *
Remove Consts.java from tests * Add call to get api version and default
domain * Persist fallback domain to database * Add FallbackDomainFetcher to
handle fetch from cache, database and API * Properly receive thrown
exception from dropwizard task execution * Add Mockito for testing mocks *
Add JavaDoc for FallbackDomainFetcher
---
pom.xml | 4 +--
.../wire/bots/hold/FallbackDomainFetcher.java | 9 +++++
src/main/java/com/wire/bots/hold/Service.java | 36 +++++++++++++++----
.../db/migration/V107__add_metadata_table.sql | 4 +--
.../bots/hold/FallbackDomainFetcherTest.java | 2 +-
5 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/pom.xml b/pom.xml
index c255d0e..33772e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,8 +137,8 @@
org.mockito
- mockito-all
- 1.10.19
+ mockito-core
+ 5.14.1
test
diff --git a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
index 58e7a40..40741e9 100644
--- a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
+++ b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
@@ -19,6 +19,12 @@ public class FallbackDomainFetcher implements Runnable {
* Fetches from API and compares against database value (if any), then inserts into database and updates cache value.
* If value received from the API is different from what is saved in the database, a [RuntimeException] is thrown.
*
+ *
+ * This fallback domain is necessary for LegalHold to work with Federation (as it needs id@domain) and not just the ID anymore.
+ * In case there is a mismatch we are throwing a RuntimeException so it stops the execution of this app, so in an event
+ * of already having a defined default domain saved in the database and this app restarts with a different domain
+ * we don't get mismatching domains.
+ *
* @param loginClient [{@link LoginClient}] as API to get backend configuration containing default domain.
* @param metadataDAO [{@link MetadataDAO}] as DAO to get/insert default domain to database.
*
@@ -41,9 +47,12 @@ public void run() {
metadataDAO.insert(MetadataDAO.FALLBACK_DOMAIN_KEY, apiVersionResponse.domain);
Cache.setFallbackDomain(apiVersionResponse.domain);
} else {
+ System.out.println("EEEEEEEE -> " + apiVersionResponse.domain);
if (metadata.value.equals(apiVersionResponse.domain)) {
+ System.out.println("EEEEEEEE -> p1");
Cache.setFallbackDomain(apiVersionResponse.domain);
} else {
+ System.out.println("EEEEEEEE -> p2");
String formattedExceptionMessage = String.format(
"Database already has a default domain as %s and instead we got %s from the Backend API.",
metadata.value,
diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java
index 4b2615f..61a1ed8 100644
--- a/src/main/java/com/wire/bots/hold/Service.java
+++ b/src/main/java/com/wire/bots/hold/Service.java
@@ -55,6 +55,8 @@
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import javax.ws.rs.client.Client;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Service extends Application {
@@ -92,7 +94,7 @@ protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(Config config
}
@Override
- public void run(Config config, Environment environment) {
+ public void run(Config config, Environment environment) throws ExecutionException, InterruptedException {
this.config = config;
this.environment = environment;
Service.metrics = environment.metrics();
@@ -129,17 +131,37 @@ public void run(Config config, Environment environment) {
addResource(ServiceAuthenticationFilter.ServiceAuthenticationFeature.class);
- environment
- .lifecycle()
- .executorService("fallback_domain_fetcher")
- .build()
- .execute(
+// environment
+// .lifecycle()
+// .executorService("fallback_domain_fetcher")
+// .build()
+// .submit(
+// new FallbackDomainFetcher(
+// new LoginClient(httpClient),
+// metadataDAO
+// )
+// );
+
+ Runnable run = new Runnable() {
+ @Override
+ public void run(){
new FallbackDomainFetcher(
new LoginClient(httpClient),
metadataDAO
- )
+ ).run();
+ }
+ };
+
+ final Future> fallbackDomainFetcher = environment
+ .lifecycle()
+ .executorService("fallback_domain_fetcher")
+ .build()
+ .submit(
+ run
);
+ fallbackDomainFetcher.get();
+
environment.healthChecks().register(
"SanityCheck",
new SanityCheck(accessDAO, httpClient)
diff --git a/src/main/resources/db/migration/V107__add_metadata_table.sql b/src/main/resources/db/migration/V107__add_metadata_table.sql
index 86e2406..ef255d4 100644
--- a/src/main/resources/db/migration/V107__add_metadata_table.sql
+++ b/src/main/resources/db/migration/V107__add_metadata_table.sql
@@ -1,4 +1,4 @@
CREATE TABLE Metadata (
- key VARCHAR NOT NULL UNIQUE,
- value VARCHAR NOT NULL
+ key VARCHAR(255) PRIMARY KEY,
+ value VARCHAR(255) NOT NULL
);
diff --git a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
index 0b83ffe..26f9c4c 100644
--- a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
+++ b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
@@ -10,7 +10,7 @@
import org.junit.Before;
import org.junit.Test;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;
From c7e416cda9beeec7ad1581fa703ff6dc902fac8c Mon Sep 17 00:00:00 2001
From: alexandreferris
Date: Mon, 7 Oct 2024 14:59:51 +0200
Subject: [PATCH 5/5] feat(get-domain-from-backend) Use new Helium API to fetch
backend domain * Update Helium to 1.4.1 * Add assertions to major tests *
Remove Consts.java from tests * Add call to get api version and default
domain * Persist fallback domain to database * Add FallbackDomainFetcher to
handle fetch from cache, database and API * Properly receive thrown
exception from dropwizard task execution * Add Mockito for testing mocks *
Add JavaDoc for FallbackDomainFetcher
---
pom.xml | 4 +--
.../wire/bots/hold/FallbackDomainFetcher.java | 9 +++++++
src/main/java/com/wire/bots/hold/Service.java | 25 +++++++++++++------
.../db/migration/V107__add_metadata_table.sql | 4 +--
.../bots/hold/FallbackDomainFetcherTest.java | 2 +-
5 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/pom.xml b/pom.xml
index c255d0e..33772e3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,8 +137,8 @@
org.mockito
- mockito-all
- 1.10.19
+ mockito-core
+ 5.14.1
test
diff --git a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
index 58e7a40..40741e9 100644
--- a/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
+++ b/src/main/java/com/wire/bots/hold/FallbackDomainFetcher.java
@@ -19,6 +19,12 @@ public class FallbackDomainFetcher implements Runnable {
* Fetches from API and compares against database value (if any), then inserts into database and updates cache value.
* If value received from the API is different from what is saved in the database, a [RuntimeException] is thrown.
*
+ *
+ * This fallback domain is necessary for LegalHold to work with Federation (as it needs id@domain) and not just the ID anymore.
+ * In case there is a mismatch we are throwing a RuntimeException so it stops the execution of this app, so in an event
+ * of already having a defined default domain saved in the database and this app restarts with a different domain
+ * we don't get mismatching domains.
+ *
* @param loginClient [{@link LoginClient}] as API to get backend configuration containing default domain.
* @param metadataDAO [{@link MetadataDAO}] as DAO to get/insert default domain to database.
*
@@ -41,9 +47,12 @@ public void run() {
metadataDAO.insert(MetadataDAO.FALLBACK_DOMAIN_KEY, apiVersionResponse.domain);
Cache.setFallbackDomain(apiVersionResponse.domain);
} else {
+ System.out.println("EEEEEEEE -> " + apiVersionResponse.domain);
if (metadata.value.equals(apiVersionResponse.domain)) {
+ System.out.println("EEEEEEEE -> p1");
Cache.setFallbackDomain(apiVersionResponse.domain);
} else {
+ System.out.println("EEEEEEEE -> p2");
String formattedExceptionMessage = String.format(
"Database already has a default domain as %s and instead we got %s from the Backend API.",
metadata.value,
diff --git a/src/main/java/com/wire/bots/hold/Service.java b/src/main/java/com/wire/bots/hold/Service.java
index 4b2615f..dcae767 100644
--- a/src/main/java/com/wire/bots/hold/Service.java
+++ b/src/main/java/com/wire/bots/hold/Service.java
@@ -55,6 +55,8 @@
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import javax.ws.rs.client.Client;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Service extends Application {
@@ -92,7 +94,7 @@ protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(Config config
}
@Override
- public void run(Config config, Environment environment) {
+ public void run(Config config, Environment environment) throws ExecutionException, InterruptedException {
this.config = config;
this.environment = environment;
Service.metrics = environment.metrics();
@@ -129,17 +131,26 @@ public void run(Config config, Environment environment) {
addResource(ServiceAuthenticationFilter.ServiceAuthenticationFeature.class);
- environment
- .lifecycle()
- .executorService("fallback_domain_fetcher")
- .build()
- .execute(
+ Runnable run = new Runnable() {
+ @Override
+ public void run(){
new FallbackDomainFetcher(
new LoginClient(httpClient),
metadataDAO
- )
+ ).run();
+ }
+ };
+
+ final Future> fallbackDomainFetcher = environment
+ .lifecycle()
+ .executorService("fallback_domain_fetcher")
+ .build()
+ .submit(
+ run
);
+ fallbackDomainFetcher.get();
+
environment.healthChecks().register(
"SanityCheck",
new SanityCheck(accessDAO, httpClient)
diff --git a/src/main/resources/db/migration/V107__add_metadata_table.sql b/src/main/resources/db/migration/V107__add_metadata_table.sql
index 86e2406..ef255d4 100644
--- a/src/main/resources/db/migration/V107__add_metadata_table.sql
+++ b/src/main/resources/db/migration/V107__add_metadata_table.sql
@@ -1,4 +1,4 @@
CREATE TABLE Metadata (
- key VARCHAR NOT NULL UNIQUE,
- value VARCHAR NOT NULL
+ key VARCHAR(255) PRIMARY KEY,
+ value VARCHAR(255) NOT NULL
);
diff --git a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
index 0b83ffe..26f9c4c 100644
--- a/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
+++ b/src/test/java/com/wire/bots/hold/FallbackDomainFetcherTest.java
@@ -10,7 +10,7 @@
import org.junit.Before;
import org.junit.Test;
-import static org.mockito.Matchers.any;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;