def form_post(): """ Process a form submission (login, edit, etc).""" # The input is stored in Flask's request global. # Each submitted form has an input field named 'submit_X' for some X, # and is handled by a corresponding function submit_X() # if it passes its authorize_* permissions check. keys_named_submit = filter(lambda s: re.match('submit', s), request.form.keys()) print_debug(' handle_post : submit keys = "{}" '.format(keys_named_submit)) submit_what = keys_named_submit[0] print_debug(' handle_post : submit_what = "{}" '.format(submit_what)) if submit_what not in form_handlers: print_debug(' handle_post: OOPS - illegal submit_what ') flash('* incorrect form submission *', 'formerror') return request.base_url elif form_handlers[submit_what]['authorize'](): result = form_handlers[submit_what]['handler']() print_debug(' handle_post : submit result = "{}" '.format(result)) return result else: print_debug(' handle_post: form submission authorization failed ') flash('* authorization error *', 'formerror') return request.base_url
async def main(): if BILI_UID == '你的 Bilibili UID': print_status('** 未指定 Bilibili UID!') exit(1) if (APP_ID == '你的 Bangumi App ID' and APP_SECRET == '你的 Bangumi App Secret'): print_status('** 未指定 Bangumi 授权设置!') exit(1) print_debug('创建构造编号映射任务 -> [get_bili2bgm_map]') get_bili2bgm_map_task = loop.create_task(get_bili2bgm_map()) print_debug('创建取得 Bilibili 授权任务 -> [auth_bili]') auth_bili_task = loop.create_task(auth_bili(SESSDATA, BILI_JCT, BUVID3)) print_debug('创建取得 Bangumi 授权任务 -> [auth_bgm]') auth_bgm_task = loop.create_task(auth_bgm(APP_ID, APP_SECRET)) print_debug('等待任务...') bili2bgm_map = await get_bili2bgm_map_task bili_auth_data = await auth_bili_task bgm_auth_data = await auth_bgm_task print_status('正在迁移...') print_debug('等待更新数据任务 -> [get_and_update]') await get_and_update(bili2bgm_map, bili_auth_data, BILI_UID, bgm_auth_data)
def submit_removeuser(): """ The user clicked "remove" on the sys/users page """ print_debug(' submit_removeuser: '******'choose_remove'] if username: message = request.page.course.drop(username) if message: flash(message, 'drop') return request.page.url
def submit_permissions(): """ handle setting folder permissions - .access.yaml stuff """ rights = { 'read': parse_access_string(request.form['read_access']), 'write': parse_access_string(request.form['write_access']) } access_abspath = request.page.write_access_file(rights) print_debug(' submit_permissions : access path {} '.format(access_abspath)) git.add_and_commit(request.page, access_abspath) return url_for('mainroute', pagepath=request.page.path, action='edit')
def submit_enroll(): """ Enroll someone in this course. """ username = request.form['username'] rolename = request.form['submit_enroll'] print_debug(' submit_enroll: user={}, role={}'.format(username, rolename)) user = Person.by_username(username) request.page.course.enroll(user, rolename, create_work=(rolename == 'student')) return request.page.url
async def auth_bgm(app_id, app_secret): '''取得 Bangumi 授权''' code = None async def handler(request): '''Bangumi 授权请求处理器''' nonlocal code code = request.query['code'] return web.Response( content_type='text/html', text='<!DOCTYPE html><html><body><h1 align="center">' 'Bangumi 授权请求已接受,请关闭此页面。' '</h1></body></html>') print_debug('创建 Bangumi 授权请求处理器...') app = web.Application() app.add_routes([web.get('/', handler)]) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, 'localhost', 3000) await site.start() print_debug('打开 Bangumi 授权页面...') link = ( f'https://bgm.tv/oauth/authorize?client_id={app_id}&response_type=code' ) webbrowser_open(link) print_status('请在弹出的授权页面中点击授权。') print_status('若授权页面没有自动弹出,请手动复制链接至浏览器中打开:') print_status(f'{link}') print_debug('等待 Bangumi 授权请求...') while code is None: await sleep(0.001) await site.stop() await runner.shutdown() print_status('正在尝试取得授权...') print_debug('请求 Bangumi 授权码...') bgm_auth_data_raw = await try_for_times_async_json( # 尝试五次 5, lambda: client.post('https://bgm.tv/oauth/access_token', data={ 'grant_type': 'authorization_code', 'client_id': app_id, 'client_secret': app_secret, 'code': code, 'redirect_uri': 'http://localhost:3000' })) token = (f'{bgm_auth_data_raw["token_type"]}' f' {bgm_auth_data_raw["access_token"]}') print_debug('完成!') return token
def submit_delete(): """ handle folder delete form """ # example request.form would be {'submit_delete':'delete', # '/full/path/file1.md':'checkboxdelete', # '/full/path/folder2/':'checkboxdelete'} abspaths = list( filter(lambda path: request.form[path] == 'checkboxdelete', request.form.keys())) print_debug(' submit_delete : {}'.format(abspaths)) git.rm_and_commit(request.page, abspaths) return url_for('mainroute', pagepath=request.page.path, action='edit')
def submit_edituser(): """ edit existing user - admin only """ username = request.form['username'] name = request.form['name'] email = request.form['email'] password = request.form['password'] print_debug(' submit_edituser: '******'username={} name="{}" email={} password=""'.format( username, name, email, password)) Person.edit_person(username, name, email, password) return request.base_url + '?username=' + username
def submit_newuser(): """ create new user """ username = request.form['username'] name = request.form['name'] email = request.form['email'] password = request.form['password'] print_debug(' create_person: ' + \ 'username={} name="{}" email={} password=""'.format( username, name, email, password)) Person.create_person(username, name, email, password) return url_base + '/sys/user?username=' + username
def next_level(): # advance to the next level message('You go down a floor.', tcod.light_violet) settings.save_level_state() settings.dungeon_level += 1 try: settings.load_level_state() except: print_debug("map not found. making new map") make_map() settings.save_level_state() initialize_fov()
def submit_password(): password = request.form['password'] if not safe.check(password): flash('Oops: that password is too easily guessed. ' + \ 'Try again with a longer one using a mix of numbers, ' + \ 'symbols, upper and lower case.', 'user') print_debug( ' submit_password: failed safe.check("{}")'.format(password)) return request.base_url + '?action=edit' else: request.page.user.set_password(password) print_debug(' submit_password: password reset') return request.base_url
async def get_one_bili_data(data: SimpleNamespace, page: int): '''获取单个 Bilibili 追番数据''' print_debug(f'获取追番数据 @ {page} ...') bangumi_data = await try_for_times_async_chain( # 尝试三次 3, lambda: data.user.get_subscribed_bangumis(page, BangumiType.BANGUMI)) data.bangumi_total += len(bangumi_data['list']) data.bangumi_remaining.extend( map(lambda bangumi: (bangumi['media_id'], bangumi['follow_status']), bangumi_data['list'])) data.bili_processed_count += 1 if page == 1: return ceil(bangumi_data['total'] / 15) # 计算并返回总页数
async def auth_bili(sessdata, bili_jct, buvid3): '''取得 Bilibili 授权''' if (sessdata != '你的 Bilibili SESSDATA' and bili_jct != '你的 Bilibili bili_jct' and buvid3 != '你的 Bilibili buvid3'): credential = Credential(sessdata=sessdata, bili_jct=bili_jct, buvid3=buvid3) else: print_debug('未指定 Bilibili 授权设置!') credential = Credential() print_debug('完成!') return credential
def submit_login(): """ handle <input name='submit_login' ...> form submission. """ # invoked from handle_post() print_debug(' submit_login: username = "******" '.format( request.form['username'])) user = Person.by_username(request.form['username']) print_debug(' submit_login: user = "******"'.format(user)) if user.is_anonymous() or \ not user.check_password(request.form['password']): flash('Oops: wrong username or password.', 'login') return url_for('mainroute', pagepath=request.page.path, action='login') else: user.logged_in = True login_user(user) return url_for('mainroute', pagepath=request.page.path)
def __init__(self, description: str): """Create an instance of the detector class Parameters ---------- description (str): A few-word description of the specific detector model """ from lib.squeezedet_keras.main.config.create_config import load_dict, squeezeDet_config from lib.squeezedet_keras.main.model.modelLoading import load_only_possible_weights print_debug(f'\nPreparing {description}...') self.keras_model: Model self.description = description # Load configuration from config.json and set a few custom values config_dictionary: Dict[str, Any] = { **squeezeDet_config(''), **load_dict(os.path.abspath('config.json')), 'SCORE_THRESHOLD': 0.5, } self.config: Any = EasyDict(config_dictionary) # Only supports one image in each batch yet self.config.BATCH_SIZE = 1 # Load the model using the class' implemented "load_model" method print_debug('Loading model...') model_file = self.load_model() # If the model is loaded and a weights file is given, set the input layer's shape to be the # expected shape of the input image (from config.json) if hasattr(self, 'keras_model' ) and self.keras_model is not None and model_file != '': # Create new (fix-sized) input layer new_input: Tensor = layers.Input( batch_shape=(1, self.config.IMAGE_HEIGHT, self.config.IMAGE_WIDTH, 3)) new_layers: Model = self.keras_model(new_input) self.keras_model = Model(new_input, new_layers) # Load weights for each layer if it exist load_only_possible_weights(self.keras_model, model_file)
async def update_one_bgm_data(data: SimpleNamespace, bgm_id: int, status: str): '''更新单个 Bangumi 动画数据''' print_debug(f'开始更新 @ {bgm_id} -> {status} ...') update_flag = True if SKIP_COLLECTED: # 获取当前收藏状态 collection_status_json = await try_for_times_async_json( # 尝试三次 3, lambda: client.get(f'https://api.bgm.tv/collection/{bgm_id}', headers={'Authorization': data.bgm_auth_data})) if ('status' in collection_status_json and collection_status_json['status']['type'] == status): update_flag = False if update_flag: if status == 'collect': # 看过 -> 更新分集进度 # 获取分集总数 subject_data = await try_for_times_async_json( # 尝试三次 3, lambda: client.get(f'https://api.bgm.tv/subject/{bgm_id}', headers= {'Authorization': data.bgm_auth_data})) eps_count = subject_data['eps_count'] print_debug(f'更新分集进度 @ {bgm_id} -> {eps_count} ...') if not READ_ONLY: response = await try_for_times_async_chain( # 尝试三次 3, lambda: client.post( f'https://api.bgm.tv' f'/subject/{bgm_id}/update/watched_eps', data={'watched_eps': eps_count}, headers={'Authorization': data.bgm_auth_data})) response.raise_for_status() print_debug(f'更新收藏 @ {bgm_id} -> {status} ...') if not READ_ONLY: response = await try_for_times_async_chain( # 尝试三次 3, lambda: client.post( f'https://api.bgm.tv/collection/{bgm_id}/update', data={'status': status}, headers={'Authorization': data.bgm_auth_data})) response.raise_for_status() else: print_debug(f'跳过 @ {bgm_id} -> {status} ...') data.bangumi_processed_count += 1 print_debug(f'完成 @ {bgm_id}!')
def submit_newcourse(): """ create new course """ #print_debug('submit_newcourse: {}'.format(request.form)) name = request.form['name'] # e.g. "Intro Programming" path = request.form[ 'path'] # should have form term/folder e.g. fall2018/cs1 copyfrom = request.form['copyfrom'] # e.g. "fall2017/cs1" startdate = path_to_startdate(path) title = name_to_htmltitle(name) print_debug(' submit_newcourse: name = "{}"'.format(name)) print_debug(' path = "{}"'.format(path)) print_debug(' copyfrom = "{}"'.format(copyfrom)) newcourse = Course.create_course(name, path, start=startdate, name_as_title=title, copyfrom=copyfrom) for name in request.form['faculty'].split(','): try: faculty = Person.get(username=name.strip()) except: faculty = None if not faculty: try: faculty = Person.get(username=name.strip()) except: faculty = None if faculty: today = str(Time())[:10] newcourse.enroll(faculty, 'faculty', today, create_work=False) return newcourse.url
def __quantize_model(converter: tensorflow.lite.TFLiteConverter, model: Detector) -> Any: print_debug('\nConverting model, this will take some time...') # Get sample data to be used during converstion image_files: List[str] = [ os.path.abspath(os.path.join(IMAGES_PATH, image)) for image in os.listdir(IMAGES_PATH) ] annotation_files: List[str] = [ os.path.abspath(os.path.join(ANNOTATIONS_PATH, annotations)) for annotations in os.listdir(ANNOTATIONS_PATH) ] try: # Set optimizations to perform on model to be compatible with edge TPUs converter.optimizations = [tensorflow.lite.Optimize.DEFAULT] converter.representative_dataset = lambda: __input_data_generator( model, image_files, annotation_files) converter.target_spec.supported_ops = [ tensorflow.lite.OpsSet.TFLITE_BUILTINS_INT8 ] converter.inference_input_type = tensorflow.uint8 converter.inference_output_type = tensorflow.uint8 # Start conversion return converter.convert() except Exception as exception: # pylint: disable=broad-except print_debug('Error: Could not convert model to TFLite') print_debug(str(exception))
def submit_assignments(): """ handle assignment editing """ print_debug(' submit_assignments: ') print_debug(' request.form is {}'.format(request.form)) assignment_data = parse_assignment_data(request.form) print_debug(' len(assignment_data) = {}'.format(len(assignment_data))) request.page.course.update_assignments(assignment_data) return request.base_url # reload assignments page without edit
async def update_bgm_data(data: SimpleNamespace): '''更新 Bangumi 动画数据''' print_debug('创建更新单个 Bangumi 数据任务...') while not data.get_bili_data_task.done(): await check_and_update_bgm_data(data) await sleep(0.001) await check_and_update_bgm_data(data) print_debug('等待更新单个 Bangumi 数据任务...') await gather(*data.update_one_bgm_data_tasks) print_debug('完成!')
async def get_bili_data(data: SimpleNamespace): '''获取 Bilibili 追番数据''' print_debug('获取第一页 Bilibili 追番数据...') try: data.bili_total_count = await get_one_bili_data(data, 1) except ResponseCodeException: print_status('** Bilibili 授权设置不正确,无法读取隐私设置' '未公开的 Bilibili 追番数据!') exit(1) print_debug('创建并等待获取单个 Bilibili 追番数据任务...') await gather(*(loop.create_task(get_one_bili_data(data, page)) for page in range(2, data.bili_total_count + 1))) print_debug('完成!')
async def get_and_update(bili2bgm_map, bili_auth_data, bili_uid, bgm_auth_data): '''获取 Bilibili 番剧数据并更新 Bangumi 动画数据''' data = SimpleNamespace( bili2bgm_map=bili2bgm_map, user=User(bili_uid, bili_auth_data), bili_auth_data=bili_auth_data, bgm_auth_data=bgm_auth_data, bili_processed_count=0, bili_total_count=None, bangumi_total=0, # [(bili media id, 1: 想看 | 2: 在看 | 3: 看过), ...] bangumi_remaining=deque(), bangumi_processed_count=0, bangumi_failed=deque(), bangumi_failed_count=0, animation_points=1, get_bili_data_task=None, update_bgm_data_task=None, update_one_bgm_data_tasks=deque(), print_unknown_tasks=deque()) print_debug('创建获取 Bilibili 数据任务 -> [get_bili_data]') data.get_bili_data_task = loop.create_task(get_bili_data(data)) print_debug('创建更新 Bangumi 数据任务 -> [update_bgm_data]') data.update_bgm_data_task = loop.create_task(update_bgm_data(data)) print_debug('等待任务...') while data.bili_total_count is None: await sleep(0.001) while not (data.get_bili_data_task.done() and data.update_bgm_data_task.done()): await print_progress(data) await sleep(0.1) await data.get_bili_data_task await data.update_bgm_data_task await print_progress(data) await gather(*data.print_unknown_tasks) await print_progress(data) print()
def submit_edit(): """ handle file edit form """ # ... including student work pages. # invoked from handle_post() # the form text data is in the form dict key, i.e. request.form['edit_text'] # print_debug(' submit_edit: request.form : {}'.format(request.form.items())) # # request.form will look something like # { 'submit_edit' : u'save page', # submit button # 'edit_text' : u'page content\r\n===\r\n etc' # textarea # } # # If this is a work page, then update the Work database object. # (The Work object is created in Page.get_from_path) if request.page.is_work: now = str(Time()) # string with current time with db.atomic(): if request.page.user_role.name == 'faculty': page = request.page page.work.faculty_modified = now # If checkbox for 'submitted' and that didn't have a value, # then set it - used to mark work as submitted, # i.e. student emails work & faculty submits. if "submitted_checkbox" in request.form \ and not page.work.submitted: due = Time(page.work_due) print_debug(" submit_edit: due = {}".format(str(due))) if "on_time_checkbox" in request.form: due.shift_minutes(-5) else: due.shift_minutes(5) page.work.submitted = str(due) print_debug(" submit_edit: submitted set to {}".format( \ page.work.submitted)) if 'grade' in request.form: page.work.grade = str(request.form['grade']) else: request.page.work.student_modified = now if not request.page.work.submitted: request.page.work.submitted = now request.page.work.save() # Save the page content to a file and to git. bytes_written = request.page.write_content(request.form['edit_text']) print_debug(' submit_edit: bytes_written = {}'.format(bytes_written)) git.add_and_commit(request.page) return request.base_url # ... and reload it without ?action=edit
def submit_createfolder(): """ handle folder creation """ # example request.form is {'submit_createfolder': 'create', # 'foldername': 'testfolder'} # page.abs path is current directory i.e. /User/mahoney/.../folder1/ foldername = request.form['foldername'] print_debug(' submit_createfolder : foldername="{}" '.format(foldername)) if not is_clean_folder_name(foldername): print_debug(' submit_createfolder: illegal chars in foldername') flash('Oops: folder names may only contain ' + \ 'lowercase letters, numbers, or underbar.', 'folder') flash(foldername) return url_for('mainroute', pagepath=request.page.path, action='edit') folderpath = os.path.join(request.page.path, foldername) folderabspath = os.path.join(request.page.abspath, foldername) print_debug( ' submit_createfolder : newfolderabspath="{}" '.format(folderabspath)) Page.new_folder(folderabspath, user=request.page.user) return url_for('mainroute', pagepath=request.page.path, action='edit')
def __evaluate_models(): # Uncomment the line below to disable GPU in tensorflow, so that models can be benchmarked on # CPU only # os.environ['CUDA_VISIBLE_DEVICES'] = "-1" initialize_environment() # Uncomment line below to run detection on video displaying the bounding boxes on it # SSDTFLite().evaluate_performance(0, is_display=True) models = [ 'RetinaNet', 'SSD TFLite v2', 'SSD TFLite v1', 'YOLOv3', ] # Evaluate accuracy of models one-by-one statistics = [ __evaluate_model(RetinaNet()), __evaluate_model(SSDTFLite('v2')), __evaluate_model(SSDTFLite('v1')), __evaluate_model(YOLOv3()), ] # Convert the statistics to the correct format to be passed to the tabulate library aggregated_statistics = [[models[index], *current_statistics, fps] for index, (current_statistics, fps) in enumerate(statistics)] # Show evaluation results in a table in command line print_debug(f'\nResults on {SAMPLE_COUNT} samples\n') print_debug(tabulate( aggregated_statistics, headers=['Model', 'Precision', 'Recall', 'F1 Score', 'mAP', 'FPS'] )) print_debug('\nExiting...')
def evaluate_performance(self, video_path: Union[str, int], is_display: bool = False) -> float: """Evaluates the performance of the current model in terms of frames per second Parameters ---------- video_path (Union[str, int]): Path of the video used for evaluating model performance is_display (bool, optional (default: false)): Switch to enable or disable displaying the video and the detection boxes while doing the performance evaluation Returns ------- float: Mean FPS count for the duration of the evaluation Raises ------ IOError: The error if the given video can't be opened """ print_debug('\nEvaluating performance...') # Open video feed video = cv2.VideoCapture(video_path) if not video.isOpened(): raise IOError("Couldn't open webcam or video") # Initialize timings and fps counter elapsed_time = 0.0 frames_in_second = 0 previous_time = time.time() fps_measurements = [] fps_text = 'N/A' if is_display: # Initialize window for video display cv2.namedWindow('result', cv2.WINDOW_NORMAL) cv2.resizeWindow('result', (960, 720)) while True: # Read a frame from video result, frame = video.read() if not result: break # Run object detection using the current model (self) predictions = self.__detect_batch(([Image.fromarray(frame)], cast(BatchAnnotations, numpy.zeros((0, 0, 10))))) batch_boxes = predictions[0] if len(predictions) > 0 else [] boxes = batch_boxes[0][0] if len(batch_boxes) > 0 else [] # Calculate elapsed and detection time current_time = time.time() detection_time = current_time - previous_time previous_time = current_time elapsed_time += detection_time frames_in_second = frames_in_second + 1 if elapsed_time > 1: # If one second elapsed, save current fps measurement and reset fps counter elapsed_time = elapsed_time - 1 fps_measurements.append(frames_in_second) frames_in_second = 0 fps_text = str(fps_measurements[-1]) print_debug(f'FPS: {fps_text}') if len(fps_measurements) > 9 and not is_display: break if is_display: # If display is turned on, show the current detection result (bounding box on image) for [ymin, xmin, ymax, xmax] in boxes: cv2.rectangle(frame, (ymin, xmin), (ymax, xmax), (0, 255, 0), 4) cv2.putText(frame, text=f'FPS: {fps_text}', org=(3, 15), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.50, color=(0, 255, 0), thickness=2) cv2.imshow('result', frame) # Interrupt performance evaluation if q is pressed if cv2.waitKey(1) & 0xFF == ord('q'): break # Print the mean of all the measured fps values mean_fps = statistics.mean(fps_measurements) print_debug(f'Mean FPS: {mean_fps}') return mean_fps
def evaluate( self, images_path: str, annotations_path: str, total_samples: int, video_path: str, ) -> Tuple[List[StatisticsEntry], float]: """Evaluates the current model in terms of its image detection quality and performance Parameters ---------- images_path (str): Path of the image directory, where the evaluation images can be loaded from annotations_path (str): Path of the annotations directory, where the correct annotations for the evaluation images can be loaded from total_samples (int): Number of samples to use to evaluate the model's detection quality video_path (str): Path of the video to use for performance evaluation Returns ------- Tuple[List[StatisticsEntry], float]: Tuple of model evaluation statistics (precision, recall, F1 score, mAP) and the performance metric (FPS) Raises ------ IOError: The error if the given video can't be opened """ from lib.squeezedet_keras.main.model.evaluation import compute_statistics print_debug( f'\nEvaluating {self.description} on {total_samples} samples...') # Load image names and annotations image_files: List[str] = [ os.path.abspath(os.path.join(images_path, image)) for image in os.listdir(images_path) ] annotation_files: List[str] = [ os.path.abspath(os.path.join(annotations_path, annotations)) for annotations in os.listdir(annotations_path) ] # Get predictions in batches boxes: List[Boxes] = [] classes: List[Classes] = [] scores: List[Scores] = [] annotations: List[BatchAnnotations] = [] sample_count = 0 for data in self.data_generator(image_files, annotation_files, total_samples): _, batch_annotations = data (batch_boxes, batch_classes, batch_scores) = self.__detect_batch(data) boxes.append(batch_boxes[0]) classes.append(batch_classes[0]) scores.append(batch_scores[0]) annotations.append(batch_annotations) sample_count += 1 if sample_count % 10 == 0: print_debug(f'{sample_count}/{total_samples}') # Increment class ids, because evaluation script removes zero-labels incremented_class_ids = { 'CLASS_TO_IDX': {name: id + 1 for name, id in self.config.CLASS_TO_IDX.items()} } # Get statistics on prediction results model_statistics: Statistics = compute_statistics( boxes, classes, scores, annotations, EasyDict({ **self.config, **incremented_class_ids })) # Print evaluation results (precision, recall, f1, AP) statistics_zip = cast( Iterator[Tuple[float, float, float, List[float]]], zip(*model_statistics)) accuracy_statistics: List[StatisticsEntry] = [] for index, (precision, recall, f1_score, average_precision) in enumerate(statistics_zip): print_debug( f'{self.config.CLASS_NAMES[index]} - precision: {precision}, ' f'recall: {recall}, f1: {f1_score}, ' f'mAP: {statistics.mean(average_precision)}') accuracy_statistics.append((precision, recall, f1_score, statistics.mean(average_precision))) return accuracy_statistics, self.evaluate_performance(video_path)
def mainroute(pagepath): # home page for default 'umber' course if pagepath == '' or pagepath == 'home': return redirect('/' + url_base + '/site/docs/home') print_debug('- ' * 30) print_debug(' mainroute: pagepath = "{}"'.format(pagepath)) print_debug(' mainroute: request.url = "{}"'.format(request.url)) print_debug(' mainroute: request.args = "{}"'.format(request.args)) print_debug(' mainroute: current_user = {}'.format(current_user)) # -- testing session & cookie --- #print_debug(' mainroute: session = {}'.format(session)) #color = 'red' #if color != '': # session['color'] = color # ------------------------------- # If the url is 'foo.md' then redirect to canonical url 'foo'. (basepath, extension) = os.path.splitext(pagepath) if extension == '.md': (ignore1, ignore2, query) = split_url(request.url) redirect_url = '/' + url_base + '/' + basepath if query: redirect_url += '?' + query print_debug('redirecting to "{}"'.format(redirect_url)) return redirect(redirect_url) # Get the corresponding Page object and its file settings. page = Page.get_from_path(pagepath, revision=request.args.get('revision', None), action=request.args.get('action', None), user=current_user) print_debug(' mainroute: page.abspath = {}'.format(page.abspath)) # If a course for the isn't found, a special 'error' course # will be returned as a signal. if page.course.name == 'error': return abort(404) # "not found" print_debug(' mainroute: course.name = "{}"'.format(page.course.name)) print_debug(' mainroute: course.url = "{}"'.format(page.course.url)) print_debug(' mainroute: page.access = {}'.format(page.access)) print_debug(' mainroute: page can read = {}, write = {}'.format( page.can['read'], page.can['write'])) print_debug((' mainroute: page exists = {},' + \ ' is_file = {}, is_dir = {}').format( page.exists, page.is_file, page.is_dir)) # Redirect directories which don't end in '/' to '/'. if page.is_dir and len(pagepath) > 0 and pagepath[-1] != '/': print_debug('redirecting directory to /') return redirect(url_for('mainroute', pagepath=pagepath) + '/') # Redirect directories to index.md or index.html if either exists. if page.is_dir: for index in ('index.md', 'index.html'): if os.path.exists(os.path.join(page.abspath, index)): indexpath = os.path.join(pagepath, index) return redirect(url_for('mainroute', pagepath=indexpath)) # Redirect nonexisting nonystem editable pages to ?action=edit # ... but not if this is the POST that is trying to create it. if page.can['write'] and not page.exists and not page.action and \ not page.is_sys and not page.is_dir and \ not request.method == 'POST' : return redirect(page.url + '?action=edit') # Don't serve up any invisible "dot" files - reload enclosing folder. # This includes (.access.yaml, .keep) among possible others. if len(page.name) > 0 and page.name[0] == '.': url = page.url while page.url[-1] != '/' and len(page.url) > 0: url = url[:-1] if len(page.url) > 12 and page.url[-12:] == '.access.yaml': return redirect(page.url[:-12]) else: return redirect(page.course.url) # Store the page object (and therefore page.course and page.user) # in the request, so that the request action handler doesn't need args. request.page = page if request.method == 'POST' and 'dropzone' in request.args: print_debug('-- dropzone file upload --') # i.e. handle dropzonejs.com return ajax_upload() elif request.method == 'POST': print_debug(' mainroute: POST') reload_url = form_post() return redirect(reload_url) elif (not page.is_dir and (page.ext == '' or not page.ext in ('.md')) and page.can['read'] and page.exists): # readable pages that shouldn't be in umber's window pane : # just serve up their content. # (If the page isn't readable, then render_template(main.html) below # will show the error page within the umber setting.) # TODO: Do the right thing for actions like ?version=xxx or ?history ? # TODO: Handle what was _html for .py and .html # with ?something (?html , ?source, ?pretty) ? # TODO: forward these sorts of requests to apache or other server?? # TODO: handle unknown mimetype better, perhaps don't send file at all? print_debug(' -- mainroute - raw-ish content ') print_debug(' mimetype={}'.format(page.get_mimetype())) print_debug(' page.name_with_ext = {}'.format(page.name_with_ext)) print_debug(' page.path = {}'.format(page.path)) print_debug(' request.args = {}'.format(str(request.args))) _content = page.content() _mimetype = page.get_mimetype() if 'html' in request.args: print_debug(' pygmentizing ...') _content = pygmentize(_content, filename=page.name_with_ext) _mimetype = 'text/html' return Response(_content, mimetype=_mimetype) else: # umber page : folder or *.md or sys/* return render_template('main.html', name='main', page=page, user=page.user, course=page.course, debug=True)
def ajax_upload(): """ handle ajax file upload """ # dropzone sends one ajax request per file, so this invocation is for # one file even if multiple files have been dropped on the web page. page = request.page print_debug(' ajax_upload ') print_debug(' request.form.keys() : {}'.format(request.form.keys())) print_debug(' destination : "{}"'.format(page.abspath)) print_debug(' page.url : {}'.format(page.url)) # Make sure that this user is authorized to put files here. if not page.can['write']: return ajax_response(False, 'Oops - invalid permissions for file upload.') if page.is_dir: abspath = page.abspath else: # create .attachments folder if need be abspath = page.attachments_folder() if not os.path.exists(abspath): try: os.mkdir(abspath) except: print_debug(' submit_createfolder: os.makedir failed') return ajax_response(False, 'error creating attachments folder') for upload in request.files.getlist("file"): # Should be only one file when using dropbox, I think. # TODO: send something other than success if there's a problem here, # probably with a try: except: block. filename = secure_filename(upload.filename) print_debug(' file : "{}"'.format(filename)) destination = os.path.join(abspath, filename) upload.save(destination) # TODO: do the github stuff asyncronously ? git.add_and_commit(page, abspath=destination) print_debug(" sending ajax response ") return ajax_response(True, 'upload success')
def submit_grades(): """ handle setting all course grades from grid """ print_debug('submit grades') print_debug(request.form) Work.edit_grades(request.form) return url_for('mainroute', pagepath=request.page.path)