Esempio n. 1
0
async def show_progress(session: CommandSession):
    """progress: 查询本周刷题进度(周日18点为界线)

用法:
progress
"""
    group_id = session.ctx['group_id']
    qq_id = session.ctx['user_id']

    dm = DataManager(group_id)

    accounts = dm.query_binded_accounts(qq_id)

    starttime = last_sunday()
    endtime = dm.get_latest_csttime_by_qq(qq_id)

    vs, ve = dm.report_by_qq(qq_id, starttime, endtime)

    tf = "%Y/%m/%d %H:%M"

    msg = f"""Progress this week:
[{starttime.strftime(tf)}] Accepted: {vs}
[{endtime.strftime(tf)}] Accepted: {ve} (+{ve-vs})"""
    
    await session.send(msg)
Esempio n. 2
0
async def report_total(session: CommandSession):
    group_id = session.ctx['group_id']
    group_info = await session.bot.get_group_info(group_id=group_id)
    group_name = group_info['group_name']
    member_count = group_info['member_count']

    dm = DataManager(group_id)

    starttime = long_long_ago()
    endtime = cstnow()

    data = dm.report(starttime, endtime)
    data = [[alias, ac_now] for alias, _, ac_now in data if ac_now > 0]

    data.sort(reverse=True, key=itemgetter(1))

    lines = autoalign(data, formatter=lambda x: "| {} | {:<5} |".format(*x))

    entries = min(member_count, REPORT_TOTAL_MAX_ENTRIES, len(data))
    header = f"{group_name} Top {entries} / {member_count}\n"
    header += "# | Name | Accepted |"
    await session.send(header)

    for msg in multiline_msg_generator(lines[:entries], lineno=True):
        await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
Esempio n. 3
0
async def handle_accounts(session: CommandSession):
    """accounts: 查询当前已绑定账号

用法:
accounts
"""
    group_id = session.ctx['group_id']
    qq_id = session.ctx['user_id']

    argv = session.args['argv']
    at_someone = None
    if argv and '-u' in argv and qq_id in SUPERUSERS:
        at_someone = argv[-1]
        qq_id = parse_cq_at(at_someone)

    dm = DataManager(group_id)
    accounts = dm.query_binded_accounts(qq_id)

    if accounts:
        msg = '已绑定账号:\n' + '\n'.join([u+'@'+p for u, p in accounts])
    else:
        msg = '并没有绑定账号。'
    
    if at_someone:
        await session.send(f"{at_someone} {msg}")
    else:
        await session.send(msg, at_sender=True)
Esempio n. 4
0
async def test_db_refactor(session: CommandSession):
    group_id = 1234

    dm = DataManager(group_id)
    
    ok, snapshot = await dm.get_and_save_user_summary(QQ_ID, 'nuullll', 'leetcode')
    await session.send(str(snapshot.accepted))
Esempio n. 5
0
async def handle_init_db(session: CommandSession):
    argv = session.args['argv']
    cleanup = True if '-c' in argv else False
    
    msg = '正在初始化数据库...'
    if cleanup:
        msg += '(重置)'
    await session.send(msg)

    group_id = session.ctx['group_id']
    members = await session.bot.get_group_member_list(group_id=group_id)

    dm = DataManager(group_id)
    success = dm.init(members, cleanup)

    await session.send('成功导入{}位成员信息'.format(success))
