Beispiel #1
0
        public static void DecrementZoom(RemoteWebDriver aDriver, ViewBounds aViewBounds)
        {
            aViewBounds.Zoom = Math.Clamp(aViewBounds.Zoom - 1, 10, 21);
            aDriver.ExecuteScript($"map.setZoom(arguments[0]);", aViewBounds.Zoom);

            // Another shitty hack, but we need to wait for the map to zoom out and recache markers,
            // and this is a lot easier than tryign to hook into the JS event.
            Util.RandomWait(1500).Wait();
        }
Beispiel #2
0
        private IEnumerable <TargetResponse> QueryTargetList(ViewBounds aViewBounds)
        {
            Console.WriteLine("Requesting Address Targets. Request: {0}", aViewBounds.LatLngString);

            //I think the max limit is 1000
            var response       = _client.GetAsync($"rest/targets/list?n={aViewBounds.N}&s={aViewBounds.S}&e={aViewBounds.E}&w={aViewBounds.W}&limit=1000").GetAwaiter().GetResult();
            var responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

            return(JsonConvert.DeserializeObject <IEnumerable <TargetResponse> >(responseString));
        }
Beispiel #3
0
        public static void CenterOnViewBounds(RemoteWebDriver aDriver, ViewBounds aBounds)
        {
            if (aBounds != null)
            {
                // You can provide your own debug coordinates by
                // going to the dev console and get values from "viewBounds" object.

                // Force a recenter and refresh to ensure that our cache is correct before we query for this marker info.
                // likely unnecessary, but being paranoid here in case a desync happens.
                aDriver.ExecuteScript($"map.setCenter({aBounds.LatLngString});");
                aDriver.ExecuteScript($"refreshMapMarkers();");
            }
        }
Beispiel #4
0
        public static ViewBounds GetCurrentViewBounds(RemoteWebDriver aDriver)
        {
            ViewBounds returnVal = null;

            // grab the current viewbounds from the user.
            var objDict = aDriver.ExecuteScript("return viewBounds") as System.Collections.Generic.Dictionary <string, object>;

            if (objDict != null)
            {
                returnVal = new ViewBounds(objDict);
            }

            return(returnVal);
        }
Beispiel #5
0
        // Gets all available addresses from the current user's view rectangle.
        public async Task <int> GetTargetAddresses(RemoteWebDriver aDriver, ViewBounds aViewBounds)
        {
            var totalResponses = 0;

            if (aViewBounds != null)
            {
                // Ensure that we aren't querying a location that someone else has already sent to.
                // We also don't support multi-family dwellings yet. (Purely becuase I haven't scripted the UX for it yet)
                _targetResponses = QueryTargetList(aViewBounds).Where((response) => response.NeedsApplication && response.IsSingleHousehold)
                                   .ToList();

                double totalTargets = _targetResponses.Count;
                Console.WriteLine($"Found a total of for {totalTargets} target Ids.");

                // Using its own variable since the blocking collection
                // can have elements removed from it from another thread.
                foreach (var response in _targetResponses)
                {
                    var addrResponse = await _client.GetAsync($"https://mapthe.vote/rest/addresses/list?targetId={response.Id}");

                    var responseString = await addrResponse.Content.ReadAsStringAsync();

                    var addresses = JsonConvert.DeserializeObject <IEnumerable <AddressResponse> >(responseString);

                    // TODO: Support for multi family dwellings.
                    if (addresses.Count() == 1)
                    {
                        var addy = addresses.First();
                        ParsedAddresses.Add(addy);
                        ++totalResponses;

                        Console.WriteLine($"Queued up submission for Target ID: |{addy.Id}|,  {addy.Addr} @ Lat: {addy.Lat}, Lng: {addy.Lng}");
                    }
                }
            }

            ParsedAddresses.CompleteAdding();
            Console.WriteLine($"A total of {totalResponses} marker infos were successfully queried from target IDs.");

            return(totalResponses);
        }
