def new(cls, password: str, sid_orig: str) -> None: db = get_mongodb() db[cls.collection_name].insert({ "sid_orig": sid_orig, "time": datetime.datetime.now(), "password": password })
def new_register_request(cls, sid_orig: str, verification_method: str, status: str, password: str = None) -> str: """ add a new register request :param sid_orig: original sid :param verification_method: password or email :param status: status of the request :param password: if register by password, save everyclass password (not jw password) here :return: the `request_id` """ if verification_method not in ("email", "password"): raise ValueError( "verification_method must be one of email, password") db = get_mongodb() doc = { "request_id": uuid.uuid4(), "create_time": datetime.datetime.now(), "sid_orig": sid_orig, "verification_method": verification_method, "status": status } if password: doc.update({"password": generate_password_hash(password)}) db[cls.collection_name].insert(doc) return str(doc["request_id"])
def exist(cls, sid_orig: str) -> bool: """check if a student has registered""" db = get_mongodb() result = db.user.find_one({'sid_orig': sid_orig}) if result: return True return False
def create_index(cls) -> None: db = get_mongodb() db.get_collection(cls.collection_name).create_index( [("course_id", 1), ("teach_type", 1), ("teacher_id_str", 1)], unique=True) db.get_collection(cls.collection_name).create_index([("cotc_id", 1)], unique=True)
def get_visitors(cls, sid_orig: str) -> List[Dict]: """获得访客列表""" db = get_mongodb() result = db[cls.collection_name].find({ "host": sid_orig }).sort("last_time", -1).limit(50) visitor_list = [] for people in result: stu_cache = RedisCacheDAO.get_student(people["visitor"]) if stu_cache: visitor_list.append({ "name": stu_cache.name, "sid": stu_cache.sid, "visit_time": people["last_time"] }) else: # query api-server with elasticapm.capture_span('rpc_search'): rpc_result = HttpRpc.call( method="GET", url='{}/v1/search/{}'.format( current_app.config['API_SERVER_BASE_URL'], people["visitor"]), retry=True) visitor_list.append({ "name": rpc_result["student"][0]["name"], "sid": rpc_result["student"][0]["sid"], "visit_time": people["last_time"] }) RedisCacheDAO.set_student( Student(sid_orig=people["visitor"], name=rpc_result["student"][0]["name"], sid=rpc_result["student"][0]["sid"])) return visitor_list
def get_level(cls, sid_orig: str) -> int: """获得学生的隐私级别。0为公开,1为实名互访,2为自己可见。默认为配置文件中定义的 DEFAULT_PRIVACY_LEVEL""" db = get_mongodb() doc = mongo_with_retry(db[cls.collection_name].find_one, {"sid_orig": sid_orig}, num_retries=1) return doc["level"] if doc else get_config().DEFAULT_PRIVACY_LEVEL
def get_my_review(cls, cotc_id: int, student_id: str) -> Dict: db = get_mongodb() doc = db.get_collection(cls.collection_name).find_one({ "cotc_id": cotc_id, "student_id": student_id }) return doc
def add_user(cls, sid_orig: str, password: str) -> None: """add a user""" db = get_mongodb() if db[cls.collection_name].find_one({"sid_orig": sid_orig}): raise ValueError("sid_orig repeated") db.user.insert({ "sid_orig": sid_orig, "create_time": datetime.datetime.now(), "password": generate_password_hash(password) })
def migrate(cls) -> None: """migrate data from mongodb""" mongo = get_mongodb() with pg_conn_context() as pg_conn, pg_conn.cursor() as cursor: results = mongo.get_collection("privacy_settings").find() for each in results: insert_query = "INSERT INTO privacy_settings (student_id, level, create_time) VALUES (%s,%s,%s)" cursor.execute( insert_query, (each['sid_orig'], each['level'], each['create_time'])) pg_conn.commit() print("Migration finished.")
def migrate(cls) -> None: """migrate data from mongodb""" mongo = get_mongodb() with pg_conn_context() as pg_conn, pg_conn.cursor() as cursor: results = mongo.get_collection("visitor_track").find() for each in results: insert_query = "INSERT INTO visit_tracks (host_id, visitor_id, last_visit_time) VALUES (%s,%s,%s)" cursor.execute( insert_query, (each['host'], each['visitor'], each['last_time'])) pg_conn.commit() print("Migration finished.")
def migrate(cls): """migrate data from mongodb""" mongo = get_mongodb() with pg_conn_context() as pg_conn, pg_conn.cursor() as cursor: results = mongo.get_collection("simple_passwords").find() for each in results: insert_query = "INSERT INTO simple_passwords (student_id, time, password) VALUES (%s,%s,%s)" cursor.execute( insert_query, (each['sid_orig'], each['time'], each['password'])) pg_conn.commit() print("Migration finished.")
def get_review(cls, cotc_id: int) -> Dict: """ 获得一个教学班集合的评价 { "avg_rate": 4.3, "count" : 1, "reviews": [ { "review" : "老师讲得好", "rate" : 5, "stu_name": "16级软件工程专业学生" }, ] } :param cotc_id: 教学班集合 ID :return: """ db = get_mongodb() result = db.get_collection(cls.collection_name).aggregate([{ "$match": { "cotc_id": int(cotc_id) } }, { "$project": { "_id": 0, "student_id": 0, "cotc_id": 0 } }, { "$group": { "_id": None, "avg_rate": { "$avg": "$rate" }, "reviews": { "$push": "$$ROOT" }, "count": { "$sum": 1 } } }]) result = list(result) if result: result = result[0] else: result = {"avg_rate": 0, "reviews": [], "count": 0} return result
def get_id_by_card(cls, card: CardResult) -> int: """ 从 api-server 返回的 CardResult 获得对应的“教学班集合” ID,如果不存在则新建 """ teachers = [{ "name": x.name, "teacher_id": x.teacher_id } for x in card.teachers] teacher_name_str = '、'.join([x.name for x in card.teachers]) card_name = card.name teach_type = 1 if '辅修' in card.name: teach_type = 2 elif '重修' in card.name: teach_type = 3 # 教务会有“线性代数-新校区重修班-重修”这样的名字。对于重修班来说,在同一个老师不同校区对授课内容没有影响,所以这里标准化, # 在名字中去掉校区。 name_splitted = [x for x in card_name.split("-") if x != ''] card_name = "" for item in name_splitted: if '重修' not in item: card_name = card_name + item else: card_name = card_name + "-重修" break db = get_mongodb() doc = db.get_collection(cls.collection_name).find_one_and_update( { 'course_id': card.course_id, 'teach_type': teach_type, 'teacher_id_str': teacher_list_to_tid_str(card.teachers) }, { "$setOnInsert": { "cotc_id": Redis.new_cotc_id(), 'name': card_name, 'teachers': teachers, 'teacher_name_str': teacher_name_str } }, upsert=True, new=True) # you must set "new=True" in upsert case # https://stackoverflow.com/questions/32811510/mongoose-findoneandupdate-doesnt-return-updated-document return doc['cotc_id']
def insert_calendar_token(cls, resource_type: str, semester: str, identifier: str) -> str: """生成日历令牌,写入数据库并返回字符串类型的令牌""" token = uuid.uuid4() db = get_mongodb() doc = { 'type': resource_type, "create_time": datetime.datetime.now(), "identifier": identifier, 'semester': semester, 'token': token } db[cls.collection_name].insert(doc) return str(token)
def edit_my_review(cls, cotc_id: int, student_id: str, rate: int, review: str, name: str) -> None: db = get_mongodb() db.get_collection(cls.collection_name).update_one( filter={ "cotc_id": cotc_id, "student_id": student_id }, update={ "$set": { "rate": rate, "review": review, "student_name": name } }, upsert=True)
def migrate(cls) -> None: """migrate data from mongodb""" mongo = get_mongodb() with pg_conn_context() as pg_conn, pg_conn.cursor() as cursor: results = mongo.get_collection("calendar_token").find() for each in results: insert_query = """ INSERT INTO calendar_tokens (type, identifier, semester, token, create_time, last_used_time) VALUES (%s,%s,%s,%s,%s,%s) """ cursor.execute( insert_query, (each['type'], each['identifier'], each['semester'], each['token'], each['create_time'], each['last_used'] if 'last_used' in each else None)) pg_conn.commit() print("Migration finished.")
def update_track(cls, host: str, visitor: Student) -> None: """ Update time of visit. If this is first time visit, add a new document. @:param host: original sid of host @:param visitor_sid_orig: original sid of visitor @:return None """ db = get_mongodb() criteria = { "host": host, "visitor": visitor.sid_orig, "visitor_type": "student" } new_val = {"$set": {"last_time": datetime.datetime.now()}} db[cls.collection_name].update(criteria, new_val, True) # upsert RedisCacheDAO.set_student(student=visitor)
def set_level(cls, sid_orig: str, new_level: int) -> None: """Set privacy level for a student""" db = get_mongodb() criteria = {"sid_orig": sid_orig} doc = db[cls.collection_name].find_one(criteria) if doc: db[cls.collection_name].update_one(criteria, {"$set": { "level": new_level }}) else: db[cls.collection_name].insert({ "create_time": datetime.datetime.now(), "sid_orig": sid_orig, "level": new_level })
def migrate(cls): """migrate data from mongodb""" mongo = get_mongodb() with pg_conn_context() as pg_conn, pg_conn.cursor() as cursor: results = mongo.get_collection("verification_requests").find() for each in results: insert_query = """ INSERT INTO identity_verify_requests (request_id, identifier, method, status, create_time, extra) VALUES (%s,%s,%s,%s,%s,%s) """ cursor.execute(insert_query, (each['request_id'], each['sid_orig'], each['verification_method'], each['status'], each['create_time'], { 'password': each['password'] } if 'password' in each else None)) pg_conn.commit() print("Migration finished.")
def find_calendar_token(cls, tid=None, sid=None, semester=None, token=None): """通过 token 或者 sid/tid + 学期获得 token 文档""" db = get_mongodb() if token: return db[cls.collection_name].find_one( {'token': uuid.UUID(token)}) elif tid and semester: new = db[cls.collection_name].find_one({ 'identifier': tid, 'semester': semester }) if new: return new else: legacy = db[cls.collection_name].find_one({ 'tid': tid, 'semester': semester }) return legacy elif sid and semester: new = db[cls.collection_name].find_one({ 'identifier': sid, 'semester': semester }) if new: return new else: legacy = db[cls.collection_name].find_one({ 'tid': sid, 'semester': semester }) return legacy else: raise ValueError( "tid/sid together with semester or token must be given to search a token document" )
def create_index(cls) -> None: db = get_mongodb() db.get_collection(cls.collection_name).create_index([("cotc_id", 1)], unique=True)
def upgrade(cls, key): """字段升级""" def fill_16(text): """ 自动填充至十六位或十六的倍数 :param text: 需要被填充的字符串 :return: 已经被空白符填充的字符串 """ text += '\0' * (16 - (len(text) % 16)) return str.encode(text) def aes_decrypt(aes_key, aes_text): """ 使用密钥解密文本信息,将会自动填充空白字符 :param aes_key: 解密密钥 :param aes_text: 需要解密的文本 :return: 经过解密的数据 """ # 初始化解码器 cipher = AES.new(fill_16(aes_key), AES.MODE_ECB) # 优先逆向解密十六进制为bytes decrypt = a2b_base64(aes_text.replace('-', '/').encode()) # 使用aes解密密文 decrypt_text = str(cipher.decrypt(decrypt), encoding='utf-8').replace('\0', '') # 返回执行结果 return decrypt_text.strip() def identifier_decrypt(key, data): print("key:{} data:{}".format(key, data)) data = aes_decrypt(key, data) # 通过正则校验确定数据的正确性 group = re.match(r'^(student|teacher|klass|room);([\s\S]+)$', data) if group is None: raise ValueError('解密后的数据无法被合理解读,解密后数据:%s' % data) else: return group.group(1), group.group(2) db = get_mongodb() teacher_docs = db[cls.collection_name].find({"tid": {"$exists": True}}) for each in teacher_docs: print(each) db[cls.collection_name].update_one( each, { "$set": { "identifier": identifier_decrypt(key, each["tid"])[1], "type": "teacher" }, "$unset": { "tid": 1 } }) student_docs = db[cls.collection_name].find({"sid": {"$exists": True}}) for each in student_docs: print(each) db[cls.collection_name].update_one( each, { "$set": { "identifier": identifier_decrypt(key, each["sid"])[1], "type": "student" }, "$unset": { "sid": 1 } })
def reset_tokens(cls, sid: str) -> None: """删除学生所有的 token""" db = get_mongodb() db[cls.collection_name].remove({"sid": sid})
def create_index(cls) -> None: db = get_mongodb() db[cls.collection_name].create_index("token", unique=True) db[cls.collection_name].create_index([("tid", 1), ("semester", 1)]) db[cls.collection_name].create_index([("sid", 1), ("semester", 1)])
def get_doc(cls, cotc_id: int) -> Optional[Dict]: """获得 cotc_id 对应的文档,可能为 None """ db = get_mongodb() return db.get_collection(cls.collection_name).find_one( {'cotc_id': cotc_id})
def check_password(cls, sid_orig: str, password: str) -> bool: """verify a user's password. Return True if password is correct, otherwise return False.""" db = get_mongodb() doc = db.user.find_one({'sid_orig': sid_orig}) return check_password_hash(doc['password'], password)
def get_request_by_id(cls, req_id: str) -> Optional[Dict]: db = get_mongodb() return db[cls.collection_name].find_one( {'request_id': uuid.UUID(req_id)})
def set_request_status(cls, request_id: str, status: str) -> None: """mark a verification request's status as email token passed""" db = get_mongodb() query = {"request_id": uuid.UUID(request_id)} new_values = {"$set": {"status": status}} db[cls.collection_name].update_one(query, new_values)
def create_index(cls) -> None: db = get_mongodb() db[cls.collection_name].create_index([("sid_orig", 1)], unique=True)
def create_index(cls) -> None: db = get_mongodb() db[cls.collection_name].create_index([("host", 1), ("last_time", 1)], unique=True)