Esempio n. 6
0
async def daily_update():
    bot = nb.get_bot()

    checkpoint = set()
    for group_id in AUTO_UPDATES:
        await debug(f"Updating for group: {group_id}")
        dm = DataManager(group_id)

        members = await bot.get_group_member_list(group_id=group_id)
        dm.init(members)

        fails, successes = await dm.get_and_save_all_user_summary(checkpoint)

        await debug(f"Group [{group_id}] update failures: {fails}")

        retry = 0
        _fails = fails[:]
        while fails:
            fails = []
            for qq_id, user_id, platform in _fails:
                ok, snapshot = await dm.get_and_save_user_summary(
                    qq_id, user_id, platform)

                if not ok:
                    fails.append((qq_id, user_id, platform))
                else:
                    successes.append((qq_id, user_id, platform))

            retry += 1
            if retry >= AUTO_UPDATE_MAX_RETRIES:
                await debug(
                    f"Failures after {AUTO_UPDATE_MAX_RETRIES} retries: {fails}"
                )
                break

            _fails = fails[:]

        checkpoint.update(successes)

    for group_id, mode in AUTO_DAILY_REPORT.items():
        event = get_fake_cqevent(group_id=group_id)
        if mode == 'week_delta':
            await call_command(bot, event, 'report')
        else:
            await call_command(bot, event, 'report_total')
Esempio n. 7
0
async def handle_accounts(session: CommandSession):
    """accounts: 查询当前已绑定账号

用法:
accounts
"""
    group_id = session.ctx['group_id']
    qq_id = session.ctx['user_id']

    dm = DataManager(group_id)
    accounts = dm.query_binded_accounts(qq_id)

    if accounts:
        msg = '已绑定账号:\n' + '\n'.join([u + '@' + p for u, p in accounts])
    else:
        msg = '并没有绑定账号。'

    await session.send(msg, at_sender=True)
Esempio n. 8
0
async def report(session: CommandSession):
    group_id = session.ctx['group_id']

    dm = DataManager(group_id)

    starttime = last_sunday()
    endtime = cstnow()

    data = dm.report(starttime, endtime)
    data = [[alias, ac_now, ac_now - ac_before] for alias, ac_before, ac_now in data if ac_now > 0]

    data.sort(reverse=True, key=itemgetter(2, 1))

    lines = autoalign(data, formatter=lambda x: "| {} | {:<5} (+{}) |".format(*x))

    header = f"{starttime} - {endtime}\n"
    header += "| Name | Accepted (+delta) |"
    await session.send(header)

    for msg in multiline_msg_generator(lines, lineno=True):
        await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
Esempio n. 9
0
async def test_blog_date_parser(session: CommandSession):
    lines = []
    url_map = DataManager.query_blog()
    for qq_id, blog_urls in url_map.items():
        for url in blog_urls:
            if 'juejin' not in url:
                continue
            # if qq_id not in card_dict:
            #     line = f"{render_cq_at(qq_id)} {url}"
            # else:
            #     line = f"{card_dict[qq_id]} {url}"
            # lines.append(line)
            guess_blog_update_time(url)
Esempio n. 10
0
async def query_registered(session: CommandSession):
    argv = session.args['argv']
    
    group_id = session.ctx['group_id']
    dm = DataManager(group_id)

    members = await session.bot.get_group_member_list(group_id=group_id)

    lines = []
    for member in members:
        alias = member['card'] if member['card'] else member['nickname']
        qq_id = member['user_id']

        accounts = dm.query_binded_accounts(qq_id)
        msg = f"{alias}: "
        if accounts:
            msg += ", ".join([f"{u}@{p}" for u, p in accounts])
        else:
            msg += "NaN"

        lines.append(msg)
    
    for msg in multiline_msg_generator(lines=lines, lineno=True):
        await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
Esempio n. 11
0
async def update_all(session: CommandSession):
    group_id = session.ctx['group_id']

    dm = DataManager(group_id)

    members = await session.bot.get_group_member_list(group_id=group_id)
    await session.send("开始强制更新...")

    for member in members:
        print(member)
        ctx = {'debug': True, 'anonymous': None, 'font': 1623440, 'group_id': group_id, 'message': [{'type': 'text', 'data': {'text': 'report'}}], 'message_id': 20804, 'message_type': 'group', 'post_type': 'message', 'raw_message': 'report', 'self_id': 2210705648, 'sender': {'age': 24, 'area': '北京', 'card': '', 'level': '冒泡', 'nickname': 'Nuullll', 'role': 'owner', 'sex': 'unknown', 'title': '', 'user_id': 724463877}, 'sub_type': 'normal', 'time': 1584248424, 'user_id': 724463877, 'to_me': True}
        ctx['sender'].update(member)
        ctx['user_id'] = member['user_id']
        await call_command(nonebot.get_bot(), ctx, 'update')
    
    await session.finish("手动更新成功!")