Beispiel #6
0
        static void Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("MapThe.Vote/Map Address Builder");
            Console.WriteLine("By: CJ Stankovich https://github.com/siegeJ");
            Console.ForegroundColor = ConsoleColor.White;

            Util.PreventSleep();

            ParseCommandLineArguments(args);

            SetupDriver();

            if (!string.IsNullOrEmpty(JSESSIONID))
            {
                // Can't set a cookie for a domain that we're not yet on.
                // Go to something that we know will 404 so that we can set cookies
                // before continuing execution.
                _driver.Navigate().GoToUrl(@"https://mapthe.vote/404page");

                // TODO: Attempt to get cookie from browser.
                _driver.Manage().Cookies.AddCookie(new OpenQA.Selenium.Cookie("JSESSIONID", JSESSIONID, "mapthe.vote", "/", null));
            }

            // With our JSESSION initialized, we can move onto the actual map.
            _driver.Navigate().GoToUrl(@"https://mapthe.vote/map");

            // Need to manually log in if we don't have a valid cookie.
            if (string.IsNullOrEmpty(JSESSIONID))
            {
                MapTheVoteScripter.Login(_driver);

                var jsessionCookie = _driver.Manage().Cookies.GetCookieNamed("JSESSIONID");
                if (jsessionCookie != null)
                {
                    JSESSIONID = jsessionCookie.Value;
                }
            }

            // I hate this, but for some reason waiting for map-msg-button just doesn't work.
            Util.RandomWait(1000).Wait();

            _driver.ClickOnElement("map-msg-button", ElementSearchType.ClassName).Wait();

            DateTime startingTime = default;

            var        numFails = 0;
            var        lastNumAddressesParsed = 0;
            ViewBounds prevBounds             = null;

            var appSubmitter = new ApplicationSubmitter();

            while (numFails < 3)
            {
                Task <IEnumerable <AddressResponse> > processAppsTask = null;
                appSubmitter.SubmittedAddresses.Clear();

                try
                {
                    // Wait for user input if we've successfully parsed everything from the
                    // previous run. Otherwise we can use the same bounds again in order to
                    // re-sweep for the markers that we may have missed.
                    // This can happpen
                    var noAddressesParsed = lastNumAddressesParsed == 0;
                    if (noAddressesParsed || (prevBounds == null))
                    {
                        if (noAddressesParsed && prevBounds != null && (prevBounds.Zoom > ViewBounds.ZOOM_LIMITS.Item1))
                        {
                            MapTheVoteScripter.DecrementZoom(_driver, prevBounds);
                            // Reset fail count if we're going to try searching around.
                            numFails = 0;
                        }
                        else
                        {
                            // End execution if the user has idled out
                            var success = MapTheVoteScripter.WaitForMarkerSelection(_driver);
                            if (!success)
                            {
                                break;
                            }
                        }

                        prevBounds = MapTheVoteScripter.GetCurrentViewBounds(_driver);
                    }
                    else
                    {
                        Console.WriteLine("Repeating the previous search to find uncached values.");
                    }

                    startingTime = DateTime.Now;

                    var scraper = new AddressScraper();
                    scraper.Initialize(JSESSIONID);

                    if (prevBounds != null)
                    {
                        MapTheVoteScripter.CenterOnViewBounds(_driver, prevBounds);
                    }

                    var getAddressesTask = scraper.GetTargetAddresses(_driver, prevBounds);
                    processAppsTask = appSubmitter.ProcessApplications(_driver, scraper.ParsedAddresses);

                    Task.WaitAll(getAddressesTask, processAppsTask);

                    lastNumAddressesParsed = getAddressesTask.Result;
                }
                catch (Exception e)
                {
                    Util.LogError(ErrorPhase.Misc, e.ToString());
                }

                // Do this in case the user did something to f**k things up. This way we can still successfully write out the file.
                // TODO: Thread the filewriting.
                if (processAppsTask != null && processAppsTask.Status == TaskStatus.Running)
                {
                    processAppsTask.Wait();
                }

                var lastNumAddressesSubmitted = appSubmitter.SubmittedAddresses.Count;

                var addressesSubmitted = lastNumAddressesSubmitted != 0;
                // We wait for 3 consecutive fails before ultimately deciding to call it quits.
                numFails = addressesSubmitted ? 0 : numFails + 1;
                if (addressesSubmitted)
                {
                    var adressesSubmitted = lastNumAddressesSubmitted != 0;
                    Console.WriteLine($"Successfully submitted { lastNumAddressesSubmitted } / { lastNumAddressesParsed } applications.");

                    // Sort our addresses by Zip, City, and then address.
                    appSubmitter.SubmittedAddresses.Sort((lhs, rhs) =>
                    {
                        var compareVal = lhs.Zip5.CompareTo(rhs.Zip5);

                        if (compareVal == 0)
                        {
                            compareVal = lhs.City.CompareTo(rhs.City);

                            if (compareVal == 0)
                            {
                                compareVal = lhs.FormattedAddress.CompareTo(rhs.FormattedAddress);
                            }
                        }

                        return(compareVal);
                    });

                    WriteAddressesFile(AddressesFileName, appSubmitter.SubmittedAddresses);
                }

                Console.WriteLine("Completed in {0}", DateTime.Now - startingTime);
            }

            CombineAddressesFiles();

            Console.WriteLine("Execution complete. Restart the application to send more registration forms.");
        }