Beispiel #1
0
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"))
Beispiel #2
0
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)
Beispiel #4
0
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)
Beispiel #5
0
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",
    )
Beispiel #6
0
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)
Beispiel #8
0
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()
Beispiel #9
0
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'
Beispiel #10
0
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'
Beispiel #11
0
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)
Beispiel #12
0
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
Beispiel #14
0
        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)
Beispiel #15
0
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)
Beispiel #16
0
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)
Beispiel #18
0
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
Beispiel #19
0
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
Beispiel #20
0
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))
Beispiel #21
0
 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)
Beispiel #23
0
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')
Beispiel #24
0
 def decorated_function(*args, **kwargs):
     if not current_user.has_access(permission):
         abort(403)
     return f(*args, **kwargs)
Beispiel #25
0
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)
Beispiel #26
0
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",
    )