Esempio n. 12
0
async def update_database(session: CommandSession):
    """update: 立刻更新账号数据(冷却时间10分钟)
除此之外,爬虫会在每日18点左右自动更新账号数据(如有bug请 @Nuullll)

用法:
update
"""
    group_id = session.ctx['group_id']
    qq_id = session.ctx['user_id']
    debug = session.ctx.get('debug', False)

    if not debug:
        dm = DataManager(group_id)
        accounts = dm.query_binded_accounts(qq_id)

        await session.send("正在更新数据", at_sender=True)

        if not accounts:
            await session.finish("请先绑定账号!命令:register")

        latest = dm.get_latest_csttime_by_qq(qq_id)
        now = cstnow()
        delta = int((now - latest).total_seconds())
        print(latest, now, delta)

        await session.send(f"最近更新: {latest}")
        if delta < USER_UPDATE_COOLDOWN:
            await session.finish(f"技能冷却中:剩余{USER_UPDATE_COOLDOWN-delta}秒")

        for user_id, platform in accounts:
            ok, snapshot = await dm.get_and_save_user_summary(
                qq_id, user_id, platform)

            if not ok:
                await session.send("ID错误或网络错误!请检查后重试。")

            for msg in multiline_msg_generator(snapshot.lines):
                await session.bot.send_msg_rate_limited(group_id=group_id,
                                                        message=msg)
    else:
        dm = DataManager(group_id)
        accounts = dm.query_binded_accounts(qq_id)

        for user_id, platform in accounts:
            ok, snapshot = await dm.get_and_save_user_summary(
                qq_id, user_id, platform)

            for msg in multiline_msg_generator(snapshot.lines):
                await session.bot.send_msg_rate_limited(user_id=724463877,
                                                        message=msg)
Esempio n. 13
0
async def change_field(session: CommandSession):
    _ids = pymongo.MongoClient()[OJID_DB]['all']

    docs = _ids.find({'platform': 'leetcodecn'})

    for doc in docs:
        qq_id = doc['qq_id']

        snapshots = DataManager.get_snapshots(qq_id)

        ss = snapshots.find_and_modify(
            {'platform': 'leetcodecn'},
            {"$rename": {
                "data.Global Ranking": "data.AC Ranking"
            }})

        print(snapshots.find_one({'platform': 'leetcodecn'}))
Esempio n. 14
0
async def handle_unregister(session: CommandSession):
    """unregister: 解绑账号

用法: 
unregister [-a] [platform] [user_id]

可选参数:
-a 解绑本人所有OJ平台账号

示例:
unregister -a
unregister leetcodecn nuullll
"""
    USAGE = handle_unregister.__doc__

    # args
    argv = session.args['argv']
    if not argv:
        await session.finish(USAGE)
        return
    

    rm_all = True if '-a' in argv else False

    group_id = session.ctx['group_id']
    qq_id = session.ctx['user_id']

    if '-u' in argv and qq_id in SUPERUSERS:
        qq_id = parse_cq_at(argv[-1])

    dm = DataManager(group_id)
    if rm_all:
        candidates = dm.query_binded_accounts(qq_id)
    else:
        try:
            platform = argv[0]
            user_id = argv[1]
        except:
            await session.send("参数有误!")
            await session.finish(USAGE)
            return
        
        binded, bind_qq = dm.is_account_binded(user_id, platform)
        if not binded or bind_qq != qq_id:
            await session.finish("账号不存在,解绑失败。@我 accounts 查询已绑定账号。")
            return
        
        candidates = [(user_id, platform)]
    
    for u, p in candidates:
        dm.remove_account(qq_id, u, p)
    
    await session.finish("解绑成功。")
