Browse Source

Initial code import from Azure

main
Inga 🏳‍🌈 2 years ago
parent
commit
3fd3e62576
  1. 70
      PostDeployScripts/prepareSrc.cmd
  2. 30
      PostDeployScripts/runGulp.cmd
  3. 10
      commands.json
  4. 23
      debughost.cmd
  5. 1
      host.json
  6. 9
      messages/Tools.csx
  7. 25
      messages/UserEntity.csx
  8. 87
      messages/UserInfo.csx
  9. 54
      messages/UserSympathiesRepository.csx
  10. 32
      messages/UserSympathyEntity.csx
  11. 63
      messages/UsersMutexService.csx
  12. 26
      messages/UsersRepository.csx
  13. 16
      messages/function.json
  14. 9
      messages/project.json
  15. 423
      messages/run.csx
  16. 0
      publish.cmd

70
PostDeployScripts/prepareSrc.cmd

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
@echo off
setlocal
SET password=%1
SET repoName=srcRepo
SET repoUrl=file:///%HOMEDRIVE:~0,1%/%HOMEPATH:~1%/site/%repoName%
SET download=bot-src
echo %repoUrl%
rem cd to project root
pushd ..\wwwroot
rem init git
call git init
call git config user.name "botframework"
call git config user.email "util@botframework.com"
call git add .
call git commit -m "prepare to download source"
call git remote add srcRepo %repoUrl%
popd
rem init upstream
pushd %HOME%\site
mkdir srcRepo
cd srcRepo
call git init --bare
popd
rem push to upstream
pushd ..\wwwroot
call git push --set-upstream srcRepo master
popd
rem clone srcRepo
pushd %HOME%\site
call git clone %repoUrl% %download%
rem delete .git
cd %download%
call rm -r -f .git
popd
rem prepare for publish
pushd %HOME%\site\%download%
mkdir Properties\PublishProfiles
pushd Properties\PublishProfiles
type ..\..\PostDeployScripts\publishProfile.xml.template | sed -e s/\{WEB_SITE_NAME\}/%WEBSITE_SITE_NAME%/g > %WEBSITE_SITE_NAME%-Web-Deploy.pubxml
popd
set SOLUTION_NAME=
for /f "delims=" %%a in ('dir /b *.sln') do @set SOLUTION_NAME=%%a
type PostDeployScripts\publish.cmd.template | sed -e s/\{SOLUTION_NAME\}/%SOLUTION_NAME%/g | sed -e s/\{PUBLISH_PROFILE\}/%WEBSITE_SITE_NAME%-Web-Deploy.pubxml/g | sed -e s/\{PASSWORD\}/%password%/g > publish.cmd
type PostDeployScripts\publishSettings.xml.template | sed -e s/\{WEB_SITE_NAME\}/%WEBSITE_SITE_NAME%/g | sed -e s/\{PASSWORD\}/%password%/g > PostDeployScripts\%WEBSITE_SITE_NAME%.PublishSettings
popd
rem preare the zip file
%HOMEDRIVE%\7zip\7za a %HOME%\site\%download%.zip %HOME%\site\%download%\*
rem cleanup git stuff
pushd ..\wwwroot
call rm -r -f .git
popd
pushd %HOME%\site
call rm -r -f %download%
call rm -r -f %repoName%
popd
endlocal

30
PostDeployScripts/runGulp.cmd

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
@echo off
setlocal
rem enumerate each folder under root and check for existence of gulpfile.cs
rem if gulpfile exists, run the default gulp task
for /d %%d in (..\wwwroot\*) do (
echo check %%d
pushd %%d
if exist package.json (
echo npm install --production
call npm install --production
) else (
echo no package.json found
)
if exist gulpfile.js (
echo run gulp
gulp
) else (
echo no gulpfile.js found
)
popd
)
echo record deployment timestamp
date /t >> ..\deployment.log
time /t >> ..\deployment.log
echo ---------------------- >> ..\deployment.log
echo Deployment done

10
commands.json

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
{
"commands": {
"debughost": {
"fileName": "cmd.exe",
"workingDirectory": ".",
"arguments": "/c debughost.cmd"
}
},
"-vs-binding": { "ProjectOpened": [ "debughost" ] }
}

