From 93c0c0f0c9c215cc7a9688119896dfcb0c84750e Mon Sep 17 00:00:00 2001 From: "tanglinchuanz@163.com" Date: Tue, 1 Mar 2022 11:23:21 +0800 Subject: [PATCH 1/4] crontab timer support --- Dockerfile | 2 ++ requirements.txt | 3 ++- wxcloudrun/settings.py | 10 +++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 421e250..94bc312 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,3 +33,5 @@ CMD ["python3", "manage.py", "runserver", "0.0.0.0:80"] RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ && apk del tzdata + +RUN python3 manage.py crontab add \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 2f1aaf4..774e439 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ PyJWT==2.3.0 PyMySQL==1.0.2 requests==2.27.1 urllib3==1.26.8 -pycryptodome==3.9.7 \ No newline at end of file +pycryptodome==3.9.7 +django_crontab \ No newline at end of file diff --git a/wxcloudrun/settings.py b/wxcloudrun/settings.py index ad3cbf1..f0ab93b 100644 --- a/wxcloudrun/settings.py +++ b/wxcloudrun/settings.py @@ -29,6 +29,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django_crontab', 'wxcloudrun', 'wxBackendsapi' ] @@ -123,6 +124,9 @@ LOGGING = { }, # 过滤 'filters': { + 'require_debug_false': { + '()': 'django.utils.log.RequireDebugFalse', + }, }, # 定义具体处理日志的方式 'handlers': { @@ -166,7 +170,7 @@ LOGGING = { 'mail_admins': { 'level': 'ERROR', 'class': 'django.utils.log.AdminEmailHandler', - # 'filters': ['require_debug_false'], + 'filters': ['require_debug_false'], 'include_html': True, } }, @@ -187,6 +191,10 @@ LOGGING = { } } +CRONJOBS = [ + ('*/1 * * * *', 'wxBackendsapi.views.timer', ['',''], {}, '>> /var/log/crontab.log') +] + # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ -- Gitee From c99e7726b895452b5832bdcd7614db486e9c58e5 Mon Sep 17 00:00:00 2001 From: "tanglinchuanz@163.com" Date: Tue, 1 Mar 2022 14:30:20 +0800 Subject: [PATCH 2/4] =?UTF-8?q?crontab=20=E6=94=B9=E4=B8=BA=E6=AF=8F?= =?UTF-8?q?=E5=B0=8F=E6=97=B630=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wxcloudrun/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wxcloudrun/settings.py b/wxcloudrun/settings.py index f0ab93b..3c7c968 100644 --- a/wxcloudrun/settings.py +++ b/wxcloudrun/settings.py @@ -192,7 +192,7 @@ LOGGING = { } CRONJOBS = [ - ('*/1 * * * *', 'wxBackendsapi.views.timer', ['',''], {}, '>> /var/log/crontab.log') + ('30 * * * *', 'wxBackendsapi.views.timer', ['',''], {}, '>> /var/log/crontab.log') ] # Internationalization -- Gitee From 17e57ea836d34ceff33f4305222ffcd234012726 Mon Sep 17 00:00:00 2001 From: "tanglinchuanz@163.com" Date: Wed, 2 Mar 2022 12:52:41 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=B7=BB=E5=8A=A0isShow=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0014_ddlinfo_isshow.py | 18 ++++++++++++++++++ wxBackendsapi/models.py | 1 + wxcloudrun/settings.py | 4 ++-- wxcloudrun/views.py | 2 +- 4 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 wxBackendsapi/migrations/0014_ddlinfo_isshow.py diff --git a/wxBackendsapi/migrations/0014_ddlinfo_isshow.py b/wxBackendsapi/migrations/0014_ddlinfo_isshow.py new file mode 100644 index 0000000..9d6df1e --- /dev/null +++ b/wxBackendsapi/migrations/0014_ddlinfo_isshow.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.8 on 2022-03-01 15:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wxBackendsapi', '0013_ddlinfo_modulename'), + ] + + operations = [ + migrations.AddField( + model_name='ddlinfo', + name='isShow', + field=models.BooleanField(default=True, verbose_name='isShow'), + ), + ] diff --git a/wxBackendsapi/models.py b/wxBackendsapi/models.py index a07b658..d5444fc 100644 --- a/wxBackendsapi/models.py +++ b/wxBackendsapi/models.py @@ -27,6 +27,7 @@ class DDLInfo(models.Model): # courseState = models.BooleanField("Course State", default=True) assState = models.BooleanField("Assignment State", default=True) isSubmit = models.BooleanField("isSubmit", default=False) + isShow = models.BooleanField("isShow", default=True) moduleName = models.CharField("Module Name", max_length=100, default="") class Meta: verbose_name = "DDLInfo" diff --git a/wxcloudrun/settings.py b/wxcloudrun/settings.py index 3c7c968..db6e56a 100644 --- a/wxcloudrun/settings.py +++ b/wxcloudrun/settings.py @@ -72,8 +72,8 @@ DATABASES = { 'ENGINE': 'django.db.backends.mysql', 'NAME': os.environ.get("MYSQL_DATABASE", 'UIC_Circles'), 'USER': os.environ.get("MYSQL_USERNAME", 'root'), - 'HOST': os.environ.get("MYSQL_ADDRESS", "192.168.10.113:3306").split(':')[0], - 'PORT': os.environ.get("MYSQL_ADDRESS", "192.168.10.113:3306").split(':')[1], + 'HOST': os.environ.get("MYSQL_ADDRESS", "127.0.0.1:3306").split(':')[0], + 'PORT': os.environ.get("MYSQL_ADDRESS", "127.0.0.1:3306").split(':')[1], 'PASSWORD': os.environ.get("MYSQL_PASSWORD", '12345678'), 'OPTIONS': {'charset': 'utf8mb4'}, } diff --git a/wxcloudrun/views.py b/wxcloudrun/views.py index 7ebf976..f226f4b 100644 --- a/wxcloudrun/views.py +++ b/wxcloudrun/views.py @@ -62,7 +62,7 @@ def login(request, _): weixinRsp = json.loads(weixinRsp) # skip weixin auth - # weixinRsp = {'openid': 'testid'} + weixinRsp = {'openid': 'testid'} if 'errcode' in weixinRsp or 'openid' not in weixinRsp: # weixin authorize fail -- Gitee From 6094dea69c2c53b9ef96542d0bc8a24d118b66d8 Mon Sep 17 00:00:00 2001 From: tlc123ooop Date: Wed, 2 Mar 2022 07:45:41 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=20wxcl?= =?UTF-8?q?oudrun/views.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- wxcloudrun/views.py | 236 -------------------------------------------- 1 file changed, 236 deletions(-) delete mode 100644 wxcloudrun/views.py diff --git a/wxcloudrun/views.py b/wxcloudrun/views.py deleted file mode 100644 index f226f4b..0000000 --- a/wxcloudrun/views.py +++ /dev/null @@ -1,236 +0,0 @@ -import datetime -import json -import logging -import requests -import os -import jwt - -from django.http import JsonResponse -from bs4 import BeautifulSoup -from wxBackendsapi import models -from wxBackendsapi.views import saveDDLInfo -from threading import Thread - -logger = logging.getLogger('log') -# fixed "Unverified HTTPS request is being made to xxxx" warning -requests.packages.urllib3.disable_warnings() - -def tokenValidate(request): - ret = '' - if 'Authorization' in request.headers: - try: - token = jwt.decode(request.headers['Authorization'], os.environ.get("JWT_SECRET_KEY", 'test_key12345678'), algorithms="HS256") - user = models.UserInfo.objects.get(openid = token['openid']) - if user.isLogin == False: - raise Exception("session expired", user.openid) - except BaseException as e: - ret = {'errcode': -1, 'errorMsg': str(e)} - else: - ret = {'openid': token['openid']} - else: - ret = {'errcode': -2, 'errorMsg': 'token missing'} - return ret - -def login(request, _): - """ - 登录接口 - request payload {js_code, username, password} - return {openid, access_token} - """ - rsp='' - - if request.method == 'GET' or request.method == 'get': - # GET - ret = tokenValidate(request) - if 'openid' in ret: - ret['exp']=datetime.datetime.now()+datetime.timedelta(days=7) - token = jwt.encode(ret, os.environ.get("JWT_SECRET_KEY", 'test_key12345678'), algorithm="HS256") - rsp = JsonResponse({'errcode': 0, 'errorMsg': 'Token extended success', 'access_token': token}, json_dumps_params={'ensure_ascii': False}) - else: - rsp = JsonResponse(ret, json_dumps_params={'ensure_ascii': False}) - - elif request.method == 'POST' or request.method == 'post': - # POST - body_unicode = request.body.decode('utf-8') - body = json.loads(body_unicode) - - if 'js_code' not in body or 'username' not in body or 'password' not in body: - # parameter missing - rsp = JsonResponse({'errcode': -2, 'errorMsg': 'parameter missing'}, json_dumps_params={'ensure_ascii': False}) - else: - weixinRsp = weixinAuth(body['js_code']).content.decode('utf-8') - weixinRsp = json.loads(weixinRsp) - - # skip weixin auth - weixinRsp = {'openid': 'testid'} - - if 'errcode' in weixinRsp or 'openid' not in weixinRsp: - # weixin authorize fail - rsp = JsonResponse({'errcode': weixinRsp['errcode'], 'errorMsg': weixinRsp['errmsg']}, json_dumps_params={'ensure_ascii': False}) - else: - uicRsp, session, sesskey = uicAuth(body['username'], body['password']) - - if uicRsp == {} or uicRsp.url != 'https://ispace.uic.edu.hk/my/': - # UIC authorization fail - rsp = JsonResponse({'errcode': -3, 'errorMsg': 'UIC authorization failure'}, json_dumps_params={'ensure_ascii': False}) - else: #success - #db operation - user = models.UserInfo(openid=weixinRsp['openid'], session=session, sesskey=sesskey) - user.encryptSave() - # return access token - token = jwt.encode({'openid': weixinRsp['openid'], "exp": datetime.datetime.now()+datetime.timedelta(days=7)}, os.environ.get("JWT_SECRET_KEY", 'test_key12345678'), algorithm='HS256') - rsp = JsonResponse({'errcode': 0, 'errorMsg': 'Authorization success', 'data': {'openid': '', 'access_token': token}}, json_dumps_params={'ensure_ascii': False}) - # call crawler initialize - Thread(target=saveDDLInfo, args=(weixinRsp['openid'], True)).start() - - logger.info('login openid: {}'.format(weixinRsp['openid'])) - - else: - # Incorrect request mode - rsp = JsonResponse({'errcode': -1, 'errorMsg': 'Incorrect request mode'}, json_dumps_params={'ensure_ascii': False}) - - return rsp - -def uicAuth(username, password): - """ - uic登录验证 - """ - loginUrl= "https://ispace.uic.edu.hk/login/index.php" - rsp = {} - sesskey = '' - - session = requests.Session() - try: - rsp = session.get(loginUrl, verify=False) - except BaseException as e: - logger.error('request result: '+str(e)) - else: - loginToken = BeautifulSoup(rsp.text, 'html.parser').find("input",{'name': 'logintoken'})['value'] - - postdata = { - 'anchor': "", - 'logintoken': loginToken, - 'username': username, - 'password': password - } - - header = { - 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0", - 'Referer': loginUrl - } - try: - rsp = session.post(loginUrl, postdata, headers=header, verify=False) - except BaseException as e: - logger.error('request result: '+str(e)) - else: - sesskey = BeautifulSoup(rsp.text, 'html.parser').find("input",{'name': 'sesskey'})['value'] - session = requests.utils.dict_from_cookiejar(session.cookies)['MoodleSession'] - - finally: - return rsp, session, sesskey - -def weixinAuth(js_code): - """ - 获取openid - """ - payload = { - 'appid': os.environ.get("WEIXINXCX_APPID"), - 'secret': os.environ.get("WEIXINXCX_SECRET"), - 'js_code': js_code, - 'grant_type': 'authorization_code' - } - url = 'https://api.weixin.qq.com/sns/jscode2session' - rsp = {} - try: - rsp = requests.get(url, params=payload, verify=False) - except BaseException as e: - logger.error('request result: '+str(e)) - else: - logger.info('weixinAuth result: {}'.format(rsp.content.decode('utf-8'))) - finally: - return rsp - -def notificationSend(template_id, openid, page, str1, str2, time3): - """ - 推送消息 - str1: notification content - str2: assignment name - time3: 24小时制时间格式(支持+年月日),支持填时间段,两个时间点之间用“~”符号连接 例如 15:01,或 2019年10月1日 15:01 - return: {errcode, errmsg} - """ - # cut down string larger than 20 - if len(str1)>20: - str1=str1[:18]+'…' - if len(str2)>20: - str2=str2[:18]+'…' - - postData = { - 'touser': openid, - 'template_id': template_id, - 'page': page, - 'miniprogram_state': 'trial', - 'lang': 'en_US', - 'data': { - 'thing1': { - 'value': str1[:20] - }, - 'thing2': { - 'value': str2[:20] - }, - 'time3': { - 'value': time3 - }, - } - } - url = 'https://api.weixin.qq.com/cgi-bin/message/subscribe/send' - rsp = requests.post(url, json=postData, verify=False) - logger.info('notification result: {}'.format(rsp.content.decode('utf-8'))) - return rsp - -def logout(request, _): - ret = tokenValidate(request) - if 'openid' in ret: - user = models.UserInfo.objects.get(openid=ret['openid']) - user.isLogin = False - user.save() - rsp = JsonResponse({'errcode': 0, 'errorMsg': 'log out success'}, json_dumps_params={'ensure_ascii': False}) - logger.info('logout openid: {}'.format(ret['openid'])) - else: - rsp = JsonResponse(ret, json_dumps_params={'ensure_ascii': False}) - return rsp - -def sessionExtend(openid): - user = models.UserInfo() - user.decryptGet(openid=openid) - - session = requests.Session() - session.cookies = requests.utils.cookiejar_from_dict({'MoodleSession': user.session}) - - serviceUrl = "https://ispace.uic.edu.hk/lib/ajax/service.php" - paraSess = { - 'sesskey': user.sesskey, - 'info': "core_session_touch" - } - sessData = [ - { - "args": {}, - "index": 0, - "methodname": "core_session_touch" - } - ] - header = { - 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0", - 'Referer': serviceUrl - } - try: - ret = session.post(serviceUrl, params=paraSess, json=sessData, headers=header, verify=False) - body = json.loads(ret.content.decode('utf-8'))[0] - if body['error'] is True: - raise Exception("session expired", ret) - except BaseException as e: - user = models.UserInfo.objects.get(openid=ret['openid']) - user.isLogin = False - user.save() - logger.error("session extend failed on openid: {} ".format(openid) + str(e)) - - return session, user.sesskey \ No newline at end of file -- Gitee