def check_access(): if not current_user.is_authenticated: return abort(401) if not current_user.has_access("admin"): if not current_user.has_access("judge"): return abort(403) if current_app.config["STATUS"] != "judging": flash("It is not judging phase.") return redirect(url_for("base.index"))
def update_role(u_id, role): if any([ not current_user.has_access('moderator'), not current_user.has_access('admin') and role == 'moderator', not current_user.has_access('superadmin') and role == 'admin', role == 'superadmin' ]): abort(403) if role == 'superadmin' or role not in USER_ACCESS.keys(): abort(422, 'Unknown role') accounts_logic.update_role(u_id, role) return make_ok('Successfully updated user\'s role')
def decorated_function(*args, **kwargs): if not current_user.is_authenticated: flash('Your not logged in!') return redirect(url_for('core.login', next=request.url)) elif not current_user.has_access(permission): return abort(403) return f(*args, **kwargs)
def check_access(): if not current_user.is_authenticated: return abort(401) if not current_user.has_access( "admin") and current_app.config["STATUS"] != "end": abort(403)
def listing(): page = request.args.get("page", 1, type=int) submissions = Submission.query.order_by( Submission.total_score.desc()).paginate(page, 10) judges = Role.query.filter_by(judge=True).first().users for s in submissions.items: score = 0.0 criteria_scores = { "musicRepr": 0, "gameplay": 0, "creativity": 0, "hitsound": 0, } checked_judges = [] for j in s.judgings: for criteria, score in j.scores.items(): criteria_scores[criteria] += score.score checked_judges.append(j.judge) s.missing_judges = set(judges) - set(checked_judges) s.criteria_scores = criteria_scores return render_template( "pages/result/listing.html", submissions=submissions, title="Results", admin_mode=current_user.has_access("admin") and current_app.config["STATUS"] != "end", )
def update_avatar(u_id): if current_user.id != u_id and not current_user.has_access('moderator'): abort(403, 'You cant update avatar') file = request.files['file'] users_logic.update_avatar(u_id, file) return make_ok('Avatar has been successfully updated')
def update(u_id, new_data): with get_session() as s: u = User.get_or_404(s, u_id) if u_id != current_user.id and not current_user.has_access( 'moderator'): abort(403) for param, value in new_data.items(): if param == 'tags': if not current_user.has_access('moderator'): abort(403, 'You cant change tags') u.tags = s.query(Tag).filter(Tag.name.in_(value)).all() elif param == 'interests': u.interests = s.query(Tag).filter(Tag.name.in_(value)).all() else: setattr(u, param, value)
def get(c_id): with get_session() as s: comment = Comment.get_or_404(s, c_id) if (isinstance(comment.post, Question) and comment.post.closed and not current_user.has_access('expert') and comment.post.u_id != current_user.id): abort(403) return comment.as_dict()
def delete(c_id): with get_session() as s: comment = Comment.get_or_404(s, c_id) if (not current_user.has_access('moderator') and comment.u_id != current_user.id): abort(403) comment.post.comment_count -= 1 comment.author.comment_count -= 1 comment.status = 'deleted'
def ban_user(u_id): with get_session() as s: u = User.get_or_404(s, u_id) if (u.has_access('moderator') or not current_user.has_access('moderator')): abort(403) if u.status == 'banned': abort(409, 'User has already banned') u.status = 'banned'
def account(): user = current_user.id form = EditUserForm(obj=user) if current_user.has_access("access_changing"): card = form.card_number.data if form.validate_on_submit(): if form.username.data <> current_user.username: if not username_is_available(form.username.data): flash("Username is not allowed use another", "warning") return render_template("auth/editAccountAdmin.tmpl", form=form, user=current_user) if form.email.data <> current_user.email: if not email_is_available(form.email.data): flash("Email is used use another email", "warning") return render_template("auth/editAccountAdmin.tmpl", form=form, user=current_user) if current_user.has_access("access_changing"): form.card_number.data = card new_user = user.update(**form.data) login_user(new_user) flash("Saved successfully", "info") return redirect(request.args.get('next') or url_for('public.index')) return render_template("auth/editAccountAdmin.tmpl", form=form, user=current_user)
def update(c_id, text): with get_session() as s: comment = Comment.get_or_404(s, c_id) if (isinstance(comment.post, Question) and comment.post.closed and not current_user.has_access('moderator') and comment.post.u_id != current_user.id): abort(403) if not text: abort(422, 'Comment text should not be empty') comment.text = text
def create_post(): PostClass = get_post_class(request.path) data = get_json() if PostClass == Question: schemas.question.validate(data) if data['closed'] is True and not current_user.has_access('expert'): abort(422, 'You cannot create closed questions') elif PostClass == Article: schemas.article.validate(data) validate_tags(data['tags']) p_id = posts_logic.create(PostClass, data) return make_ok(f'{PostClass.__name__} #{p_id} successfully created'), 201
def wrapper(*args, **kwargs): if not hasattr(current_user, "id"): # TODO add proper response return None # CHECK USER ACCESS RIGHTS has_access = current_user.has_access(current_user.id, asset) # RETURN IF USER DOES NOT HAVE ACCESS if not has_access: return None # RETURN FUNCTION AS NORMAL OTHERWISE else: return f(*args, **kwargs)
def datatable(dataset): """List a table with the images and their ratings.""" # Figure out how to send Dataset ds_model = Dataset.query.filter_by(name=dataset).first_or_404() all_raters = request.args.get('all_raters', 0, type=int) only_ratings = request.args.get('only_ratings', 0, type=int) # Double check sharing ratings all_raters = all_raters if ds_model.sharing else 0 # Double check rater's access if not current_user.has_access(ds_model): flash(f"You don't have access to {dataset.name}", 'danger') all_raters_string = "all_raters" if all_raters else None return redirect( url_for('main.dashboard', all_raters_string=all_raters_string)) col_names = ['Type', 'Sub', 'Sess', 'Cohort', 'Rating', 'Comment'] columns = {**dict.fromkeys(col_names, None)} columns['Type'] = bool(sum([bool(i.imgtype) for i in ds_model.images])) columns['Sub'] = bool(sum([bool(i.subject) for i in ds_model.images])) columns['Sess'] = bool(sum([bool(i.session) for i in ds_model.images])) columns['Cohort'] = bool(sum([bool(i.cohort) for i in ds_model.images])) columns['Rating'] = bool( sum([bool(i.ratings.all()) for i in ds_model.images])) comments = [ bool(r.comment) for r in Rating.query.join(Image).filter(Image.dataset == ds_model) ] subratings = [ bool(r.subratings.all()) for r in Rating.query.join(Image).filter(Image.dataset == ds_model) ] columns['Comment'] = (sum(comments) or sum(subratings)) return render_template("dt/datatable.html", DS=ds_model, types=columns['Type'], subs=columns['Sub'], sess=columns['Sess'], cohorts=columns['Cohort'], ratings=columns['Rating'], comms=columns['Comment'], all_raters=all_raters, only_ratings=only_ratings)
def listing(): page = request.args.get("page", 1, type=int) submissions: List[Submission] = Submission.query.paginate(page, 10) for s in submissions.items: s.has_judged = False for judging in s.judgings: if judging.judge.osu_uid == current_user.osu_uid: s.has_judged = True s.my_judging = judging return render_template( "pages/judge/listing.html", submissions=submissions, title="Judge", admin_mode=current_user.has_access("admin") and current_app.config["STATUS"] != "judging", )
def get_posts(u_id=None): PostClass = get_post_class(request.path) args = request.args offset = args.get('offset') limit = args.get('limit') closed = args.get('closed') archived = args.get('archived') tags = args['tags'].split(',') if ('tags' in args) else None # todo: move to validation module if (archived and u_id != current_user.id and not current_user.has_access('moderator')): abort(403) posts = posts_logic.get_many(PostClass, u_id, closed, tags, offset, limit, archived) return jsonify(posts)
def Controlled(name: str = None, alt: str = None, component=""): """ access-control for an arbitrary Dash component arguments component: - object subclassing dash.development.base_component.Component or a JSON-serializable type - the component to return if the user has access to it name: str - the permission's unique name - if empty, the permission has no access control and is shown to all users """ ret = html.Div() if not alt in [None, "div", "bad"]: pass elif not hasattr(current_user, "is_authenticated"): pass elif current_user.is_authenticated: permission_access = current_user.has_access(name) if permission_access: ret = component else: # RETURN A BLANK DIV, SHOWING NOTHING ON SCREEN if alt is None: pass # RETURN A DIV SHOWING ACCESS DENIED elif alt == "div": ret = html.Div("Access Denied") # REDIRECT THE USER TO THE BAD PAGE elif alt == "bad": ret = html.Div( dcc.Location(id="bad-url-redirect", pathname="/bad", refresh=True)) return ret
def Controlled(name: str = None, alt: str = None, component="", custom_value="", func=None): """ access-control for an arbitrary Dash component arguments component: - object subclassing dash.development.base_component.Component or a JSON-serializable type - the component to return if the user has access to it name: str - the permission's unique name - if empty, the permission has no access control and is shown to all users alt: str - blank | "div" | "bad" | "custom" - how to handle user lacking access - values blank: return `""` (most common) `"div"`: return an `html.Div` that says `"Access Denied"` `"bad"`: return a link that sends the user to your /bad URL (customizable - useful for full-page control) `"custom"`: return a custom value defined in the `custom_value` parameter custom_value: - object subclassing dash.development.base_component.Component or a JSON-serializable type - something custom to return if the user doesn't have access - only used if alt="custom" func: - a function used to check if the user has access - use if you don't want to use the current_user system """ ret = html.Div() if not alt in [None, "div", "bad", "custom"]: pass elif not hasattr(current_user, "is_authenticated"): pass elif current_user.is_authenticated: if func is None: permission_access = current_user.has_access(name) else: permission_access = func(name) if permission_access: ret = component else: # RETURN A BLANK DIV, SHOWING NOTHING ON SCREEN if alt is None: pass # RETURN A DIV SHOWING ACCESS DENIED elif alt == "div": ret = html.Div("Access Denied") # REDIRECT THE USER TO THE BAD PAGE elif alt == "bad": ret = html.Div( dcc.Location(id="bad-url-redirect", pathname="/bad", refresh=True)) elif alt == "custom": return custom_value return ret
def rate(name_dataset): """Page to view images and rate them.""" # If dataset doesn't exist abort with 404 dataset = Dataset.query.filter_by(name=name_dataset).first_or_404() # All raters all_raters = request.args.get('all_raters', 0, type=int) # Double check sharing/all_raters all_raters = all_raters if dataset.sharing else 0 # Double check rater's access if not current_user.has_access(dataset): flash(f"You don't have access to {dataset.name}", 'danger') all_raters_string = "all_raters" if all_raters else None return redirect(url_for('main.dashboard', all_raters_string=all_raters_string)) # Static directory statics_dir = os.path.join(current_app.config['ABS_PATH'], 'static') # Dictionary with all possible filters filters = { "image": request.args.get('image', None, type=str), "rating": request.args.get('rating_filter', None, type=int), "rater": request.args.get('rater_filter', None, type=str), "type": request.args.get('type_filter', None, type=str), "subject": request.args.get('sub_filter', None, type=str), "session": request.args.get('sess_filter', None, type=str), "cohort": request.args.get('cohort_filter', None, type=str) } # INIT with all dataset's images imgs = dataset.images # Unrated images (used for filtering later) unrated = imgs.filter_by(ratings=None) # Paging pagination, page = True, request.args.get('page', 1, type=int) prev = request.args.get('prev', 0, type=int) subquery = Image.query.join(Rating).filter(Image.dataset == dataset, Rating.rater == current_user) _, prev_img, prev_time = subquery.order_by(Rating.timestamp.desc()).\ add_columns(Image.name, Rating.timestamp).first() \ if subquery.first() else None, None, None # If last rating is younger than 3 minutes give option de undo back = 0 if not prev_time \ else 1 if (datetime.utcnow() - prev_time).total_seconds() < 360 \ else 0 # TODO apply subqueries to this mess... # TODO add an example to remember what I meant with 'subqueries' if filters["image"]: # If there is an image filtering, just show the image # There is nothing else to do (filter, query, etc...) img = dataset.images.filter_by(name=filters["image"]).first_or_404() # No need of pagination (Only 1 image); REWRITE VAR pagination, page = False, None else: imgs = imgs.filter_by(imgtype=filters["type"]) \ if filters["type"] else imgs imgs = imgs.filter_by(subject=filters["subject"]) \ if filters["subject"] else imgs imgs = imgs.filter_by(session=filters["session"]) \ if filters["session"] else imgs imgs = imgs.filter_by(cohort=filters["cohort"]) \ if filters["cohort"] else imgs if filters["rating"] is not None or filters["rater"]: imgs = imgs.join(Rating) imgs = imgs.\ filter(Rating.rater == Rater.query.filter_by( username=filters["rater"]).first()) \ if filters["rater"] else imgs if filters["rating"] is None: pass elif filters["rating"] == 0: if all_raters: # Images marked 'PENDING' by any rater pending = imgs.filter(Rating.rating == 0) # QUERY: UNRATED + PENDING # Unless they have another rating imgs = pending.union(unrated).distinct() else: # Images with ratings from CURRENT_RATER (except pending) # rated = imgs.filter(Rating.rater == current_user, # Rating.rating > 0) rated = db.session.query(Image.id).\ filter(Image.dataset == dataset).\ join(Rating).\ filter(Rating.rater == current_user, Rating.rating != 0).\ subquery() # All images, except Rated imgs = imgs.filter(Image.id.not_in(rated)).\ union(unrated).distinct() elif filters["rating"] < 4: if all_raters: imgs = imgs.filter(Rating.rating == filters["rating"]).\ distinct() else: imgs = imgs.filter(Rating.rating == filters["rating"], Rating.rater == current_user) else: flash('Invalid filtering; Showing all images...', 'danger') return redirect(url_for('main.rate', all_raters=all_raters, name_dataset=name_dataset)) imgs = imgs.order_by(Image.name.asc()).paginate(page, 1, False) \ if pagination else None # If after filtering the query ends empty, return all of them (f**k it...) if pagination and not imgs.items: flash('Filter ran out of images in filter; Showing all images...', 'info') return redirect(url_for('main.rate', all_raters=all_raters, name_dataset=name_dataset)) # Image will be first image of list; Paginate takes care of everything # If there's no pagination, then an image was filtered, so img is declared img = imgs.items[0] if pagination else img # Ratings from the resulting query after filtering all_ratings = img.ratings.all() # Fix PATH from database for showing the images in browser path = img.path.replace(f'{statics_dir}/', "") # Filtering boolean for HTML purposes filtering = bool(filters["image"] or filters["rating"] or filters["rating"] == 0 or filters["type"] or filters["subject"] or filters["session"] or filters["rater"]) img_subratings = img.subratings_by_user(current_user) subratings_json = [{ "id": s.id, "selected": s in img_subratings, "rating": s.rating, "keybinding": s.keybinding } for s in dataset.subratings] # Rating form form = RatingForm() if form.validate_on_submit(): subratings_list = [] sr_data = [s.split("_") for s in form.subratings.data.split("___")] for sr in sr_data: sr_model = Precomment.query.get(sr[0]) if sr_model and sr[1] == "true": # CHECK THIS subratings_list.append(sr_model) img.set_rating(user=current_user, rating=form.rating.data, comment=form.comment.data, subratings=subratings_list) db.session.commit() return redirect(request.url) return render_template('rate.html', DS=dataset, form=form, imgs=imgs, pagination=pagination, all_ratings=all_ratings, img_name=img.name, img_path=path, title=img.name, filters=filters, filtering=filtering, prev=prev, all_raters=all_raters, prev_img=prev_img, back=back, subratings=dataset.subratings, subratings_data=subratings_json, rating=img.rating_by_user(current_user), comment=img.comment_by_user( current_user, add_subratings=False))
def wrapped(*args, **kwargs): if current_user: required_role = UserRole.from_name(role) if current_user.has_access(required_role): return f(*args, **kwargs) abort(401, description='Sorry, you do not have access')
def wrapped(*args, **kwargs): if not current_user.has_access(role): abort(403) return f(*args, **kwargs)
def delete_avatar(u_id): if current_user.id != u_id and not current_user.has_access('moderator'): abort(403, 'You cant delete avatar') users_logic.delete_avatar(u_id) return make_ok('Avatar has been successfully deleted')
def decorated_function(*args, **kwargs): if not current_user.has_access(permission): abort(403) return f(*args, **kwargs)
def load_dataset(directory=None): """Page to load new datasets from within HOST.""" data_dir = os.path.join(current_app.config['ABS_PATH'], 'static/datasets/preloaded') # All raters all_raters = request.args.get('all_raters', 0, type=int) # Choices of directories to load in form dir_choices = [ d for d in os.listdir(data_dir) if os.path.isdir(os.path.join(data_dir, d)) ] dir_choices.sort() info = {'directory': directory, 'new_imgs': 0} if directory is not None: # Save useful info for jinja template info['model'] = Dataset.query.filter_by(name=directory).first() # Check access before loading files if info['model']: info['access'] = current_user.has_access(info['model']) info['saved_imgs'] = info['model'].images.count() else: info['access'] = True info['saved_imgs'] = 0 if info['access']: # Count the files in the directory all_files = [] for root, _, files in os.walk(os.path.join(data_dir, directory)): all_files.extend([ os.path.join(root, f) for f in files if not f.startswith('.') ]) info['new_imgs'] = len(all_files) - info['saved_imgs'] form = LoadDatasetForm() form.dir_name.choices = dir_choices # Form submission must be restricted by access in template if form.validate_on_submit(): if info['model']: new_dataset = False else: # If dataset is not a Dataset Model (does not exist), create it info['model'] = Dataset(name=form.dir_name.data, creator=current_user) db.session.add(info['model']) new_dataset = True flash(f"{info['model'].name} was created as an OPEN dataset", 'info') if len(all_files) > 10: current_user.launch_task('load_data', f"Loading {info['new_imgs']} new images " f"to {info['model'].name} dataset...", icon='load', alert_color='primary', files=all_files, dataset_name=info['model'].name, new_dataset=new_dataset, ignore_existing=True) db.session.commit() else: try: # Function returns number of uploaded images loaded_imgs = load_data(all_files, dataset=info['model'], host=True, new_dataset=new_dataset) except OrphanDatasetError: # If orphaned dataset, delete it # TODO this somehow throws an error; look into this # db.session.delete(info['model']) flash( 'No new files were successfully loaded ' 'leaving the dataset empty', 'warning') else: if not new_dataset and loaded_imgs == 0: flash('No new files were successfully loaded', 'warning') else: flash(f'{loaded_imgs} file(s) successfully loaded!', 'success') finally: # Commit changes in database db.session.commit() return redirect(url_for('main.dashboard', all_raters=all_raters)) # Form validation errors for _, error in form.errors.items(): flash(error[0], 'danger') return render_template('data/load_dataset.html', form=form, title="Load Dataset", dictionary=info, all_raters=all_raters)
def submit(): submitted_entry: Optional[Submission] = Submission.query.filter_by( mapper_id=current_user.osu_uid ).first() form = EntryForm() if form.validate_on_submit(): f = form.osz.data data_path = current_app.config.get("DATA_PATH", current_app.instance_path) # Generate random filename for original osz file. existing_filename = True while existing_filename: filename = generate_id() + ".osz" if not os.path.exists(filename): existing_filename = False path_original = os.path.join( data_path, "osz-original", filename, ) f.save(path_original) # Generate random mapper name for anon judging phase. existing_name = True while existing_name: mapper_anon_name = generate_name() if not Submission.query.filter_by(anon_name=mapper_anon_name).first(): existing_name = False path_modified = os.path.join( data_path, "osz", mapper_anon_name + ".osz", ) try: artist, title, version = prepare_osz(f, path_modified, mapper_anon_name) except ValueError as e: flash(str(e)) traceback.print_exc() os.remove(path_original) return render_template( "pages/submit.html", form=form, submitted_entry=submitted_entry, title="Submit", ) # Remove previously submitted entry if submitted_entry: delete_submission(submitted_entry) submission = Submission( # We don't need to know the absolute path of the file. file_path=path_original.replace(data_path, ""), anon_path=path_modified.replace(data_path, ""), mapper=current_user, artist=artist, title=title, difficulty=version, anon_name=mapper_anon_name, ) db.session.add(submission) db.session.commit() flash("Submitted!") return redirect(url_for("base.index")) return render_template( "pages/submit.html", form=form, submitted_entry=submitted_entry, title="Submit", admin_mode=current_user.has_access("admin") and current_app.config["STATUS"] != "mapping", )