23
debughost.cmd

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
@echo off
set size=0
call func settings list -data > %temp%\settings-list
call :filesize %temp%\settings-list
if NOT %size% == 0 goto show
@echo ----------------------------------------------------------------------
@echo To fetch your bot service settings run the following command:
@echo func azure functionapp fetch-app-settings [YOUR_BOT_SERVICE_NAME]
@echo ----------------------------------------------------------------------
goto start
:show
type %temp%\settings-list
erase %temp%\settings-list
:start
@func host start -p 3978
goto :eof
:filesize
set size=%~z1
exit /b 0

1
host.json

@ -0,0 +1 @@ @@ -0,0 +1 @@
{}

9
messages/Tools.csx

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using Microsoft.Bot.Connector;
public static class Tools
{
public static string FormatUserId(string channelId, ChannelAccount user)
{
return $"{channelId.Length}_{channelId}_{user.Id}";
}
}

25
messages/UserEntity.csx

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
#r "Newtonsoft.Json"
#load "Tools.csx"
using Newtonsoft.Json;
using Microsoft.Bot.Connector;
using Microsoft.WindowsAzure.Storage.Table;
public class UserEntity : TableEntity
{
public UserEntity() {}
public UserEntity(Activity activity, UserInfo userInfo) : base(userInfo.Key, "_")
{
this.RawUserInfo = JsonConvert.SerializeObject(userInfo);
this.RawOriginalActivity = JsonConvert.SerializeObject(activity);
}
public string RawUserInfo { get; set; }
public string RawOriginalActivity { get; set; }
public UserInfo UserInfo => JsonConvert.DeserializeObject<UserInfo>(this.RawUserInfo);
public Activity OriginalActivity => JsonConvert.DeserializeObject<Activity>(this.RawOriginalActivity);
}

87
messages/UserInfo.csx

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
#r "Newtonsoft.Json"
using System.Xml.Linq;
using Microsoft.Bot.Connector;
using Newtonsoft.Json;
public class UserInfo
{
public UserInfo()
{
}
public static UserInfo CreateFromTelegramChannelData(string channel, dynamic infoFromChannelData)
{
var userInfo = new UserInfo
{
Channel = channel,
Id = infoFromChannelData.id?.ToString(),
Name = infoFromChannelData.username?.ToString(),
FirstName = infoFromChannelData.first_name?.ToString(),
LastName = infoFromChannelData.last_name?.ToString(),
};
if (string.IsNullOrEmpty(userInfo.Channel))
{
throw new System.ArgumentNullException("channel");
}
if (string.IsNullOrEmpty(userInfo.Id))
{
throw new System.ArgumentNullException("id");
}
return userInfo;
}
public static UserInfo CreateFromTelegramFrom(Activity activity)
{
return CreateFromTelegramChannelData(activity.ChannelId, ((dynamic)activity.ChannelData).message.@from);
}
public static UserInfo CreateFromTelegramForwardedFrom(Activity activity)
{
return CreateFromTelegramChannelData(activity.ChannelId, ((dynamic)activity.ChannelData).message.forward_from);
}
[JsonProperty(PropertyName = "channel")]
public string Channel { get; set; }
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "first_name")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "last_name")]
public string LastName { get; set; }
[JsonIgnore]
public string Key => $"{this.Channel.Length}_{this.Channel}_{this.Id}";
[JsonIgnore]
public ChannelAccount ChannelAccount => new ChannelAccount(id: this.Id, name: this.Name);
public override string ToString()
{
if (!string.IsNullOrEmpty(this.Name))
{
return $"@{this.Name}";
}
return string.Join(" ", new[] { this.FirstName, this.LastName });
}
public XNode ToTelegramHtml()
{
if (!string.IsNullOrEmpty(this.Name))
{
return new XText(this.ToString());
}
return new XElement("a", new XAttribute("href", string.Empty/*$"tg://user?id={this.Id}"*/), this.ToString());
}
}

