-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add feature: get original tweets from azure service #288
Add feature: get original tweets from azure service
- Loading branch information
Showing
9 changed files
with
284 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace DotNetRu.Azure | ||
{ | ||
/// <summary> | ||
/// Shared logger | ||
/// </summary> | ||
internal static class ApplicationLogging | ||
{ | ||
internal static ILoggerFactory LoggerFactory { get; set; }// = new LoggerFactory(); | ||
internal static ILogger CreateLogger<T>() => LoggerFactory.CreateLogger<T>(); | ||
internal static ILogger CreateLogger(string categoryName) => LoggerFactory.CreateLogger(categoryName); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using DotNetRu.AzureService; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.Extensions.Logging; | ||
using Newtonsoft.Json; | ||
|
||
namespace DotNetRu.Azure | ||
{ | ||
[Route("tweet")] | ||
public class TweetController : ControllerBase | ||
{ | ||
private readonly ILogger logger; | ||
|
||
private readonly TweetSettings tweetSettings; | ||
|
||
private readonly PushNotificationsManager pushNotificationsManager; | ||
|
||
public TweetController( | ||
ILogger<DiagnosticsController> logger, | ||
TweetSettings tweetSettings, | ||
PushNotificationsManager pushNotificationsManager) | ||
{ | ||
this.logger = logger; | ||
this.tweetSettings = tweetSettings; | ||
this.pushNotificationsManager = pushNotificationsManager; | ||
} | ||
|
||
[HttpGet] | ||
[Route("get_original")] | ||
public async Task<IActionResult> GetOriginalTweets() | ||
{ | ||
try | ||
{ | ||
var tweets = await TweetService.GetAsync(tweetSettings); | ||
var json = JsonConvert.SerializeObject(tweets); | ||
|
||
return new OkObjectResult(json); | ||
} | ||
catch (Exception e) | ||
{ | ||
logger.LogCritical(e, "Unhandled error while getting original tweets"); | ||
return new ObjectResult(e) | ||
{ | ||
StatusCode = StatusCodes.Status500InternalServerError | ||
}; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace DotNetRu.Azure | ||
{ | ||
public static class StringExtensions | ||
{ | ||
internal static string ConvertToUsualUrl(this string input, List<KeyValuePair<string, string>> replacements) | ||
{ | ||
var returnString = new StringBuilder(input); | ||
foreach (var replacement in replacements) | ||
{ | ||
returnString.Replace(replacement.Key, replacement.Value); | ||
} | ||
|
||
return Regex.Replace(returnString.ToString(), @"https:\/\/t\.co\/.+$", string.Empty); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using System; | ||
|
||
namespace DotNetRu.Azure | ||
{ | ||
public class Tweet | ||
{ | ||
public Tweet(ulong statusID) | ||
{ | ||
StatusID = statusID; | ||
} | ||
|
||
private string tweetedImage; | ||
|
||
public bool HasImage => !string.IsNullOrWhiteSpace(this.tweetedImage); | ||
|
||
public string TweetedImage | ||
{ | ||
get => this.tweetedImage; | ||
set => this.tweetedImage = value; | ||
} | ||
|
||
public int? NumberOfLikes { get; set; } | ||
|
||
public int NumberOfRetweets { get; set; } | ||
|
||
public int NumberOfComments { get; set; } | ||
|
||
public ulong StatusID { get; } | ||
|
||
public string Text { get; set; } | ||
|
||
public string Image { get; set; } | ||
|
||
public string Url { get; set; } | ||
|
||
public string Name { get; set; } | ||
|
||
public string ScreenName { get; set; } | ||
|
||
public DateTime CreatedDate { get; set; } | ||
|
||
public string TitleDisplay => this.Name; | ||
|
||
public string SubtitleDisplay => "@" + this.ScreenName; | ||
|
||
public string DateDisplay => this.CreatedDate.ToShortDateString(); | ||
|
||
public Uri TweetedImageUri | ||
{ | ||
get | ||
{ | ||
try | ||
{ | ||
if (string.IsNullOrWhiteSpace(this.TweetedImage)) | ||
{ | ||
return null; | ||
} | ||
|
||
return new Uri(this.TweetedImage); | ||
} | ||
catch | ||
{ | ||
// TODO ignored | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
|
||
public bool HasAttachedImage => !string.IsNullOrWhiteSpace(this.TweetedImage); | ||
|
||
public override string ToString() | ||
{ | ||
return $"[Name={Name};Text={Text};Retweets={NumberOfRetweets};Likes={NumberOfLikes}"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text.RegularExpressions; | ||
using System.Threading.Tasks; | ||
using DotNetRu.AzureService; | ||
using LinqToTwitter; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace DotNetRu.Azure | ||
{ | ||
internal class TweetService | ||
{ | ||
private static readonly ILogger Logger = ApplicationLogging.CreateLogger(nameof(TweetService)); | ||
|
||
/// <summary> | ||
/// Returns tweets by SpdDotNet/DotNetRu (if it's retweet then original tweet is returned instead of retweet) | ||
/// </summary> | ||
/// <returns> | ||
/// Returns a list of tweets. | ||
/// </returns> | ||
internal static async Task<List<Tweet>> GetAsync(TweetSettings tweetSettings) | ||
{ | ||
try | ||
{ | ||
var auth = new ApplicationOnlyAuthorizer | ||
{ | ||
CredentialStore = | ||
new InMemoryCredentialStore | ||
{ | ||
ConsumerKey = | ||
tweetSettings.ConsumerKey, | ||
ConsumerSecret = | ||
tweetSettings.ConsumerSecret | ||
}, | ||
}; | ||
await auth.AuthorizeAsync(); | ||
|
||
using var twitterContext = new TwitterContext(auth); | ||
var spbDotNetTweets = | ||
await (from tweet in twitterContext.Status | ||
where tweet.Type == StatusType.User && tweet.ScreenName == "spbdotnet" | ||
&& tweet.TweetMode == TweetMode.Extended | ||
select tweet).ToListAsync(); | ||
|
||
var dotnetRuTweets = | ||
await (from tweet in twitterContext.Status | ||
where tweet.Type == StatusType.User && tweet.ScreenName == "DotNetRu" | ||
&& tweet.TweetMode == TweetMode.Extended | ||
select tweet).ToListAsync(); | ||
|
||
var unitedTweets = spbDotNetTweets.Union(dotnetRuTweets).Where(tweet => !tweet.PossiblySensitive).Select(GetTweet); | ||
|
||
var tweetsWithoutDuplicates = unitedTweets.GroupBy(tw => tw.StatusID).Select(g => g.First()); | ||
|
||
var sortedTweets = tweetsWithoutDuplicates.OrderByDescending(x => x.CreatedDate).ToList(); | ||
|
||
return sortedTweets; | ||
} | ||
catch (Exception e) | ||
{ | ||
Logger.LogError(e, "Unhandled error while getting original tweets"); | ||
} | ||
|
||
return new List<Tweet>(); | ||
} | ||
|
||
private static Tweet GetTweet(Status tweet) | ||
{ | ||
var sourceTweet = tweet.RetweetedStatus.StatusID == 0 ? tweet : tweet.RetweetedStatus; | ||
|
||
var urlLinks = | ||
sourceTweet.Entities.UrlEntities.Select(t => new KeyValuePair<string, string>(t.Url, t.DisplayUrl)).ToList(); | ||
|
||
var profileImage = sourceTweet.User?.ProfileImageUrl.Replace("http://", "https://", StringComparison.InvariantCultureIgnoreCase); | ||
if (profileImage != null) | ||
{ | ||
//normal image is 48x48, bigger image is 73x73, see https://developer.twitter.com/en/docs/accounts-and-users/user-profile-images-and-banners | ||
profileImage = Regex.Replace(profileImage, @"(.+)_normal(\..+)", "$1_bigger$2"); | ||
} | ||
|
||
return new Tweet(sourceTweet.StatusID) | ||
{ | ||
TweetedImage = | ||
tweet.Entities?.MediaEntities.Count > 0 | ||
? tweet.Entities?.MediaEntities?[0].MediaUrlHttps ?? string.Empty | ||
: string.Empty, | ||
NumberOfLikes = sourceTweet.FavoriteCount, | ||
NumberOfRetweets = sourceTweet.RetweetCount, | ||
ScreenName = sourceTweet.User?.ScreenNameResponse ?? string.Empty, | ||
Text = sourceTweet.FullText.ConvertToUsualUrl(urlLinks), | ||
Name = sourceTweet.User?.Name, | ||
CreatedDate = tweet.CreatedAt, | ||
Url = $"https://twitter.com/{sourceTweet.User?.ScreenNameResponse}/status/{tweet.StatusID}", | ||
Image = profileImage | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters