public async Task <User> LoginAsync(User user) { var db = _dbFactory.CreateDbContext(); // If it is feedreader user already (has id property), query user in db. if (!string.IsNullOrEmpty(user.Id)) { user = await db.Users.Include(u => u.Feeds).ThenInclude(f => f.Feed).FirstOrDefaultAsync(u => u.Id == user.Id); if (user == null) { throw new UnauthorizedAccessException(); } } else { // Not feedreader uuid, try to find from the related uuid index. var dbUser = await db.Users.Include(u => u.Feeds).ThenInclude(f => f.Feed).FirstOrDefaultAsync(u => u.ThirdPartyId == user.ThirdPartyId); if (dbUser != null) { user = dbUser; } else { // Not found, let's register it. user.Id = Guid.NewGuid().ToString("N").ToLower(); user.RegistrationTimeInUtc = DateTime.UtcNow; db.Users.Add(user); } } // Update last active time. user.LastActiveTimeInUtc = DateTime.UtcNow; await db.SaveChangesAsync(); // Generate our jwt token. var now = DateTimeOffset.UtcNow; user.Token = new JwtBuilder() .WithAlgorithm(new HMACSHA256Algorithm()) .WithSecret(Environment.GetEnvironmentVariable(Consts.ENV_KEY_JWT_SECRET)) .AddClaim("iss", Consts.FEEDREADER_ISS) .AddClaim("aud", Consts.FEEDREADER_AUD) .AddClaim("uid", user.Id) .AddClaim("iat", now.ToUnixTimeSeconds()) .AddClaim("exp", now.AddDays(7).ToUnixTimeSeconds()) .Encode(); return(user); }
public async Task UnsubscribeFeedAsync(string feedUri, User user) { var feedId = Utils.Sha256(feedUri.Trim().ToLower()); var userFeed = new ServerCore.Models.UserFeed { UserId = user.Id, FeedId = feedId }; var db = _dbFactory.CreateDbContext(); db.UserFeeds.Attach(userFeed); db.UserFeeds.Remove(userFeed); await db.SaveChangesAsync(); }
public async Task UpdateFeedAsync(string feedUri, string newFeedGroup, User user) { // Get the original feed. var feedId = Utils.Sha256(feedUri.Trim().ToLower()); var db = _dbFactory.CreateDbContext(); var userFeed = await db.UserFeeds.FindAsync(user.Id, feedId); if (userFeed == null) { throw new ExternalErrorExceptionNotFound(); } userFeed.Group = newFeedGroup; await db.SaveChangesAsync(); }
public async Task MarkItemsAsReaded(User user, string feedUri, DateTime lastReadedTime) { var feedId = Utils.Sha256(feedUri.Trim().ToLower()); var db = _dbFactory.CreateDbContext(); var userFeed = await db.UserFeeds.FindAsync(user.Id, feedId); if (userFeed == null) { throw new ExternalErrorExcepiton("'feedUri' is not found."); } // Update with latest feed info. userFeed.LastReadedTimeInUtc = lastReadedTime.ToUniversalTime(); await db.SaveChangesAsync(); }
public async Task AddRemoveFavoriteAsync(string feedItemId, bool add, User user) { var db = _dbFactory.CreateDbContext(); var userFeedItem = await db.UserFeedItems.FindAsync(user.Id, feedItemId); if (userFeedItem == null) { if (add) { db.UserFeedItems.Add(new UserFeedItem { UserId = user.Id, FeedItemId = feedItemId, IsFavorite = true, }); } } else { userFeedItem.IsFavorite = add; } await db.SaveChangesAsync(); }
public async Task <Feed> GetFeedItemsAsync(string feedUri, string feedShortId, int page, User user) { if (string.IsNullOrEmpty(feedUri) && string.IsNullOrEmpty(feedShortId)) { throw new ExternalErrorExcepiton($"FeedUri and FeedShortId can't be empty in both."); } string feedId = null; var db = _dbFactory.CreateDbContext(); if (string.IsNullOrEmpty(feedShortId)) { var originalUri = feedUri; feedUri = feedUri.Trim().ToLower(); feedId = Utils.Sha256(feedUri); } // Get feed information. // If the user blob is not null, we will get the feed from the user blob because user might customize the group and name on this feed. ServerCore.Models.UserFeed userFeed = null; ServerCore.Models.Feed feedInDb = null; if (user != null) { userFeed = await db.UserFeeds.Include(f => f.Feed).FirstOrDefaultAsync(u => u.UserId == user.Id && (u.FeedId == feedId || u.Feed.ShortId == feedShortId)); feedInDb = userFeed?.Feed; } // If we didn't get the feed, two possibility: // 1. The feed is not subscribed by user yet. // 2. Anonymous user. // No matter for which case, we will try to get the feed info from feed info table directly. if (feedInDb == null) { feedInDb = await db.Feeds.FirstOrDefaultAsync(f => f.Id == feedId || f.ShortId == feedShortId); } if (feedInDb == null) { throw new ExternalErrorExcepiton($"Feed '{feedUri ?? feedShortId}' is not found."); } feedId = feedInDb.Id; var feed = new Feed { ShortId = feedInDb.ShortId, Description = feedInDb.Description, IconUri = feedInDb.IconUri, Name = feedInDb.Name, OriginalUri = feedInDb.Uri, Uri = feedUri, WebsiteLink = feedInDb.WebSiteUri, }; if (userFeed != null) { feed.Group = userFeed.Group; } // Get feed items. var feedItems = await db.FeedItems .Where(f => f.FeedId == feedId) .OrderByDescending(f => f.PublishTimeInUtc) .Skip(page * 50) .Take(50).ToListAsync(); if (feedItems.Count > 0) { feed.Items = feedItems.Select(f => new FeedItem { Id = f.Id, Summary = f.Summary, Content = f.Content, PermentLink = f.Uri, PubDate = f.PublishTimeInUtc, Title = f.Title, TopicPictureUri = f.TopicPictureUri, }).ToList(); } // Mark readed or not. if (userFeed != null && userFeed.LastReadedTimeInUtc.Ticks != 0) { foreach (var feedItem in feed.Items) { if (feedItem.PubDate <= userFeed.LastReadedTimeInUtc) { feedItem.IsReaded = true; } } } // Mark stared or not. if (user != null) { // Mark stared or not var favorites = db.UserFeedItems.Where(f => f.UserId == user.Id && f.IsFavorite).Select(f => f.FeedItemId).ToList(); if (favorites.Count > 0) { foreach (var feedItem in feed.Items) { if (favorites.Find(id => id == feedItem.PermentLink.Sha256()) != null) { feedItem.IsStared = true; } } } } // All done. return(feed); }
public async Task <Feed> SubscribeFeedAsync(string feedOriginalUri, string customGroup, User user) { Feed feed = null; string feedUriHash = null; var db = _dbFactory.CreateDbContext(); for (var i = 0; i < 10; ++i) { var feedUri = feedOriginalUri.Trim().ToLower(); feedUriHash = Utils.Sha256(feedUri); // Do we have this feed already? var feedInDb = await db.Feeds.FindAsync(feedUriHash); if (feedInDb == null) { // Get information of this feed. feed = await RefreshFeedAsync(feedOriginalUri, noItems : true); if (feed.Error != null) { // This uri may not be the feed uri. It maybe the webpage, let's try to find out the potential feed uri in this webpage. feedOriginalUri = await DiscoverFeedUriAsync(feedOriginalUri); if (string.IsNullOrWhiteSpace(feedOriginalUri)) { break; } continue; } // Save to feed table. feedInDb = new ServerCore.Models.Feed { Description = feed.Description, IconUri = feed.IconUri, Id = feedUriHash, UriHash = feedUriHash, Name = feed.Name, RegistrationTimeInUtc = DateTime.UtcNow, WebSiteUri = feed.WebsiteLink, Uri = feed.OriginalUri, }; db.Feeds.Add(feedInDb); var tryTimes = 0; for (; tryTimes < 10; ++tryTimes) { if (tryTimes == 0) { feedInDb.ShortId = Utils.Crc32(feedInDb.Id); } else { feedInDb.ShortId = Utils.Crc32(feedInDb.Id + tryTimes); } try { await db.SaveChangesAsync(); feed.ShortId = feedInDb.ShortId; break; } catch (DbUpdateException ex) when(ex.IsUniqueConstraintException()) { if (await _dbFactory.CreateDbContext().Feeds.FindAsync(feedUriHash) != null) { // Save to ignore. break; } } } if (tryTimes < 10) { break; } else { throw new ExternalErrorExcepiton($"Save feed {feed.OriginalUri} failed."); } } else { feed = new Feed { ShortId = feedInDb.ShortId, Description = feedInDb.Description, IconUri = feedInDb.IconUri, Name = feedInDb.Name, OriginalUri = feedInDb.Uri, Uri = feedUri, WebsiteLink = feedInDb.WebSiteUri, }; break; } } Debug.Assert(feed != null); Debug.Assert(feedUriHash != null); // User user customized group. feed.Group = customGroup; // Save to usersfeeds table. db.UserFeeds.Add(new ServerCore.Models.UserFeed { UserId = user.Id, FeedId = feedUriHash, Group = customGroup }); try { await db.SaveChangesAsync(); } catch (DbUpdateException ex) when(ex.IsUniqueConstraintException()) { // Save to ignore. } // Return return(feed); }
public async Task <List <ServerCore.Models.FeedItem> > GetStaredFeedItemsAsync(int page, User user) { var db = _dbFactory.CreateDbContext(); return(await db.UserFeedItems .Where(f => f.UserId == user.Id && f.IsFavorite) .OrderByDescending(f => f.FeedItem.PublishTimeInUtc) .Skip(page * 50) .Take(50) .Include(f => f.FeedItem) .ThenInclude(f => f.Feed) .Select(f => f.FeedItem) .ToListAsync()); }
public async Task UnstarFeedItemAsync(string feedItemPermentLink, DateTime pubDate, User user) { // Remove from the star items table. var db = _dbFactory.CreateDbContext(); var feedItemId = feedItemPermentLink.Sha256(); var userFeedItem = await db.UserFeedItems.FindAsync(user.Id, feedItemId); if (userFeedItem != null) { userFeedItem.IsFavorite = false; await db.SaveChangesAsync(); } }