Ejemplo n.º 1
0
        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"))));
        }
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        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]"));
        }
Ejemplo n.º 4
0
        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"))));
        }
Ejemplo n.º 5
0
        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]")));
        }
Ejemplo n.º 6
0
        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"))));
        }
Ejemplo n.º 7
0
        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]")));
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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"))));
        }
Ejemplo n.º 11
0
        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);
        }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        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);
        }
Ejemplo n.º 14
0
        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);
        }
Ejemplo n.º 15
0
        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);
        }
Ejemplo n.º 16
0
        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);
        }
Ejemplo n.º 17
0
        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
        }
Ejemplo n.º 18
0
        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);
        }
Ejemplo n.º 19
0
        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
        }