54
messages/UserSympathiesRepository.csx

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
#load "Tools.csx"
#load "UserSympathyEntity.csx"
using Microsoft.Bot.Connector;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
public class UserSympathiesRepository
{
private CloudTable UserSympathiesTable { get; }
public UserSympathiesRepository(CloudTable userSympathiesTable)
{
this.UserSympathiesTable = userSympathiesTable;
}
public async Task AddSympathy(UserSympathyEntity entity)
{
var insertOperation = TableOperation.Insert(entity);
await this.UserSympathiesTable.ExecuteAsync(insertOperation);
}
public UserSympathyEntity[] GetAllSympathies(UserInfo user)
{
var key = user.Key;
var condition = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, key);
var query = new TableQuery<UserSympathyEntity>().Where(condition);
var result = this.UserSympathiesTable.ExecuteQuery(query);
return result.ToArray();
}
public async Task<UserSympathyEntity> GetSympathyIfExists(string sourceKey, string targetKey)
{
var retrieveOperation = TableOperation.Retrieve<UserSympathyEntity>(sourceKey, targetKey);
var retrievedResult = await this.UserSympathiesTable.ExecuteAsync(retrieveOperation);
return (UserSympathyEntity)(retrievedResult?.Result);
}
public async Task<UserSympathyEntity> GetSympathyIfExists(UserInfo source, string targetKey)
{
return await GetSympathyIfExists(source.Key, targetKey);
}
public async Task<UserSympathyEntity> GetSympathyIfExists(UserInfo source, UserInfo target)
{
return await GetSympathyIfExists(source, target.Key);
}
public async Task DeleteSympathy(UserSympathyEntity entity)
{
var deleteOperation = TableOperation.Delete(entity);
await this.UserSympathiesTable.ExecuteAsync(deleteOperation);
}
}

32
messages/UserSympathyEntity.csx

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
#r "Newtonsoft.Json"
#load "Tools.csx"
#load "UserInfo.csx"
using Newtonsoft.Json;
using Microsoft.Bot.Connector;
using Microsoft.WindowsAzure.Storage.Table;
public class UserSympathyEntity : TableEntity
{
public UserSympathyEntity() {}
public UserSympathyEntity(Activity activity, UserInfo sympathySource, UserInfo sympathyTarget)
: base(sympathySource.Key, sympathyTarget.Key)
{
this.RawUserInfo = JsonConvert.SerializeObject(sympathySource);
this.RawOriginalActivity = JsonConvert.SerializeObject(activity);
this.RawSympathyTarget = JsonConvert.SerializeObject(sympathyTarget);
}
public string RawUserInfo { get; set; }
public string RawOriginalActivity { get; set; }
public string RawSympathyTarget { get; set; }
public UserInfo UserInfo => JsonConvert.DeserializeObject<UserInfo>(this.RawUserInfo);
public Activity OriginalActivity => JsonConvert.DeserializeObject<Activity>(this.RawOriginalActivity);
public UserInfo SympathyTargetInfo => JsonConvert.DeserializeObject<UserInfo>(this.RawSympathyTarget);
}

63
messages/UsersMutexService.csx

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
#load "UserEntity.csx"
using System;
using Microsoft.Bot.Connector;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
public class UsersMutexService
{
public interface IMutex
{
Task Leave();
}
private class TableMutex : IMutex
{
private CloudTable Table { get; }
private TableEntity Entity { get; }
public TableMutex(CloudTable table, TableEntity entity)
{
this.Table = table;
this.Entity = entity;
}
public async Task Leave()
{
var operation = TableOperation.Delete(this.Entity);
await this.Table.ExecuteAsync(operation);
}
}
private CloudTable UsersMutexTable { get; }
public UsersMutexService(CloudTable usersMutexTable)
{
this.UsersMutexTable = usersMutexTable;
}
public async Task<IMutex> Enter(Activity activity)
{
var newEntity = new TableEntity(Tools.FormatUserId(activity.ChannelId, activity.From), "_");
var retrieveOperation = TableOperation.Retrieve<TableEntity>(newEntity.PartitionKey, newEntity.RowKey);
var oldEntityUntyped = (await this.UsersMutexTable.ExecuteAsync(retrieveOperation)).Result;
if (oldEntityUntyped != null)
{
var oldEntity = (TableEntity)oldEntityUntyped;
if (oldEntity.Timestamp.AddHours(1) < DateTimeOffset.UtcNow)
{
var deleteOperation = TableOperation.Delete(oldEntity);
await this.UsersMutexTable.ExecuteAsync(deleteOperation);
}
}
var insertOperation = TableOperation.Insert(newEntity);
await this.UsersMutexTable.ExecuteAsync(insertOperation);
var savedEntity = (await this.UsersMutexTable.ExecuteAsync(retrieveOperation)).Result;
return new TableMutex(this.UsersMutexTable, (TableEntity)savedEntity);
}
}

