def get_conn(self, keyword: str, keyword_type: AutoReplyContentType, channel_oid: ObjectId, case_insensitive: bool = True) -> \ Optional[AutoReplyModuleModel]: ret: Optional[AutoReplyModuleModel] = \ self.find_one_casted( { AutoReplyModuleModel.KEY_KW_CONTENT: keyword, AutoReplyModuleModel.KEY_KW_TYPE: keyword_type, AutoReplyModuleModel.ChannelId.key: channel_oid, AutoReplyModuleModel.Active.key: True }, parse_cls=AutoReplyModuleModel, collation=case_insensitive_collation if case_insensitive else None) if ret: now = now_utc_aware() if ret.can_be_used(now): q_found = {AutoReplyModuleModel.Id.key: ret.id} u_query = { "$set": { AutoReplyModuleModel.LastUsed.key: now }, "$inc": { AutoReplyModuleModel.CalledCount.key: 1 } } self.update_one_async(q_found, u_query) return ret return None
def test_to_string(self): now = now_utc_aware() seoul_tzinfo = LocaleInfo.get_tzinfo("Asia/Taipei") actual_str = self.get_data().to_string(self.get_user_model()) expected_str = [ Timer.FUTURE.format( event=TestTimerListResult.TMR_3.title, diff=t_delta_str( TestTimerListResult.TMR_3.get_target_time_diff(now)), time=localtime(TestTimerListResult.TMR_3.target_time, seoul_tzinfo)), Timer.FUTURE.format( event=TestTimerListResult.TMR_4.title, diff=t_delta_str( TestTimerListResult.TMR_4.get_target_time_diff(now)), time=localtime(TestTimerListResult.TMR_4.target_time, seoul_tzinfo)), "", Timer.PAST_CONTINUE.format( event=TestTimerListResult.TMR_2.title, diff=t_delta_str( TestTimerListResult.TMR_2.get_target_time_diff(now)), time=localtime(TestTimerListResult.TMR_2.target_time, seoul_tzinfo)), "", Timer.PAST_DONE.format( event=TestTimerListResult.TMR_1.title, diff=t_delta_str( TestTimerListResult.TMR_1.get_target_time_diff(now)), time=localtime(TestTimerListResult.TMR_1.target_time, seoul_tzinfo)) ] expected_str = "\n".join(expected_str) self.assertEqual(actual_str, expected_str)
def get_notify(self, channel_oid: ObjectId, within_secs: Optional[int] = None) -> List[TimerModel]: now = now_utc_aware() filter_ = { TimerModel.ChannelOid.key: channel_oid, TimerModel.TargetTime.key: { "$lt": now + timedelta(seconds=within_secs if within_secs else Bot. Timer.MaxNotifyRangeSeconds), "$gt": now }, TimerModel.Notified.key: False } ret = list( self.find_cursor_with_count(filter_, parse_cls=TimerModel).sort([ (TimerModel.TargetTime.key, pymongo.ASCENDING) ])) self.update_many_async(filter_, {"$set": { TimerModel.Notified.key: True }}) return ret
def _remove_update_ops_(self, remover_oid: ObjectId): return { "$set": { AutoReplyModuleModel.Active.key: False, AutoReplyModuleModel.RemovedAt.key: now_utc_aware(), AutoReplyModuleModel.RemoverOid.key: remover_oid } }
def record_message(self, channel_oid: ObjectId, user_root_oid: ObjectId, message_type: MessageType, message_content: Any, proc_time_secs: float): self.insert_one_data(ChannelOid=channel_oid, UserRootOid=user_root_oid, MessageType=message_type, MessageContent=str(message_content) [:Database.MessageStats.MaxContentCharacter], ProcessTimeSecs=proc_time_secs, Timestamp=now_utc_aware())
def test_dt_naive(self): self.assertTrue(is_tz_naive(datetime.now())) self.assertTrue(is_tz_naive(datetime.utcnow())) self.assertTrue(is_tz_naive(localtime().replace(tzinfo=None))) self.assertFalse(is_tz_naive(now_utc_aware())) self.assertTrue(is_tz_naive(datetime(2020, 5, 7))) self.assertTrue(is_tz_naive(datetime.min)) self.assertFalse(is_tz_naive( datetime.min.replace(tzinfo=timezone.utc))) self.assertTrue(is_tz_naive(datetime.max)) self.assertFalse(is_tz_naive( datetime.max.replace(tzinfo=timezone.utc)))
def __post_init__(self, cursor): now = now_utc_aware() for mdl in cursor: self.has_data = True if mdl.is_after(now): self.future.append(mdl) else: if mdl.countup: self.past_continue.append(mdl) else: self.past_done.append(mdl)
def test_locale_info(self): """Only testing if the info can be acquired without any exceptions. Not testing the correctness.""" for locale in locales: with self.subTest(locale=locale): self.assertIsNotNone(locale.current_utc_hr_offset) pytzinfo = locale.to_tzinfo() now = now_utc_aware() self.assertIsNotNone(pytzinfo) self.assertIsNotNone(pytzinfo.utcoffset(now)) self.assertIsNotNone(pytzinfo.dst(now)) self.assertIsNotNone(pytzinfo.tzname(now)) self.assertEqual(locale.pytz_code, pytzinfo.tzidentifier)
def process_timer_notification( e: TextMessageEventObject) -> List[HandledMessageEvent]: within_secs = min( TimerManager.get_notify_within_secs( MessageRecordStatisticsManager.get_message_frequency( e.channel_oid, Bot.Timer.MessageFrequencyRangeMin)), Bot.Timer.MaxNotifyRangeSeconds) tmr_ntf = TimerManager.get_notify(e.channel_oid, within_secs) tmr_up = TimerManager.get_time_up(e.channel_oid) ret = [] if tmr_up: ret.append(_("**{} timer(s) have timed up!**").format(len(tmr_up))) ret.append("") for tmr in tmr_up: ret.append( _("- {event} has timed up! (at {time})").format( event=tmr.title, time=localtime(tmr.target_time, e.user_model.config.tzinfo))) if tmr_ntf: if ret: ret.append("-------------") now = now_utc_aware() ret.append( _("**{} timer(s) will time up in less than {:.0f} minutes!**"). format(len(tmr_ntf), within_secs / 60)) ret.append("") for tmr in tmr_ntf: ret.append( _("- {event} will time up after [{diff}]! (at {time})").format( event=tmr.title, diff=t_delta_str(tmr.get_target_time_diff(now)), time=localtime(tmr.target_time, e.user_model.config.tzinfo))) if ret and ret[-1] == "": ret = ret[:-1] if ret: return [HandledMessageEventText(content="\n".join(ret))] else: return []
def get(self, request, *args, **kwargs): root_oid = get_root_oid(request) if root_oid and now_utc_aware() - root_oid.generation_time < timedelta( days=Website.NewRegisterThresholdDays): messages.info( request, _('It seems that you haven\'t integrate your account. ' 'Visit <a href="{}{}">this page</a> to know what to do to fully utilize this bot!' ).format( HostUrl, reverse("page.doc.botcmd.cmd", kwargs={"code": cmd_uintg.main_cmd_code})), extra_tags="safe") return render_template(request, _("Home Page"), "index.html")
def test_fill_all_none(self): tr = TimeRange() now = now_utc_aware() self.assertIsNone(tr.start) self.assertIsNone(tr.start_org) self.assertAlmostEquals(0, abs((tr.end - now).total_seconds()), 0) self.assertIsNone(tr.tzinfo_) self.assertFalse(tr.expandable) self.assertFalse(tr.expanded) self.assertTrue(tr.is_inf) self.assertEqual(math.inf, tr.hr_length_org) self.assertEqual(math.inf, tr.hr_length) self.assertEqual(f"- ~ {now.strftime('%m-%d')}", tr.expr_period_short) self.assertAlmostEquals(tr.end_time_seconds, time_to_seconds(now), 0) prd = tr.get_periods() self.assertListEqual([tr], prd)
def get(self, request, *args, **kwargs): u_data = RootUserManager.get_root_data_api_token( self.request.COOKIES[keys.Cookies.USER_TOKEN]) excde_list = ExecodeManager.get_queued_execodes(u_data.model.id) return render_template( self.request, _("Account Home"), "account/main.html", { "root_data": u_data.model, "api_user_data": u_data.model_api, "execode_list": excde_list, "onplat_user_data_list": u_data.model_onplat_list, "reg_time_str": t_delta_str(now_utc_aware() - u_data.model.id.generation_time) })
def get_message_frequency(self, channel_oid: ObjectId, within_mins: Union[float, int] = 720) -> float: """Get message frequency in terms of seconds per message.""" rct_msg_count = self.count_documents({ MessageRecordModel.ChannelOid.key: channel_oid, OID_KEY: { "$gt": ObjectId.from_datetime(now_utc_aware() - timedelta(minutes=within_mins)) } }) if rct_msg_count > 0: return (within_mins * 60) / rct_msg_count else: return 0.0
def _delete_recent_module_(self, keyword): """Delete modules which is created and marked inactive within `Bot.AutoReply.DeleteDataMins` minutes.""" now = now_utc_aware() self.delete_many( { OID_KEY: { "$lt": ObjectId.from_datetime(now), "$gt": ObjectId.from_datetime(now - timedelta( minutes=Bot.AutoReply.DeleteDataMins)) }, AutoReplyModuleModel.KEY_KW_CONTENT: keyword, AutoReplyModuleModel.Active.key: False }, collation=case_insensitive_collation if AutoReply.CaseInsensitive else None)
def data_days_collected(collection, filter_, *, hr_range: Optional[int] = None, start: Optional[datetime] = None, end: Optional[datetime] = None): """ Returns the count of days collected in data. Notice that this is different from ``days_collected`` in ``__init__()`` because this one connects to the database to calculate the actual days collected in the filtered dataset while the one in ``__init__()`` will not be checked and assume that it is true. ``hr_range`` will be ignored if both ``start`` and ``end`` is specified. """ trange = TimeRange(range_hr=hr_range, start=start, end=end, end_autofill_now=False) if trange.is_inf: oldest = collection.find_one(filter_, sort=[(OID_KEY, pymongo.ASCENDING)]) if not oldest: return HourlyResult.DAYS_NONE now = now_utc_aware() if start: start = make_tz_aware(start) if start and start > now: return HourlyResult.DAYS_NONE if end: end = make_tz_aware(end) return max( ((end or now) - ObjectId(oldest[OID_KEY]).generation_time).total_seconds() / 86400, 0) else: return trange.hr_length / 24
def test_nfill_range_only(self): tr = TimeRange(range_hr=120, end_autofill_now=False) now = now_utc_aware() expected_start = now - timedelta(hours=120) self.assertAlmostEquals( 0, abs((expected_start - tr.start).total_seconds()), 0) self.assertAlmostEquals( 0, abs((expected_start - tr.start_org).total_seconds()), 0) self.assertIsNone(tr.end) self.assertIsNone(tr.tzinfo_) self.assertFalse(tr.expandable) self.assertFalse(tr.expanded) self.assertTrue(tr.is_inf) self.assertAlmostEquals(120, tr.hr_length_org, 0) self.assertAlmostEquals(120, tr.hr_length, 0) self.assertEqual(f"{expected_start.strftime('%m-%d')} ~ -", tr.expr_period_short) self.assertAlmostEquals(tr.end_time_seconds, time_to_seconds(now), 0) prd = tr.get_periods() self.assertListEqual([tr], prd)
def __post_init__(self): msg_count = len(self.data) proc_secs = [msg.model.process_time_secs for msg in self.data] self.avg_processing_secs = sum(proc_secs) / msg_count counter = {mt: 0 for mt in MessageType} for entry in self.data: counter[MessageType.cast(entry.model.message_type)] += 1 self.msg_composition = HandledMessagesComposition(counter) self.unique_sender_count = len( {data.model.user_root_oid for data in self.data}) if self.data: self.message_frequency = \ (now_utc_aware() - self.data[-1].model.id.generation_time).total_seconds() / msg_count else: self.message_frequency = 0.0
def get_current( self, user_oid: ObjectId, source_channel_oid: ObjectId, *, update_expiry: bool = True) -> Optional[RemoteControlEntryModel]: """ Get the current activating remote control. Upon found, update the expiry time if `update_expiry` is set to `True`. :return: Current activating remote control. `None` if not found. """ filter_ = { RemoteControlEntryModel.UserOid.key: user_oid, RemoteControlEntryModel.SourceChannelOid.key: source_channel_oid } now = now_utc_aware() ret = self.find_one_casted(filter_, parse_cls=RemoteControlEntryModel) # Entry not found if not ret: return None if update_expiry: # Update the object to be returned and the object in the database new_expiry = now + timedelta( seconds=Bot.RemoteControl.IdleDeactivateSeconds) ret.expiry_utc = new_expiry self.update_one_async( filter_, {"$set": { RemoteControlEntryModel.ExpiryUtc.key: new_expiry }}) # Ensure TTL - TTL may not work under millisecond scale if now < ret.expiry_utc: return RemoteControlEntryModel.cast_model(ret) else: return None
def test_fill_range_hr_0(self): tr = TimeRange(range_hr=0) now = now_utc_aware() expected_start_end = now self.assertAlmostEquals( 0, abs((expected_start_end - tr.start).total_seconds()), 0) self.assertAlmostEquals( 0, abs((expected_start_end - tr.start_org).total_seconds()), 0) self.assertAlmostEquals(0, abs((tr.end - now).total_seconds()), 0) self.assertIsNone(tr.tzinfo_) self.assertTrue(tr.expandable) self.assertFalse(tr.expanded) self.assertFalse(tr.is_inf) self.assertAlmostEquals(0, tr.hr_length_org, 0) self.assertAlmostEquals(0, tr.hr_length, 0) self.assertEqual( f"{expected_start_end.strftime('%m-%d')} ~ {now.strftime('%m-%d')}", tr.expr_period_short) self.assertAlmostEquals(tr.end_time_seconds, time_to_seconds(now), 0) prd = tr.get_periods() self.assertListEqual([tr], prd)
def get_time_up(self, channel_oid: ObjectId) -> List[TimerModel]: now = now_utc_aware() filter_ = { TimerModel.ChannelOid.key: channel_oid, TimerModel.TargetTime.key: { "$lt": now }, TimerModel.NotifiedExpired.key: False } ret = list( self.find_cursor_with_count(filter_, parse_cls=TimerModel).sort([ (TimerModel.TargetTime.key, pymongo.ASCENDING) ])) self.update_many_async( filter_, {"$set": { TimerModel.NotifiedExpired.key: True }}) return ret
def test_nfill_start(self): start_dt = datetime(2020, 4, 4, 1, 1, 1, tzinfo=pytz.UTC) tr = TimeRange(start=start_dt, end_autofill_now=False) now = now_utc_aware() hr_diff = (now - start_dt).total_seconds() / 3600 self.assertAlmostEquals(0, abs((start_dt - tr.start).total_seconds()), 0) self.assertAlmostEquals(0, abs((start_dt - tr.start_org).total_seconds()), 0) self.assertIsNone(tr.end) self.assertIsNone(tr.tzinfo_) self.assertFalse(tr.expandable) self.assertFalse(tr.expanded) self.assertTrue(tr.is_inf) self.assertAlmostEquals(hr_diff, tr.hr_length_org, 0) self.assertAlmostEquals(hr_diff, tr.hr_length, 0) self.assertEqual(f"{start_dt.strftime('%m-%d')} ~ -", tr.expr_period_short) self.assertAlmostEquals(tr.end_time_seconds, time_to_seconds(now), 0) prd = tr.get_periods() self.assertListEqual([tr], prd)
def to_string(self, user_model): now = now_utc_aware() tzinfo = user_model.config.tzinfo ret = [] if self.future: for tmr in self.future: ret.append( Timer.FUTURE.format(event=tmr.title, diff=t_delta_str( tmr.get_target_time_diff(now)), time=localtime(tmr.target_time, tzinfo))) ret.append("") # Separator if self.past_continue: for tmr in self.past_continue: ret.append( Timer.PAST_CONTINUE.format( event=tmr.title, diff=t_delta_str(tmr.get_target_time_diff(now)), time=localtime(tmr.target_time, tzinfo))) ret.append("") # Separator if self.past_done: for tmr in self.past_done: ret.append( Timer.PAST_DONE.format(event=tmr.title, time=localtime( tmr.target_time, tzinfo))) # Take out the final separator if ret and ret[-1] == "": ret = ret[:-1] return "\n".join(ret)
def record_boot_dt(): boot_dt_utc["dt"] = now_utc_aware()