Esempio n. 15
0
async def get_latest_blogs():
    bot = nb.get_bot()
    # members = await session.bot.get_group_member_list(group_id=group_id)
    # # build qq_id -> card dict
    # card_dict = {member['user_id']: (member['card'] if member['card'] else member['nickname']) for member in members}

    # query all
    recent_updated = []
    now = datetime.now()

    url_map = DataManager.query_blog()
    for qq_id, blog_urls in url_map.items():
        for url in blog_urls:
            # if qq_id not in card_dict:
            #     line = f"{render_cq_at(qq_id)} {url}"
            # else:
            #     line = f"{card_dict[qq_id]} {url}"
            # lines.append(line)
            text, dt = guess_blog_update_time(url)

            if text is None:
                continue

            if (now - dt).days <= 2:
                recent_updated.append((qq_id, url, dt.strftime("%Y-%m-%d")))

    if not recent_updated:
        return

    lines = [f"{render_cq_at('all')} 以下博客近2天内有更新,大家快去学习吧"]
    for qq_id, url, dt_str in recent_updated:
        line = f"{render_cq_at(qq_id)} {url} {dt_str}"
        lines.append(line)

    for group_id in AUTO_BLOG_PUSHES:
        for msg in multiline_msg_generator(lines=lines, lineno=False):
            await bot.send_msg_rate_limited(group_id=group_id, message=msg)
Esempio n. 16
0
async def daily_update():
    bot = nb.get_bot()

    for group_id in AUTO_UPDATES:
        await debug(f"Updating for group: {group_id}")
        dm = DataManager(group_id)

        members = await bot.get_group_member_list(group_id=group_id)
        dm.init(members)

        fails = await dm.get_and_save_all_user_summary()

        await debug(f"Group [{group_id}] update failures: {fails}")

        retry = 0
        while fails:
            fails = []
            for qq_id, user_id, platform in fails:
                ok, snapshot = await dm.get_and_save_user_summary(
                    qq_id, user_id, platform)

                if not ok:
                    fails.append((qq_id, user_id, platform))

            retry += 1
            if retry >= AUTO_UPDATE_MAX_RETRIES:
                await debug(
                    f"Failures after {AUTO_UPDATE_MAX_RETRIES} retries: {fails}"
                )
                break

    for group_id, mode in AUTO_DAILY_REPORT.items():
        ctx = {
            'anonymous': None,
            'font': 1623440,
            'group_id': group_id,
            'message': [{
                'type': 'text',
                'data': {
                    'text': 'report'
                }
            }],
            'message_id': 20804,
            'message_type': 'group',
            'post_type': 'message',
            'raw_message': 'report',
            'self_id': 2210705648,
            'sender': {
                'age': 24,
                'area': '北京',
                'card': '',
                'level': '冒泡',
                'nickname': 'Nuullll',
                'role': 'owner',
                'sex': 'unknown',
                'title': '',
                'user_id': 724463877
            },
            'sub_type': 'normal',
            'time': 1584248424,
            'user_id': 724463877,
            'to_me': True
        }
        if mode == 'week_delta':
            await call_command(bot, ctx, 'report')
        else:
            await call_command(bot, ctx, 'report_total')


# @nb.scheduler.scheduled_job('cron', hour='12')
# async def report_hns():

#     print("Waiting for coingecko...")
#     ok, html = await Spider.render_html_with_splash('https://www.coingecko.com/en/coins/handshake')

#     if not ok:
#         return

