/// <summary> /// 创建 <see cref="CouponGiftList"/> /// </summary> /// <param name="currentUserId">当前用户Id</param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="cachedData"><see cref="CachedDataProvider"/></param> /// <param name="userManager"><see cref="KeylolUserManager"/></param> /// <param name="coupon"><see cref="CouponProvider"/></param> public static async Task <CouponGiftList> CreateAsync(string currentUserId, KeylolDbContext dbContext, CachedDataProvider cachedData, KeylolUserManager userManager, CouponProvider coupon) { var queryResult = await dbContext.CouponGifts.Where(g => DateTime.Now < g.EndTime) .OrderByDescending(g => g.CreateTime) .ToListAsync(); var currentUser = await userManager.FindByIdAsync(currentUserId); var result = new CouponGiftList(queryResult.Count); foreach (var g in queryResult) { GiftProcessor processor; switch (g.Type) { case CouponGiftType.Custom: processor = new CustomProcessor(); break; case CouponGiftType.SteamCnCredit: processor = new SteamCnCreditProcessor(dbContext, userManager, coupon); break; case CouponGiftType.SteamGiftCard: processor = new SteamGiftCardProcessor(dbContext, coupon); break; default: throw new ArgumentOutOfRangeException(); } var stateTreeGift = new CouponGift { Id = g.Id, Name = g.Name, Descriptions = Helpers.SafeDeserialize <List <string> >(g.Descriptions), Price = g.Price, ThumbnailImage = g.ThumbnailImage, Type = g.Type }; processor.Initialize(currentUser, g); await processor.FillPropertiesAsync(stateTreeGift); result.Add(stateTreeGift); } return(result); }
/// <summary> /// 判断指定用户是否有足够文券触发指定事件 /// </summary> /// <param name="userId">用户 ID</param> /// <param name="event">文券事件</param> /// <returns>可以触发指定事件返回 true,不能则返回 false</returns> public async Task <bool> CanTriggerEventAsync(string userId, CouponEvent @event) { var user = await _userManager.FindByIdAsync(userId); return(user.Coupon + @event.ToCouponChange() >= 0); }
/// <summary> /// 获取新的完整状态树 /// </summary> /// <param name="state">当前 UI 状态</param> /// <param name="userManager"><see cref="KeylolUserManager"/></param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="coupon"><see cref="CouponProvider"/></param> /// <param name="cachedData"><see cref="CachedDataProvider"/></param> /// <param name="pointIdCode">据点识别码</param> /// <param name="authorIdCode">作者识别码</param> /// <param name="userIdCode">用户识别码</param> /// <param name="sidForAuthor">文章在作者名下的序号</param> /// <param name="keyword">搜索关键字</param> /// <returns>完整状态树</returns> public static async Task <Root> Locate(string state, [Injected] KeylolUserManager userManager, [Injected] KeylolDbContext dbContext, [Injected] CouponProvider coupon, [Injected] CachedDataProvider cachedData, string pointIdCode = null, string authorIdCode = null, string userIdCode = null, int sidForAuthor = 0, string keyword = null) { var root = new Root(); var currentUserId = StateTreeHelper.GetCurrentUserId(); var isOperator = StateTreeHelper.GetCurrentUser().IsInRole(KeylolRoles.Operator); if (await StateTreeHelper.CanAccessAsync <Root>(nameof(CurrentUser))) { var user = await userManager.FindByIdAsync(currentUserId); root.CurrentUser = await CurrentUser.CreateAsync(user, userManager, dbContext, coupon, cachedData); } switch (state) { case "entrance": root.Entrance = await EntranceLevel.CreateAsync(currentUserId, States.Entrance.EntrancePage.Auto, dbContext, cachedData); break; case "entrance.discovery": root.Entrance = await EntranceLevel.CreateAsync(currentUserId, States.Entrance.EntrancePage.Discovery, dbContext, cachedData); break; case "entrance.points": root.Entrance = await EntranceLevel.CreateAsync(currentUserId, States.Entrance.EntrancePage.Points, dbContext, cachedData); break; case "entrance.timeline": root.Entrance = await EntranceLevel.CreateAsync(currentUserId, States.Entrance.EntrancePage.Timeline, dbContext, cachedData); break; case "aggregation.point": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.Auto, dbContext, cachedData) }; break; case "aggregation.point.frontpage": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.Frontpage, dbContext, cachedData) }; break; case "aggregation.point.intel": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.Intel, dbContext, cachedData) }; break; case "aggregation.point.product": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.Product, dbContext, cachedData) }; break; case "aggregation.point.timeline": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.Timeline, dbContext, cachedData) }; break; case "aggregation.point.edit.info": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.EditInfo, dbContext, cachedData) }; break; case "aggregation.point.edit.style": root.Aggregation = new AggregationLevel { Point = await PointLevel.CreateAsync(currentUserId, pointIdCode, States.Aggregation.Point.EntrancePage.EditStyle, dbContext, cachedData) }; break; case "aggregation.user": root.Aggregation = new AggregationLevel { User = await UserLevel.CreateAsync(currentUserId, userIdCode, EntrancePage.Auto, dbContext, cachedData, userManager) }; break; case "aggregation.user.dossier": root.Aggregation = new AggregationLevel { User = await UserLevel.CreateAsync(currentUserId, userIdCode, EntrancePage.Dossier, dbContext, cachedData, userManager) }; break; case "aggregation.user.people": root.Aggregation = new AggregationLevel { User = await UserLevel.CreateAsync(currentUserId, userIdCode, EntrancePage.People, dbContext, cachedData, userManager) }; break; case "aggregation.user.timeline": root.Aggregation = new AggregationLevel { User = await UserLevel.CreateAsync(currentUserId, userIdCode, EntrancePage.Timeline, dbContext, cachedData, userManager) }; break; case "aggregation.user.edit": root.Aggregation = new AggregationLevel { User = await UserLevel.CreateAsync(currentUserId, userIdCode, EntrancePage.Edit, dbContext, cachedData, userManager) }; break; case "content.article": root.Content = new ContentLevel { Article = await States.Content.Article.ArticlePage.CreateAsync(authorIdCode, sidForAuthor, currentUserId, isOperator, dbContext, cachedData, userManager) }; break; case "content.activity": root.Content = new ContentLevel { Activity = await ActivityPage.CreateAsync(authorIdCode, sidForAuthor, currentUserId, isOperator, dbContext, cachedData, userManager) }; break; case "post-office.unread": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(PostOffice))) { root.PostOffice = new PostOfficeLevel { Unread = await UnreadPage.CreateAsync(currentUserId, dbContext, cachedData) } } ; break; case "post-office.social-activity.comment": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(PostOffice))) { root.PostOffice = new PostOfficeLevel { SocialActivity = new SocialActivityLevel { Comment = await CommentPage.CreateAsync(currentUserId, dbContext, cachedData) } } } ; break; case "post-office.social-activity.like": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(PostOffice))) { root.PostOffice = new PostOfficeLevel { SocialActivity = new SocialActivityLevel { Like = await LikePage.CreateAsync(currentUserId, dbContext, cachedData) } } } ; break; case "post-office.social-activity.subscriber": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(PostOffice))) { root.PostOffice = new PostOfficeLevel { SocialActivity = new SocialActivityLevel { Subscriber = await SubscriberPage.CreateAsync(currentUserId, dbContext, cachedData) } } } ; break; case "post-office.missive": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(PostOffice))) { root.PostOffice = new PostOfficeLevel { Missive = await MissivePage.CreateAsync(currentUserId, dbContext, cachedData) } } ; break; case "coupon.detail": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(Coupon))) { root.Coupon = new CouponLevel { Detail = await DetailPage.CreateAsync(currentUserId, dbContext, userManager) } } ; break; case "coupon.store": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(Coupon))) { root.Coupon = new CouponLevel { Store = await StorePage.CreateAsync(currentUserId, dbContext, cachedData, userManager, coupon) } } ; break; case "coupon.ranking": if (await StateTreeHelper.CanAccessAsync <Root>(nameof(Coupon))) { root.Coupon = new CouponLevel { Ranking = await RankingPage.CreateAsync(currentUserId, dbContext, cachedData) } } ; break; case "search.point": root.Search = new SearchLevel { Point = await PointPage.CreateAsync(currentUserId, keyword, dbContext, cachedData) }; break; case "search.article": root.Search = new SearchLevel { Article = await ArticlePage.CreateAsync(keyword, dbContext, cachedData) }; break; case "search.user": root.Search = new SearchLevel { User = await UserPage.CreateAsync(currentUserId, keyword, dbContext, cachedData) }; break; default: throw new NotSupportedException("Not supported state."); } return(root); }
private static async Task <object> ParseDescriptionAsync(string descriptionText, KeylolDbContext dbContext, KeylolUserManager userManager) { var description = Helpers.SafeDeserialize <JObject>(descriptionText); if (description == null) { return(Helpers.SafeDeserialize <string>(descriptionText)); } Func <object, JObject> jObject = o => JObject.FromObject(o, new JsonSerializer { NullValueHandling = NullValueHandling.Ignore }); Func <string, string, Task> fillUser = async(field, newField) => { if (description[field] != null) { var user = await userManager.FindByIdAsync((string)description[field]); if (user != null) { description.Remove(field); description[newField] = jObject(new { user.UserName, user.IdCode }); } } }; Func <string, string> truncateContent = content => content.Length > 15 ? $"{content.Substring(0, 15)} …" : content; if (description["ArticleId"] != null) { var article = await dbContext.Articles.FindAsync((string)description["ArticleId"]); if (article != null) { description.Remove("ArticleId"); description["Article"] = jObject(new { article.Title, article.SidForAuthor, article.Author.IdCode }); } } if (description["CommentId"] != null || description["ArticleCommentId"] != null) { var commentId = description["ArticleCommentId"] ?? description["CommentId"]; var comment = await dbContext.ArticleComments.FindAsync((string)commentId); if (comment != null) { description.Remove("ArticleCommentId"); description.Remove("CommentId"); description["ArticleComment"] = jObject(new { Content = truncateContent(comment.UnstyledContent), ArticleAuthorIdCode = comment.Article.Author.IdCode, comment.Article.SidForAuthor, comment.SidForArticle }); } } if (description["ActivityId"] != null) { var activity = await dbContext.Activities.FindAsync((string)description["ActivityId"]); if (activity != null) { description.Remove("ActivityId"); description["Activity"] = jObject(new { Content = PostOffice.PostOfficeMessageList.CollapseActivityContent(activity, 15), activity.SidForAuthor, activity.Author.IdCode }); } } if (description["ActivityCommentId"] != null) { var comment = await dbContext.ActivityComments.FindAsync((string)description["ActivityCommentId"]); if (comment != null) { description.Remove("ActivityCommentId"); description["ActivityComment"] = jObject(new { Content = truncateContent(comment.Content), ArticleAuthorIdCode = comment.Activity.Author.IdCode, comment.Activity.SidForAuthor, comment.SidForActivity }); } } if (description["CouponGiftId"] != null) { var gift = await dbContext.CouponGifts.FindAsync((string)description["CouponGiftId"]); if (gift != null) { description.Remove("CouponGiftId"); description["CouponGift"] = jObject(new { gift.Id, gift.Name }); } } await fillUser("OperatorId", "Operator"); await fillUser("UserId", "User"); await fillUser("InviterId", "Inviter"); return(description); }
/// <summary> /// 抓取指定用户的 Steam App 库 /// </summary> /// <param name="userId">用户 ID</param> /// <param name="dbContext"><see cref="KeylolDbContext"/></param> /// <param name="userManager"><see cref="KeylolUserManager"/></param> /// <param name="redis"><see cref="RedisProvider"/></param> /// <param name="cachedData"><see cref="CachedDataProvider.CachedDataProvider"/></param> /// <returns>如果抓取成功,返回 <c>true</c></returns> public static async Task <bool> UpdateUserSteamGameRecordsAsync([NotNull] string userId, KeylolDbContext dbContext, KeylolUserManager userManager, RedisProvider redis, CachedDataProvider.CachedDataProvider cachedData) { var cacheKey = UserSteamGameRecordsCrawlerStampCacheKey(userId); var redisDb = redis.GetDatabase(); var cacheResult = await redisDb.StringGetAsync(cacheKey); if (cacheResult.HasValue) { return(false); } await redisDb.StringSetAsync(cacheKey, DateTime.Now.ToTimestamp(), UserSteamGameRecordsUpdatePeriod); try { var user = await userManager.FindByIdAsync(userId); var steamId = new SteamID(); steamId.SetFromSteam3String(await userManager.GetSteamIdAsync(user.Id)); string allGamesHtml; if (user.SteamBotId != null && user.SteamBot.IsOnline()) { var botCoordinator = SteamBotCoordinator.Sessions[user.SteamBot.SessionId]; allGamesHtml = await botCoordinator.Client.Curl(user.SteamBotId, $"http://steamcommunity.com/profiles/{steamId.ConvertToUInt64()}/games/?tab=all&l=english"); } else { allGamesHtml = await HttpClient.GetStringAsync( $"http://steamcommunity.com/profiles/{steamId.ConvertToUInt64()}/games/?tab=all&l=english"); } if (string.IsNullOrWhiteSpace(allGamesHtml)) { throw new Exception(); } var match = Regex.Match(allGamesHtml, @"<script language=""javascript"">\s*var rgGames = (.*)"); if (!match.Success) { throw new Exception(); } var trimed = match.Groups[1].Value.Trim(); var games = JArray.Parse(trimed.Substring(0, trimed.Length - 1)); var oldRecords = (await dbContext.UserSteamGameRecords.Where(r => r.UserId == user.Id).ToListAsync()) .ToDictionary(r => r.SteamAppId, r => r); foreach (var game in games) { var appId = (int)game["appid"]; UserSteamGameRecord record; if (oldRecords.TryGetValue(appId, out record)) { oldRecords.Remove(appId); } else { record = new UserSteamGameRecord { UserId = user.Id, SteamAppId = appId }; dbContext.UserSteamGameRecords.Add(record); } record.TwoWeekPlayedTime = game["hours"] != null ? (double)game["hours"] : 0; record.TotalPlayedTime = game["hours_forever"] != null ? (double)game["hours_forever"] : 0; if (game["last_played"] != null) { record.LastPlayTime = Helpers.DateTimeFromTimeStamp((ulong)game["last_played"]); } } dbContext.UserSteamGameRecords.RemoveRange(oldRecords.Values); await dbContext.SaveChangesAsync(); await cachedData.Users.PurgeSteamAppLibraryCacheAsync(userId); return(true); } catch (Exception) { await redisDb.KeyExpireAsync(cacheKey, SilenceTime); return(false); } }