Example #1
0
        private static bool SendTweet(ILogger log, Models.Tweet tweet, Dictionary <string, string> statesDict)
        {
            tweet.VotingMembers = GetMemberVotes(log, tweet.MemberPositions, statesDict);

            // Creates an image of senator voting positions to upload along with the tweet
            var filePath = CreateImage(log, tweet);

            if (!string.IsNullOrEmpty(filePath))
            {
                byte[] file1 = File.ReadAllBytes(filePath);

                log.LogInformation($"Uploading image for tweet...");
                var media = Upload.UploadBinary(file1);
                log.LogInformation($"Image upload complete!");

                log.LogInformation($"Publishing tweet...");
                var tweetResponse = Tweetinvi.Tweet.PublishTweet(tweet.TweetText, new PublishTweetOptionalParameters
                {
                    Medias = new List <Tweetinvi.Models.IMedia> {
                        media
                    }
                });
                if (tweetResponse == null)
                {
                    log.LogError($"Tweet was unable to be published");
                    return(false);
                }
                else
                {
                    log.LogInformation($"Tweet published! TweetId: {tweetResponse.Id}");
                    return(true);
                }
            }
            return(false);
        }
Example #2
0
        private static string CreateImage(ILogger log, Models.Tweet tweet)
        {
            log.LogInformation($"Creating image for tweet...");

            // TODO: Move these constants to a constants file
            var DEFAULT_TWEET_IMAGE_WIDTH          = 1230;
            var DEFAULT_TWEET_IMAGE_HEIGHT         = 1625;
            var DEFAULT_TWEET_IMAGE_FONT_SIZE      = 25;
            var DEFAULT_LINE_HEIGHT                = 30;
            var ESTIMATED_NUMBER_OF_CHARS_PER_LINE = 110;
            var MEMBER1_NAME_START_X               = 225;
            var MEMBER1_VOTE_START_X               = 575;
            var MEMBER2_NAME_START_X               = 725;
            var MEMBER2_VOTE_START_X               = 1075;
            var VOTE_RESULTS_START_X               = 425;
            var FINAL_RESULT_START_X               = 543;
            var imageWidth  = DEFAULT_TWEET_IMAGE_WIDTH;
            var imageHeight = DEFAULT_TWEET_IMAGE_HEIGHT;
            var regularFont = SystemFonts.CreateFont("Arial", DEFAULT_TWEET_IMAGE_FONT_SIZE, FontStyle.Regular);
            var boldFont    = SystemFonts.CreateFont("Arial", DEFAULT_TWEET_IMAGE_FONT_SIZE, FontStyle.Bold);

            var numberOfLines = 0;

            if (!string.IsNullOrEmpty(tweet.BillSummary))
            {
                // If there is a bill summary, make additional room for the "Bill Summary:" header, the Bill Summary
                // text, and a trailing new line on the image canvas
                numberOfLines = tweet.BillSummary.Length / ESTIMATED_NUMBER_OF_CHARS_PER_LINE;
                imageHeight  += numberOfLines * DEFAULT_LINE_HEIGHT + (DEFAULT_LINE_HEIGHT * 2);
            }
            else if (!string.IsNullOrEmpty(tweet.VoteDescription))
            {
                // If there is a vote description, make additional room for the "Vote Description:" header, the Vote Description
                // text, and a trailing new line on the image canvas
                numberOfLines = tweet.VoteDescription.Length / ESTIMATED_NUMBER_OF_CHARS_PER_LINE;
                imageHeight  += numberOfLines * DEFAULT_LINE_HEIGHT + (DEFAULT_LINE_HEIGHT * 2);
            }

            log.LogInformation($"Image width: {imageWidth} Image height: {imageHeight}");
            using (Image <Rgba32> img = new Image <Rgba32>(imageWidth, imageHeight))
            {
                // Set the background color of the image to white
                img.Mutate(ctx => ctx.Fill(Rgba32.White));

                // The height to draw on the canvas
                var y = 5;

                // The width to draw on the canvas
                var x = 5;

                // Populate image with header text
                if (!string.IsNullOrEmpty(tweet.BillSummary))
                {
                    img.Mutate(ctx => ctx.DrawText($"Bill Summary:", boldFont, Rgba32.Black, new PointF(x, y)));
                    var textGraphicOptions = new TextGraphicsOptions(true)
                    {
                        HorizontalAlignment = HorizontalAlignment.Left,
                        VerticalAlignment   = VerticalAlignment.Top,
                        WrapTextWidth       = imageWidth
                    };
                    y += DEFAULT_LINE_HEIGHT;
                    img.Mutate(ctx => ctx.DrawText(textGraphicOptions, tweet.BillSummary, regularFont, Rgba32.Black, new PointF(x, y)));
                    y += DEFAULT_LINE_HEIGHT * numberOfLines + DEFAULT_LINE_HEIGHT;
                }
                else if (!string.IsNullOrEmpty(tweet.VoteDescription))
                {
                    img.Mutate(ctx => ctx.DrawText($"Vote Description:", boldFont, Rgba32.Black, new PointF(x, y)));
                    var textGraphicOptions = new TextGraphicsOptions(true)
                    {
                        HorizontalAlignment = HorizontalAlignment.Left,
                        VerticalAlignment   = VerticalAlignment.Top,
                        WrapTextWidth       = imageWidth
                    };
                    y += DEFAULT_LINE_HEIGHT;
                    img.Mutate(ctx => ctx.DrawText(textGraphicOptions, tweet.VoteDescription, regularFont, Rgba32.Black, new PointF(x, y)));
                    y += DEFAULT_LINE_HEIGHT * numberOfLines + DEFAULT_LINE_HEIGHT;
                }

                // Populate canvas with senate vote positions
                var totalYes       = 0;
                var totalNo        = 0;
                var totalNotVoting = 0;
                foreach (var memberVote in tweet.VotingMembers)
                {
                    var member1 = memberVote.Item1;
                    var member2 = memberVote.Item2;
                    img.Mutate(ctx => ctx.DrawText($"{member1.State}:", boldFont, Rgba32.Black, new PointF(x, y)));

                    var member1Position = member1.VotePosition.ToLower();
                    // NOTE: _1 variable is unused. Used here so terinary operand can be used to reduce code size
                    var _1 = member1Position == "yes" ? totalYes += 1 : member1Position == "no" ? totalNo += 1 : totalNotVoting += 1;

                    var member2Position = member2.VotePosition.ToLower();
                    // NOTE: _2 variable is unused. Used here so terinary operand can be used to reduce code size
                    var _2 = member2Position == "yes" ? totalYes += 1 : member2Position == "no" ? totalNo += 1 : totalNotVoting += 1;

                    // Draw Member 1 results on canvas
                    DrawMemberPositionOnCanvas(img, boldFont, regularFont, member1, MEMBER1_NAME_START_X, MEMBER1_VOTE_START_X, y);

                    // Draw Member 2 results on canvas
                    DrawMemberPositionOnCanvas(img, boldFont, regularFont, member2, MEMBER2_NAME_START_X, MEMBER2_VOTE_START_X, y);

                    y += DEFAULT_LINE_HEIGHT;
                }

                // Populate canvas with vote results
                y += DEFAULT_LINE_HEIGHT;
                img.Mutate(ctx => ctx.DrawText($"Yes: {totalYes}     No: {totalNo}     Not Voting: {totalNotVoting}", boldFont, Rgba32.Black, new PointF(VOTE_RESULTS_START_X, y)));
                y += DEFAULT_LINE_HEIGHT;
                img.Mutate(ctx => ctx.DrawText($"Majority Position Required: {tweet.VoteType}", boldFont, Rgba32.Black, new PointF(VOTE_RESULTS_START_X, y)));
                y += DEFAULT_LINE_HEIGHT;

                var resultColor = Rgba32.Black;
                switch (tweet.ShortResult)
                {
                case "AGREED":
                case "CONFIRMED":
                case "SUCCEEDED":
                case "PASSED":
                    resultColor = Rgba32.Green;
                    break;

                case "FAILED":
                case "NOT SUSTAINED":
                case "VETO SUSTAINED":
                case "REJECTED":
                    resultColor = Rgba32.Red;
                    break;

                default:
                    resultColor = Rgba32.Black;
                    break;
                }

                img.Mutate(ctx => ctx.DrawText($"{tweet.ShortResult}", boldFont, resultColor, new PointF(FINAL_RESULT_START_X, y)));

                // Save as image
                return(SaveImage(log, img));
            }
        }
