def test_get_close_db(app): with app.app_context(): db = get_db() assert db is get_db() # 退出环境后, 连接应当已关闭 with pytest.raises(sqlite3.ProgrammingError) as e: db.execute('SELECT 1') assert 'closed' in str(e.value)
def test_say(client, app): assert "你必须说点什么" in send(client, 'say') assert "我记在脑子里啦" in send(client, 'say anything') with app.app_context(): db = get_db() res = db.execute('select * from treehole').fetchall() assert len(res) != 0
def test_log(app): with app.app_context(): c = get_db() log = c.execute('select * from log').fetchall() for i in log: print(tuple(i)) assert len(log) > 0
def log(context: Context): c = get_db() log_time = datetime.fromtimestamp(context.time) inserted_data = (context.message, context.name, context.user_id, context.time, str(log_time)) c.execute("insert into log values (?,?,?,?,?)", inserted_data) c.commit()
def unlock(): with app.app_context(): try: c = get_db() c.execute( "update misc set value = '0' where key = 'mutex'") c.commit() except sqlite3.OperationalError: pass
def dig(self): """随机从树洞取一条消息""" c = get_db() length = c.execute('select count(*) from treehole').fetchone()[0] rand = random.randrange(length) secret = c.execute( f'select message from treehole limit 1 offset {rand}').fetchone( )['message'] return reply("某个人说:" + secret, at_sender=False)
def start_xiuxian(context: Context): c = get_db() if not 0 <= datetime.fromtimestamp(context.time).time().hour < 5: return if c.execute(f'select * from xiuxian_emulator where id = {context.user_id}').fetchone() is None: c.execute('insert into xiuxian_emulator values (?,?,?,?,?,?)', (context.user_id, context.name, 0, 0, '', '')) c.commit() send(context, f'[CQ:at,qq={context.user_id}],你已经成功筑基,一个新的世界已经对你敞开!') accumulate_exp(context)
def query_ky(): c = get_db() data = c.execute('select * from misc where key = "ky_date"').fetchone() if data is None: return "管理员还未设定考研时间,使用 /setky 设定考研时间" ky_date_str = data['value'] ky_date = date(int(ky_date_str[:4]), int(ky_date_str[4:6]), int(ky_date_str[6:])) days_to_ky = (ky_date - date.today()).days if days_to_ky in (0, -1): return f"{ky_date_str[:4]}年度研究生考试正在进行中" return f"距离{ky_date_str[:4]}年度研究生考试还有{days_to_ky}天"
def randomly_save_message_to_treehole(context: Context): c = get_db() message = re.sub(r"\[CQ:(image|at).*?]", '', context.message).strip() if message == "": return if random.random() < current_app.config['RANDOMLY_SAVE_TO_TREEHOLE_RATE']: timestamp = context.time readable_time = datetime.fromtimestamp(timestamp) c.execute("insert into treehole values (?,?,?,?,?,'random_pick')", (message, timestamp, readable_time, context.name, context.user_id)) c.commit()
def ghs_reminder(app): c = get_db() data = c.execute( 'select * from misc where key = "last_ghs_date"').fetchone() if data is None: return last_ghs_date = data['value'] period = (date.today() - date.fromisoformat(last_ghs_date)).days if period > 0: send(GroupContext.build(group_id=app.config["GHS_NOTIFY_GROUP"]), message=f"提醒:距离上次 ghs 已经过去了{period}天。") else: return
def rest_statistic(self): """获取作息统计信息。""" c = get_db() rest_list = c.execute('select * from rest_record where id = ?', (self.context.user_id, )).fetchall() valid_record = [i for i in rest_list if i['sleep_time'] != ''] msg = average_rest_time(valid_record, 7) + \ average_rest_time(valid_record, 30) + \ average_rest_time(valid_record, 365) if msg == "": return reply("暂无数据。") else: return reply(msg)
def xiuxian_ranking(self): """修仙排行""" c = get_db() res = c.execute( 'select * from xiuxian_emulator order by exp desc limit 10' ).fetchall() if len(res) == 0: return reply('呜呼!仙道中落,世间竟无人修仙!') msg = "" for i, person in enumerate(res): msg += f"{i + 1}. {person['nickname']} {xiuxian_level[person['level']][0]}期 " \ f"经验{person['exp']}/{xiuxian_level[person['level']][1]}\n" return reply(msg, at_sender=False)
def test_randomly_save_message_to_treehole(app): # we don't use HTTP client because it's too slow from bot.utils import randomly_save_message_to_treehole from bot.context import GroupContext data = data_generator('foobar', auto_prefix_slash=False) context = GroupContext(data) with app.app_context(): for _ in range(1000): randomly_save_message_to_treehole(context) db = get_db() res = db.execute('select * from treehole').fetchall() print("Len =", len(res)) assert len(res) != 0
def zaoguys(self): """获取起床列表""" c = get_db() today = date.fromtimestamp(self.context.time) zao_list = c.execute( 'select nickname, wake_timestamp from rest_record where wake_time like ?', (str(today) + "%", )).fetchall() msg = "" index = 1 for person in zao_list: waken_time = datetime.fromtimestamp(person['wake_timestamp']) msg += f"\n{index}. {person['nickname']}, {waken_time.hour:02d}:{waken_time.minute:02d}" index += 1 if msg == "": return reply('o<<(≧口≦)>>o 还没人起床') return reply(msg)
def init_background_tasks(app): """ 不同 job 之间的间隔应大于 1 分钟, 否则会导致某些 job 不被执行. job 的执行函数第一个参数为当前的 app """ with app.app_context(): c = get_db() c.execute('BEGIN EXCLUSIVE') mutex = c.execute("select * from misc where key = 'mutex'").fetchone() if mutex is None: c.execute("insert into misc values ('mutex', '1')") start_flag = 1 elif mutex['value'] == '0': c.execute("update misc set value = '1' where key = 'mutex'") start_flag = 1 else: start_flag = 0 c.commit() # end of exclusive transaction if start_flag: apsched = ModifiedBackgroundScheduler(app) apsched.add_job(ky_reminder, trigger='cron', hour=12, minute=0, id='ky_reminder') apsched.add_job(ghs_reminder, trigger='cron', hour=21, minute=30, id='ghs_reminder') apsched.start() def unlock(): with app.app_context(): try: c = get_db() c.execute( "update misc set value = '0' where key = 'mutex'") c.commit() except sqlite3.OperationalError: pass atexit.register(unlock) return apsched return None
def say(self): """向树洞里说一句话""" c = get_db() try: self.context.args[0] except IndexError: return reply("你必须说点什么。") secret = " ".join(self.context.args) timestamp = self.context.time time = datetime.fromtimestamp(timestamp) c.execute( "insert into treehole values (?,?,?,?,?,'say')", (secret, timestamp, time, self.context.name, self.context.user_id)) c.commit() return reply("我记在脑子里啦!")
def test_scheduled_task(app, requests_mock): """ 所有定时任务都在这里测试. """ from bot.scheduled_tasks import init_background_tasks r = MessageHandler() requests_mock.post('http://127.0.0.1:5700/send_msg', json=r.handler) with app.app_context(): c = get_db() c.execute("update misc set value = '0' where key = 'mutex'") c.commit() scheduler = init_background_tasks(app) scheduler.get_job('ky_reminder').func() assert '年度研究生考试还有' in r.message scheduler.get_job('ghs_reminder').func() assert '距离上次 ghs 已经过去' in r.message
def setky(self): """ 设置考研日期 """ c = get_db() try: ky_date_str = self.context.args[0] date(int(ky_date_str[:4]), int(ky_date_str[4:6]), int(ky_date_str[6:])) if len(ky_date_str) != 8: raise ValueError data = c.execute( "select * from misc where key = 'ky_date'").fetchone() if data is None: c.execute("insert into misc values ('ky_date', ?)", (ky_date_str, )) else: c.execute("update misc set value = ? where key = 'ky_date'", (ky_date_str, )) c.commit() return reply("设置成功") except (IndexError, ValueError): return reply("考研时间格式必须为yyyyMMdd")
def accumulate_exp(context: Context): c = get_db() now_datetime = datetime.fromtimestamp(context.time) now_time = now_datetime.time() if not 0 <= now_time.hour < 8: return user = c.execute(f'select * from xiuxian_emulator where id = {context.user_id}').fetchone() if user is not None: if user['last_speaking_timestamp'] == "" \ or date.fromtimestamp(user['last_speaking_timestamp']) != date.fromtimestamp(context.time): last_speaking_datetime = now_datetime.replace(hour=0, minute=0, second=0) else: last_speaking_datetime = datetime.fromtimestamp(user['last_speaking_timestamp']) delta = now_datetime - last_speaking_datetime if delta.total_seconds() < 60: # This may reduce database updates return if now_time.hour < 5 or (timedelta(minutes=1) <= delta < timedelta(hours=3)): elapsed_minute = int(delta.total_seconds() / 60) else: return exp = user['exp'] + elapsed_minute level = user['level'] while exp > xiuxian_level[level][1]: if xiuxian_level[level][0] == '渡劫': send(context, '温馨提示: 渡劫需遵守渡劫基本法, 文明渡劫, 从我做起.') send(context, f'恭喜[CQ:at,qq={context.user_id}]道友渡劫成功, 飞升成仙!') else: send(context, f'[CQ:at,qq={context.user_id}],' f'你已经成功突破了{xiuxian_level[level][0]}期,进入{xiuxian_level[level + 1][0]}期。') level += 1 c.execute('update xiuxian_emulator ' 'set level=?, exp=?, last_speaking_timestamp=?, last_speaking_time=? where id=?', (level, exp, now_datetime.timestamp(), now_datetime.isoformat(), user['id'])) if context.name != user['nickname']: c.execute('update xiuxian_emulator set nickname=? where id=?', (context.name, user['id'])) c.commit()
def wan(self): """睡觉""" c = get_db() start_xiuxian(self.context) current_user = c.execute( f'select wake_timestamp from rest_record ' f'where id ={self.context.user_id} ORDER BY wake_timestamp DESC LIMIT 1' ).fetchone() current_time = datetime.fromtimestamp(self.context.time) if current_user is None \ or current_time - datetime.fromtimestamp(current_user['wake_timestamp']) > timedelta(hours=24): return reply('Pia!<(=o ‵-′)ノ☆ 不起床就睡,睡死你好了~') wake_time = datetime.fromtimestamp(current_user['wake_timestamp']) duration = current_time - wake_time if duration < timedelta(minutes=30): return reply("你不是才起床吗?") else: msg = "" try: delay_minute = int(self.context.args[0]) sleep_time = current_time + timedelta(minutes=delay_minute) duration += timedelta(minutes=delay_minute) msg += f"将在{delay_minute}分钟后睡觉。\n" except (IndexError, ValueError): sleep_time = current_time c.execute( "update rest_record set sleep_timestamp = ?, sleep_time = ? " "where id = ? and wake_timestamp = ?", (sleep_time.timestamp(), sleep_time, self.context.user_id, current_user['wake_timestamp'])) c.commit() msg += '今日共清醒{}秒,辛苦了'.format( str(duration).replace(':', '小时', 1).replace(':', '分', 1)) return reply(msg)
def zao(self): """起床""" c = get_db() today = date.fromtimestamp(self.context.time) current_user = c.execute( 'select * from rest_record where id = ? and wake_time like ?', (self.context.user_id, str(today) + "%")).fetchone() if current_user is None or date.fromtimestamp( current_user['wake_timestamp']) != today: last_user = c.execute( "SELECT wake_timestamp, waken_num FROM rest_record ORDER BY wake_timestamp DESC LIMIT 1" ).fetchone() if last_user is None or date.fromtimestamp( last_user['wake_timestamp']) != today: # 新的一天 waken_num = 1 else: waken_num = last_user['waken_num'] + 1 wake_timestamp = self.context.time wake_time = datetime.fromtimestamp(self.context.time) inserted_data = (self.context.user_id, wake_timestamp, wake_time, self.context.name, waken_num, '', '') # 注意顺序 c.execute("insert into rest_record values (?,?,?,?,?,?,?)", inserted_data) c.commit() try: greeting = self.context.args[0] except IndexError: greeting = '少年' return reply(f"你是第{waken_num:d}起床的{greeting}。") elif current_user['sleep_timestamp'] != '': return reply("你不是睡了吗?") else: return reply("你不是起床过了吗?")
def test_zao_db(app): with app.app_context(): c = get_db() res = c.execute("select * from rest_record").fetchone() print(tuple(res)) assert 1