def POST(self): stat, UserInfo = CheckLogin() if stat: data = web.input() UID = UserInfo.get('UID').encode('utf-8') sql = "SELECT PassWord FROM Users WHERE UID='%s'" % UID OldPassWord = db.QueryFirst(sql)[0].encode('utf-8') if data.get('OldPassWord') == OldPassWord: try: UserName = data['UserName'].encode('utf-8') Tel = data['Tel'].encode('utf-8') E_mail = data['E-mail'].encode('utf-8') MaxFiles = int(data['MaxFiles']) MaxSize = int(data['MaxSize']) NameRule = data['NameRule'].encode('utf-8') Downloader = data['Downloader'].encode('utf-8') NewPassword = data['NewPassWord'].encode('utf-8') if not NewPassword: NewPassword = OldPassWord sql = "UPDATE Users SET UserName='******', Tel='%s', PassWord='******', " \ "`E-mail`='%s', MaxFiles=%d, MaxSize=%d, NameRule='%s', " \ "Downloader='%s' WHERE UID='%s'" % (UserName, Tel, NewPassword, E_mail, MaxFiles, MaxSize, NameRule, Downloader, UID) db.Execute(sql) return Notice(u'操作成功', u'信息修改成功,请返回查看。', '/settings') except: return Notice(u'操作失败', u'异常错误,请检查你的输入是否合法!', '/settings') else: return Notice(u'操作失败', u'密码错误!', '/settings') else: web.seeother('/login')
def POST(self): data = web.input() UID = data.get('UID').encode('utf-8') # 首先检查UID是否合法 if not UID.isalnum(): return Notice(u'注册失败', u'用户ID必须由字母和数字构成!', '/register') # 其次检查UID是否重复 result = db.QueryFirst("SELECT * FROM Users WHERE UID='%s'" % UID) if result: return Notice(u'注册失败', u'重复的学号/工号!', '/register') try: UserName = data.get('UserName').encode('utf-8') PassWord = data.get('PassWord').encode('utf-8') Tel = data.get('Tel').encode('utf-8') E_mail = data.get('E-mail').encode('utf-8') MaxSize = int(data.get('MaxSize')) MaxFiles = int(data.get('MaxFiles')) # TODO: 更改数据库格式,去除无用设置 sql = "INSERT INTO `Users`(`UID`,`SessionID`,`UserStatus`," \ "`UserName`,`PassWord`,`Tel`,`E-mail`,`MaxSize`,`MaxFiles`,`Downloader`) " \ "VALUES ('%s',NULL,1,'%s','%s','%s','%s',%d,%d,'%s');" \ % (UID, UserName, PassWord, Tel, E_mail, MaxSize, MaxFiles, cfg.read('downloader')) # 尝试为用户创建家目录 user_path = os.path.join(cfg.read('global_pos'), UID) if not os.path.exists(user_path): os.mkdir(user_path) # 如果家目录创建成功,才更新数据库 db.Execute(sql) return Notice(u'注册成功', u'请使用你新注册的帐号登录系统。', '/login') except Exception, err: return Notice(u'注册失败', u'错误: %s 请检查你的注册信息是否合法有效!' % err, '/register')
def POST(self): stat, UserInfo = CheckLogin() if stat: if UserInfo['UserStatus'] == USER_STATUS_FORBIDDEN: return json.dumps({'status': 401, 'msg': u'被封禁用户无权操作!'}) UID = UserInfo['UID'].encode('utf-8') data = web.input(month=[], day=[], hour=[], minute=[]) action = data.get('action', '') URL_Rule = data.get('URL_Rule', '').encode('utf-8') # 检查URL是否合法 if match('^\w+://', URL_Rule) is None: URL_Rule = 'http://%s' % URL_Rule Rule_Name = data.get('Rule_Name', '').encode('utf-8') Status = int(data.get('Status', '0')) TaskID = int(data.get('TaskID', '0')) if action == 'modify': try: sql = "UPDATE UserTask SET URL_Rule='%s', Status=%d, Rule_Name='%s' "\ "WHERE TaskID=%d" % (URL_Rule, Status, Rule_Name, TaskID) db.Execute(sql) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, e: return json.dumps({ 'status': 400, 'msg': u'意外错误:%s。请检查你的输入数据。' % e }) elif action == 'delete': try: # 注意要删除任务对应文件夹: sql = "SELECT `UID`, `SubDirectory` FROM `UserTask` WHERE `TaskID` = %d" % TaskID Dirs = db.QueryFirst(sql) del_path = os.path.join(cfg.read('global_pos'), Dirs[0].decode('utf-8'), Dirs[1].decode('utf-8')) if Dirs[1] and os.path.exists(del_path): rmtree(del_path) sql = "DELETE FROM `UserTask` WHERE `TaskID`=%d" % TaskID db.Execute(sql) sql = "DELETE FROM `CurrentTask` WHERE `TaskID`=%d" % TaskID db.Execute(sql) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, e: return json.dumps({ 'status': 400, 'msg': u'意外错误:%s。删除失败!' % e })
def GET(self): stat, UserInfo = CheckLogin() if stat: sql = 'UPDATE Users SET SessionID = NULL WHERE UID = "%s"' % UserInfo[ 'UID'] db.Execute(sql) web.seeother('index') else: return Notice(u'访问错误', u'当前您尚未登录,请返回登录。', '/index')
def clean_worker(self): sql = "SELECT `UID`, `MaxSize`, `MaxFiles` FROM `Users`" all_users = db.Query(sql) base_dir = cfg.read('global_pos') for user in all_users: UID = user[0] MaxSize = user[1] MaxFiles = user[2] user_home_dir = os.path.join(base_dir, UID) TotalSize, TotalFiles = get_dir_size(user_home_dir) TotalSize /= (1024 * 1024) # 如果超出了文件数量配额或者文件大小配额 if TotalSize > MaxSize or TotalFiles > MaxFiles: # 首先暂停该用户所有任务 sql = "UPDATE `UserTask` SET `Status` = 0 WHERE `UID` = '%s'" % UID db.Execute(sql) # 其次删除所有正在进行的任务 sql = "DELETE FROM `CurrentTask` WHERE `UID` = '%s'" % UID db.Execute(sql)
def __init__(self, is_debug=False): self.prev_day = {} self.thread_pool = ThreadPool( is_debug, int(cfg.read('max_threads')), int(cfg.read('max_buf')), ) # 注意先清空先前留下的下载任务 # TODO: 改为继续执行先前未完成的任务 db.Execute("DELETE FROM `CurrentTask`")
def __init__(self, URL, Location, TaskID, check_type, check_size, is_debug): sql = "UPDATE `CurrentTask` SET `Status` = 2 WHERE `TaskID` = %d" % TaskID db.Execute(sql) self.download(URL, Location, is_debug) status = self.check_if_success(Location, check_type, check_size, is_debug) if status: # 若下载成功,则从未完成列表中删除 sql = "DELETE FROM `CurrentTask` WHERE `TaskID` = %d" % TaskID log.log_message( u'[INFO] Task %d downloaded successfully to %s at %s' % (TaskID, Location, datetime.now().ctime())) else: # 首先删除下载失败的文件 if os.path.exists(Location): os.remove(Location) # 然后将其下载次数+1以降低优先级,并且恢复正常状态 sql = "UPDATE `CurrentTask` SET `RepeatTimes` = `RepeatTimes` + 1, " \ "`Status` = 1 WHERE `TaskID` = %d" % TaskID log.log_message(u'[INFO] Task %d download to %s failed at %s' % (TaskID, Location, datetime.now().ctime())) db.Execute(sql)
def POST(self): data = web.input() UID = data.get('UID') PassWd = data.get("password") expire = data.get('expires') sql = 'SELECT UserName, UserStatus FROM Users WHERE UID = "%s" AND PassWord = "******"' \ % (UID, PassWd) result = db.QueryFirst(sql) if result: SessionID = sha.new(repr(time()) + str(random())).hexdigest() web.setcookie('SessionID', SessionID, int(expire)) sql = 'UPDATE Users SET SessionID = "%s" WHERE UID = "%s"' % ( SessionID, UID) db.Execute(sql) web.seeother('/index') else: return Notice(u'登录失败', u'密码错误', '/login')
def update_worker(self, overwrite_time=None): # TODO: 添加任务前先检查当前网络是否连通 # 首先选择所有任务列表中未暂停且未被下载中的任务 sql = "SELECT * FROM `CurrentTask` WHERE `Status` = 1 ORDER BY `RepeatTimes` ASC" all_task = db.Query(sql) # 对于每一项任务进行处理,加入缓冲区 for task in all_task: # 利用任务的时区信息,实例化两个时间戳 # 并且计算当前时刻在目标时区是几点 TimeZone = timezone(task[7]) if overwrite_time is None: Now = datetime.now(TimeZone) else: Now = overwrite_time StartTime = TimeZone.localize(parser.parse(task[4])) FinishTime = TimeZone.localize(parser.parse(task[5])) TaskID = task[6] if Now > FinishTime: # 如果任务已经超时,直接删除 sql = "DELETE FROM `CurrentTask` WHERE `TaskID` = %d" % TaskID db.Execute(sql) elif Now < StartTime: # 如果该任务尚未开始,就继续处理下一项任务 continue else: # 如果这项任务应该被执行,就将其放入缓冲区 sql = "SELECT `Downloader`, `CheckType`, `CheckSize` FROM `UserTask` WHERE `TaskID` = %d" % TaskID task_data = db.QueryFirst(sql) data = { 'TaskID': TaskID, 'URL': task[1], # 注意这里的编码,需要传入unicode 'Location': task[3].decode('utf-8'), 'Downloader': task_data[0], 'CheckType': task_data[1], 'CheckSize': task_data[2] } self.thread_pool.insert(data)
def POST(self): stat, UserInfo = CheckLogin() if stat and UserInfo['UserStatus'] == USER_STATUS_ADMIN: data = web.input() action = data.get('action') # TODO: 增加一个停止/启动所有线程的功能 if action == 'modify': try: UID = data.get('UID').encode('utf-8') UserName = data.get('UserName').encode('utf-8') PassWord = data.get('PassWord').encode('utf-8') MaxFiles = int(data.get('MaxFiles')) MaxSize = int(data.get('MaxSize')) sql = "UPDATE Users SET UserName='******', PassWord='******', MaxFiles=%d, MaxSize=%d " \ "WHERE UID='%s'" % (UserName, PassWord, MaxFiles, MaxSize, UID) db.Execute(sql) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except: return json.dumps({ 'status': 400, 'msg': u'未知错误!请检查数据是否合法!' }) elif action == 'delete': try: UID = data.get('UID').encode('utf-8') if UID == 'root': raise Exception(u'不允许删除管理员!') sql = "DELETE FROM `Users` WHERE `UID`='%s'" % UID db.Execute(sql) sql = "DELETE FROM `UserTask` WHERE `UID`='%s'" % UID db.Execute(sql) sql = "DELETE FROM `CurrentTask` WHERE `UID`='%s'" % UID db.Execute(sql) # 最后注意删除用户的目录 del_path = os.path.join(cfg.read('global_pos'), UID) if os.path.exists(del_path): rmtree(del_path) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, err: return json.dumps({ 'status': 400, 'msg': u'%s\n请检查学号/工号是否合法!' % err }) elif action == 'config': # TODO: 增加几个新设置项的处理机制 try: # TODO: 这里可以为更多设置项增加检查函数,似乎这就是单子的一种用法吧? CheckFunc = { 'SiteName': None, 'GlobalPos': check_path, 'DateCheckingInterval': int, 'WorkerCheckingInterval': int, 'CleanerCheckingInterval': int, 'PortName': int, 'MaxThreads': int, 'MaxBuf': int } ConfigName2Str = { 'SiteName': 'site_name', 'GlobalPos': 'global_pos', 'DateCheckingInterval': 'date_checking_interval', 'WorkerCheckingInterval': 'worker_checking_interval', 'CleanerCheckingInterval': 'cleaner_checking_interval', 'PortName': 'port_name', 'MaxThreads': 'max_threads', 'MaxBuf': 'max_buf' } # 首先检查一遍全部数据,看其中是否有空项 for key in ConfigName2Str.keys(): val = data.get(key) if not val: raise Exception(u'提交的数据中存在无效项/空项!') if CheckFunc[key]: CheckFunc[key](val) # 如果所有数据正常,就直接继续更新 for key in ConfigName2Str.keys(): val = data.get(key) cfg.write(ConfigName2Str[key], val) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, err: return json.dumps({ 'status': 400, 'msg': u'%s\n请检查输入数据是否合法!' % err })
class ModifyRules(): def GET(self): stat, UserInfo = CheckLogin() if stat: if UserInfo['UserStatus'] == USER_STATUS_FORBIDDEN: return Notice(u'无效访问', u'被封禁用户无权操作!', '/login') MyTemplate = CreateMyTemplate('ModifyRules.html') if UserInfo['UserStatus'] == USER_STATUS_ADMIN: sql = "SELECT Rule_Name, URL_Rule, Status, RepeatType, RepeatValue, TaskID, TimeZone " \ "FROM UserTask" else: sql = "SELECT Rule_Name, URL_Rule, Status, RepeatType, RepeatValue, TaskID, TimeZone " \ "FROM UserTask WHERE UID='%s'" % UserInfo['UID'] results = db.Query(sql) return MyTemplate.render(results=results, **UserInfo) else: return Notice(u'无效访问', u'请先登录!', '/login') def POST(self): stat, UserInfo = CheckLogin() if stat: if UserInfo['UserStatus'] == USER_STATUS_FORBIDDEN: return json.dumps({'status': 401, 'msg': u'被封禁用户无权操作!'}) UID = UserInfo['UID'].encode('utf-8') data = web.input(month=[], day=[], hour=[], minute=[]) action = data.get('action', '') URL_Rule = data.get('URL_Rule', '').encode('utf-8') # 检查URL是否合法 if match('^\w+://', URL_Rule) is None: URL_Rule = 'http://%s' % URL_Rule Rule_Name = data.get('Rule_Name', '').encode('utf-8') Status = int(data.get('Status', '0')) TaskID = int(data.get('TaskID', '0')) if action == 'modify': try: sql = "UPDATE UserTask SET URL_Rule='%s', Status=%d, Rule_Name='%s' "\ "WHERE TaskID=%d" % (URL_Rule, Status, Rule_Name, TaskID) db.Execute(sql) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, e: return json.dumps({ 'status': 400, 'msg': u'意外错误:%s。请检查你的输入数据。' % e }) elif action == 'delete': try: # 注意要删除任务对应文件夹: sql = "SELECT `UID`, `SubDirectory` FROM `UserTask` WHERE `TaskID` = %d" % TaskID Dirs = db.QueryFirst(sql) del_path = os.path.join(cfg.read('global_pos'), Dirs[0].decode('utf-8'), Dirs[1].decode('utf-8')) if Dirs[1] and os.path.exists(del_path): rmtree(del_path) sql = "DELETE FROM `UserTask` WHERE `TaskID`=%d" % TaskID db.Execute(sql) sql = "DELETE FROM `CurrentTask` WHERE `TaskID`=%d" % TaskID db.Execute(sql) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, e: return json.dumps({ 'status': 400, 'msg': u'意外错误:%s。删除失败!' % e }) elif action == 'add': try: RepeatType = data['RepeatType'] TimeZone = data['TimeZone'].encode('utf-8') lst_day = ['0', data['Weekday']] lst_month = ['0', '0', '0'] lst_year = ['0', '0', '0', '0', data.get('year')] lst_day.extend(data['day']) lst_month.extend(data['month']) lst_minute = data['minute'] lst_hour = data['hour'] dic2idx = { 'day': 0, 'week': 1, 'month': 2, 'year': 3, 'once': 4 } dic2val = { 'day': REP_PER_DAY, 'week': int(data['Weekday']), 'month': REP_PER_MONTH, 'year': REP_PER_YEAR, 'once': REP_PER_ONCE } idx = dic2idx[RepeatType] RepeatLevel = dic2val[RepeatType] RepeatValue = ' '.join( map( str, map(int, [ lst_year[idx], lst_month[idx], lst_day[idx], lst_hour[idx], lst_minute[idx] ]))) SubDir = data.get('Sub_Dir', '') NameRule = data.get('NameRule', 'auto').encode('utf-8') Downloader = data.get('Downloader', 'aria2').encode('utf-8') CheckType = data.get('CheckType', 'auto').encode('utf-8') TaskTime = int(data.get('TaskTime', '12')) CheckSize = int(data.get('CheckSize', '4096')) sql = "INSERT INTO UserTask (UID, URL_Rule, Rule_Name, RepeatType, RepeatValue, " \ "TimeZone, Status, SubDirectory, NameRule, TaskTime, Downloader, CheckType, CheckSize) " \ "VALUES ('%s', '%s', '%s', %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s', %d)" % \ (UID, URL_Rule, Rule_Name, RepeatLevel, RepeatValue, TimeZone, Status, SubDir.encode('utf-8'), NameRule, TaskTime, Downloader, CheckType, CheckSize) if len(URL_Rule) == 0 or len(Rule_Name) == 0: raise Exception(u'请输入有效的下载链接和任务名称') # 为任务建立子目录 # 注意路径必须是unicode编码的! Rule_Folder = os.path.join(cfg.read('global_pos'), UID, SubDir) if not os.path.exists(Rule_Folder): os.mkdir(Rule_Folder) db.Execute(sql) return json.dumps({'status': 200, 'msg': u'操作成功!'}) except Exception, err: return json.dumps({ 'status': 400, 'msg': u'意外错误:%s。请检查你的输入数据。' % err })
def update_calendar(self, overwrite_time=None): # 注意同一个规则所实例化的任务,只能被添加一次 sql = "SELECT * FROM `UserTask` WHERE " \ "`TaskID` NOT IN (SELECT `TaskID` FROM `CurrentTask`) " \ "AND `Status` != 0" this_day = {} all_tasks = db.Query(sql) for task in all_tasks: # 首先读取时区信息,并转换为当前任务所在时区的时间 TimeZone = timezone(str(task[6])) if overwrite_time is None: today = datetime.now(TimeZone) else: today = overwrite_time # 然后判断在该时区是否进入了新的一天 is_new_day = False if self.prev_day.get(TimeZone, None) is None \ or today.day != self.prev_day[TimeZone]: this_day[TimeZone] = today.day is_new_day = True # 如果确实进入了新的一天 if is_new_day: # 首先生成任务开始和结束时间 # 同样注意转换为任务所在的时区 date_nums = map(int, task[5].split()) StartTime = datetime(year=today.year, month=today.month, day=today.day, hour=date_nums[3], minute=date_nums[4], tzinfo=TimeZone) FinishTime = StartTime + timedelta(hours=task[10]) # 生成一些与日期相关的数据 yesterday = today + timedelta(days=-1) tomorrow = today + timedelta(days=1) keywords = { '%year%': today.year, '%mon%': today.month, '%day%': today.day, '%prev_year%': yesterday.year, '%prev_mon%': yesterday.month, '%prev_day%': yesterday.day, '%next_year%': tomorrow.year, '%next_mon%': tomorrow.month, '%next_day%': tomorrow.day } for key in keywords.keys(): keywords[key] = '%02d' % keywords[key] # 其次生成下载链接 # 用dict中的关键字不断替换URL中字符串 TaskID = task[0] UID = task[1] URL = task[2] for key in keywords.keys(): while URL.find(key) != -1: URL = URL.replace(key, keywords[key]) # 生成URL后,更新文件保存位置: # 1. 首先读取全局位置 Location = cfg.read('global_pos') # 2. 然后定位到用户家目录位置 Location = os.path.join(Location, UID) # 3. 再定位到规则目录位置,这里的类型都是unicode RuleName = task[3] SubDir = task[8] if SubDir: if type(SubDir) == str: SubDir = SubDir.decode('utf-8') Location = os.path.join(Location, SubDir) # 4. 最后根据命名规则确定文件名 if task[9] == 'auto': Location = os.path.join(Location, URL.split('/')[-1]) else: Location = os.path.join(Location, RuleName + '.' + URL.split('.')[-1]) # 重新转换编码 if type(Location) == unicode: Location = Location.encode('utf-8') sql = "INSERT INTO `CurrentTask` VALUES ('%s', '%s', 1, '%s', '%s', '%s', %d, '%s', 0)" % ( UID, URL, Location, StartTime.ctime(), FinishTime.ctime(), TaskID, TimeZone.zone) RepeatType = int(task[4]) if RepeatType == REP_PER_DAY: # 如果是每天执行的任务,直接添加到任务列表 db.Execute(sql) elif REP_PER_MON <= RepeatType <= REP_PER_SUN: # 如果是周任务,则当前weekday必须匹配 if today.isoweekday() == RepeatType: db.Execute(sql) elif RepeatType == REP_PER_MONTH: # 如果是月任务,日期必须匹配 if today.day == date_nums[2]: db.Execute(sql) elif RepeatType == REP_PER_YEAR: # 如果是年任务,月日必须匹配 if today.month == date_nums[1] and today.day == date_nums[2]: db.Execute(sql) elif RepeatType == REP_PER_ONCE: # 对于仅执行一次的任务,年月日必须匹配 # 并且放入任务列表中后就暂停掉这项任务 if today.year == date_nums[0] and today.month == date_nums[1] and today.day == date_nums[2]: db.Execute(sql) db.Execute("UPDATE `UserTask` SET `Status` = 0 WHERE `TaskID` = %d" % TaskID) self.prev_day = this_day