Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
        /// <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);
        }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
0
        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);
            }
        }