예제 #1
0
    async def get(self, request: HTTPConnection):
        id = request.path_params["id"]

        challenge = await Challenge.get(id)

        if challenge is None:
            return abort(404, "Challenge not found")

        if not can_edit(request):
            return abort(400)

        form = ChallengeForm(
            title=challenge.title,
            content=challenge.content,
            flag_or_answer=challenge.flag or challenge.answer,
            is_flag=challenge.flag is not None,
            hidden=challenge.hidden,
            depreciated=challenge.depreciated,
            points=challenge.points,
            tags=challenge.tags,
        )

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(include_hidden=True))

        return templates.TemplateResponse(
            "challenge/edit.j2",
            {
                "request": request,
                "form": form,
                "challenge": challenge,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #2
0
    async def get(self, request: HTTPConnection):
        id = request.path_params["id"]

        blog = await Blog.get(id)

        if blog is None:
            return abort(404, "Blog not found")

        if not can_edit(request):
            return abort(400)

        form = PostForm(title=blog.title, tags=blog.tags, content=blog.content)

        images = await encoded_existing_images(request)
        tags = ujson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "blog/edit.j2",
            {
                "request": request,
                "form": form,
                "blog": blog,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
async def writeups_all_tags(request: HTTPConnection):
    tags = await get_all_tags()

    return templates.TemplateResponse("writeups/tag_list.j2", {
        "request": request,
        "tags": tags
    })
예제 #4
0
    async def get(self, request: HTTPConnection):
        id = request.path_params["id"]

        writeup = await Writeup.get(id)

        if writeup is None:
            return abort(404, "Writeup not found")

        if not can_edit(request, writeup.author_id):
            return abort(400)

        form = WriteupForm(
            title=writeup.title,
            tags=writeup.tags,
            content=writeup.content,
            private=writeup.private,
        )

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(True))

        return templates.TemplateResponse(
            "writeups/edit.j2",
            {
                "request": request,
                "form": form,
                "writeup": writeup,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #5
0
async def blog_all_tags(request: HTTPConnection):
    tags = await get_all_tags()

    grouped_blogs = await blogs_grouped()

    return templates.TemplateResponse(
        "blog/tag_list.j2", {"request": request, "tags": tags, "grouped_blogs": grouped_blogs}
    )
예제 #6
0
    async def post(self, request: HTTPConnection):
        form = await request.form()

        form = ChallengeForm(form)

        is_valid = form.validate()

        if not slug(form.title.data):
            is_valid = False
            form.title.errors.append(
                "A valid url-safe name cannot be generated for this title.")

        if (await Challenge.query.where(
                sa.or_(
                    Challenge.title == form.title.data,
                    Challenge.slug == slug(form.title.data),
                )).gino.first() is not None):
            is_valid = False
            form.title.errors.append(
                f"A challenge with the title conflicting with '{form.title.data}' already exists."
            )

        if is_valid:
            f_a = form.flag_or_answer.data
            flag, answer = (f_a, None) if form.is_flag.data else (None, f_a)

            challenge = await Challenge.create_auto(
                title=form.title.data,
                content=form.content.data,
                flag=flag,
                answer=answer,
                hidden=form.hidden.data,
                depreciated=form.depreciated.data,
                points=form.points.data,
                tags=form.tags.data,
            )

            url = request.url_for("challenge_view", slug=challenge.slug)

            if not challenge.hidden:
                await log_create("challenge", challenge.title,
                                 request.user.username, url)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(include_hidden=True))

        return templates.TemplateResponse(
            "challenge/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #7
0
async def challenge_all_tags(request: HTTPConnection):
    tags = await get_all_tags()

    return templates.TemplateResponse(
        "challenge/tag_list.j2",
        {
            "request": request,
            "tags": tags
        },
    )
예제 #8
0
    async def post(self, request: HTTPConnection):
        id = request.path_params["id"]

        blog = await Blog.get(id)

        if blog is None:
            return abort(404, "Blog not found")

        if not can_edit(request, blog.author_id):
            return abort(400)

        form = await request.form()

        form = PostForm(form)

        is_valid = form.validate()

        if not slug(form.title.data):
            is_valid = False
            form.title.errors.append(
                "A valid url-safe name cannot be generated for this title.")

        if blog.title != blog.title.data:
            if (await Blog.query.where(
                    sa.or_(Blog.title == form.title.data,
                           Blog.slug == slug(form.title.data))).gino.first()
                    is not None):
                is_valid = False
                form.title.errors.append(
                    f"A blog with the title '{form.title.data}' already exists."
                )

        if is_valid:
            await blog.update_auto(title=form.title.data,
                                   tags=form.tags.data,
                                   content=form.content.data).apply()

            url = request.url_for("blog_view", slug=blog.slug)
            await log_edit("blog", blog.title, request.user.username, url)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "blog/edit.j2",
            {
                "request": request,
                "form": form,
                "blog": blog,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #9
0
async def blog_index(request: HTTPConnection):
    latest = (await Blog.load(author=User).order_by(sa.desc(Blog.creation_date)
                                                    ).gino.all())

    rendered = [(w, length_constrained_plaintext_markdown(w.content))
                for w in latest]

    return templates.TemplateResponse("blog/index.j2", {
        "request": request,
        "blog": rendered
    })
예제 #10
0
    async def post(self, request: HTTPConnection):
        form = await request.form()

        form = WriteupForm(form)

        is_valid = form.validate()

        if not slug(form.title.data):
            is_valid = False
            form.title.errors.append(
                "A valid url-safe name cannot be generated for this title."
            )

        if (
            await Writeup.query.where(
                sa.or_(
                    Writeup.title == form.title.data,
                    Writeup.slug == slug(form.title.data),
                )
            ).gino.first()
            is not None
        ):
            is_valid = False
            form.title.errors.append(
                f"A writeup with the title conflicting with '{form.title.data}' already exists."
            )

        if is_valid:
            writeup = await Writeup.create_auto(
                author_id=request.user.discord_id,
                title=form.title.data,
                tags=form.tags.data,
                content=form.content.data,
                private=form.private.data,
            )

            url = request.url_for("writeups_view", slug=writeup.slug)
            await log_create("writeup", writeup.title, request.user.username, url)

            return redirect_response(url=url)

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(True))

        return templates.TemplateResponse(
            "writeups/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #11
0
async def blog_by_user(request: HTTPConnection):
    user = request.path_params["user"]

    blog = (await Blog.load(author=User).where(User.username == user).order_by(
        sa.desc(Blog.creation_date)).gino.all())

    rendered = [(w, length_constrained_plaintext_markdown(w.content))
                for w in blog]

    return templates.TemplateResponse("writeups/index.j2", {
        "request": request,
        "writeups": rendered
    })
예제 #12
0
async def blog_index(request: HTTPConnection):
    latest = await Blog.query.order_by(sa.desc(Blog.creation_date)).limit(20).gino.all()

    rendered = [
        (w, shorten(plaintext_markdown(w.content), width=800, placeholder="..."))
        for w in latest
    ]

    grouped_blogs = await blogs_grouped()

    return templates.TemplateResponse(
        "blog/index.j2", {"request": request, "blog": rendered, "grouped_blogs": grouped_blogs}
    )
예제 #13
0
async def blog_view(request: HTTPConnection):
    slug = request.path_params["slug"]

    blog = await Blog.query.where(Blog.slug == slug).gino.first()

    if blog is None:
        return abort(404, "Blog not found")

    rendered = highlight_markdown(blog.content)

    return templates.TemplateResponse(
        "blog/view.j2", {"blog": blog, "request": request, "rendered": rendered}
    )
async def writeups_search(request: HTTPConnection):
    s_query = request.query_params.get("search", "")

    # sorry about this
    query = pg_search(sa.select([Writeup.join(User)]), s_query, sort=True)
    query = query.column(
        sa.func.ts_headline(
            search_manager.options["regconfig"],
            Writeup.content,
            sa.func.tsq_parse(search_manager.options["regconfig"], s_query),
            f"StartSel=**,StopSel=**,MaxWords=70,MinWords=30,MaxFragments=3",
        ).label("headline"))

    writeups = await query.as_scalar().gino.all()

    def build_writeup(r):
        """we get back a RowProxy so manually construct the writeup from it."""

        author = User(discord_id=r.discord_id,
                      username=r.username,
                      email=r.email)

        writeup = Writeup(
            id=r.id,
            author_id=r.author_id,
            title=r.title,
            slug=r.slug,
            tags=r.tags,
            content=r.content,
            creation_date=r.creation_date,
            edit_date=r.edit_date,
        )

        writeup.author = author
        return writeup

    writeups = [(build_writeup(r), r.headline) for r in writeups]

    rendered = [(w,
                 shorten(plaintext_markdown(headline),
                         width=300,
                         placeholder="...")) for (w, headline) in writeups]

    return templates.TemplateResponse(
        "writeups/index.j2",
        {
            "request": request,
            "writeups": rendered,
            "query": s_query
        },
    )
async def writeups_index(request: HTTPConnection):
    latest = (await
              Writeup.load(author=User).order_by(sa.desc(Writeup.creation_date)
                                                 ).limit(20).gino.all())

    rendered = [(w,
                 shorten(plaintext_markdown(w.content),
                         width=300,
                         placeholder="...")) for w in latest]

    return templates.TemplateResponse("writeups/index.j2", {
        "request": request,
        "writeups": rendered
    })
예제 #16
0
    async def get(self, request: HTTPConnection):
        form = ChallengeForm()

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(include_hidden=True))

        return templates.TemplateResponse(
            "challenge/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #17
0
async def blog_by_tag(request: HTTPConnection):
    tag = request.path_params["tag"]

    blog = (await
            Blog.load(author=User).where(Blog.tags.contains([tag])
                                         ).order_by(sa.desc(Blog.creation_date)
                                                    ).gino.all())

    rendered = [(w, length_constrained_plaintext_markdown(w.content))
                for w in blog]

    return templates.TemplateResponse("blog/index.j2", {
        "request": request,
        "blog": rendered
    })
예제 #18
0
    async def get(self, request: HTTPConnection):
        form = WriteupForm()

        images = await encoded_existing_images(request)
        tags = orjson.dumps(await get_all_tags(True))

        return templates.TemplateResponse(
            "writeups/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
예제 #19
0
async def writeups_index(request: HTTPConnection):
    latest = (
        await Writeup.load(author=User)
        .order_by(sa.desc(Writeup.creation_date))
        .gino.all()
    )

    rendered = [
        (w, length_constrained_plaintext_markdown(w.content))
        for w in latest
        if not should_skip_writeup(w, request.user.is_authed)
    ]

    return templates.TemplateResponse(
        "writeups/index.j2", {"request": request, "writeups": rendered}
    )
async def writeups_by_tag(request: HTTPConnection):
    tag = request.path_params["tag"]

    writeups = (await Writeup.load(author=User).where(
        Writeup.tags.contains([tag])).order_by(sa.desc(Writeup.creation_date)
                                               ).gino.all())

    rendered = [(w,
                 shorten(plaintext_markdown(w.content),
                         width=300,
                         placeholder="...")) for w in writeups]

    return templates.TemplateResponse("writeups/index.j2", {
        "request": request,
        "writeups": rendered
    })
예제 #21
0
async def writeups_view(request: HTTPConnection):
    slug = request.path_params["slug"]

    writeup = await Writeup.load(author=User).where(Writeup.slug == slug).gino.first()

    if writeup is None:
        return abort(404, "Writeup not found")

    if should_skip_writeup(writeup, request.user.is_authed):
        return redirect_response(url=request.url_for("need_auth"))

    rendered = highlight_markdown(writeup.content)

    return templates.TemplateResponse(
        "writeups/view.j2",
        {"writeup": writeup, "request": request, "rendered": rendered},
    )
예제 #22
0
async def blog_search(request: HTTPConnection):
    s_query = request.query_params.get("search", "")

    # sorry about this
    query = pg_search(sa.select([Blog.join(User)]), s_query, sort=True)
    query = query.column(
        sa.func.ts_headline(
            search_manager.options["regconfig"],
            Blog.content,
            sa.func.tsq_parse(search_manager.options["regconfig"], s_query),
            f"StartSel=**,StopSel=**,MaxWords=70,MinWords=30,MaxFragments=3",
        ).label("headline"))

    blog = await query.as_scalar().gino.all()

    def build_blog(r):
        """we get back a RowProxy so manually construct the blog from it."""

        author = User(discord_id=r.discord_id,
                      username=r.username,
                      email=r.email)

        blog = Blog(
            id=r.id,
            author_id=r.author_id,
            title=r.title,
            slug=r.slug,
            tags=r.tags,
            content=r.content,
            creation_date=r.creation_date,
            edit_date=r.edit_date,
        )

        return blog

    blog = [(build_blog(r), r.headline) for r in blog]

    rendered = [(w, length_constrained_plaintext_markdown(headline))
                for (w, headline) in blog]

    return templates.TemplateResponse("blog/index.j2", {
        "request": request,
        "blog": rendered,
        "query": s_query
    })
예제 #23
0
async def challenge_by_tag(request: HTTPConnection):
    tag = request.path_params["tag"]

    solves = sa.func.count(CompletedChallenge.challenge_id).label("solves")

    select = [Challenge, solves]
    columns = (Challenge, ColumnLoader(solves))

    if request.user.is_authenticated:
        solved_challenges = (db.select([
            CompletedChallenge.challenge_id
        ]).where(CompletedChallenge.season == CURRENT_SEASON).where(
            CompletedChallenge.discord_id == request.user.discord_id).cte(
                "solved_challenges"))

        solved = (sa.exists().where(
            solved_challenges.c.challenge_id == Challenge.id).label("solved"))

        select.append(solved)
        columns = (*columns, ColumnLoader(solved))

    challenges = await (db.select(select).select_from(
        Challenge.outerjoin(
            CompletedChallenge,
            (Challenge.id == CompletedChallenge.challenge_id)
            & (CompletedChallenge.season == CURRENT_SEASON),
        )).group_by(Challenge.id).where(Challenge.tags.contains(
            [tag])).order_by(Challenge.creation_date.desc(),
                             Challenge.id.desc()).gino.load(columns).all())

    rendered = [(
        w,
        length_constrained_plaintext_markdown(w.content),
        solves,
        did_solve and did_solve[0],
    ) for (w, solves, *did_solve) in challenges
                if not should_skip_challenge(w, request.user.is_admin)]

    return templates.TemplateResponse(
        "challenge/index.j2",
        {
            "request": request,
            "challenges": rendered,
        },
    )
async def writeups_view(request: HTTPConnection):
    slug = request.path_params["slug"]

    writeup = await Writeup.load(author=User).where(Writeup.slug == slug
                                                    ).gino.first()

    if writeup is None:
        return abort(404, "Writeup not found")

    rendered = highlight_markdown(writeup.content)

    return templates.TemplateResponse(
        "writeups/view.j2",
        {
            "writeup": writeup,
            "request": request,
            "rendered": rendered
        },
    )
예제 #25
0
async def blog_search(request: HTTPConnection):
    s_query = request.query_params.get("search", "")

    # sorry about this
    query = pg_search(sa.select([Blog]), s_query, sort=True)
    query = query.column(
        sa.func.ts_headline(
            search_manager.options["regconfig"],
            Blog.content,
            sa.func.tsq_parse(search_manager.options["regconfig"], s_query),
            f"StartSel=**,StopSel=**,MaxWords=70,MinWords=30,MaxFragments=3",
        ).label("headline")
    )

    blog = await query.as_scalar().gino.all()

    def build_blog(r):
        """we get back a RowProxy so manually construct the blog from it."""

        blog = Blog(
            id=r.id,
            title=r.title,
            slug=r.slug,
            tags=r.tags,
            content=r.content,
            creation_date=r.creation_date,
            edit_date=r.edit_date,
        )

        return blog

    blog = [(build_blog(r), r.headline) for r in blog]

    rendered = [
        (w, shorten(plaintext_markdown(headline), width=800, placeholder="..."))
        for (w, headline) in blog
    ]

    grouped_blogs = await blogs_grouped()

    return templates.TemplateResponse(
        "blog/index.j2", {"request": request, "blog": rendered, "query": s_query, "grouped_blogs": grouped_blogs}
    )
예제 #26
0
async def writeups_by_tag(request: HTTPConnection):
    tag = request.path_params["tag"]

    writeups = (
        await Writeup.load(author=User)
        .where(Writeup.tags.contains([tag]))
        .order_by(sa.desc(Writeup.creation_date))
        .gino.all()
    )

    rendered = [
        (w, length_constrained_plaintext_markdown(w.content))
        for w in writeups
        if not should_skip_writeup(w, request.user.is_authed)
    ]

    return templates.TemplateResponse(
        "writeups/index.j2", {"request": request, "writeups": rendered}
    )
예제 #27
0
async def blog_by_tag(request: HTTPConnection):
    tag = request.path_params["tag"]

    blog = (
        await Blog.query.where(Blog.tags.contains([tag]))
        .order_by(sa.desc(Blog.creation_date))
        .gino.all()
    )

    rendered = [
        (w, shorten(plaintext_markdown(w.content), width=800, placeholder="..."))
        for w in blog
    ]

    grouped_blogs = await blogs_grouped()

    return templates.TemplateResponse(
        "blog/index.j2", {"request": request, "blog": rendered, "grouped_blogs": grouped_blogs}
    )
예제 #28
0
async def challenge_view(request: HTTPConnection):
    slug = request.path_params["slug"]

    solves = sa.func.count(CompletedChallenge.challenge_id).label("solves")

    challenge = await (db.select([Challenge, solves]).select_from(
        Challenge.outerjoin(
            CompletedChallenge,
            (Challenge.id == CompletedChallenge.challenge_id)
            & (CompletedChallenge.season == CURRENT_SEASON),
        )).group_by(Challenge.id).where(Challenge.slug == slug).gino.load(
            (Challenge, ColumnLoader(solves))).first())

    if challenge is None:
        return abort(404, "Challenge not found")

    challenge, solves = challenge

    if should_skip_challenge(challenge, request.user.is_admin):
        return abort(404, "Challenge not found")

    if request.user.is_authenticated:
        solved_challenge = await CompletedChallenge.query.where(
            (CompletedChallenge.discord_id == request.user.discord_id)
            & (CompletedChallenge.challenge_id == challenge.id)
            & (CompletedChallenge.season == CURRENT_SEASON)).gino.first()
    else:
        solved_challenge = False

    rendered = highlight_markdown_unsafe(challenge.content)

    return templates.TemplateResponse(
        "challenge/view.j2",
        {
            "challenge": challenge,
            "request": request,
            "rendered": rendered,
            "solves": solves,
            "submit_form": AnswerForm(),
            "solved_challenge": solved_challenge,
        },
    )
    async def post(self, request: HTTPConnection):
        id = request.path_params["id"]

        writeup = await Writeup.get(id)

        if writeup is None:
            return abort(404, "Writeup not found")

        if not can_edit(request, writeup.author_id):
            return abort(400)

        form = await request.form()

        form = PostForm(form)

        if form.validate():
            await writeup.update_auto(
                author_id=request.user.discord_id,
                title=form.title.data,
                tags=form.tags.data,
                content=form.content.data,
            ).apply()

            url = request.url_for("writeups_view", slug=writeup.slug)
            await log_edit("writeup", writeup.title, request.user.username,
                           url)

            return RedirectResponse(url=url)

        images = await encoded_existing_images(request)
        tags = ujson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "writeups/edit.j2",
            {
                "request": request,
                "form": form,
                "writeup": writeup,
                "existing_images": images,
                "existing_tags": tags,
            },
        )
    async def post(self, request: HTTPConnection):
        form = await request.form()

        form = PostForm(form)

        is_valid = form.validate()

        if (await Writeup.query.where(Writeup.title == form.title.data
                                      ).gino.first() is not None):
            is_valid = False
            form.errors.setdefault("title", []).append(
                f"A writeup with the title '{form.title.data}' already exists."
            )

        if is_valid:
            writeup = await Writeup.create_auto(
                author_id=request.user.discord_id,
                title=form.title.data,
                tags=form.tags.data,
                content=form.content.data,
            )

            url = request.url_for("writeups_view", slug=writeup.slug)
            await log_create("writeup", writeup.title, request.user.username,
                             url)

            return RedirectResponse(url=url)

        images = await encoded_existing_images(request)
        tags = ujson.dumps(await get_all_tags())

        return templates.TemplateResponse(
            "writeups/new.j2",
            {
                "request": request,
                "form": form,
                "existing_images": images,
                "existing_tags": tags,
            },
        )