protected Browser GetBrowser(List <object> dependencies, AuthenticatedAs authenticatedAs = AuthenticatedAs.User)
        {
            return(new Browser(with =>
            {
                if (authenticatedAs == AuthenticatedAs.User)
                {
                    with.RequestStartup((container, pipelines, context) =>
                    {
                        var claims = new[]
                        {
                            new Claim(JwtRegisteredClaimNames.Aud, authenticatedAs == AuthenticatedAs.Service ? Audiences.SynthesisMicroservice : Audiences.Synthesis),
                            new Claim(JwtRegisteredClaimNames.Sub, PrincipalId.ToString()),
                            new Claim(ClaimTypes.Tenant, TenantId.ToString()),
                            new Claim(ClaimTypes.Group, string.Join(",", Guid.NewGuid().ToString(), Guid.NewGuid().ToString()))
                        };
                        var identity = new ClaimsIdentity(
                            claims,
                            AuthenticationTypes.Basic);
                        context.CurrentUser = new ClaimsPrincipal(identity);
                    });
                }

                if (authenticatedAs == AuthenticatedAs.Service)
                {
                    with.RequestStartup((container, pipelines, context) =>
                    {
                        var claims = new[]
                        {
                            new Claim(JwtRegisteredClaimNames.Aud, authenticatedAs == AuthenticatedAs.Service ? Audiences.SynthesisMicroservice : Audiences.Synthesis),
                            new Claim(JwtRegisteredClaimNames.Sub, PrincipalId.ToString()),
                            new Claim(ClaimTypes.Group, string.Join(",", Guid.NewGuid().ToString(), Guid.NewGuid().ToString()))
                        };
                        var identity = new ClaimsIdentity(
                            claims,
                            AuthenticationTypes.Basic);
                        context.CurrentUser = new ClaimsPrincipal(identity);
                    });
                }

                foreach (var dependency in dependencies)
                {
                    with.Dependency(dependency);
                }

                with.Dependency(_metadataRegistryMock.Object);
                with.Dependency(_tokenValidatorMock.Object);
                with.Dependency(PolicyEvaluatorMock.Object);
                with.Dependency(_loggerFactoryMock.Object);

                with.Module <TModule>();
            }));
        }
        protected Browser GetBrowser(List <object> dependencies, AuthenticatedAs authenticatedAs = AuthenticatedAs.User)
        {
            _policyEvaluatorMock
            .Setup(x => x.EvaluateAsync(It.IsAny <PolicyEvaluationContext>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(authenticatedAs != AuthenticatedAs.Forbidden ? PermissionScope.Allow : PermissionScope.Deny);

            return(new Browser(with =>
            {
                if (authenticatedAs != AuthenticatedAs.None)
                {
                    with.RequestStartup((container, pipelines, context) =>
                    {
                        var claims = new[]
                        {
                            new Claim(JwtRegisteredClaimNames.Aud, authenticatedAs == AuthenticatedAs.Service ? Audiences.SynthesisMicroservice : Audiences.Synthesis),
                            new Claim(JwtRegisteredClaimNames.Sub, Guid.NewGuid().ToString()),
                            new Claim(ClaimTypes.Tenant, TenantId.ToString()),
                            new Claim(ClaimTypes.Group, Guid.NewGuid().ToString()),
                            new Claim(ClaimTypes.Group, Guid.NewGuid().ToString())
                        };
                        var identity = new ClaimsIdentity(
                            claims,
                            AuthenticationTypes.Basic);
                        context.CurrentUser = new ClaimsPrincipal(identity);
                    });
                }

                foreach (var dependency in dependencies)
                {
                    with.Dependency(dependency);
                }

                with.Dependency(_metadataRegistryMock.Object);
                with.Dependency(_tokenValidatorMock.Object);
                with.Dependency(_policyEvaluatorMock.Object);
                with.Dependency(_loggerFactoryMock.Object);

                with.Module <TModule>();
            }));
        }
 protected Browser GetBrowser(AuthenticatedAs authenticatedAs = AuthenticatedAs.User)
 {
     return(GetBrowser(BrowserDependencies, authenticatedAs));
 }
        internal override void GetResponse()
        {
            bool getCookies = CheckCookiesAndSetVariables(); // needs to be called before below log msg, as the AuthenticatedAs is assigned in this func

            if (!IsIgnoredFile(URLUntilTokens))
            {
                Logging.Log(Logging.LogSeverity.Info, NameOrIdentity + " requested " + URLUntilTokens + $"{(AuthenticatedAs == null ? "" : "  -Auth: " + AuthenticatedAs.ToString("AN"))}" + $"{(Viewing == null ? "" : "   -View: " + Viewing.ToString("AN"))}", (AuthenticatedAs == null ? "" :  AuthenticatedAs.AccountName + "/") + "Web");
            }
            if (getCookies && CheckAuth())
            {     // Ensure they are permitted to view that page
                if (CheckRedirect())
                { // Check if we should redirect fire
                    if (URLUntilTokens == "/")
                    {
                        Title = "Y11 Awards";

                        string text = "<label>Your votes for each category:</label>";
                        text += $"<table><tr><th>Category</th><th>First</th><th>Second</th></tr>";
                        int catCount = 0;
                        foreach (var category in Program.Database.AllCategories.Values)
                        { // builds information into a table, for display.
                            catCount++;
                            string clrClass = (catCount % 2 == 0) ? " class=\"tblEven\"" : "";
                            string catText  = "<tr" + clrClass + "><td>{0}</td><td>{1}</td><td>{2}</td></tr>";
                            var    users    = category.GetVotesBy(AuthenticatedAs);
                            catText = string.Format(catText, category.Prompt, users.Item1?.FullName ?? "N/A", users.Item2?.FullName ?? "N/A");
                            text   += catText;
                        }
                        text += "</table>";
                        Body  = text; Code = HttpStatusCode.OK;
                    }
                    else if (URLUntilTokens == "/WebStyles.css")
                    { // returns web styling
                        Body = Properties.Resources.WebStyles;
                        Code = HttpStatusCode.OK;
                        IgnoreHTMLFormatting = true; // without any HTML formatting
                        Headers.Add("Content-Type", "text/css");
                    }
                    else if (URLUntilTokens == "/WebScripts.js")
                    { // as with the CSS above
                        Body = Properties.Resources.WebScripts;
                        Code = HttpStatusCode.OK;
                        IgnoreHTMLFormatting = true;
                        Headers.Add("Content-Type", "text/javascript");
                    }
                    else if (URLUntilTokens == "/all")
                    {
                        if (AuthenticatedAs == null)
                        {
                            // we should redirect them to get authenticated.
                            AdditionalHeadText = $"<meta http-equiv=\"refresh\" content=\"5; URL = http://{Program.GetLocalIPAddress()}/\" />";
                            Body = $"<label class=\"error\">You need to be authenticated.<br>You will be redirected shortly.<br><br>If not, head to http://{Program.GetLocalIPAddress()}/</label>";
                            Code = HttpStatusCode.Unauthorized;
                            return;
                        }
                        bool showRunnerUp = false;
                        if (this.Tokens.TryGetValue("run", out string irrelevant))
                        {
                            showRunnerUp = true;
                        }
                        string cssClass = ((ClientIP == Program.GetLocalIPAddress() || ClientIP == "127.0.0.1" || Program.Options.Allow_NonLocalHost_WebConnections || AuthenticatedAs.Flags.Contains(Flags.Coundon_Staff))) ? "" : "class=\"hidden\"";
                        // anyone can access the info
                        // but, we hide some data via css
                        // which isnt particularly secure.. might change in future.
                        // however: I have set the javascript to remove any information within a [REDACTED] element
                        // which means that it is in no way secure - its still being sent
                        // BUT it is impossible to get the data using just Inspect element, which will prevent access from most/all
                        Code = HttpStatusCode.OK; Title = "Y11: All Data";
                        string htmlPage        = Properties.Resources.WebAllDataPage; // this is the base template, which data will be added into
                        int    notVoted        = Program.Database.AllStudents.Count;  // start with all students added
                        int    currentlyVoting = 0;
                        int    alreadyVoted    = 0;
                        string width           = "25%";
                        if (showRunnerUp)
                        {
                            width = "20%";
                        }
                        string style = $" style=\"width:{width};\"";
                        foreach (var student in Program.Database.AllStudents.Values)
                        { // removes them as needed to increment the two above
                            if (Program.Database.AlreadyVotedNames.Contains(student.AccountName))
                            {
                                notVoted--;
                                alreadyVoted++;
                            }
                            else if (SocketHandler.CurrentClients.FirstOrDefault(x => x.User.AccountName == student.AccountName) != null)
                            {
                                notVoted--;
                                currentlyVoting++;
                            }
                        }
                        // Displays how many total votes have been made, and how many unique people have been voted, for each category.
                        string categoryTable      = $"<table><tr><th>Category</th><th>Total Votes (by people)</th><th>Unique Voted (num people voted)</th></tr>";
                        int    totalVotes         = 0;
                        int    highestPeopleVoted = 0;
                        foreach (var category in Program.Database.AllCategories.Values)
                        {
                            int votes = 0;
                            foreach (var list in category.Votes)
                            {
                                votes += list.Value.Count;
                            }
                            string tempClass = (category.ID % 2 == 0) ? "class=\"tblEven\"" : "";
                            string format    = $"<tr {tempClass}><td>{category.Prompt}</td><td>{votes}</td><td>{category.Votes.Count}</td></tr>";
                            categoryTable += format;
                            totalVotes    += votes;
                            if (category.Votes.Count > highestPeopleVoted)
                            {
                                highestPeopleVoted = category.Votes.Count;
                            }
                        }
                        categoryTable += $"<tr><td><strong>Totals</strong><td>{totalVotes}</td><td>{highestPeopleVoted}</td></tr>";
                        categoryTable += "</table>";

                        string winnersTable = $"<table><tr{style}><th>Category</th><th>First Winner</th><th>Second Winner</th>";
                        if (showRunnerUp)
                        {
                            winnersTable += $"<th>Runner up</th>";
                        }
                        winnersTable += $"<th>Difference</th></tr>";
                        foreach (var category in Program.Database.AllCategories.Values)
                        {
                            var    highestVote          = category.HighestAtPosition(0);
                            var    highestWinners       = highestVote.Item1;
                            var    secondHighestVote    = category.HighestAtPosition(1);
                            var    secondHighestWinners = secondHighestVote.Item1;
                            string first = $"{string.Join(", ", highestWinners.Select(x => x.ToString("FN LN (TT)")))}";
                            if (string.IsNullOrWhiteSpace(first))
                            {
                                first = "N/A";
                            }
                            string second = $"{string.Join(", ", secondHighestWinners.Select(x => x.ToString("FN LN (TT)")))}";
                            if (string.IsNullOrWhiteSpace(second))
                            {
                                second = "N/A";
                            }
                            string format = "<tr><td>{1}</td><td {0}>{4}: {2}</td><td {0}>{5}: {3}</td>";
                            format = string.Format(format,
                                                   cssClass, category.Prompt,
                                                   first, second, $"<strong>{highestVote.Item2}</strong>",
                                                   $"<strong>{secondHighestVote.Item2}</strong>");
                            if (showRunnerUp)
                            {
                                var    runnerUp        = category.HighestAtPosition(2);
                                var    runnerUpWinners = runnerUp.Item1;
                                string asString        = string.Join(", ", runnerUpWinners.Select(x => x.ToString("FN LN (TT)")));
                                if (string.IsNullOrWhiteSpace(asString))
                                {
                                    asString = "N/A";
                                }
                                format += $"<td><strong>{runnerUp.Item2}</strong>: {asString}</td>";
                                format += $"<td>{secondHighestVote.Item2 - runnerUp.Item2}</td>"; // show difference betwene second/runner
                            }
                            else
                            { // show difference between two winners
                                format += $"<td>{highestVote.Item2 - secondHighestVote.Item2}</td>";
                            }
                            format       += "</tr>";
                            winnersTable += format;
                        }
                        winnersTable += "</table>";


                        // replaces data from the templace, see the WebAllDataPage.txt
                        Dictionary <string, string> ReplaceValues = new Dictionary <string, string>()
                        {
                            { "[[NUM_NOT_VOTED]]", notVoted.ToString() },
                            { "[[NUM_VOTED]]", alreadyVoted.ToString() },
                            { "[[NUM_VOTING]]", currentlyVoting.ToString() },
                            { "[[HIDENOT]]", cssClass },
                            { "[[CATEGORY_TABLE]]", categoryTable },
                            { "[[WINNER_TABLE]]", winnersTable }
                        };
                        foreach (var keypair in ReplaceValues)
                        {
                            htmlPage = htmlPage.Replace(keypair.Key, keypair.Value);
                        }

                        Body = htmlPage;
                        // This is commented out because it works.
                        // I've added this in because i'm aware that technically speaking
                        // another <DOCTYPE html> and <head> and <body> elements are being put into the preexisting <body> location
                        // but google chrome seems to work it out.. and it works. So there's that.
                        // forceIgnoreWebpage = true;
                    }
                    else if (URLUntilTokens == "/student")
                    {
                        if (!AuthenticatedAs.Flags.Contains(Flags.Coundon_Staff) && !AuthenticatedAs.Flags.Contains(Flags.System_Operator))
                        {
                            Body  = "<label class=\"error\">You do not have access to view other people's votes.</label>";
                            Code  = HttpStatusCode.Forbidden;
                            Title = "Forbidden";
                            return;
                        }
                        if (Viewing == null)
                        {
                            Body  = "<label class=\"error\">You will need to enter the information of the desired student:</label><br>" + HTML_ViewPage;
                            Code  = HttpStatusCode.BadRequest;
                            Title = "Invalid Info";
                            return;
                        }
                        else
                        {
                            string text = $"<label>{Viewing.ToString("FN LN")}'s votes for each category:</label>";
                            text += $"<table><tr><th>Category</th><th>First</th><th>Second</th></tr>";
                            int catCount = 0;
                            foreach (var category in Program.Database.AllCategories.Values)
                            { // builds information into a table, for display.
                                catCount++;
                                string clrClass = (catCount % 2 == 0) ? " class=\"tblEven\"" : "";
                                string catText  = "<tr" + clrClass + "><td>{0}</td><td>{1}</td><td>{2}</td></tr>";
                                var    users    = category.GetVotesBy(Viewing);
                                catText = string.Format(catText, category.Prompt, users.Item1?.FullName ?? "N/A", users.Item2?.FullName ?? "N/A");
                                text   += catText;
                            }
                            text += "</table>";
                            text += "<button id=\"btnid\" onclick=\"resetStudent();\">Change student</button>";

                            Body = text; Code = HttpStatusCode.OK;
                        }
                    }
                    else if (URLUntilTokens == "/voted")
                    {
                        if (!AuthenticatedAs.Flags.Contains(Flags.System_Operator))
                        {
                            Body  = "<label class=\"error\">You do not have access that page.</label>";
                            Code  = HttpStatusCode.Forbidden;
                            Title = "Forbidden";
                            return;
                        }
                        if (this.Tokens.TryGetValue("user", out string accountName))
                        {
                            string filter = "";
                            if (Tokens.TryGetValue("filter", out string f))
                            {
                                filter = f;
                            }
                            if (Program.TryGetUser(accountName, out User user))
                            {
                                string text = $"Votes for {user.FirstName}:";
                                text += "<table>" +
                                        "<tr><th>Category</th><th>Votes</th><th>People voted</th></tr>";
                                foreach (var category in Program.Database.AllCategories.Values)
                                {
                                    string row   = $"<tr><td>{category.Prompt}</td>";
                                    var    votes = category.GetVotesFor(user);
                                    row  += $"<td>{votes.Count}</td>";
                                    row  += $"<td>{string.Join(", ", votes.Select(x => x.AccountName == filter ? $"<strong>{x.FullName}</strong>" : x.FullName))}</td>";
                                    row  += "</tr>";
                                    text += row;
                                }
                                text += "</table>";
                                Body  = text;
                            }
                            else
                            {
                                Body = "<label class=\"error\">The user provided is unknown.</label>";
                                Code = HttpStatusCode.BadRequest;
                            }
                        }
                        else
                        {
                            Body = "<label class=\"error\">You did not pass a proper URL query paramator of name 'user'" +
                                   ", containing the account name of the student desired</label>";
                            Code = HttpStatusCode.BadRequest;
                        }
                    }
                    else if (URLUntilTokens == "/category")
                    {
                        if (!AuthenticatedAs.Flags.Contains(Flags.System_Operator))
                        {
                            Body  = "<label class=\"error\">You do not have access that page.</label>";
                            Code  = HttpStatusCode.Forbidden;
                            Title = "Forbidden";
                            return;
                        }
                        if (this.Tokens.TryGetValue("id", out string strId))
                        {
                            bool displayUsers = false;
                            if (this.Tokens.TryGetValue("full", out string irrelevant))
                            {
                                displayUsers = true;
                            }
                            if (int.TryParse(strId, out int id) && id >= 1 && id <= Program.Database.AllCategories.Count)
                            {
                                var    category        = Program.Database.AllCategories[id];
                                string startText       = "";
                                User   filterUser      = null;
                                int    numVotesFilter  = 0;
                                string usersVoteFilter = "";
                                if (this.Tokens.TryGetValue("filter", out string accn))
                                {
                                    if (Program.TryGetUser(accn, out filterUser))
                                    { // success
                                    }
                                    else
                                    {
                                        startText = "<label class=\"error\">Filter user was unkown</label>";
                                    }
                                }
                                string text = $"<p>{category.Prompt}</p><br><table>" +
                                              $"<tr><th>Nominee</th><th>Number of votes</th>";
                                if (displayUsers)
                                {
                                    text += $"<th>Voters</th>";
                                }
                                text += "</tr>"; // close row
                                foreach (var vote in category.Votes.OrderByDescending(x => x.Value.Count))
                                {
                                    if (Program.TryGetUser(vote.Key, out User user))
                                    {
                                        string row   = $"<tr><td>{user.ToString("FN LN TT")}<td>{vote.Value.Count}</td>";
                                        string users = string.Join(", ", vote.Value.Select(x => x == filterUser ? $"<strong>{x.ToString("FN LN")}</strong>" : x.ToString("FN LN")));
                                        if (displayUsers)
                                        {
                                            row += $"<td>{users}</td>";
                                        }
                                        row  += "</tr>";
                                        text += row;
                                        if (user == filterUser)
                                        {
                                            numVotesFilter  = vote.Value.Count;
                                            usersVoteFilter = users;
                                        }
                                    }
                                }
                                text += "</table>";
                                if (filterUser != null)
                                {
                                    string filterRow = $"<tr class=\"error\"><td>{filterUser.ToString("AN FN LN")}</td><td>{numVotesFilter}</td>";
                                    if (displayUsers)
                                    {
                                        filterRow += $"<td>{usersVoteFilter}</td>";
                                    }
                                    text = text.Replace("</th></tr>", "</th></tr>" + filterRow); // put this in first after headers.
                                }
                                Body  = startText + text;
                                Code  = HttpStatusCode.OK;
                                Title = "Y11 - Category";
                            }
                            else
                            {
                                Body = $"<label class=\"error\">Your provided ID must be an Integer, and between 1 and {Program.Database.AllCategories.Count}</label>";
                                Code = HttpStatusCode.BadRequest;
                                return;
                            }
                        }
                        else
                        {
                            Body = "<label class=\"error\">You did not include a ?id= URL query paramater</label>";
                            Code = HttpStatusCode.BadRequest;
                            return;
                        }
                    }
                    else if (URLUntilTokens == "/novote")
                    {
                        string text = $"<table>" +
                                      $"<tr><th>Tutor</th><th>Account Name</th><th>Full Name</th><tr>";
                        string emailList = "<p>";
                        foreach (var student in Program.Database.AllStudents.Values)
                        {
                            if (!student.HasVoted)
                            {
                                text      += $"<tr><td>{student.Tutor}</td><td>{student.AccountName}</td><td>{student.FullName}</td></tr>";
                                emailList += $"{student.AccountName}@coundoncourt.org; ";
                            }
                        }
                        text += "</table><br>" + emailList + "</p>";
                        Body  = text;
                        Code  = HttpStatusCode.OK;
                        Title = "Non voters.";
                    }
                    else if (URLUntilTokens == "/percentage")
                    {
                        string text = "<p>";
                        if (Tokens.TryGetValue("value", out string strValue))
                        {
                            if (int.TryParse(strValue, out int value))
                            {
                                if (value > 100 || value < 0)
                                {
                                    text = "<label class=\"error\">Value must be an integer between 0-100, inclusive</label>";
                                }
                                else
                                {
                                    var random = new Random(DateTime.Now.Millisecond * DateTime.Now.Day);
                                    foreach (var student in Program.Database.AllStudents.Values)
                                    {
                                        int thisStudent = random.Next(0, 101);
                                        if (thisStudent < value)
                                        {
                                            text += $"{student.AccountName}@coundoncourt.org; ";
                                        }
                                    }
                                    text += "</p>";
                                }
                            }
                        }
                        Body  = text;
                        Title = "Voters";
                    }
                    else
                    { // unknown/not set up request
                        Body = "<label class=\"error\">404 - Unkown request.</label>"; Code = HttpStatusCode.NotFound; Title = "404 - Not Found";
                    }
                }
            }
        }