Skip to content

Commit

Permalink
Merge pull request #298 from finos/spring-bot-develop
Browse files Browse the repository at this point in the history
9.0.0.BETA Release
  • Loading branch information
pankaj-a-khandelwal-db authored Mar 3, 2022
2 parents 5e7b001 + b01838e commit 1a2805b
Show file tree
Hide file tree
Showing 25 changed files with 594 additions and 514 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
*/
package org.finos.springbot.example.todo;

import org.finos.springbot.workflow.annotations.RequiresChatList;
import org.finos.springbot.workflow.annotations.RequiresUserList;
import org.finos.springbot.workflow.annotations.Work;
import org.finos.springbot.workflow.content.Chat;
import org.finos.springbot.workflow.content.User;

/**
Expand All @@ -13,12 +15,20 @@
*/
@Work(index = false)
@RequiresUserList
@RequiresChatList
public class NewItemDetails {


String description;
User assignTo;
Chat room;

public Chat getRoom() {
return room;
}
public void setRoom(Chat room) {
this.room = room;
}
public NewItemDetails() {
super();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* Whether or not to show this command on the help menu
*/
boolean addToHelp() default true;

/**
* Whether this command can be exposed as a button Help Page
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
import org.finos.springbot.teams.form.TeamsFormConverter;
import org.finos.springbot.teams.form.TeamsFormDeserializerModule;
import org.finos.springbot.teams.handlers.TeamsResponseHandler;
import org.finos.springbot.teams.history.AzureBlobStorageTeamsHistory;
import org.finos.springbot.teams.history.MemoryTeamsHistory;
import org.finos.springbot.teams.history.StateStorageBasedTeamsHistory;
import org.finos.springbot.teams.history.StorageIDResponseHandler;
import org.finos.springbot.teams.history.TeamsHistory;
import org.finos.springbot.teams.messages.MessageActivityHandler;
import org.finos.springbot.teams.response.templating.EntityMarkupTemplateProvider;
import org.finos.springbot.teams.state.AzureBlobStateStorage;
import org.finos.springbot.teams.state.TeamsStateStorage;
import org.finos.springbot.teams.templating.adaptivecard.AdaptiveCardConverterConfig;
import org.finos.springbot.teams.templating.adaptivecard.AdaptiveCardTemplateProvider;
import org.finos.springbot.teams.templating.adaptivecard.AdaptiveCardTemplater;
Expand All @@ -37,12 +38,12 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import org.springframework.validation.Validator;

import com.azure.storage.blob.BlobServiceClient;
Expand All @@ -67,7 +68,7 @@
ThymleafEngineConfig.class,
AdaptiveCardConverterConfig.class,
ThymeleafConverterConfig.class,
TeamsConversationsConfig.class
TeamsConversationsConfig.class,
})


Expand Down Expand Up @@ -121,7 +122,7 @@ public TeamsResponseHandler teamsResponseHandler(
EntityMarkupTemplateProvider markupTemplater,
AdaptiveCardTemplateProvider formTemplater,
ThymeleafTemplateProvider displayTemplater,
TeamsHistory th,
TeamsStateStorage th,
TeamsConversations tc) {
return new TeamsResponseHandler(
null, // attachment handler
Expand All @@ -134,32 +135,28 @@ public TeamsResponseHandler teamsResponseHandler(

@Bean
@ConditionalOnMissingBean
public StorageIDResponseHandler teamsStorageIDResponseHandler(TeamsHistory th) {
public StorageIDResponseHandler teamsStorageIDResponseHandler(TeamsStateStorage th) {
return new StorageIDResponseHandler(th);
}


public static enum StorageType { MEMORY, BLOB, DB };


@Bean
@ConditionalOnProperty(name = "teams.storage.type", havingValue = "blob")
@ConditionalOnMissingBean
public TeamsHistory teamsHistory(
@Value("${teams.storage.type:blob}") StorageType st,
public TeamsStateStorage teamsAzureBlobStateStorage(
@Value("${teams.storage.connection-string:}") String blobStorageConnectionString,
@Value("${teams.storage.container:workflow-data}") String container) {

if ((st == StorageType.MEMORY) || !StringUtils.hasText(blobStorageConnectionString)) {
LOG.warn("Not configuring blob storage - using memory to store conversation state. NOT FOR PRODUCTION");
return new MemoryTeamsHistory();
} else if (st == StorageType.BLOB) {
BlobServiceClient c = new BlobServiceClientBuilder()
.connectionString(blobStorageConnectionString)
.buildClient();
BlobServiceClient c = new BlobServiceClientBuilder()
.connectionString(blobStorageConnectionString)
.buildClient();

return new AzureBlobStorageTeamsHistory(c, ejc, container);
} else {
throw new TeamsException("Couldn't configure TeamsHistory with "+st);
}
return new AzureBlobStateStorage(c, ejc, container);
}

@Bean
@ConditionalOnMissingBean
public TeamsHistory teamsHistory(TeamsStateStorage tss) {
return new StateStorageBasedTeamsHistory(tss);
}


Expand All @@ -179,9 +176,9 @@ public MessageActivityHandler teamsMessageActivityHandler(
TeamsHTMLParser parser,
FormValidationProcessor fvp,
TeamsConversations tc,
TeamsHistory th,
TeamsStateStorage teamsStateStorage,
TeamsFormConverter fc) {
return new MessageActivityHandler(messageConsumers, tc, th, parser, fc, fvp);
return new MessageActivityHandler(messageConsumers, tc, teamsStateStorage, parser, fc, fvp);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import org.finos.springbot.workflow.content.Tag;
import org.finos.springbot.workflow.content.User;

import com.fasterxml.jackson.annotation.JsonIncludeProperties;

@Work(index = false)
public final class TeamsUser implements User, TeamsMention, TeamsAddressable {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

Expand All @@ -14,11 +13,8 @@
import org.finos.springbot.teams.content.TeamsMultiwayChat;
import org.finos.springbot.teams.content.TeamsUser;
import org.finos.springbot.teams.turns.CurrentTurnContext;
import org.finos.springbot.workflow.content.Addressable;
import org.finos.springbot.workflow.content.Chat;
import org.finos.springbot.workflow.content.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.microsoft.bot.builder.BotFrameworkAdapter;
import com.microsoft.bot.builder.TurnContext;
Expand All @@ -33,15 +29,22 @@
import com.microsoft.bot.schema.ConversationReference;
import com.microsoft.bot.schema.ResourceResponse;

public class TeamsConversationsImpl implements TeamsConversations {

private static final Logger LOG = LoggerFactory.getLogger(TeamsConversationsImpl.class);
/**
* Teams doesn't seem to support lookup of the list of conversations a bot is
* involved in, which makes it impossible to write getAllAddressables().
*
* This is left as a problem for the subclass ;)
*
* @author [email protected]
*
*/
public abstract class AbstractTeamsConversations implements TeamsConversations {

private MicrosoftAppCredentials mac;
private BotFrameworkAdapter bfa;
private ChannelAccount botAccount;

public TeamsConversationsImpl(BotFrameworkAdapter bfa, MicrosoftAppCredentials mac, ChannelAccount botAccount) {
public AbstractTeamsConversations(BotFrameworkAdapter bfa, MicrosoftAppCredentials mac, ChannelAccount botAccount) {
super();
this.mac = mac;
this.bfa = bfa;
Expand All @@ -65,29 +68,6 @@ public boolean isSupported(User u) {
return u instanceof TeamsUser;
}

@Override
public Set<Addressable> getAllAddressables() {
try {
return getConversations().getConversations().get().getConversations().stream()
.map(c -> new TeamsMultiwayChat(c.getId(), ""))
.collect(Collectors.toSet());
} catch (Exception e) {
throw new TeamsException("Couldn't do getAllAddressables", e);
}
}

@Override
public Set<TeamsChat> getAllChats() {
// TODO Auto-generated method stub
return null;
}

@Override
public TeamsChat getExistingChat(String name) {
// TODO Auto-generated method stub
return null;
}

@Override
public TeamsChat ensureChat(TeamsChat r, List<TeamsUser> users, Map<String, Object> meta) {
// TODO Auto-generated method stub
Expand Down Expand Up @@ -237,9 +217,12 @@ private TurnContext getWorkingTurnContext(TeamsAddressable ta) {

public CompletableFuture<ResourceResponse> handleActivity(Activity activity, TeamsAddressable to) {
TurnContext ctx = getWorkingTurnContext(to);
ensureRoomRecorded(to);
return ctx.sendActivity(activity);
}

protected abstract void ensureRoomRecorded(TeamsAddressable to);

private ConversationReference createConversationReference(TeamsAddressable address) {
ConversationAccount ca = address == null ? null : getConversationAccount(address);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package org.finos.springbot.teams.conversations;

import static org.finos.springbot.teams.state.TeamsStateStorage.ADDRESSABLE_KEY;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.finos.springbot.entityjson.EntityJson;
import org.finos.springbot.teams.content.TeamsAddressable;
import org.finos.springbot.teams.content.TeamsChat;
import org.finos.springbot.teams.history.StateStorageBasedTeamsHistory;
import org.finos.springbot.teams.state.TeamsStateStorage;
import org.finos.springbot.teams.state.TeamsStateStorage.Filter;
import org.finos.springbot.workflow.content.Addressable;
import org.finos.springbot.workflow.content.Chat;

import com.microsoft.bot.builder.BotFrameworkAdapter;
import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
import com.microsoft.bot.schema.ChannelAccount;

public class StateStorageBasedTeamsConversations extends AbstractTeamsConversations {

public static final String ADDRESSABLE_INFO = "addressable-info";
public static final String ADDRESSABLE_TYPE = "addressable-type";
public static final String CHAT = "chat";
public static final String USER = "user";


protected final TeamsStateStorage tss;

public StateStorageBasedTeamsConversations(BotFrameworkAdapter bfa, MicrosoftAppCredentials mac,
ChannelAccount botAccount, TeamsStateStorage tss) {
super(bfa, mac, botAccount);
this.tss = tss;
}

@Override
public Set<Addressable> getAllAddressables() {
List<Filter> filters = new ArrayList<>();
filters.add(new Filter(ADDRESSABLE_INFO));
Iterable<Map<String, Object>> it = tss.retrieve(filters, false);
return new HashSet<>(StateStorageBasedTeamsHistory.findObjectsFromItems(Addressable.class, it));
}

@Override
public Set<TeamsChat> getAllChats() {
List<Filter> filters = new ArrayList<>();
filters.add(new Filter(ADDRESSABLE_INFO));
filters.add(new Filter(ADDRESSABLE_TYPE, CHAT, "="));
Iterable<Map<String, Object>> it = tss.retrieve(filters, false);
return new HashSet<>(StateStorageBasedTeamsHistory.findObjectsFromItems(TeamsChat.class, it));
}

@Override
public TeamsChat getExistingChat(String name) {
return getAllChats().stream()
.filter(tc -> tc.getName().equals(name))
.findFirst()
.orElse(null);
}

@Override
protected void ensureRoomRecorded(TeamsAddressable to) {
String file = to.getKey()+"/addressable";

Optional<Map<String, Object>> data = tss.retrieve(file);

if (!data.isPresent()) {
Map<String, String> tags = new HashMap<>();
tags.put(ADDRESSABLE_INFO, TeamsStateStorage.PRESENT);
tags.put(ADDRESSABLE_TYPE, to instanceof Chat ? CHAT : USER);
tags.put(ADDRESSABLE_KEY, to.getKey());
EntityJson ej = new EntityJson();
ej.put(ADDRESSABLE_INFO, to);
tss.store(file, tags, ej);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Properties;

import org.finos.springbot.teams.state.TeamsStateStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand Down Expand Up @@ -32,9 +33,10 @@ public MicrosoftAppCredentials microsoftCredentials(@Value("${teams.app.tennantI
public TeamsConversations teamsConversations(
BotFrameworkAdapter bfa,
MicrosoftAppCredentials mac,
@Value("${teams.bot.id:}") String id) {
@Value("${teams.bot.id:}") String id,
TeamsStateStorage teamsState) {
ChannelAccount botAccount = new ChannelAccount(id);
return new TeamsConversationsImpl(bfa, mac, botAccount);
return new StateStorageBasedTeamsConversations(bfa, mac, botAccount, teamsState);
}


Expand Down
Loading

0 comments on commit 1a2805b

Please sign in to comment.