Example #1
0
def callback() -> Any:
    """Callback endpoint for SSO service

    Returns:
        Any: Redirect to home page if everything went well, else return 401.
    """
    try:
        discord.callback()
        if DISCORD_GUILD_ID:
            if not verify():
                # When the callback succeeds, the token for the user gets set in memory
                # Since the user isn't a member of the guild, we reset the session
                # to prevent access to the API
                session.clear()
                return abort(401)

        resp = discord.fetch_user()
        # Assume successful login
        if not check_if_user_exists(resp.id):
            add_user(resp.username, resp.id, resp.avatar_url)
        else:
            current_app.logger.info(f"User {resp.username} has just signed in")
            # Update last login time
            update_login_time(resp.id)

        return redirect(url_for("index.home"))
    except RateLimited:
        return "We are currently being rate limited, try again later."
Example #2
0
def watch_stream(username: str, unique_id: Union[str, None] = None) -> Any:
    """Generates a page to watch streams with.

    Args:
        username (str): The user whose stream to watch
        unique_id (Union[str, None], optional): The unique ID of a stream.
        This is only set if the stream is either private, or archived.
        Defaults to None.

    Returns:
        Any: Static page rendered by Flask.
    """
    stream = get_livestreams_by_username(username)
    if stream and not unique_id:
        # Regular livestream
        return render_template("watch.html", live=True, stream=stream)

    if unique_id:
        # Lets first check if its an unlisted stream
        unlisted = get_unlisted_livestreams_by_username(username)
        if unlisted:
            # Unlisted stream
            return render_template("watch.html", live=True, stream=unlisted)

        # It's an archived stream at this point
        try:
            stream = get_archived_stream(unique_id)
            return return_stream_page(unique_id, stream)
        except StopIteration:
            pass

        # Unlisted and archived
        try:
            stream = get_archived_stream(unique_id,
                                         all_metadata=True,
                                         private=True)
            if bool(stream["archivable"]) and bool(stream["unlisted"]):
                return return_stream_page(unique_id, stream)
        except StopIteration:
            pass

        # Private stream
        try:
            user = discord.fetch_user()
            stream = get_archived_stream(unique_id, private=True)
            if stream["user_snowflake"] == user.id:
                return return_stream_page(unique_id, stream)
            else:
                return render_template("alert.html",
                                       error="Invalid stream key.")
        except StopIteration:
            # The stream ID doesn't exist at all at this point
            return (
                render_template("alert.html", error="Invalid stream key."),
                404,
            )

    return render_template("watch.html")
Example #3
0
def manage_stream(unique_id: str) -> Any:
    """Manage a stream's properties via its unique ID. 

    Args:
        unique_id (str): The stream's unique ID.

    Returns:
        Any: A static page rendered by Flask.
    """
    user = discord.fetch_user()
    form = StreamGenerationForm()
    stream = query_one(
        "SELECT title, description, category, archivable, unlisted, user_snowflake FROM stream WHERE unique_id = ?",
        [unique_id],
    )

    if not stream:
        return render_template("alert.html", error="Invalid stream ID."), 404

    # Populate the stream editing form.
    form.title.data = stream["title"]
    form.description.data = stream["description"]
    form.category.data = stream["category"]
    form.archivable.data = stream["archivable"]
    form.unlisted.data = stream["unlisted"]

    if stream["user_snowflake"] == user.id:
        if request.method == "GET":
            return render_template("manage_stream.html",
                                   form=form,
                                   unique_id=unique_id)

        if request.method == "POST":
            form = StreamGenerationForm(request.form)
            if form.validate():
                keys_to_change = {}
                for key, value in form.data.items():
                    if stream[key] != value:
                        keys_to_change[key] = value
                update_db_fields(unique_id, **keys_to_change)
                return render_template("manage_stream.html",
                                       form=form,
                                       unique_id=unique_id,
                                       update=True)
    else:
        # User does not have access to manage this stream ID.
        return abort(403)
Example #4
0
def generate_stream_key() -> Any:
    form = StreamGenerationForm(request.form)
    server = f"rtmp://{environ.get('RTMP_SERVER')}"
    if request.method == "GET":
        return render_template("generate_stream.html",
                               form=form,
                               server=server)
    else:
        user = discord.fetch_user()
        snowflake = user.id

        keyvar = uuid.uuid4()
        stream_key = str(keyvar)[0:8]
        unique_id = str(keyvar)[24:32]

        if form.validate():
            title = form.title.data
            description = form.description.data
            category = form.category.data
            archivable = form.archivable.data
            unlisted = form.unlisted.data

            add_stream_to_db(
                snowflake,
                title,
                description,
                category,
                archivable,
                unique_id,
                stream_key,
                unlisted,
            )

            return render_template(
                "generate_stream.html",
                form=form,
                user=user,
                key=stream_key,
                id=unique_id,
                unlisted=unlisted,
                server=server,
            )
Example #5
0
def me() -> Text:
    """Render a page to manage stream properties

    Returns:
        Text: Static page rendered by Flask.
    """
    discord_user = discord.fetch_user()
    user = query_one("SELECT * FROM user WHERE snowflake = ?", [discord_user.id])
    streams = query_many(
        "SELECT * FROM stream WHERE user_snowflake = ?", [discord_user.id]
    )
    if streams:
        for stream in streams:
            try:
                duration = stream["end_date"] - stream["start_date"]
                stream["duration"] = str(duration)
            except TypeError:
                continue
            stream["username"] = user["username"]
        return render_template("manage_user.html", user=user, streams=streams)

    return render_template("manage_user.html", user=user)
Example #6
0
def serve_archive(unique_id: str) -> Response:
    """Serves stream from the archive.

    Args:
        unique_id (str): The stream's unique ID.

    Returns:
        Response: File being served by Flask's Response class.
    """
    user = discord.fetch_user()
    stream = query_one(
        "SELECT * FROM stream WHERE archived_file IS NOT NULL AND unique_id = ?",
        [unique_id],
    )
    if user.id == stream["user_snowflake"]:
        # The user requesting the stream created it.
        # Therefore they shall always have access to the file.
        return serve_file(stream)
    elif bool(stream["archivable"]):
        # The stream is publically archived.
        return serve_file(stream)
    else:
        # The stream does not exist.
        return abort(404)