#     def get_content(xpath):
#         try:
#             return html.xpath(xpath + "/text()")[0]
#         except:
#             return ""
#     usd = get_content("/html/body/div[2]/div[3]/div[4]/div[1]/div[2]/div[1]/span[1]")
#     usd_d = get_content("/html/body/div[2]/div[3]/div[4]/div[1]/div[2]/div[1]/span[2]/span")
#     btc = get_content("/html/body/div[2]/div[3]/div[4]/div[1]/div[2]/div[3]")
#     btc_d = get_content("/html/body/div[2]/div[3]/div[4]/div[1]/div[2]/div[3]/span/span")
#     l_24h = get_content("/html/body/div[2]/div[3]/div[6]/div/div/div[2]/div/div[1]/div/div[1]/div[1]/div[2]/div[1]/table/tbody/tr[6]/td/span[1]")
#     h_24h = get_content("/html/body/div[2]/div[3]/div[6]/div/div/div[2]/div/div[1]/div/div[1]/div[1]/div[2]/div[1]/table/tbody/tr[6]/td/span[2]")
#     l_7d = get_content("/html/body/div[2]/div[3]/div[6]/div/div/div[2]/div/div[1]/div/div[1]/div[1]/div[2]/div[1]/table/tbody/tr[7]/td/span[1]")
#     h_7d = get_content("/html/body/div[2]/div[3]/div[6]/div/div/div[2]/div/div[1]/div/div[1]/div[1]/div[2]/div[1]/table/tbody/tr[7]/td/span[2]")

#     message = f"""{datetime.now(pytz.timezone('Asia/Shanghai'))}
# HNS Hourly Report
# USD: {usd} {usd_d}
# BTC: {btc} {btc_d}
# 24h Low/High: {l_24h}/{h_24h}
# 7d Low/High: {l_7d}/{h_7d}
# """

#     bot = nb.get_bot()
#     await bot.send_msg(user_id=724463877, message=message)
Esempio n. 17
0
async def handle_blog(session: CommandSession):
    """blog: 查询本群公开博客列表/绑定博客/解绑博客

用法:
blog    // 查询博客列表
blog add <your blog url>
blog remove <your blog url> [-a]

示例:
blog add https://blog.nuullll.com
blog remove https://blog.nuullll.com
blog remove -a  // 解绑本人所有博客
"""
    argv = session.args['argv']

    group_id = session.event.group_id
    qq_id = session.event.user_id
    dm = DataManager(group_id)

    try:
        op = argv[0].lower()
        url = argv[1]
        
        if op == "add":
            if not is_valid_url(url):
                await session.send("闹闹无法获取博客内容,请检查url或网站可达性,或稍后再试")
                return
            
            dm.bind_blog(qq_id, url)
            await session.send("绑定成功!")
            
        elif op == "remove":
            remove_all = url == "-a"
            valid = is_valid_url(url)
            if not valid and not remove_all:
                await session.send("闹闹无法获取博客内容,请检查url或网站可达性,或稍后再试")
                return

            if valid:
                if not dm.unbind_blog(qq_id, url):
                    await session.send("该博客未绑定,请检查url")
                    return

            if remove_all:
                url_map = dm.query_blog(qq_id=qq_id)
                for url in url_map[qq_id]:
                    dm.unbind_blog(qq_id, url)
                
            await session.send("解绑成功!")
        else:
            raise ValueError("Usage error.")

        return
    except:
        pass

    # query all
    lines = [get_random_header()]
    url_map = dm.query_blog()
    for qq_id, blog_urls in url_map.items():
        for url in blog_urls:
            line = f"{render_cq_at(qq_id)} {url}"
            lines.append(line)
    
    for msg in multiline_msg_generator(lines=lines, lineno=False):
        await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)
Esempio n. 18
0
async def handle_reset_db(session: CommandSession):
    group_id = session.ctx['group_id']
    DataManager(group_id).reset()

    await session.send('数据库已重置')