Example #3
0
        public static async Task <List <Models.Tweet> > CreateTweets(ILogger log, HttpClient client, List <Vote> votes)
        {
            var tweets = new List <Models.Tweet>();

            foreach (var vote in votes)
            {
                var voteUri  = vote.VoteUri;
                var uri      = voteUri.Replace(HelperMethods.GetEnvironmentVariable(PRO_PUBLICA_BASE_URL), "");
                var voteResp = await client.GetStringAsync(uri);

                var    voteData       = JsonConvert.DeserializeObject <dynamic>(voteResp);
                JArray positionsArray = null;
                try
                {
                    positionsArray = voteData["results"]["votes"]["vote"]["positions"] as JArray;
                }
                catch (Exception e)
                {
                    log.LogError($"Exception when converting senate positions to JArray. Message: {e.Message}");
                    return(tweets);
                }

                var memberPositions = positionsArray.ToObject <IEnumerable <Member> >();

                // Create body of tweet
                var tweetText = CreateTweetText(log, vote, memberPositions);

                var newTweet = new Models.Tweet
                {
                    VoteDescription = vote.Description,
                    Result          = vote.Result,
                    ShortResult     = vote.ShortResult,
                    MemberPositions = memberPositions,
                    TweetText       = tweetText,
                    VoteUrl         = vote.Url,
                    VoteType        = vote.VoteType,
                    VoteDate        = vote.Date
                };

                if (!string.IsNullOrEmpty(vote.Bill.ApiUri))
                {
                    var billUri = vote.Bill.ApiUri;
                    uri = billUri.Replace(HelperMethods.GetEnvironmentVariable(PRO_PUBLICA_BASE_URL), "");
                    var billResp = await client.GetStringAsync(uri);

                    var billData = JsonConvert.DeserializeObject <dynamic>(billResp);
                    if (billData != null)
                    {
                        if (billData["results"] is JArray billArray && billArray.Count > 0)
                        {
                            vote.Bill.Summary      = billArray[0]["summary"].ToObject <string>();
                            vote.Bill.ShortSummary = billArray[0]["summary_short"].ToObject <string>();
                            newTweet.BillSummary   = vote.Bill.Summary;
                        }
                    }
                }

                tweets.Add(newTweet);
            }

            log.LogInformation($"Number of tweets attempting to be published: {tweets.Count}");
            return(tweets);
        }