26
messages/UsersRepository.csx

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
#load "UserEntity.csx"
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
public class UsersRepository
{
private CloudTable UsersTable { get; }
public UsersRepository(CloudTable usersTable)
{
this.UsersTable = usersTable;
}
public async Task AddUser(UserEntity entity)
{
var insertOperation = TableOperation.InsertOrReplace(entity);
await this.UsersTable.ExecuteAsync(insertOperation);
}
public UserEntity[] GetAllUsers()
{
var result = this.UsersTable.ExecuteQuery(new TableQuery<UserEntity>());
return result.ToArray();
}
}

16
messages/function.json

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"webHookType": "genericJson",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"disabled": false
}

9
messages/project.json

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
{
"frameworks": {
"net46":{
"dependencies": {
"Microsoft.Bot.Builder.Azure": "3.2.5"
}
}
}
}

423
messages/run.csx

@ -0,0 +1,423 @@ @@ -0,0 +1,423 @@
#r "Newtonsoft.Json"
#r "System.Xml.Linq"
#load "UserEntity.csx"
#load "UserInfo.csx"
#load "UsersRepository.csx"
#load "UsersMutexService.csx"
#load "UserSympathyEntity.csx"
#load "UserSympathiesRepository.csx"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
using Microsoft.WindowsAzure.Storage;
private static async Task ReplyWithChannelData(ConnectorClient client, Activity originalActivity, object channelData)
{
var reply = originalActivity.CreateReply();
reply.ChannelData = JsonConvert.SerializeObject(channelData);
//reply.Text = "```" + Environment.NewLine + JsonConvert.SerializeObject(channelData) + Environment.NewLine + "```";
await client.Conversations.ReplyToActivityAsync(reply);
}
private static async Task ReplyWithVideoHtml(ConnectorClient client, Activity originalActivity, string fileId, object[] xNodes)
{
var document = new XDocument(new XElement("Root", xNodes));
var flattenedNodes = document.Root.Nodes();
await ReplyWithChannelData(client, originalActivity, new {
@method = "sendDocument",
parameters = new
{
document = fileId,
caption = string.Join(string.Empty, flattenedNodes.Select(node => node.ToString(SaveOptions.DisableFormatting))),
parse_mode = "HTML",
},
});
}
private static async Task ReplyWithBigHugHtml(ConnectorClient client, Activity originalActivity, params object[] xNodes)
{
await ReplyWithVideoHtml(client, originalActivity, "CgADBAADFKAAApcdZAdWXtXmanu6FAI", xNodes);
}
private static async Task ReplyWithNowKissHtml(ConnectorClient client, Activity originalActivity, params object[] xNodes)
{
await ReplyWithVideoHtml(client, originalActivity, "CgADBQADYgADPh0YVIDk_Yb299_TAg", xNodes);
}
private static async Task ReplyWithHtml(ConnectorClient client, Activity originalActivity, params object[] xNodes)
{
var document = new XDocument(new XElement("Root", xNodes));
var flattenedNodes = document.Root.Nodes();
await ReplyWithChannelData(client, originalActivity, new {
@method = "sendMessage",
parameters = new
{
text = string.Join(string.Empty, flattenedNodes.Select(node => node.ToString(SaveOptions.DisableFormatting))),
parse_mode = "HTML",
},
});
}
private static async Task ReplyWithMarkdown(ConnectorClient client, Activity originalActivity, string md)
{
await ReplyWithChannelData(client, originalActivity, new {
@method = "sendMessage",
parameters = new
{
text = md,
parse_mode = "Markdown",
},
});
}
private static async Task RunForSympathyMessage(
ConnectorClient client,
Activity activity,
UserInfo sympathySource,
UserInfo sympathyTarget,
UserSympathiesRepository userSympathiesRepository,
UserSympathiesRepository mutualSympathiesRepository,
TraceWriter log)
{
if (sympathySource.Key == sympathyTarget.Key)
{
await ReplyWithMarkdown(client, activity, "Nope");
return;
}
var existingSympathy = await userSympathiesRepository.GetSympathyIfExists(sympathySource, sympathyTarget);
var existingMutualSympathy = await mutualSympathiesRepository.GetSympathyIfExists(sympathySource, sympathyTarget);
if (existingSympathy != null || existingMutualSympathy != null)
{
var reply0 = activity.CreateReply("You have already registered your sympathy for this person");
await client.Conversations.ReplyToActivityAsync(reply0);
return;
}
var existingSympathies = userSympathiesRepository.GetAllSympathies(sympathySource);
if (existingSympathies.Length >= 10)
{
var reply0 = activity.CreateReply("You have registered too many sympathies; try removing some");
await client.Conversations.ReplyToActivityAsync(reply0);
return;
}
var sympathyEntity = new UserSympathyEntity(activity, sympathySource, sympathyTarget);
var reverseSympathy = await userSympathiesRepository.GetSympathyIfExists(sympathyTarget, sympathySource);
if (reverseSympathy != null)
{
var reverseActivity = reverseSympathy.OriginalActivity;
await ReplyWithNowKissHtml(client, activity, new XText($"Your sympathy to {sympathyTarget} is mutual!"));
await ReplyWithNowKissHtml(client, reverseActivity, new XText($"Your sympathy to {sympathySource} is mutual!"));
await mutualSympathiesRepository.AddSympathy(sympathyEntity);
await userSympathiesRepository.DeleteSympathy(reverseSympathy);
await mutualSympathiesRepository.AddSympathy(reverseSympathy);
var sourceMutualSympathies = mutualSympathiesRepository.GetAllSympathies(sympathySource);
var targetMutualSympathies = mutualSympathiesRepository.GetAllSympathies(sympathyTarget);
foreach (var commonMutual in sourceMutualSympathies.Select(s => s.RowKey).Intersect(targetMutualSympathies.Select(s => s.RowKey)))
{
var commonSympathy = await mutualSympathiesRepository.GetSympathyIfExists(commonMutual, sympathySource.Key);
var commonUserInfo = commonSympathy.UserInfo;
var text = $"Good news, {sympathySource}, {sympathyTarget}, {commonUserInfo}! You all like each other!";
await ReplyWithBigHugHtml(client, activity, new XText(text));
await ReplyWithBigHugHtml(client, reverseActivity, new XText(text));
await ReplyWithBigHugHtml(client, commonSympathy.OriginalActivity, new XText(text));
}
return;
}
await userSympathiesRepository.AddSympathy(sympathyEntity);
await ReplyWithHtml(client, activity, new XText($"You have forwarded message from {sympathyTarget} ({sympathyTarget.Id}). And you are {sympathySource} ({sympathySource.Id}). Sympathy logged!"));
}
private static IEnumerable<XNode> GetDescriptionForList(UserSympathyEntity sympathy)
{
yield return sympathy.SympathyTargetInfo.ToTelegramHtml();
yield return new XText($", added on {sympathy.Timestamp}.");
if (sympathy.Timestamp.AddDays(7) < DateTimeOffset.UtcNow)
{
yield return new XText(Environment.NewLine);
yield return new XElement("i", $"Forget:");
yield return new XText($" /forget_{sympathy.RowKey}");
}
}
private static async Task RunForList(
ConnectorClient client,
Activity activity,
UserInfo user,
UserSympathiesRepository userSympathiesRepository,
UserSympathiesRepository mutualSympathiesRepository,
TraceWriter log)
{
var nodes = new List<object>();
var sympathies = userSympathiesRepository.GetAllSympathies(user);
if (sympathies.Length == 0)
{
nodes.Add(new XElement("b", "You have no registered non-mutual sympathies"));
}
else
{
nodes.Add(new XElement("b", "Current sympathies"));
nodes.AddRange(sympathies.Select(sympathy => Enumerable.Repeat((XNode)(new XText(Environment.NewLine)), 2).Concat(GetDescriptionForList(sympathy))));
}
var mutuals = mutualSympathiesRepository.GetAllSympathies(user);
if (mutuals.Length != 0)
{
nodes.Add(new XText(Environment.NewLine));
nodes.Add(new XText(Environment.NewLine));
nodes.Add(new XElement("b", "Mutual sympathies"));
nodes.AddRange(mutuals.Select(sympathy => Enumerable.Repeat((XNode)(new XText(Environment.NewLine)), 1).Concat(GetDescriptionForList(sympathy))));
}
await ReplyWithHtml(client, activity, nodes);
}
private static async Task RunForDelete(ConnectorClient client, Activity activity, UserInfo user, string sympathyTargetKey, UserSympathiesRepository userSympathiesRepository, UserSympathiesRepository mutualSympathiesRepository, TraceWriter log)
{
var existingSympathy = await userSympathiesRepository.GetSympathyIfExists(user, sympathyTargetKey);
if (existingSympathy.Timestamp.AddDays(7) >= DateTimeOffset.UtcNow)
{
var reply0 = activity.CreateReply("You have to wait 30 days until you can forget this sympathy");
await client.Conversations.ReplyToActivityAsync(reply0);
return;
}
await userSympathiesRepository.DeleteSympathy(existingSympathy);
await RunForList(client, activity, user, userSympathiesRepository, mutualSympathiesRepository, log);
}
private static async Task RunForBroadcastMessage(ConnectorClient client, Activity activity, string broadcastText, UsersRepository usersRepository, TraceWriter log)
{
if (activity.From.Id.ToString() != "812607159")
{
var reply0 = activity.CreateReply();
reply0.Text = $"Nice try, {activity.From.Name}";
await client.Conversations.ReplyToActivityAsync(reply0);
return;
}
var messagesSent = 0;
List<string> usersFailed = new List<string>();
foreach (var userEntity in usersRepository.GetAllUsers())
{
var broadcastReply = userEntity.OriginalActivity.CreateReply($"Message from @{activity.From.Name}: {broadcastText}");
try
{
await client.Conversations.ReplyToActivityAsync(broadcastReply);
messagesSent++;
}
catch (Exception)
{
usersFailed.Add(userEntity.UserInfo.ToString());
}
}
var reply = activity.CreateReply($"Message broadcast sent to {messagesSent} users: {broadcastText}");
await client.Conversations.ReplyToActivityAsync(reply);
if (usersFailed.Any())
{
reply = activity.CreateReply($"Failed to send message to {usersFailed.Count} users: {string.Join(",", usersFailed)}");
await client.Conversations.ReplyToActivityAsync(reply);
}
}
private static async Task RunForSimpleMessage(ConnectorClient client, Activity activity, TraceWriter log)
{
//await ReplyWithMarkdown(client, activity, $"```{Environment.NewLine}{JsonConvert.SerializeObject(activity)}{Environment.NewLine}```");
await ReplyWithHtml(client, activity, new XText("Forward me someone else's message"));
}
private static async Task RunForHelp(ConnectorClient client, Activity activity, TraceWriter log)
{
await ReplyWithHtml(
client,
activity,
new [] {
new XText("Forward me someone else's message, and I'll remember that you like them (you can make me forget about that by using commands from /list)"),
new XText(Environment.NewLine),
new XText("Once they will forward me your message, I'll notify both of you that you like each other! Until then, I will keep silence."),
new XText(Environment.NewLine),
new XText("What's more, if you two have some common person with mutual sympathies between all three of you, I'll notify all three about that!"),
new XText(Environment.NewLine),
new XText(Environment.NewLine),
new XText("The idea behind this bot is that: there is a lot of introverted/shy people, who don't want to inform their crush of the feelings towards them in case these feelings are not mutual. This can result in two people having feelings toward each other, with both being afraid of expressing their feeling because each of them is not sure if other will reciprocate."),
new XText(Environment.NewLine),
new XText("The bot attempts to solve this problem, working as an escrow for people's \"feelings\", so that: (a) if two people like each other, bot will inform both of them of their feelings, and (b) if a person X likes person Y, and the feeling is not returned, bot will keep X's secret."),
new XText(Environment.NewLine),
new XText("There are also basic abuse protections in place: the number of non-mutual sympathies one can express at a time is limited, and there is a reverse cooling-off period, during which a fresh sympathy cannot be cancelled. These limitations are intended to prevent malicious user to brute-force who likes them and who doesn't."),
new XText(Environment.NewLine),
new XText(Environment.NewLine),
new XText("If you have any feedback or suggestions, feel free to contact my creator @inga_lovinde"),
});
}
private static async Task RunForMessage(
Activity activity,
UsersRepository usersRepository,
UserSympathiesRepository userSympathiesRepository,
UserSympathiesRepository mutualSympathiesRepository,
UsersMutexService usersMutexService,
TraceWriter log)
{
var client = new ConnectorClient(new Uri(activity.ServiceUrl));
if (activity.ChannelId != "telegram")
{
var reply = activity.CreateReply();
reply.Text = $"Only telegram is supported at the moment, and you're using {activity.ChannelId}";
await client.Conversations.ReplyToActivityAsync(reply);
return;
}
var userInfo = UserInfo.CreateFromTelegramFrom(activity);
await usersRepository.AddUser(new UserEntity(activity, userInfo));
var mutex = await usersMutexService.Enter(activity);
try
{
//var replyDebug = activity.CreateReply("Debug: " + Environment.NewLine + "```" + Environment.NewLine + JsonConvert.SerializeObject(activity) + Environment.NewLine + "```");
//await client.Conversations.ReplyToActivityAsync(replyDebug);
var forwardedFrom = ((dynamic)activity.ChannelData)?.message?.forward_from;
if (forwardedFrom != null)
{
await RunForSympathyMessage(
client,
activity,
userInfo,
UserInfo.CreateFromTelegramForwardedFrom(activity),
userSympathiesRepository,
mutualSympathiesRepository,
log);
return;
}
var text = activity?.Text ?? string.Empty;
if (text == "/help")
{
await RunForHelp(client, activity, log);
}
else if (text == "/list")
{
await RunForList(
client,
activity,
userInfo,
userSympathiesRepository,
mutualSympathiesRepository,
log);
}
else if (text.StartsWith("/forget_"))
{
await RunForDelete(
client,
activity,
userInfo,
text.Substring(8),
userSympathiesRepository,
mutualSympathiesRepository,
log);
}
else if (text.StartsWith("/broadcast "))
{
await RunForBroadcastMessage(
client,
activity,
text.Substring(11),
usersRepository,
log);
}
else
{
await RunForSimpleMessage(client, activity, log);
}
}
/*catch (Exception e) {
var replyDebug = activity.CreateReply("Error:" + Environment.NewLine + "```" + Environment.NewLine + JsonConvert.SerializeObject(activity) + Environment.NewLine + "```" + Environment.NewLine + Environment.NewLine + "```" + e + "```");
await client.Conversations.ReplyToActivityAsync(replyDebug);
}*/
finally
{
await mutex.Leave();
}
}
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log)
{
// Initialize the azure bot
using (BotService.Initialize())
{
// Deserialize the incoming activity
string jsonContent = await req.Content.ReadAsStringAsync();
var activity = JsonConvert.DeserializeObject<Activity>(jsonContent);
if (activity.GetActivityType() != "trigger" && activity.GetActivityType() != ActivityTypes.ConversationUpdate)
{
log.Info($"Webhook was triggered! Content: " + jsonContent);
}
// authenticate incoming request and add activity.ServiceUrl to MicrosoftAppCredentials.TrustedHostNames
// if request is authenticated
if (!await BotService.Authenticator.TryAuthenticateAsync(req, new [] {activity}, CancellationToken.None))
{
return BotAuthenticator.GenerateUnauthorizedResponse(req);
}
if (activity != null)
{
var storageAccount = CloudStorageAccount.Parse(Utils.GetAppSetting("AzureWebJobsStorage"));
var tableClient = storageAccount.CreateCloudTableClient();
var usersRepository = new UsersRepository(tableClient.GetTableReference("sympathyBotUsers"));
var userSympathiesRepository = new UserSympathiesRepository(tableClient.GetTableReference("sympathyBotUserSympathies"));
var mutualSympathiesRepository = new UserSympathiesRepository(tableClient.GetTableReference("sympathyBotMutualUserSympathies"));
var usersMutexService = new UsersMutexService(tableClient.GetTableReference("sympathyBotUserMutexes"));
// one of these will have an interface and process it
switch (activity.GetActivityType())
{
case ActivityTypes.Message:
await RunForMessage(
activity,
usersRepository,
userSympathiesRepository,
mutualSympathiesRepository,
usersMutexService,
log);
break;
case ActivityTypes.ConversationUpdate:
case ActivityTypes.Event:
case ActivityTypes.ContactRelationUpdate:
case ActivityTypes.Typing:
case ActivityTypes.DeleteUserData:
case ActivityTypes.Ping:
default:
log.Error($"Unknown activity type ignored: {activity.GetActivityType()}");
break;
}
}
return req.CreateResponse(HttpStatusCode.Accepted);
}
}

0
publish.cmd

Loading…
Cancel
Save