Esempio n. 19
0
async def register_helper(session, for_other=False):

    examples = [f"{oj}: {url.format('<id>')}" for oj, url in PLATFORM_URLS.items()]
    shuffle(examples)

    USAGE = """
用法:
register <your OJ profile url>

目前支持的OJ平台:
""" + "\n".join(examples) + """

示例:
register https://leetcode.com/nuullll
"""

    group_id = session.ctx['group_id']

    if not for_other:
        url = session.current_arg_text.strip()

        if not url:
            await session.finish("未检测到url\n" + USAGE)
            return
        
        url = url.split()[0]
        
        qq_id = session.ctx['user_id']
    else:
        argv = session.args['argv']
        qq_id, url = argv

        try:
            if qq_id.isnumeric():
                qq_id = int(qq_id)
            else:
                # infer CQ code
                qq_id = parse_cq_at(qq_id)
        except:
            await session.finish('参数错误!')
            return
    
    platform = ''
    user_id = ''
    for oj, template in PLATFORM_URLS.items():
        # escape special character in template
        template = template.replace('?', '\?')
        m = re.search(template.format('([a-zA-Z0-9_-]+)'), url)
        if m:
            platform = oj
            user_id = m.group(1)
            break
    
    if not user_id:
        await session.finish("请检查URL格式\n" + USAGE)
        return

    dm = DataManager(group_id)

    binded, bind_qq = dm.is_account_binded(user_id, platform)
    if binded:
        if bind_qq == qq_id:
            await session.finish(f"您已绑定{user_id}@{platform},请勿重复操作。")
        else:
            await session.finish(f"绑定失败,{user_id}@{platform}已被用户[CQ:at,qq={bind_qq}]绑定!")
        return

    ok, snapshot = await dm.get_and_save_user_summary(qq_id, user_id, platform)

    if not ok:
        await session.send("ID错误或网络错误!请检查后重试。")
        return
    
    if not dm.bind_account(qq_id, user_id, platform):
        await session.finish("绑定失败,代码线程不安全。")
        return

    await session.send(f"{user_id}@{platform}绑定成功!")
    for msg in multiline_msg_generator(snapshot.lines):
        await session.send(msg)
Esempio n. 20
0
async def handle_blog(session: CommandSession):
    """blog: 查询本群公开博客列表/绑定博客/解绑博客

用法:
blog    // 查询博客列表
blog add <your blog url>
blog remove <your blog url> [-a]

示例:
blog add https://blog.nuullll.com
blog remove https://blog.nuullll.com
blog remove -a  // 解绑本人所有博客
"""
    argv = session.args['argv']

    group_id = session.event.group_id
    qq_id = session.event.user_id
    dm = DataManager(group_id)

    try:
        op = argv[0].lower()
        url = argv[1]

        if op == "add":
            if not is_valid_url(url):
                await session.send("闹闹无法获取博客内容,请检查url或网站可达性,或稍后再试")
                return

            if dm.bind_blog(qq_id, url):
                await session.send("绑定成功!")
            else:
                await session.send("该博客你已经绑定过啦!")

        elif op == "remove":
            remove_all = url == "-a"

            if remove_all:
                url_map = dm.query_blog(qq_id=qq_id)
                for url in url_map[qq_id]:
                    dm.unbind_blog(qq_id, url)
            else:
                if not dm.unbind_blog(qq_id, url):
                    await session.send("该博客未绑定,请检查url")
                    return

            await session.send("解绑成功!")
        else:
            raise ValueError("Usage error.")

        return
    except:
        pass

    members = await session.bot.get_group_member_list(group_id=group_id)
    # build qq_id -> card dict
    name_dict = {
        member['user_id']: (member['card'], member['nickname'])
        for member in members
    }

    # query all
    lines = []
    url_map = dm.query_blog()
    for qq_id, blog_urls in url_map.items():
        for url in blog_urls:
            if qq_id not in name_dict:
                line = f"{render_cq_at(qq_id)} {url}"
            else:
                card, nickname = name_dict[qq_id]
                card = f"({card})" if card else ""
                line = f"{nickname}{card} {url}"
            lines.append(line)

    shuffle(lines)
    lines = [get_random_header()] + lines
    for msg in multiline_msg_generator(lines=lines, lineno=False):
        await session.bot.send_msg_rate_limited(group_id=group_id, message=msg)