コード例 #1
0
        public void Send(bool disableFilter)
        {
            var appId       = ConfigurationManager.AppSettings["MicrosoftAppId"];
            var appPassword = ConfigurationManager.AppSettings["MicrosoftAppPassword"];

            var nowUtc = DateTime.Now.ToUniversalTime();

            Log($"UTC現在時刻- {nowUtc}");

            var usersRepo = new UsersRepository();
            var users     = usersRepo.GetAllUsers().RunAsSync();

            var conversationStateRepo = new ConversationStateRepository();

            Log($"処理ユーザー数: {users.Count()}");
            foreach (var user in users)
            {
                try
                {
                    Log($"ユーザー: {user.NickName}({user.UserId}) ---");

                    var startHhmm = Hhmm.Parse(user.AskEndOfWorkStartTime);
                    var endHhmm   = Hhmm.Parse(user.AskEndOfWorkEndTime);

                    // 24時超過分をオフセットして比較する
                    // 19:00~26:00 の設定だった時に、翌日の深夜1時(25時)も送信対象となるように。
                    var offsetHour = endHhmm.Hour - 23;
                    if (offsetHour < 0)
                    {
                        offsetHour = 0;
                    }
                    Log($"オフセット時間: {offsetHour}h");

                    var tzUser    = TimeZoneInfo.FindSystemTimeZoneById(user.TimeZoneId);
                    var nowUserTz = TimeZoneInfo.ConvertTimeFromUtc(nowUtc, tzUser); // ユーザーのタイムゾーンでの現在時刻
                    Log($"ユーザータイムゾーンの現在時刻(オフセット前): {nowUserTz}");
                    nowUserTz = nowUserTz.AddHours(-offsetHour);
                    var nowHour         = nowUserTz.Hour + offsetHour;
                    var nowStepedMinute = nowUserTz.Minute / 30 * 30;
                    Log($"ユーザータイムゾーンの現在時刻(オフセット前、丸め後): {nowHour}時{nowStepedMinute:00}分");

                    var startTotalMinute = (startHhmm.Hour - offsetHour) * 60 + startHhmm.Minute;
                    var endTotalMinute   = (endHhmm.Hour - offsetHour) * 60 + endHhmm.Minute;
                    var nowTotalMinute   = (nowHour - offsetHour) * 60 + nowStepedMinute;
                    Log($"ユーザータイムゾーンの現在時刻(オフセット後、丸め後): {(nowHour - offsetHour)}時{nowStepedMinute:00}分");
                    Log($"判定時刻範囲(オフセット前): {startHhmm.Hour}時{startHhmm.Minute:00}分~{endHhmm.Hour}時{endHhmm.Minute:00}分");
                    Log($"判定時刻範囲(オフセット後): {(startHhmm.Hour - offsetHour)}時{startHhmm.Minute:00}分~{(endHhmm.Hour - offsetHour)}時{endHhmm.Minute:00}分");

                    if (startTotalMinute >= endTotalMinute)
                    {
                        Log($"{user.UserId} は、開始時刻({user.AskEndOfWorkStartTime})と終了時刻({user.AskEndOfWorkEndTime})が逆転しているので何もしない。");
                        continue;
                    }

                    var nowUserTzDateText = $"{nowUserTz.Year:0000}/{nowUserTz.Month:00}/{nowUserTz.Day:00}";  // ユーザーTZ現在時刻を文字列化

                    var stateEntity = conversationStateRepo.GetStatusByUserId(user.UserId).RunAsSync();

                    var currentTargetDate = stateEntity?.TargetDate ?? "2000/01/01";

                    // ターゲット日付と現在時刻が同じで、
                    // 打刻済/今日はもう聞かないで/休日だったら何もしない
                    var currentState = stateEntity?.State ?? AskingState.None;
                    if (!disableFilter)
                    {
                        if (string.Equals(nowUserTzDateText, currentTargetDate) &&
                            (currentState == AskingState.DoNotAskToday || currentState == AskingState.Punched || currentState == AskingState.TodayIsOff))
                        {
                            Log($"ターゲット日付({currentTargetDate})とユーザーTZ現在日付({nowUserTzDateText})が同じで、State が {currentState} なので何もしない");
                            continue;
                        }

                        // 今日の曜日はユーザー設定で有効か?
                        var enableDayOfWeek = (user.DayOfWeekEnables?.Length ?? 0) - 1 > (int)nowUserTz.DayOfWeek ?
                                              (user.DayOfWeekEnables[(int)nowUserTz.DayOfWeek] == '1') : true;
                        if (!enableDayOfWeek)
                        {
                            Log($"ユーザーTZ現在日付({nowUserTzDateText})の曜日は仕事が休みなので何もしない");
                            continue;
                        }

                        // FIXME 毎年ある祝日か、単発の休日かの管理が面倒なので、とりまオミットしておく
                        //// 祝日か?(面倒だからJson文字列のまま検索しちゃう)
                        //var isHoliday = user.HolidaysJson?.Contains($"\"{nowUserTz:M/d}\"") ?? false; // "6/1" みたいにダブルコートして検索すればいいっしょ
                        //if (isHoliday)
                        //{
                        //    Log($"ユーザーTZ現在日付({nowUserTzText})の休日に設定されている何もしない");
                        //    continue;
                        //}

                        var containsTimeRange = startTotalMinute <= nowTotalMinute && nowTotalMinute <= endTotalMinute;

                        // 聞き取り終了時刻を過ぎていたらStateをNoneにする
                        // AskingEoW のまま y を打たれると打刻できてしまうので。
                        if (startTotalMinute > endTotalMinute)
                        {
                            conversationStateRepo.UpsertState(
                                user.PartitionKey, user.UserId, AskingState.None, $"{endHhmm.Hour:00}{endHhmm.Minute:00}",
                                nowUserTzDateText).RunAsSync();
                        }

                        if (!containsTimeRange)
                        {
                            Log($"現在時刻({nowUserTz}) が {user.AskEndOfWorkStartTime} から {user.AskEndOfWorkEndTime} の範囲外なので何もしない");
                            continue;
                        }
                    }

                    var conversationRef = JsonConvert.DeserializeObject <ConversationReference>(user.ConversationRef);

                    MicrosoftAppCredentials.TrustServiceUrl(conversationRef.ServiceUrl);
                    var connector = new ConnectorClient(new Uri(conversationRef.ServiceUrl), appId, appPassword);

                    var userAccount = new ChannelAccount(id: user.UserId);
                    var res         = connector.Conversations.CreateDirectConversation(conversationRef.Bot, userAccount);

                    // conversationRef.GetPostToUserMessage() では Slack にポストできなかったので、
                    // 普通に CreateMessageActivity した。
                    var message = Activity.CreateMessageActivity();
                    message.From         = conversationRef.Bot;
                    message.Recipient    = userAccount;
                    message.Conversation = new ConversationAccount(id: res.Id);

                    message.Text = $"{user.NickName} さん、お疲れさまです。{nowHour}時{nowStepedMinute:00}分 です、今日のお仕事は終わりましたか?\n\n" +
                                   $"--\n\ny:終わった\n\nn:終わってない\n\nd:今日は徹夜";
                    message.Locale = "ja-Jp";

                    //message.Attachments.Add(new Attachment()
                    //{
                    //    ContentType = AdaptiveCard.ContentType,
                    //    Content = MakeAdaptiveCard()
                    //});

                    connector.Conversations.SendToConversation((Activity)message);

                    conversationStateRepo.UpsertState(
                        user.PartitionKey, conversationRef.User.Id, AskingState.AskingEoW, $"{nowHour:00}{nowStepedMinute:00}",
                        nowUserTzDateText).RunAsSync();

                    Log($"メッセージを送信しました。 ({message.Text})");
                }
                catch (Exception ex)
                {
                    Log($"メッセージ送信に失敗しました。 ({ex.Message} - {ex.StackTrace})");
                }
            }
        }