From 5f9d5eb0b9a9cbba84ce170b3491e4b9fe043845 Mon Sep 17 00:00:00 2001 From: ZMXC01 <2393899036@qq.com> Date: Thu, 11 May 2023 02:20:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=B9=BF=E4=B8=9C=E5=9C=B0?= =?UTF-8?q?=E5=8C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++- TeenStudy/utils/dxx.py | 170 +++++++++++++++++++++++++++++++++++ TeenStudy/utils/utils.py | 13 +++ TeenStudy/web/api/add.py | 100 ++++++++++++++++++++- TeenStudy/web/pages/add.py | 96 ++++++++++++++++++++ TeenStudy/web/pages/admin.py | 113 ++++++++++++++++++++++- pyproject.toml | 4 +- 7 files changed, 501 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 729f690..05e0535 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ - 本项目为[青年大学习提交](https://github.com/ZM25XC/nonebot_plugin_auto_teenstudy) `Web UI`版 - 本项目基于[nonebot2](https://github.com/nonebot/nonebot2)和[go-cqhttp](https://github.com/Mrs4s/go-cqhttp),使用本插件前请先阅读以上两个项目的使用文档 - **启动插件之后,一定要登录后台在推送列表中添加需要开启大学习功能的群聊** +- **本项目无法在国外IP环境下使用,如有开启代理,请关闭或添加代理规则** - 需要抓包的地区,绑定后尽量别进官方公众号,避免token或cookie刷新导致无法提交 - 本项目需要部署在公网可访问的容器中,并开放端口(nonebot2配置的port),否则大部分功能将出现异常 - 欢迎加入[QQ群](https://jq.qq.com/?_wv=1027&k=NGFEwXyS),交流讨论。 @@ -36,6 +37,7 @@ |青春湖北|支持|无需抓包| |江西共青团|支持|无需抓包| |安徽共青团|支持|无需抓包| +|广东共青团|支持|无需抓包| |青春上海|支持|微信扫码绑定| |青春浙江|支持|微信扫码绑定| |江苏共青团|支持|需要自行抓包| @@ -58,7 +60,6 @@ |海南共青团|待开发|| |津彩青春|待开发|| |青春黔言|待开发|| -|广东共青团|待开发|| |青春柳州|待开发|| |辽宁共青团|待开发|| |宁夏共青团|待开发|| @@ -159,13 +160,20 @@ ## 更新日志 -### 2023/05/06 +### 2023/05/11 + +- 增加广东地区,无需抓包[#13](https://github.com/ZM25XC/TeenStudy/issues/13),感谢[@neal240](https://github.com/neal240)提供账号测试 + + +
+2023/05/06 - 增加吉林地区,需要自行抓包 - 修复超管更改登录密码后用原密码能继续登录问题 - 添加二维码转链接开关,需要自行在后台配置页面打开 - 调整部分依赖 +
2023/04/12 diff --git a/TeenStudy/utils/dxx.py b/TeenStudy/utils/dxx.py index ab463c7..f139165 100644 --- a/TeenStudy/utils/dxx.py +++ b/TeenStudy/utils/dxx.py @@ -3,6 +3,7 @@ import re import secrets import time +import urllib.parse from anti_useragent import UserAgent from httpx import AsyncClient @@ -905,3 +906,172 @@ async def jilin(user_id: int) -> dict: "status": 500, "msg": f"提交失败,{e}" } + + +async def guangdong(user_id: int) -> dict: + """ + 广东共青团 + :param user_id:用户ID + :return: + """ + result = await User.filter(user_id=user_id).values() + if not result: + return { + "status": 500, + "msg": "用户数据不存在!" + } + else: + dxx_id = result[0]['dxx_id'] + token = result[0]["token"] + answer = await Answer.all().order_by("time").values() + try: + study_headers = { + 'Host': 'youthstudy.12355.net', + 'Connection': 'keep-alive', + 'X-Litemall-Token': token, + 'X-Litemall-IdentiFication': 'young', + 'User-Agent': 'MicroMessenger', + 'Accept': '*/*', + 'Origin': 'https://youthstudy.12355.net', + 'X-Requested-With': 'com.tencent.mm', + 'Sec-Fetch-Site': 'same-origin', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://youthstudy.12355.net/h5/', + 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', + } + new_study_url = "https://youthstudy.12355.net/saomah5/api/young/chapter/new" + async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client: + study_response = await client.get(url=new_study_url) + study_response.encoding=study_response.charset_encoding + if study_response.json()["errno"] == 0: + chapterId = study_response.json().get('data').get('entity').get('id') + title = study_response.json().get('data').get('entity').get('name').replace('“青年大学习”', "").strip() + commit_url = "https://youthstudy.12355.net/saomah5/api/young/course/chapter/saveHistory" + async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client: + commit_response = await client.post(url=commit_url, data={ + "chapterId": chapterId + }) + if commit_response.json()["errno"] == 0: + await User.filter(user_id=user_id).update( + token=token, + commit_time=time.time(), + catalogue=title + ) + await commit(user_id=user_id, catalogue=title, status=True) + return { + "status": 0, + "catalogue": title, + "msg": "提交成功!" + } + else: + await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False) + return { + "status": 500, + "msg": "提交失败!" + } + else: + token_headers = { + 'Host': 'tuanapi.12355.net', + 'Connection': 'keep-alive', + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'Origin': 'https://tuan.12355.net', + 'User-Agent': 'MicroMessenger', + 'X-Requested-With': 'com.tencent.mm', + 'Sec-Fetch-Site': 'same-site', + 'Sec-Fetch-Mode': 'cors', + 'Referer': 'https://tuan.12355.net/wechat/view/YouthLearning/page.html', + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', + } + ger_param_url = f"https://tuanapi.12355.net/questionnaire/getYouthLearningUrl?mid={dxx_id}" + async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client: + param_response = await client.get(url=ger_param_url) + if param_response.json()["status"] == 200: + content = param_response.json()["youthLearningUrl"].split("=")[-1] + token_url = "https://youthstudy.12355.net/apih5/api/user/get" + token_headers = { + 'Host': 'youthstudy.12355.net', + 'Connection': 'keep-alive', + 'Content-Length': '134', + 'Origin': 'https://youthstudy.12355.net', + 'X-Litemall-Token': '', + 'X-Litemall-IdentiFication': 'young', + 'User-Agent': 'MicroMessenger', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': '*/*', + 'X-Requested-With': 'com.tencent.mm', + 'Sec-Fetch-Site': 'same-origin', + 'Sec-Fetch-Mode': 'cors', + 'Referer': 'https://youthstudy.12355.net/h5/', + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7' + } + async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client: + token_response = await client.post(url=token_url, data="sign="+urllib.parse.quote(content)) + if token_response.json()["errno"] == 0: + token = token_response.json()['data']['entity']['token'] + study_headers = { + 'Host': 'youthstudy.12355.net', + 'Connection': 'keep-alive', + 'X-Litemall-Token': token, + 'X-Litemall-IdentiFication': 'young', + 'User-Agent': 'MicroMessenger', + 'Accept': '*/*', + 'Origin': 'https://youthstudy.12355.net', + 'X-Requested-With': 'com.tencent.mm', + 'Sec-Fetch-Site': 'same-origin', + 'Sec-Fetch-Mode': 'cors', + 'Sec-Fetch-Dest': 'empty', + 'Referer': 'https://youthstudy.12355.net/h5/', + 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', + } + new_study_url = "https://youthstudy.12355.net/saomah5/api/young/chapter/new" + async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client: + study_response = await client.get(url=new_study_url) + if study_response.json()["errno"] == 0: + chapterId = study_response.json().get('data').get('entity').get('id') + title = study_response.json().get('data').get('entity').get('name').replace( + '"青年大学习”', "").strip() + commit_url = "https://youthstudy.12355.net/saomah5/api/young/course/chapter/saveHistory" + async with AsyncClient(headers=study_headers, timeout=30, max_redirects=5) as client: + commit_response = await client.post(url=commit_url, data={ + "chapterId": chapterId + }) + if commit_response.json()["errno"] == 0: + await User.filter(user_id=user_id).update( + token=token, + commit_time=time.time(), + catalogue=title + ) + await commit(user_id=user_id, catalogue=title, status=True) + return { + "status": 0, + "catalogue": title, + "msg": "提交成功!" + } + else: + await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False) + return { + "status": 500, + "msg": "提交失败!" + } + else: + await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False) + return { + "status": 500, + "msg": "提交失败,token获取失效!" + } + else: + await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False) + return { + "status": 500, + "msg": "提交失败,token获取失效!" + } + except Exception as e: + logger.error(e) + await commit(user_id=user_id, catalogue=answer[-1]["catalogue"], status=False) + return { + "status": 500, + "msg": "提交失败!" + } diff --git a/TeenStudy/utils/utils.py b/TeenStudy/utils/utils.py index 324a687..72d7009 100644 --- a/TeenStudy/utils/utils.py +++ b/TeenStudy/utils/utils.py @@ -170,6 +170,15 @@ class UserModel(BaseModel): "status": True, "catalogue": None }, + { + "area": "广东", + "host": "tuanapi.12355.net", + "referer": None, + "origin": "https://tuan.12355.net", + "url": "https://youthstudy.12355.net/saomah5/api/young/chapter/new", + "status": True, + "catalogue": None + }, ] RESOURCE = [ { @@ -506,6 +515,8 @@ async def distribute_area(user_id: int, area: str) -> dict: return await dxx.chongqing(user_id=user_id) elif area == "吉林": return await dxx.jilin(user_id=user_id) + elif area == "广东": + return await dxx.guangdong(user_id=user_id) else: return { "status": 404, @@ -531,6 +542,8 @@ async def distribute_area_url(province: str, user_id: int, group_id: int) -> dic province = "chongqing" elif province == "吉林": province = "jilin" + elif province == "广东": + province="guangdong" data = f"http://{config['DXX_IP']}:{config['DXX_PORT']}/TeenStudy/api/{province}?user_id={user_id}&group_id={group_id}" img = qrcode.make(data=data) buf = BytesIO() diff --git a/TeenStudy/web/api/add.py b/TeenStudy/web/api/add.py index 47df102..2e96d23 100644 --- a/TeenStudy/web/api/add.py +++ b/TeenStudy/web/api/add.py @@ -1,6 +1,7 @@ import json import re import time +import urllib.parse from typing import Optional from fastapi import APIRouter @@ -8,7 +9,7 @@ from httpx import AsyncClient from ..pages.add import hubei_page, jiangxi_page, jiangsu_page, anhui_page, sichuan_page, shandong_page, \ - chongqing_page, jilin_page + chongqing_page, jilin_page, guangdong_page from ..utils.add import write_to_database from ...models.accuont import User, AddUser from ...models.dxx import JiangXi @@ -651,7 +652,7 @@ async def jilin_add(data: dict) -> JSONResponse: user_id = data["user_id"] if await User.filter(user_id=user_id).count(): return JSONResponse({ - "status": 0, + "status": 500, "msg": "添加失败!,用户信息存在!" }) else: @@ -718,3 +719,98 @@ async def jilin(user_id: int, group_id: int): return RedirectResponse( url="/TeenStudy/login" ) + + +@route.post("/guangdong/add", response_class=HTMLResponse) +async def guangdong_add(data: dict) -> JSONResponse: + user_id = data["user_id"] + if await User.filter(user_id=user_id).count(): + return JSONResponse({ + "status": 500, + "msg": "添加失败!,用户信息存在!" + }) + else: + try: + url = data["url"] + dxx_id = re.findall(r"memberId=(.*?)&showMemberAdditionNames", url)[0] + token_headers = { + 'Host': 'tuanapi.12355.net', + 'Connection': 'keep-alive', + 'Accept': 'application/json, text/javascript, */*; q=0.01', + 'Origin': 'https://tuan.12355.net', + 'User-Agent': 'MicroMessenger', + 'X-Requested-With': 'com.tencent.mm', + 'Sec-Fetch-Site': 'same-site', + 'Sec-Fetch-Mode': 'cors', + 'Referer': 'https://tuan.12355.net/wechat/view/YouthLearning/page.html', + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7', + } + ger_param_url = f"https://tuanapi.12355.net/questionnaire/getYouthLearningUrl?mid={dxx_id}" + async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client: + param_response = await client.get(url=ger_param_url) + if param_response.json()["status"] == 200: + content = param_response.json()["youthLearningUrl"].split("=")[-1] + token_url = "https://youthstudy.12355.net/apih5/api/user/get" + token_headers = { + 'Host': 'youthstudy.12355.net', + 'Connection': 'keep-alive', + 'Origin': 'https://youthstudy.12355.net', + 'X-Litemall-Token': '', + 'X-Litemall-IdentiFication': 'young', + 'User-Agent': 'MicroMessenger', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': '*/*', + 'X-Requested-With': 'com.tencent.mm', + 'Sec-Fetch-Site': 'same-origin', + 'Sec-Fetch-Mode': 'cors', + 'Referer': 'https://youthstudy.12355.net/h5/', + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7' + } + async with AsyncClient(headers=token_headers, timeout=30, max_redirects=5) as client: + token_response = await client.post(url=token_url, data="sign="+urllib.parse.quote(content)) + if token_response.json()["errno"] == 0: + token = token_response.json()['data']['entity']['token'] + name = token_response.json()['data']['entity']['nickName'] + organization_id = token_response.json()['data']['entity']['organizeId'] + data["name"] = name + data["organization_id"] = organization_id + data["dxx_id"] = dxx_id + data["token"]=token + data.pop("url") + status = await write_to_database(data=data) + if status: + return JSONResponse( + { + "status": 0, + "msg": "添加成功!" + } + ) + else: + return JSONResponse({ + "status": 500, + "msg": "添加失败!" + }) + else: + return JSONResponse({"status": 500, "msg": "添加失败!"}) + else: + return JSONResponse({"status": 500, "msg": "添加失败!"}) + except Exception as e: + return JSONResponse({ + "status": 500, + "msg": f"添加失败,{e}" + }) + + +@route.get("/guangdong", response_class=HTMLResponse) +async def guangdong(user_id: int, group_id: int): + result = await AddUser.filter(user_id=user_id, group_id=group_id, status="未通过").count() + if result: + return guangdong_page.render( + site_title='广东共青团 | TeenStudy', + site_icon="https://i.328888.xyz/2023/02/23/xIh5k.png" + ) + return RedirectResponse( + url="/TeenStudy/login" + ) diff --git a/TeenStudy/web/pages/add.py b/TeenStudy/web/pages/add.py index 14c7f6b..968e258 100644 --- a/TeenStudy/web/pages/add.py +++ b/TeenStudy/web/pages/add.py @@ -842,3 +842,99 @@ ) jilin_page = Page(title='添加大学习', body=[logo, Divider(), jilin_table, footer]) + +guangdong_table = Form( + title="广东共青团", + mode=DisplayModeEnum.horizontal, + api="post:/TeenStudy/api/guangdong/add", + redirect="/TeenStudy/login", + body=[ + Alert(level=LevelEnum.info, + className='white-space-pre-wrap', + body=( + "链接获取方式:\n12355青春之声公众号\n智慧团建-认证资料-生成电子团员证,点击最下方生成按钮。\n在团员证页面复制链接 应为:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true \n其中xxxxxx即为mid")), + InputText( + label="用户ID", + description="用户ID,为用户QQ号,无需填写", + name="user_id", + value="${user_id}", + disabled=True + ), + InputText( + label="通知群ID", + description="通知群号,无需填写", + name="group_id", + value="${group_id}", + disabled=True + ), + InputText( + label="地区", + description="所处省份", + name="area", + value="广东", + disabled=True + ), + InputText( + label="登录密码", + type='input-password', + description="可不填,默认为用户ID", + name="password", + inline=False, + required=False, + value="", + clearable=True, + maxLength=16 + ), + InputText( + label="姓名", + description="您的姓名", + name="name", + inline=False, + required=True, + value="", + clearable=True, + maxLength=8 + ), + InputText( + label="url", + description="链接格式:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true", + name="url", + inline=False, + required=True, + value="", + clearable=True, + maxLength=512 + ), + InputText( + label="学校", + description="你就读的高校", + name="university", + inline=False, + required=True, + value="", + clearable=True, + maxLength=24 + ), + InputText( + label="学院", + description="学院名称", + name="college", + inline=False, + required=True, + value="", + clearable=True, + maxLength=32 + ), + InputText( + label="团支部", + description="团支部|班级,没有可不填", + name="organization", + inline=False, + required=False, + value="", + clearable=True, + maxLength=32 + )] +) + +guangdong_page = Page(title='添加大学习', body=[logo, Divider(), guangdong_table, footer]) diff --git a/TeenStudy/web/pages/admin.py b/TeenStudy/web/pages/admin.py index dc3bee0..1b68d1d 100644 --- a/TeenStudy/web/pages/admin.py +++ b/TeenStudy/web/pages/admin.py @@ -1394,6 +1394,115 @@ ] ) +"""广东地区添加用户""" +guangdong_table = Form( + title="广东共青团", + mode=DisplayModeEnum.horizontal, + api="post:/TeenStudy/api/guangdong/add", + redirect="/TeenStudy/login", + body=[ + Alert(level=LevelEnum.info, + className='white-space-pre-wrap', + body=( + "链接获取方式:\n12355青春之声公众号\n智慧团建-认证资料-生成电子团员证,点击最下方生成按钮。\n在团员证页面复制链接 应为:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true \n其中xxxxxx即为mid")), + Select( + label="群聊", + name="group_id", + description="需要添加的群组", + checkAll=False, + source="get:/TeenStudy/api/get_group_list", + value='', + multiple=False, + required=True, + searchable=True, + joinValues=False, + extractValue=True, + statistics=True, + ), + Select( + label="用户ID", + name="user_id", + description="需要添加的用户ID", + checkAll=False, + source="get:/TeenStudy/api/get_member_list?group_id=${group_id}", + value='', + multiple=False, + required=True, + searchable=True, + joinValues=False, + extractValue=True, + statistics=True, + hiddenOn="${group_id==''?true:false}" + ), + InputText( + label="地区", + description="所处省份", + name="area", + value="广东", + disabled=True + ), + InputText( + label="登录密码", + type='input-password', + description="可不填,默认为用户ID", + name="password", + inline=False, + required=False, + value="", + clearable=True, + maxLength=16 + ), + InputText( + label="姓名", + description="您的姓名", + name="name", + inline=False, + required=True, + value="", + clearable=True, + maxLength=8 + ), + InputText( + label="url", + description="链接格式:https://tuan.12355.net/wechat/view/information/member_certification_generated.html?memberId=xxxxxx&showMemberAdditionNames=&showMemberRewardIds=&isShowAllFee=true", + name="url", + inline=False, + required=True, + value="", + clearable=True, + maxLength=512 + ), + InputText( + label="学校", + description="你就读的高校", + name="university", + inline=False, + required=True, + value="", + clearable=True, + maxLength=24 + ), + InputText( + label="学院", + description="学院名称", + name="college", + inline=False, + required=True, + value="", + clearable=True, + maxLength=32 + ), + InputText( + label="团支部", + description="团支部|班级,没有可不填", + name="organization", + inline=False, + required=False, + value="", + clearable=True, + maxLength=32 + )] +) """推送群聊模板""" push_table = CRUD(mode='table', title='', @@ -1475,6 +1584,8 @@ schema=Page(title='重庆共青团', body=[chongqing_table])) jilin_page = PageSchema(url='/add/jilin', icon='fa fa-pen-to-square', label='吉青飞扬', schema=Page(title='吉青飞扬', body=[jilin_table])) +guangdong_page = PageSchema(url='/add/guangdong', icon='fa fa-pen-to-square', label='广东共青团', + schema=Page(title='广东共青团', body=[guangdong_table])) admin_app = App(brandName='TeenStudy', logo='https://i.328888.xyz/2023/02/23/xIh5k.png', header=header, @@ -1483,7 +1594,7 @@ admin_page, PageSchema(icon='fa fa-circle-user', label='成员管理', children=[list_page, hubei_page, jiangxi_page, jiangsu_page, anhui_page, - sichuan_page, shandong_page, chongqing_page, jilin_page]), + sichuan_page, shandong_page, chongqing_page, jilin_page,guangdong_page]), PageSchema(url="/notice", label='推送列表', icon='fa fa-bell', schema=Page(title='', body=[push_table])), PageSchema(url="/request", label='申请记录', icon='fa fa-circle-info', diff --git a/pyproject.toml b/pyproject.toml index 1397bf3..2c38d3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] -name = "teenstudy" -version = "0.1.7" +name = "TeenStudy" +version = "0.1.8" description = "基于nonebot2异步框架的青年大学自动提交插件基于nonebot2的青年大学习自动提交插件,用于自动完成大学习,在后台留下记录,返回完成截图" authors = ["ZM25XC "] license="MIT"