def _delete(self, msg): string = msg.content try: argv = string.split() article_id = int(argv[1]) except: logger.info("_delete parse string fail: " + string) return "delete 失败,不是合法的输入,请检查格式" db = DbOperator() success, result = db.find_article(article_id) if not success: logger.debug("_delete fetch nothing: " + string) return "试图删除编号为" + str(article_id) + "的文章,但未找到" user = msg.source if result['open_id'] == user: # 确实是本人的观察目标 if update_article_status(article_id, False, optionals={ "reason": REASON_DELETE_BY_USER }): return "成功删除观察目标:" + str(article_id) else: logger.error("_delete process fail: " + string) return "您的输入合法,但后台处理失败,请联系管理员" else: logger.info(user + " try to delete article: " + str(article_id)) return str(article_id) + " 不是您的观察目标,无法删除"
def ob_this_one(self, URL, open_id): """Add a new article to watch list. This function receive a unique(guaranteed by caller) article URL to be observed. It first check the accessibility of the article, then add it to watch list in database. Args: URL : str Returns: success: bool """ db = DbOperator() # 先添加一次,然后获取 article_id 给 Checker 用 success, article_id = db.db_add_helper(URL, open_id, FAKE_PATH_PLACE_HOLDER, STATUS_NEW_UNKNOWN) if not success: print("db_add_helper FAIL!!!") logger.warning("ob_this_one fail, add db fail: " + " ".join(map(str, [article_id, URL, open_id]))) return False self.q.put(article_id=article_id, url=URL, download=True, block=True, timeout=1) # 放进 Checker 的队列就不管了。后续由回调函数实现 return True
def _status(self, msg): open_id = msg.source db = DbOperator() success, user = db.find_user(open_id) if not success: logger.info("_status can't find user:"******"没有找到邮箱绑定记录,请重新绑定" email = user['email'] return "你的账号现在绑定邮箱为:" + email
def _list(self, msg): open_id = msg.source db = DbOperator() success, article_list = db.find_my_article(open_id) if not success: logger.info("_list no record by user:"******"没有正在观察中的记录" reply = "现有" + str(len(article_list)) + "条记录观察中\n-------\n" URL_list = [] for item in article_list: URL_list.append(str(item['article_id']) + " " + item['URL']) reply = reply + "\n\n".join(URL_list) return reply
def ob_all(self): """Observe all objects in watch list. No paras needed. It automatically fetches data from database, then loop through all items. Args: Returns: success: bool """ db = DbOperator() success, watch_list = db.fetch_all_article() if not success: logger.warning("ob_all find nothing") return False for item in watch_list: article_id = item['article_id'] URL = item['URL'] status = item['status'] start_date = item['start_date'] if _out_of_date(start_date): # 超出30天的观察目标,停止观察 backup_addr = item['backup_addr'] update_article_status(article_id, False, backup_addr) logger.info( "move article to archive: " + " ".join(map(str, [article_id, status, start_date]))) continue else: if status == 0: # 初次观察,需要制作备份 self.q.put(article_id=article_id, url=URL, download=True, block=True, timeout=1) elif status == 1: # 正常观察期,不再制作备份 self.q.put(article_id=article_id, url=URL, download=False, block=True, timeout=1) else: logger.error("Unknow article status: " + " ".join(map(str, [article_id, URL, status]))) return True
def _admin_list(self, msg): user = msg.source if user not in ADMIN_LIST: return "非管理员账号,无法执行admin命令" db = DbOperator() success, result = db.fetch_all_article() if not success: logger.info("_admin_list fetch 0") return "admin-list 查询失败,结果为空" output = [] for item in result: output.append(item['article_id']) output.append(item['URL']) output.append(item['open_id']) output.append(item['backup_addr']) output.append(item['start_date']) output.append(item['status']) output.append('--------') return "\n".join(map(str, output))
def _handle_URL(self, msg): open_id = msg.source URL = self._trim_URL(msg.content) db = DbOperator() success, result = db.find_my_article(open_id) if success: for item in result: if URL == item['URL']: reply = "目标已在观察列表中:" + URL return reply success = self.ob.ob_this_one(URL, open_id) if not success: reply = "目标初次访问异常,无法进行备份。若确定是误判,请联系管理员:[email protected]" else: reply = "收到!开始观察目标!" # 判断一下用户是否绑定邮箱,没绑定的话提供警告 success, _ = db.find_user(open_id) if not success: reply = reply + "\n--------------\n【警告】你的账号未绑定邮箱,无法收到备份及通知。请回复[help]查看规则" return reply
def _handle_email(self, msg): open_id = msg.source email = msg.content user = (open_id, email) send_flag = False db = DbOperator() success, _ = db.find_user(open_id) if success: # 已有记录,更新绑定关系 result = db.update_user(user) else: # 无记录,添加绑定关系 result = db.add_user(user) send_flag = send_user_check_email(email) if result: reply = "你的账号成功绑定邮箱:" + email if send_flag: reply += "\n--------\n" reply += """你是初次绑定邮箱,我发送了一封确认邮件给您 请检查邮箱,确认能收到我的通知邮件 (注意垃圾箱!)""" else: # db 操作失败的日志 db 那边会记录 reply = "绑定邮箱:" + email + "失败!请联系管理员处理:[email protected]" return reply
def _admin_status(self, msg): user = msg.source if user not in ADMIN_LIST: return "非管理员账号,无法执行admin命令" db = DbOperator() reply = analyze_article_status(db) reply += "\n-------\n" reply += analyze_user_status(db) reply += "\n-------\n" qsize = self.ob.get_cur_q_size() reply += "队列中的条目数量:" + str(qsize) reply += "\n-------\n" space_info = total_used_space(DEFAULT_PATH) reply += space_info return reply
def update_article_status(article_id, valid, backup_path=None): # 做点准备工作 db = DbOperator() success, item = db.find_article(article_id) if not success: # log it print("can't find article by article_id: " + str(article_id)) logger.error("can't find article by article_id: " + str(article_id)) return False URL = item['URL'] open_id = item['open_id'] success, result = db.find_user(open_id) if not success: logger.error("article & user no match: " + " ".join(map(str, [article_id, open_id]))) return False email = result['email'] if not valid: # 当文章已不可访问 if item['backup_addr'] == FAKE_PATH_PLACE_HOLDER: backup_addr = None else: backup_addr = item['backup_addr'] notify_user(email, URL, backup_addr) db.archive_article(item) logger.info("article expired, move to archive: " + " ".join(map(str, [article_id, URL]))) else: prev_status = item['status'] if prev_status == 1: # 正常观察状态,无需额外操作 return True elif prev_status == 0: # 初次完成观察,制作备份 if backup_path == None: print("backup addr not valid") return False else: new_path = _backup_article(article_id, backup_path) if new_path == None: return False article_info = (article_id, new_path, 1) # 制作备份完成,状态更新成1 return db.update_article(article_info) else: print("unknown status!") logger.error( "article status Error: " + " ".join(map(str, [article_id, open_id, prev_status]))) return True
def update_article_status(article_id, valid, backup_path=None, optionals={}): """Do jobs when article status changed. Args: article_id : int valid : bool backup_path : str optionals : dict maybe contains: "reason" shows why status changed "title" shows article title detected Returns: success: bool """ # 做点准备工作 db = DbOperator() success, item = db.find_article(article_id) if not success: # log it print("can't find article by article_id: " + str(article_id)) logger.error("can't find article by article_id: " + str(article_id)) return False open_id = item['open_id'] success, result = db.find_user(open_id) if success: email = result['email'] user_registered_flag = True else: logger.info("article & user no match: " + " ".join(map(str, [article_id, open_id]))) user_registered_flag = False # 根据状态变化执行处理 if not valid: # 当文章已不可访问 if user_registered_flag: # 用户有绑定邮箱,则执行通知 update_info = (article_id, optionals) _stop_watching(update_info, item, email, db) else: # 没有绑定邮箱,记错误日志 logger.error("article invalid, can't notify user. " + " ".join(map(str, [article_id, open_id]))) else: prev_status = item['status'] if prev_status == STATUS_NORMAL_OB: # 正常观察状态,无需额外操作 return True elif prev_status == STATUS_NEW_UNKNOWN: # 初次完成观察,制作备份 if backup_path is None: print("backup addr not valid") return False else: new_path = _backup_article(article_id, backup_path) try: title = optionals["title"] except KeyError: title = '' if new_path is None: return False article_info = (article_id, new_path, STATUS_NORMAL_OB, title) # 制作备份完成,状态更新 return db.update_article(article_info) else: print("unknown status!") logger.error("article status Error: " + " ".join(map(str, [article_id, open_id, prev_status]))) return True
def update_article_status(article_id, valid, backup_path=None, optionals={}): """Do jobs when article status changed. Args: article_id : int valid : bool backup_path : str optionals : dict maybe contains: "reason" shows why status changed "title" shows article title detected Returns: success: bool """ # 做点准备工作 db = DbOperator() success, item = db.find_article(article_id) if not success: # log it print("can't find article by article_id: " + str(article_id)) logger.error("can't find article by article_id: " + str(article_id)) return False URL = item['URL'] open_id = item['open_id'] success, result = db.find_user(open_id) if not success: logger.error("article & user no match: " + " ".join(map(str, [article_id, open_id]))) return False email = result['email'] # 开始更新数据库 if not valid: # 当文章已不可访问 if item['backup_addr'] == FAKE_PATH_PLACE_HOLDER: backup_addr = None else: backup_addr = item['backup_addr'] try: notify_user(email, URL, backup_addr) item['status'] = reason2status[optionals["reason"]] db.archive_article(item) except: logger.error("update_article_status ERROR") return False logger.info("article expired, move to archive: " + " ".join(map(str, [article_id, URL]))) else: prev_status = item['status'] if prev_status == STATUS_NORMAL_OB: # 正常观察状态,无需额外操作 return True elif prev_status == STATUS_NEW_UNKNOWN: # 初次完成观察,制作备份 if backup_path == None: print("backup addr not valid") return False else: new_path = _backup_article(article_id, backup_path) if new_path == None: return False article_info = (article_id, new_path, STATUS_NORMAL_OB) # 制作备份完成,状态更新 return db.update_article(article_info) else: print("unknown status!") logger.error("article status Error: " + " ".join(map(str, [article_id, open_id, prev_status]))) return True