public void Ruling_ByNameAndSet() { var cmd = new Command() { Cmd = "ruling", Arguments = new string[] { "Duel Decks Anthology, Divine vs. Demonic", "Fallen Angel" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.Contains("http://localhost/ruling/394029")))); }
public void GetRandomCardByDescription_MultipleSets() { var cmd = new Command() { Cmd = "desc", Arguments = new string[] { "a" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, messengerMock.Object ).Result; messengerMock.Verify(m => m.SendMessage(It.Is <string>(c => c.EndsWith(".jpg"))), Times.Once); messengerMock.Verify(m => m.SendMessage(It.Is <string>(c => c.Contains("Also in sets:"))), Times.Once); }
public void CardSetsList_ByNameAndSetCode() { var cmd = new Command() { Cmd = "cardsets", Arguments = new string[] { "FEM", "Spore Cloud" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage("Spore Cloud appears in sets: Fallen Empires [FEM], Masters Edition II [ME2]")); }
public void Ruling_ByNameAndSetCode() { var cmd = new Command() { Cmd = "ruling", Arguments = new string[] { "DD3_DVD", "Fallen Angel" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, messengerMock.Object ).Result; messengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.Contains("http://localhost/ruling/394029")))); }
public void LatestEDH_NameContains_Empty() { var cmd = new Command() { Cmd = "latestedh", Arguments = new string[] { "xxxx" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, messengerMock.Object ).Result; messengerMock.Verify(m => m.SendMessage( It.Is <string>(s => s == "Latest EDH decks: [0/3]"))); }
public void ImgCommand_ByNameAndSetCode() { var cmd = new Command() { Cmd = "img", Arguments = new string[] { "FEM", "Spore Cloud" } }; var msg = new GroupMeMessage(); bool handled = imgCommandPlugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.EndsWith(".jpg")))); }
public void ImgCommand_NoName() { var cmd = new Command() { Cmd = "img", Arguments = new string[] { "" } }; var msg = new GroupMeMessage(); bool handled = imgCommandPlugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.IsAny <string>()), Times.Never); Assert.False(handled); }
public void LatestFeatured_NameContains() { var cmd = new Command() { Cmd = "featured", Arguments = new string[] { "esper" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage( It.Is <string>(s => s == "Featured decks: Deck 3 (Esper) [http://deck3] [1/3]"))); }
public void SImgCommand_ByName_NoName() { var cmd = new Command() { Cmd = "simg", Arguments = new string[] { "" } }; var msg = new GroupMeMessage(); simgCommandPlugin.OnLoad(); bool handled = simgCommandPlugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; Assert.IsFalse(handled); }
public void ImgHiresCommand_ByNameAndSet() { var cmd = new Command() { Cmd = "imghires", Arguments = new string[] { "Fallen Empires", "Spore Cloud" } }; var msg = new GroupMeMessage(); bool handled = imgCommandPlugin.OnCommand( cmd, msg, messengerMock.Object ).Result; messengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.EndsWith(".jpg")))); }
public void GetPrice_ByNameAndSet_NoCardFound_RunAutocomplete() { string name = "spore bloud"; // Setup IAutocompleter mock response unitTestContext.AutocompleterMock.Setup(ac => ac.GetAutocompleteAsync("spore")) .ReturnsAsync(() => new List <string>() { "Spore Frog", "Spore Burst", "Sporemound", "Spore Cloud", "Spore Flower" }); var cmd = new Command() { Cmd = "tcg", Arguments = new string[] { "C13", name } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.StartsWith("Did you mean Spore Frog"))), Times.Once); }
public void GetPrice_ByName() { string name = "Inquisition of Kozilek"; var cmd = new Command() { Cmd = "ebay", Arguments = new string[] { name } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.StartsWith(string.Format("The eBay Buy It Now price for '{0}' is", name)))), Times.Once); }
public void ScryCommand_ByNameAndSet_NoSet() { var cmd = new Command() { Cmd = "scry", Arguments = new string[] { "", "Spore Cloud" } }; var msg = new GroupMeMessage(); scryCommandPlugin.OnLoad(); bool handled = scryCommandPlugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; Assert.IsFalse(handled); }
public void ImgCommand_ByNameAndSet_NoSet() { var cmd = new Command() { Cmd = "img", Arguments = new string[] { "", "Spore Cloud" } }; var msg = new GroupMeMessage(); bool handled = imgCommandPlugin.OnCommand( cmd, msg, messengerMock.Object ).Result; messengerMock.Verify(m => m.SendMessage(It.IsAny <string>()), Times.Never); Assert.False(handled); }
public void GetFlavor_NoText() { unitTestContext.StoreMock.Setup(s => s.GetRandomFlavorText()) .Returns(() => Task.FromResult("")); var cmd = new Command() { Cmd = "flavor", Arguments = new string[] { } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.IsAny <string>()), Times.Never); }
public void GetPrice_ByName() { string name = "Inquisition of Kozilek"; // Setup mock to return price for this card by name unitTestContext.PriceStoreMock.Setup(ps => ps.GetCardPrice(name)) .Returns(() => new CardPrice() { Name = name, SearchName = SearchHelper.GetSearchValue(name), SetCode = "ROE", PriceFoil = "$100", PriceDiff = "10%" }); var cmd = new Command() { Cmd = "tcg", Arguments = new string[] { "Inquisition of Kozilek" } }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, unitTestContext.MessengerMock.Object ).Result; unitTestContext.MessengerMock.Verify(m => m.SendMessage(It.Is <string>(s => s.StartsWith("Inquisition of Kozilek [ROE]"))), Times.Once); }
public BotModule( BotConfig botConfig, IMessengerFactory messengerFactory, IPluginManager pluginManager, ICommandParser commandParser, ILoggingService loggingService, IReporter reporter) : base("/bot") { #region Bot Route Post["/{token}", true] = async(parameters, ct) => { try { // Get the request's body as a string, for logging string request_string = this.Request.Body.AsString(); string sentToken = parameters.token; // If the passed token segment does not match the secret token, return NotAcceptable status if (botConfig.BotRoutes.FirstOrDefault(r => r.SecretToken == sentToken) == null) { string errMsg = string.Format("POST request from {0}: Token '{1}' was invalid.\nREQUEST = {2}", this.Request.UserHostAddress, sentToken, request_string); loggingService.Warning(errMsg); reporter.Warning(errMsg); return(HttpStatusCode.NotAcceptable); } var message = new GroupMeMessage(); // Bind and validate the request to GroupMeMessage var msg = this.BindToAndValidate(message); if (!ModelValidationResult.IsValid) { string errMsg = string.Format("POST request from {0}: Message was invalid.\nREQUEST = {1}", this.Request.UserHostAddress, request_string); loggingService.Warning(errMsg); reporter.Warning(errMsg); return(HttpStatusCode.NotAcceptable); } // Don't handle messages sent from ourself if (message.name.ToLower() == botConfig.BotName.ToLower()) { return(HttpStatusCode.NotAcceptable); } if (string.IsNullOrEmpty(message.text)) { loggingService.Debug("POST request from {0}: Message text is empty or null.\nREQUEST = {1}", this.Request.UserHostAddress, request_string); return(HttpStatusCode.NotAcceptable); } loggingService.Trace("MSG: From: {0} [UID: {1}]; Body: {2}", message.name, message.user_id, message.text); // Parse the command var command = commandParser.Parse(message.text); if (command != null) { if (!string.IsNullOrEmpty(command.Cmd)) { // Get instance of IMessenger for this bot route var botMessenger = messengerFactory.Create(sentToken); loggingService.Trace("Received command: {0}", command.Cmd); if (command.Cmd.ToLower() == "help") { bool helpHandled = await pluginManager.HandledHelpCommand(command, botMessenger); } else { // If a message is in a command format '<cmd>\s[message]', // have the plugin manager see if any loaded plugins are set to respond to that command bool handled = await pluginManager.HandleCommand(command, message, botMessenger); if (!handled) { pluginManager.SendMessage(message, botMessenger); } } } } return(HttpStatusCode.Accepted); } catch (Exception er) { reporter.Error("MAIN ERROR", er); loggingService.Error(er, string.Format("** MAIN ERROR: {0}", er.Message)); return(HttpStatusCode.BadGateway); } }; #endregion }
public void WhatsHot() { // Setup ICardPriceStore mock priceStoreMock.Setup(ps => ps.GetCardsByPriceIncrease(It.IsAny <int>())) .Returns(() => new List <CardPrice>() { new CardPrice() { Name = "Collected Company", SearchName = "collectedcompany", SetCode = "DTK", PriceDiff = "106%", PriceDiffValue = 106, PriceMid = "$9.24", PriceLow = "$7.61", PriceFoil = "$31.50" }, new CardPrice() { Name = "Dack Fayden", SearchName = "dackfayden", SetCode = "CNS", PriceDiff = "72%", PriceDiffValue = 72, PriceMid = "$48.14", PriceLow = "$34.99", PriceFoil = "$329.82" }, new CardPrice() { Name = "Inkmoth Nexus", SearchName = "inkmothnexus", SetCode = "MBS", PriceDiff = "65%", PriceDiffValue = 65, PriceMid = "$23.00", PriceLow = "$18.50", PriceFoil = "$57.70", }, new CardPrice() { Name = "Dimir Signet", SearchName = "dimirsignet", SetCode = "ARC", PriceDiff = "46%", PriceDiffValue = 46, PriceMid = "$0.70", PriceLow = "$0.38", PriceFoil = "", }, new CardPrice() { Name = "Elvish Archers", SearchName = "elvisharchers", SetCode = "LEB", PriceDiff = "36%", PriceDiffValue = 36, PriceMid = "$90.00", PriceLow = "$90.00", PriceFoil = "", }, }); var cmd = new Command() { Cmd = "whatshot" }; var msg = new GroupMeMessage(); bool handled = plugin.OnCommand( cmd, msg, messengerMock.Object ).Result; messengerMock.Verify(m => m.SendMessage("Today's Hot Cards - Collected Company [DTK]: $9.24 up 106%, Dack Fayden [CNS]: $48.14 up 72%, Inkmoth Nexus [MBS]: $23.00 up 65%, Dimir Signet [ARC]: $0.70 up 46%, Elvish Archers [LEB]: $90.00 up 36%"), Times.Once); }
public IndexModule( BotConfig botConfig, IMtgStore mtgStore, IMessenger messenger, IPluginManager pluginManager, ICommandParser commandParser, ILoggingService loggingService, IReporter reporter, ICardPriceStore priceStore) { Get["/"] = parameters => { loggingService.Warning("GET request from {0}: Path '{1}' was invalid.", this.Request.UserHostAddress, this.Request.Path); return(View["index/index.html"]); }; #region Card Search Route Get["/api/search/{term?}", true] = async(parameters, ct) => { var sw = Stopwatch.StartNew(); int limit = 200; string term = parameters.term; if (string.IsNullOrEmpty(term) || term.StartsWith("?")) { return(Response.AsJson(new { SearchTerm = "", Limit = limit, Cards = new List <Card>() })); } var db_cards = await mtgStore.AdvancedSearchCards(term, limit); if (db_cards == null) { string msg = string.Format("No cards found using name '{0}'", term); loggingService.Error(msg); return(Response.AsJson(new { SearchTerm = term, Limit = limit, Cards = new List <Card>() }).StatusCode = HttpStatusCode.NotAcceptable); } // Get price information var cards = db_cards.Select(c => new { Name = c.Name, Code = c.SetId, Set = c.SetName, Cost = c.Cost, CostSymbols = c.CostWithSymbols, Type = c.FullType, Rarity = c.Rarity, Img = c.Img, MultiverseId = c.MultiverseId, SearchName = c.SearchName, Symbol = c.SetAsKeyRuneIcon, Desc = c.Desc, DescSymbols = c.DescWithSymbols, ConvertedManaCost = c.Cmc, Prices = GetCardPrice(priceStore, c.MultiverseId) }).OrderByDescending(c => c.SearchName); sw.Stop(); return(Response.AsJson(new { SearchTerm = term, Limit = limit, Elapsed = sw.Elapsed.ToString(), Cards = cards, })); }; // // Testing out paging Post["/api/0.x/search", true] = async(parameters, ct) => { var sw = Stopwatch.StartNew(); int limit = 1000; //string term = parameters.term; var query = this.Bind <SearchQuery>(); if (query == null) { return(HttpStatusCode.NotAcceptable); } if (string.IsNullOrEmpty(query.SearchTerm)) { return(HttpStatusCode.NotAcceptable); } var db_cards = await mtgStore.SearchCards(query.SearchTerm, query.Page, limit); if (db_cards == null) { string msg = string.Format("No cards found using name '{0}'", query.SearchTerm); loggingService.Error(msg); return(Response.AsJson(new { SearchTerm = query.SearchTerm, Limit = limit, Cards = new List <Card>() }).StatusCode = HttpStatusCode.NotAcceptable); } var cards = db_cards.Select(c => new { Name = c.Name, Code = c.SetId, Set = c.SetName, Cost = c.Cost, CostSymbols = c.CostWithSymbols, Type = c.FullType, Rarity = c.Rarity, Img = c.Img, MultiverseId = c.MultiverseId, SearchName = c.SearchName, Symbol = c.SetAsKeyRuneIcon, Desc = c.Desc, DescSymbols = c.DescWithSymbols, ConvertedManaCost = c.Cmc, Prices = GetCardPrice(priceStore, c.MultiverseId) }).OrderByDescending(c => c.SearchName); sw.Stop(); return(Response.AsJson(new { SearchTerm = query.SearchTerm, Limit = limit, Elapsed = sw.Elapsed.ToString(), Cards = cards })); }; #endregion // priceincreases route Get["/priceincreases/"] = parameters => { int limit = 10; List <CardPrice> prices = priceStore.GetCardsByPriceIncrease(limit); return(Response.AsJson <List <CardPrice> >(prices)); }; // pricedecreases route Get["/pricedecreases/"] = parameters => { int limit = 10; List <CardPrice> prices = priceStore.GetCardsByPriceDecrease(limit); return(Response.AsJson <List <CardPrice> >(prices)); }; // Price changes Get["/price-changes", true] = async(parameters, ct) => { int limit = 100; var sw = Stopwatch.StartNew(); List <CardPrice> db_increases = priceStore.GetCardsByPriceIncrease(limit); List <CardPrice> db_decreases = priceStore.GetCardsByPriceDecrease(limit); var increases = db_increases.Select(c => new { Name = c.Name, Code = c.SetCode, Symbol = c.SetAsKeyRuneIcon, MultiverseId = c.MultiverseId, PriceDiff = c.PriceDiff, PriceDiffValue = c.PriceDiffValue, PriceMid = c.PriceMid, PriceFoil = c.PriceFoil, Img = c.ImageUrl, LastUpdated = c.LastUpdated.ToShortDateString(), Url = c.Url }); var decreases = db_decreases.Select(c => new { Name = c.Name, Code = c.SetCode, Symbol = c.SetAsKeyRuneIcon, MultiverseId = c.MultiverseId, PriceDiff = c.PriceDiff, PriceDiffValue = c.PriceDiffValue, PriceMid = c.PriceMid, PriceFoil = c.PriceFoil, Img = c.ImageUrl, LastUpdated = c.LastUpdated.ToShortDateString(), Url = c.Url }); sw.Stop(); return(View["index/price-changes.html", new { Elapsed = sw.Elapsed.ToString(), Limit = limit, Increased = increases, Decreased = decreases }]); }; // Ruling route Get["/ruling/{id:int}", true] = async(parameters, ct) => { var sw = Stopwatch.StartNew(); int cardMultiverseId = parameters.id; var card = await mtgStore.GetCard(cardMultiverseId); if (card == null) { string msg = string.Format("No card found using multiverseId '{0}'", cardMultiverseId); loggingService.Error(msg); return(msg); } var set = await mtgStore.GetSetByCode(card.SetId); if (set == null) { string msg = string.Format("No set found using code '{0}'", card.SetId); loggingService.Error(msg); return(msg); } // Get price information var cardPrice = priceStore.GetCardPrice(card.MultiverseId); sw.Stop(); return(View["index/ruling.html", new { Elapsed = sw.Elapsed.ToString(), Card = card, SetCode = !string.IsNullOrEmpty(set.GathererCode) ? set.GathererCode : set.Code, CardPrices = new { Url = cardPrice != null ? cardPrice.Url : "", Low = cardPrice != null ? cardPrice.PriceLow : "", Mid = cardPrice != null ? cardPrice.PriceMid : "", Foil = cardPrice != null ? cardPrice.PriceFoil : "", Diff = cardPrice != null ? cardPrice.PriceDiff : "", } }]); }; // Get search results Get["/search/{name}", true] = async(parameters, ct) => { var sw = Stopwatch.StartNew(); int limit = 100; string name = parameters.name; if (string.IsNullOrEmpty(name)) { return(HttpStatusCode.Accepted); } var cards = await mtgStore.SearchCards(name, limit); if (cards == null) { string msg = string.Format("No cards found using name '{0}'", name); loggingService.Error(msg); return(msg); } sw.Stop(); return(View["index/search.html", new { SearchTerm = name, Limit = limit, Elapsed = sw.Elapsed.ToString(), Cards = cards }]); }; #region Sets Get["/sets", true] = async(parameters, ct) => { var sets = await mtgStore.GetSets(); return(View["listSets.html", new { Sets = sets.Select(s => new { Name = s.Name, Code = s.Code, Block = s.Block, Type = s.Type, ReleasedOn = s.ReleasedOn.ToShortDateString(), ReleasedOnSort = s.ReleasedOn, Symbol = s.SetAsKeyRuneIcon }).OrderByDescending(s => s.ReleasedOnSort) }]); }; Get["/set/{set}", true] = async(parameters, ct) => { string setCode = parameters.set; var set = await mtgStore.GetSetByCode(setCode); var db_cards = await mtgStore.GetCardsBySet(set.Name); // Get price information var cards = db_cards.Select(c => new { Name = c.Name, Code = c.SetId, Set = c.SetName, Cost = c.Cost, CostSymbols = c.CostWithSymbols, Type = c.FullType, Rarity = c.Rarity, Img = c.Img, MultiverseId = c.MultiverseId, SearchName = c.SearchName, Symbol = c.SetAsKeyRuneIcon, Desc = c.Desc, DescSymbols = c.DescWithSymbols, ConvertedManaCost = c.Cmc, SetSymbol = c.SetAsKeyRuneIcon }).OrderByDescending(c => c.SearchName); return(View["set.html", new { Set = set, Cards = cards }]); }; #endregion #region Bot Route Post["/bot/{token}", true] = async(parameters, ct) => { try { // Get the request's body as a string, for logging string request_string = this.Request.Body.AsString(); string sentToken = parameters.token; // If the passed token segment does not match the secret token, return NotAcceptable status if (sentToken != botConfig.SecretToken) { string errMsg = string.Format("POST request from {0}: Token '{1}' was invalid.\nREQUEST = {2}", this.Request.UserHostAddress, sentToken, request_string); loggingService.Warning(errMsg); reporter.Warning(errMsg); return(HttpStatusCode.NotAcceptable); } var message = new GroupMeMessage(); // Bind and validate the request to GroupMeMessage var msg = this.BindToAndValidate(message); if (!ModelValidationResult.IsValid) { string errMsg = string.Format("POST request from {0}: Message was invalid.\nREQUEST = {1}", this.Request.UserHostAddress, request_string); loggingService.Warning(errMsg); reporter.Warning(errMsg); return(HttpStatusCode.NotAcceptable); } // Don't handle messages sent from ourself if (message.name.ToLower() == messenger.BotName.ToLower()) { return(HttpStatusCode.NotAcceptable); } if (string.IsNullOrEmpty(message.text)) { loggingService.Debug("POST request from {0}: Message text is empty or null.\nREQUEST = {1}", this.Request.UserHostAddress, request_string); return(HttpStatusCode.NotAcceptable); } loggingService.Trace("MSG: From: {0} [UID: {1}]; Body: {2}", message.name, message.user_id, message.text); // Parse the command var command = commandParser.Parse(message.text); if (command != null) { if (!string.IsNullOrEmpty(command.Cmd)) { loggingService.Trace("Received command: {0}", command.Cmd); if (command.Cmd.ToLower() == "help") { bool helpHandled = await pluginManager.HandledHelpCommand(command, messenger); } else { // If a message is in a command format '<cmd>\s[message]', // have the plugin manager see if any loaded plugins are set to respond to that command bool handled = await pluginManager.HandleCommand(command, message, messenger); if (!handled) { pluginManager.SendMessage(message, messenger); } } } } return(HttpStatusCode.Accepted); } catch (Exception er) { reporter.Error("MAIN ERROR", er); loggingService.Error(er, string.Format("** MAIN ERROR: {0}", er.Message)); return(HttpStatusCode.BadGateway); } }; #endregion }