Commit 0d3d8593 authored by Zheng Yile's avatar Zheng Yile
Browse files

Add function `startpack`; Update requests

parent 06113ad8
Pipeline #662 failed with stages
in 0 seconds
......@@ -68,7 +68,7 @@ pid, eid 可以通过客户端查询, 也可以在网页端访问的链接中获
### 取消指定题包
`pid` `p`.
`del pid` .
取消指定题包.
### 指定题目
......@@ -81,6 +81,11 @@ pid, eid 可以通过客户端查询, 也可以在网页端访问的链接中获
`getexercise``ge`.
查看题目内容. 该函数可以指定返回类型, 直接调用默认为*dict*, 在查询时默认为*json*.
## 开始题包
`startpack`.
开始一个题包的答题. 返回类型为*json*.
## 提交代码
`open PATH`.
......@@ -89,8 +94,7 @@ pid, eid 可以通过客户端查询, 也可以在网页端访问的链接中获
`submit`.
提交代码到服务器评测. 直接调用函数的返回类型为*requests.Response*, 查询时没有返回.
根据 pid, eid 的值确定提交的题目,并以`solutioncode`的内容作为提交的代码.
*Tips: 提交之前请确保 `pid`, `eid`正确。可以获取题面以验证,方法参照:[查看题目内容](#查看题目内容)。另外建议提交之前检查一遍 `solutioncode`. 查询方法参照:[查看程序运行中的变量](#查看程序运行中的变量)。*
*Tips: 如果在提交题包中的题目的代码前没有开始过这个题包,可能会无法记录提交结果。开始题包方法参照:[开始题包](#开始题包)。提交之前请确保 `pid`, `eid`正确。可以获取题面以验证,方法参照:[查看题目内容](#查看题目内容)。另外建议提交之前检查一遍 `solutioncode`. 查询方法参照:[查看程序运行中的变量](#查看程序运行中的变量)。*
## 查询提交过的代码
......@@ -105,7 +109,7 @@ pid, eid 可以通过客户端查询, 也可以在网页端访问的链接中获
## 查看程序运行中的变量
`show [VAR]`.
查看变量名为VAR的变量; 若没有指定变量名, 则返回所有变量 *(包括 `username`, `pid`, `eid`, `lang`, `solutioncode`)*. 返回类型为*json*.
查看变量名为VAR的变量; 若没有指定变量名, 则返回`requests.variables`中的所有变量. 返回类型为*json*.
# 辅助功能
## 接口相关
......@@ -120,4 +124,4 @@ pid, eid 可以通过客户端查询, 也可以在网页端访问的链接中获
这种记录方法在绝大多数情况下保证无法从配置文件中获取密码的值,并且在密码不正确时不能获取对应的cookie.
在登录时会首先尝试匹配配置中的信息。成功匹配则直接使用配置中的cookie尝试登录,失败则会向服务器提交数据以获得新的cookie.
若在启动程序时加上`--no-cache`的选项,则会禁用配置,即不会往配置文件中写入信息,也不会从配置文件中读取信息。**但已经写入的数据不会删除。**
若在启动程序时加上`--no-cache`的选项,则会禁用配置,即不会往配置文件中写入信息,也不会从配置文件中读取信息。**但已经写入的数据不会删除。**
\ No newline at end of file
from .network import variables as net_var, client_login, logined
from .network import variables as net_var, client_login
from .argparse import ArgParser
from .requests import variables as requests_var, requests
from .report import variables as report_var
......
......@@ -3,7 +3,13 @@ from .utils import passwd_hash, cookie_encrypt, cookie_decrypt
from .cachectrl import variables as cache_var, cache_for_login as cache
import json
variables = {
'register': False
'register': False,
'me': {
'username': None,
'nickname': None,
'email': None,
'verified': None,
},
}
url = 'https://code.bdaa.pro/graphql/'
coding_base_headers = {
......@@ -95,7 +101,7 @@ def client_login(username, password = None, cookie = None):
coding_base_headers['cookie'] = cookie_decrypt(cache_var['logindic'][username]['cookie'], password)
report("Using cached cookie.")
displayName = logined()
if displayName: report("Login succeeded.({})".format(displayName))
if displayName: report('Login succeeded.({})'.format(displayName))
else:
report('Invalid cached cookie.', 1)
login(username, password)
......@@ -108,7 +114,7 @@ def client_login(username, password = None, cookie = None):
else: report('Invalid cookie input.', 3)
else: report('No username or cookie specified.', 3)
def logined():
def logined(reportUnverified:bool = True):
headers = coding_base_headers.copy()
data = json.dumps({
"operationName": None,
......@@ -129,7 +135,16 @@ def logined():
if not res: return False
res_data = json.loads(res.text)
if 'errors' in res_data: return False
else: return res_data['data']['me']['displayName']
else:
if reportUnverified and not res_data['data']['me']['verified']:
report("The user has not verified.", 1)
if not res_data['data']['me']['displayName']:
res_data['data']['me']['displayName'] = "UNDEFINED"
variables['me']['username'] = res_data['data']['me']['login']
variables['me']['nickname'] = res_data['data']['me']['displayName']
variables['me']['email'] = res_data['data']['me']['defaultEmail']
variables['me']['verified'] = res_data['data']['me']['verified']
return res_data['data']['me']['displayName']
def login(username, passwd):
report('Try login.')
......@@ -362,6 +377,9 @@ query pack($pid: ID!) {
title
}
}
viewerStatus {
ongoing
}
}
}
}'''})
......@@ -369,6 +387,51 @@ query pack($pid: ID!) {
if not res: return False
return json.loads(res.text)['data']['node']
def start_pack(pid):
if show_pack(pid)['viewerStatus']['ongoing']:
report("This pack is already ongoing.", 1)
return None
headers = coding_base_headers.copy()
data = json.dumps({
"operationName": "startSession",
"variables": {
"pid": pid
},
"query": r'''
mutation startSession($pid: ID!, $code: String) {
startSession(exercisePackId: $pid, code: $code) {
id
codingExercises {
passedCount
totalCount
edges {
node { id }
userStatus {
attempted
passed
}
}
}
pack {
id
description { content }
codingExercises {
nodes {
id
title
}
}
viewerStatus {
ongoing
due
}
}
}
}'''})
res = post(url = url, headers = headers, data = data)
if not res: return False
return json.loads(res.text)['data']['startSession']
def _login(username, passwd):
headers = login_base_headers.copy()
data = json.dumps({
......
from .network import get_exercise, get_data, submit, get_pack, show_pack
from .network import variables as net_var, get_exercise, get_data, submit, get_pack, show_pack, start_pack
from .report import report
from .utils import AliasesDict
import json
variables = {
aliases = {
'p': 'pid',
'e': 'eid',
'l': 'lang',
'sc': 'solutioncode',
}
variables = AliasesDict({
'pid': None,
'eid': None,
'lang': None,
'solutioncode': None,
'username': None
}
'solutioncode': None
}, aliases)
class requests:
class Requests:
queryres = ""
help_txt = "We haven't provide the help text. If you need, please read the code in 'codiaclient/requests.py' to help understanding."
def __str__(self):
return self.queryres
def show_msg(self, qres):
if type(qres) != str: qres = str(qres)
else: pass
......@@ -23,17 +27,7 @@ class requests:
self.queryres += '\n'
def __init__(self, conf: dict):
p = variables['pid']
e = variables['eid']
l = variables['lang']
sc = variables['solutioncode']
un = variables['username']
pid = variables['pid']
eid = variables['eid']
lang = variables['lang']
solutioncode = variables['solutioncode']
username = variables['username']
variables.update(net_var['me'])
self.queryres = ""
if len(conf) == 0: pass
else:
......@@ -42,57 +36,56 @@ class requests:
elif conf[0] in ['h', 'help']:
if len(conf) == 1: self.show_msg(self.help_txt)
else: report('Invalid request.', 1)
elif conf[0] in ['p', 'pid']:
if len(conf) == 2: variables['pid'] = conf[1]
elif len(conf) == 1: variables['pid'] = None
else: report('Invalid request.', 1)
elif conf[0] in ['e', 'eid']:
if len(conf) == 2: variables['eid'] = conf[1]
elif len(conf) == 1: variables['eid'] = None
else: report('Invalid request.', 1)
elif conf[0] in ['l', 'lang']:
if len(conf) == 2: variables['lang'] = conf[1]
elif len(conf) == 1: variables['lang'] = None
else: report('Invalid request.', 1)
elif conf[0] in ['sc', 'solutioncode']:
if len(conf) == 1: variables['solutioncode'] = None
elif conf[0] in variables or conf[0] in aliases:
if len(conf) == 2: variables[conf[0]] = conf[1]
else: report('Use `show VAR` to show the variables.', 1)
elif conf[0] in ['del', 'reset']:
if len(conf) == 2:
if conf[1] in variables or conf[1] in aliases:
variables[conf[1]] = None
else: report('Variable `{}` doesn\'t exist.'.format(conf[1]), 1)
elif len(conf) == 1:
for x in variables:
variables[x] = None
else: report('Invalid request.', 1)
elif conf[0] in ['o', 'open']:
if len(conf) == 1:
with open(conf[1], encoding = 'utf-8') as f: variables['solutioncode'] = f.read()
if len(conf) >= 2:
path = ' '.join(conf[1:])
while path[:1] == ' ': path = path[1:]
while path[-1:] == ' ': path = path[:-1]
if path[:1] == '\"': path = path[1:]
if path[-1:] == '\"': path = path[:-1]
try:
with open(path, encoding = 'utf-8') as f: variables['sc'] = f.read()
except OSError as e:
report(e, 1)
else: report('Invalid request.', 1)
elif conf[0] in ['show']:
if len(conf) == 1:
self.show_msg(json.dumps({
"username": username,
"pid": pid,
"eid": eid,
"lang": lang,
"solutioncode": solutioncode
}))
self.show_msg(json.dumps(variables))
elif len(conf) == 2:
try: self.show_msg(json.dumps({conf[1]: eval(conf[1])}))
try: self.show_msg(json.dumps({conf[1]: variables[conf[1]]}))
except Exception as e: report(e.__repr__(), 1)
else: report('Invalid request.', 1)
elif conf[0] in ['ge', 'getex', 'getexercise']:
if eid:
res = get_exercise(eid = eid, pid = pid, lang = lang, feedback = 'json')
if variables['e']:
res = get_exercise(eid = variables['e'], pid = variables['p'], lang = variables['l'], feedback = 'json')
self.show_msg(res)
else: report("No eid specified.", 1)
elif conf[0] in ['gc', 'getc', 'getcode']: # getcode [[N] to [PATH]]
if len(conf) <= 2:
if eid:
if variables['e']:
if len(conf) == 1:
res = get_data(eid = eid, pid = pid)
res = get_data(eid = variables['e'], pid = variables['p'])
self.show_msg(json.dumps(res[0]['solution']['asset']['content']))
elif len(conf) == 2:
if conf[1] == 'to':
res = get_data(eid = eid, pid = pid)
res = get_data(eid = variables['e'], pid = variables['p'])
try:
with open('./tmp.txt', 'w', encoding = 'utf-8') as f: f.write(res[0]['solution']['asset']['content'])
except Exception as e: report(e, 1)
else:
try: res = get_data(eid = eid, pid = pid, codecnt = int(conf[1]))
try: res = get_data(eid = variables['e'], pid = variables['p'], codecnt = int(conf[1]))
except ValueError: report('Invalid request: type(codecnt) should be int.', 1)
else:
if res == None: report('Invalid request.', 1)
......@@ -101,12 +94,12 @@ class requests:
else: report("No eid specified.", 1)
elif len(conf) == 3:
if conf[1] == 'to':
res = get_data(eid = eid, pid = pid)
res = get_data(eid = variables['e'], pid = variables['p'])
try:
with open(conf[2], 'w', encoding = 'utf-8') as f: f.write(res[0]['solution']['asset']['content'])
except Exception as e: report(e, 1)
elif conf[2] == 'to':
try: res = get_data(eid = eid, pid = pid, codecnt = int(conf[1]))
try: res = get_data(eid = variables['e'], pid = variables['p'], codecnt = int(conf[1]))
except ValueError: report('Invalid request: type(lastcnt) should be int.', 1)
else:
try:
......@@ -115,7 +108,7 @@ class requests:
else: report('Invalid request.', 1)
elif len(conf) == 4:
if conf[2] == 'to':
try: res = get_data(eid = eid, pid = pid, codecnt = int(conf[1]))
try: res = get_data(eid = variables['e'], pid = variables['p'], codecnt = int(conf[1]))
except ValueError: report('Invalid request: type(codecnt) should be int.', 1)
else:
try:
......@@ -125,7 +118,7 @@ class requests:
else: report('Invalid request.', 1)
elif conf[0] in ['submit']:
if len(conf) == 1:
if eid: res = submit(eid = eid, pid = pid, lang = lang, solutioncode = solutioncode)
if variables['e']: res = submit(eid = variables['e'], pid = variables['p'], lang = variables['l'], solutioncode = variables['sc'])
else: report("No eid specified.", 1)
else: report('Invalid request.', 1)
elif conf[0] in ['gp', 'getp', 'getpack']: #getpack [N] [before PID]
......@@ -154,10 +147,10 @@ class requests:
else: report('Invalid request.', 1)
elif conf[0] in ['gr', 'getr', 'getres', 'getreport', 'getreports']:
if len(conf) <= 2:
if eid:
if len(conf) == 1: res = get_data(eid = eid, pid = pid)
if variables['e']:
if len(conf) == 1: res = get_data(eid = variables['e'], pid = variables['p'])
elif len(conf) == 2:
try: res = get_data(eid = eid, pid = pid, codecnt = int(conf[1]))
try: res = get_data(eid = variables['e'], pid = variables['p'], codecnt = int(conf[1]))
except ValueError:
report('Invalid request: type(codecnt) should be int.', 1)
return
......@@ -176,9 +169,20 @@ class requests:
else: report('Invalid request.', 1)
elif conf[0] in ['sp', 'showp', 'showpack']:
if len(conf) == 1:
if pid:
res = show_pack(pid)
if variables['p']:
res = show_pack(variables['p'])
self.show_msg(json.dumps(res))
else: report("No pid specified.", 1)
else: report('Invalid request.', 1)
elif conf[0] in ['startp', 'startpack']:
if len(conf) == 1:
if variables['p']:
res = start_pack(variables['p'])
self.show_msg(json.dumps(res))
else: report("No pid specified.", 1)
else: report('Invalid request.', 1)
else: report('Invalid request.', 1)
def requests(conf: dict):
res = Requests(conf)
return res.queryres
\ No newline at end of file
from .report import report
class AliasesDict(dict):
aliaseslist = {}
def __init__(self, dict, aliaseslist = {}):
self.aliaseslist = aliaseslist
super().__init__(dict)
def __getitem__(self, attr):
if attr in self.aliaseslist: return super().__getitem__(self.aliaseslist[attr])
else: return super().__getitem__(attr)
def __setitem__(self, key, value):
if key in self.aliaseslist: return super().__setitem__(self.aliaseslist[key], value)
else: return super().__setitem__(key, value)
def passwd_hash(passwd):
try:
from hashlib import new
......@@ -23,3 +35,4 @@ def cookie_encrypt(cookie, passwd):
def cookie_decrypt(_cookie, passwd):
return str(AES.new(add_to_16(passwd), AES.MODE_ECB).decrypt(base64.decodebytes(_cookie.encode(encoding = 'utf-8'))), encoding = 'utf-8').replace('\x00', '')
......@@ -11,16 +11,15 @@ if __name__ == "__main__":
if args.origin: variables['origin'] = True
if cc.cache_var['cacheOn']: cc.cache_load()
cc.report_var['allow_error_deg'] = args.allow_error_deg
cc.requests_var['lang'] = args.lang
cc.requests_var['eid'] = args.eid
cc.requests_var['pid'] = args.pid
cc.requests_var['l'] = args.lang
cc.requests_var['e'] = args.eid
cc.requests_var['p'] = args.pid
if args.open:
cc.requests_var['solutioncode'] = args.open.read()
cc.requests_var['sc'] = args.open.read()
args.open.close()
cc.client_login(username = args.username, password = args.passwd, cookie = args.cookie)
cc.requests_var['username'] = cc.logined()
if args.request_string:
try:
if not variables['origin']:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment