Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Werewolf for Telegram/Werewolf Control/Commands/GeneralCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,44 @@ public static void Start(Update u, string[] args)
return;
}

// check for force join
bool isForceJoin = false;
if (args[1].StartsWith("forcejoin"))
{
isForceJoin = true;
// remove "force" from starting, so below if statement work for force join also
args[1] = args[1].Substring("force".Length);
}

// handle join command
if (args[1].StartsWith("join") && args[1].Length == 48) // 4 "join" + 22 node id + 22 game id
{
// check if user have validate name
bool isValid;
string msg;
(isValid, msg) = ValidatePlayerName(p.Name);
if(!isValid && !isForceJoin)
{


// TODO: move to string xml file for translation support
string warningMsg = "⚠️ If you join the game using the button below, you can join successfully, " +
"but you may receive a warning if your name is unreadable or invalid.";


string forceJoinURI = $"https://t.me/{Bot.Me.Username}/?start={"force" + args[1]}";

// send user messaage
Bot.Send(msg+"\n\n"+warningMsg, u.Message.Chat.Id, customMenu: new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithUrl("Force Join Game", forceJoinURI)
}
}));
return;
}

//okay, they are joining a game.
string nodeid = "";
string gameid = "";
Expand Down Expand Up @@ -340,6 +376,14 @@ public static void Start(Update u, string[] args)
}

game.AddPlayer(u, gameid);

// notify group about force join
if (isForceJoin) {
// TODO: move to strings xml for translation support
string forceJoinNotice = $"⚠️ Player with name '[{p.Name}](tg://user?id={p.TelegramId})' used force join button, their name is detected as unreadable by bot.";

Bot.Send(forceJoinNotice, game.GroupId, parseMode: ParseMode.Markdown);
}
return;
}
catch (AggregateException e)
Expand Down
100 changes: 97 additions & 3 deletions Werewolf for Telegram/Werewolf Control/Commands/Helpers.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
using Shared;
using Database;
using Shared;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Database;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups;
using Werewolf_Control.Handler;
using Werewolf_Control.Helpers;
using Werewolf_Control.Models;
using Telegram.Bot;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
namespace Werewolf_Control
{
Expand All @@ -33,6 +34,99 @@ public static partial class Commands
};
#endif

internal static void TestPlayerNameValidation()
{
// Fix: enable Unicode output for fancy letters and emoji
Console.OutputEncoding = System.Text.Encoding.UTF8;

var testCases = new List<(string Name, bool Expected, string Description)>
{
("John", true, "Latin letters"),
("𝕁𝕠𝕙𝕟", true, "Stylized Latin (math bold)"),
("ABC", true, "Full-width Latin"),
("李", false, "Single CJK (non-Latin) character"),
("😎😎", false, "Emoji only"),
(" ", false, "Whitespace only"),
("A", false, "Only one Latin letter"),
("AB", true, "Two Latin letters"),
("ㅤㅤㅤ", false, "Hangul fillers (invisible)"),
("⌘ KMohZaid ⌘", true, "Latin letters surrounded by symbols"),
("AswatthamA", true, "Regular Latin name"),
("Cuenta Eliminada", true, "Spanish Latin name"),
("ဂွေးဂျိနက်မမ", false, "Burmese script (non-Latin)"),
("Jasmine", true, "Regular Latin name"),
("Van", true, "Short but valid Latin name"),
("", false, "Empty string"),
("ℛ𝒶𝓃𝒶𝒹 ℬℯ𝓃 ℛ𝒶𝓂𝒶𝒹𝒶𝓃", true, "Fancy Unicode Latin")
};

foreach (var (name, expected, description) in testCases)
{
bool actual;
string msg;
(actual, msg) = Commands.ValidatePlayerName(name);

Console.WriteLine($"Name: \"{name}\"");
Console.WriteLine($"Description: {description}");
Console.WriteLine($"Message: {msg}");
Console.WriteLine($"Expected: {(expected ? "Valid" : "Invalid")}, Actual: {(actual ? "Valid" : "Invalid")}");

if (actual == expected)
{
Console.WriteLine("✅ TEST PASS");
}
else
{
Console.WriteLine("❌ TEST FAIL");
}

Console.WriteLine(new string('-', 50));
}

Console.WriteLine(new string('-', 50));
Console.WriteLine("PRESSING ENTER WILL START ACTUAL BOT RUN, AFTER WHICH YOU WILL SEE MESSED UP BOT STATUS MESSAGE.");
Console.WriteLine(new string('-', 50));
Console.ReadLine(); // this is to stop program from overriding output screen with running bot status message
}

internal static (bool, string) ValidatePlayerName(string name)
{


// TODO: move to string xml file, for translation support
string blankMsg = "❌ Your name appears to be blank. Please set a readable name in your Telegram profile and try again.";
string noEnoughReadableChar = "❌ Your name must contain at least 2 readable letters. Please update your Telegram name.";

if (string.IsNullOrWhiteSpace(name))
{
return (false, blankMsg);
}

var trimmedName = name.Trim();
var textElements = StringInfo.GetTextElementEnumerator(trimmedName);

int letterCount = 0;

while (textElements.MoveNext())
{
string element = textElements.GetTextElement();
var category = CharUnicodeInfo.GetUnicodeCategory(element, 0);

if (category == UnicodeCategory.UppercaseLetter ||
category == UnicodeCategory.LowercaseLetter)
{
letterCount++;
}
}

if (letterCount < 2)
{
return (false,noEnoughReadableChar);
}

return (true,"Valid.");
}

private static Player GetDBPlayer(long id, WWContext db)
{
return db.Players.FirstOrDefault(x => x.TelegramId == id);
Expand Down
5 changes: 5 additions & 0 deletions Werewolf for Telegram/Werewolf Control/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,13 @@ class Program
internal static readonly HttpClient xsollaClient = new HttpClient();
internal const string MasterLanguage = "English.xml";
internal static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);


static void Main(string[] args)
{
// INFO: uncomment below method call for testing. Some names are already there for testing purpose.
//Commands.TestPlayerNameValidation();

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

#if !DEBUG
Expand Down