Example #1
0
def external_clips_save(session):
	ext_channel = server.db.metadata.tables["external_channel"]
	ext_vids = server.db.metadata.tables["external_video"]
	if flask.request.values['action'] == "videos":
		# Save video selection
		with server.db.engine.begin() as conn:
			videos = []
			for video in flask.request.values.getlist('selected'):
				chanid, vodid = video.split('-', 1)
				videos.append({
					"channel": int(chanid),
					"vodid": vodid,
				})
			query = insert(ext_vids).on_conflict_do_nothing(index_elements=[ext_vids.c.vodid])
			conn.execute(query, videos)

			conn.execute(ext_vids.delete().where(ext_vids.c.vodid.notin_(v['vodid'] for v in videos)))
		return flask.redirect(flask.url_for('clips_vidlist'), code=303)
	elif flask.request.values['action'] == "add":
		# Add a new channel
		channel = get_user(name=flask.request.values['channel'])
		with server.db.engine.begin() as conn:
			conn.execute(ext_channel.insert(),
				channel=channel.name)
		return flask.redirect(flask.url_for('external_clips'), code=303)
	elif flask.request.values['action'] == "remove":
		channel = int(flask.request.values['channel'])
		with server.db.engine.begin() as conn:
			conn.execute(ext_channel.delete().where(ext_channel.c.id == channel))
		return flask.redirect(flask.url_for('external_clips'), code=303)
	else:
		raise ValueError("Unexpected mode %r" % flask.request.values['action'])
Example #2
0
async def external_clips(session):
	ext_channel = server.db.metadata.tables["external_channel"]
	ext_vids = server.db.metadata.tables["external_video"]
	external_channels = []
	with server.db.engine.begin() as conn:
		for chanid, channel in conn.execute(sqlalchemy.select([ext_channel.c.id, ext_channel.c.channel])):
			external_channels.append({
				'id': chanid,
				'channel': get_user(name=channel),
				'videos': await archive_feed_data(channel, True),
				'selected': set(vid for vid, in conn.execute(
					sqlalchemy.select([ext_vids.c.vodid]).where(ext_vids.c.channel == chanid))),
			})

	return flask.render_template("clips_external.html", session=session, channels=external_channels)
Example #3
0
async def login(return_to=None):
    if 'code' not in flask.request.values:
        if return_to is None:
            return_to = flask.request.values.get('return_to')
        flask.session['login_return_to'] = return_to

        if 'as' in flask.request.values:
            if flask.request.values['as'] not in SPECIAL_USERS:
                return www.utils.error_page("Not a recognised user name: %s" %
                                            flask.request.values['as'])
            scope = SPECIAL_USERS[flask.request.values['as']]
        else:
            scope = REQUEST_SCOPES

        # Generate a random nonce so we can verify that the user who comes back is the same user we sent away
        flask.session['login_nonce'] = uuid.uuid4().hex

        return flask.render_template(
            "login.html",
            clientid=config["twitch_clientid"],
            scope=' '.join(scope),
            redirect_uri=flask.url_for(".login", _external=True),
            nonce=flask.session['login_nonce'],
            session=await load_session(include_url=False))
    else:
        try:
            # Check that we're expecting the user to be logging in...
            expected_nonce = flask.session.pop('login_nonce', None)
            if not expected_nonce:
                raise Exception("Not expecting a login here")

            twitch_state = flask.request.values.get('state', '')
            # We have to pack the "remember me" flag into the state parameter we send via twitch, since that's where the form points... awkward
            if ':' in twitch_state:
                twitch_nonce, remember_me = twitch_state.split(':')
                remember_me = bool(int(remember_me))
            else:
                # User didn't have JS turned on, so remember me option not available
                twitch_nonce = twitch_state
                remember_me = False
            if expected_nonce != twitch_nonce:
                raise Exception("Nonce mismatch: %s vs %s" %
                                (expected_nonce, twitch_nonce))

            # Call back to Twitch to get our access token
            oauth_params = {
                'client_id': config["twitch_clientid"],
                'client_secret': config["twitch_clientsecret"],
                'grant_type': 'authorization_code',
                'redirect_uri': flask.url_for(".login", _external=True),
                'code': flask.request.values['code'],
            }
            res_json = urllib.request.urlopen(
                "https://api.twitch.tv/kraken/oauth2/token",
                urllib.parse.urlencode(oauth_params).encode()).read().decode()
            res_object = flask.json.loads(res_json)
            if not res_object.get('access_token'):
                raise Exception("No access token from Twitch: %s" % res_json)
            access_token = res_object['access_token']
            granted_scopes = res_object["scope"]

            # Use that access token to get basic information about the user
            req = urllib.request.Request("https://api.twitch.tv/kraken/")
            req.add_header("Authorization", "OAuth %s" % access_token)
            req.add_header("Client-ID", config['twitch_clientid'])
            res_json = urllib.request.urlopen(req).read().decode()
            res_object = flask.json.loads(res_json)
            if not res_object.get('token', {}).get('valid'):
                raise Exception("User object not valid: %s" % res_json)
            if not res_object.get('token', {}).get('user_name'):
                raise Exception("No user name from Twitch: %s" % res_json)
            user_name = res_object['token']['user_name'].lower()

            # If one of our special users logged in *without* using the "as" flag,
            # Twitch *might* remember them and give us the same permissions anyway
            # but if not, then we don't have the permissions we need to do our thing
            # so bounce them back to the login page with the appropriate scopes.
            if user_name in SPECIAL_USERS:
                if any(i not in granted_scopes
                       for i in SPECIAL_USERS[user_name]):
                    server.app.logger.error(
                        "User %s has not granted us the required permissions" %
                        user_name)
                    flask.session['login_nonce'] = uuid.uuid4().hex
                    return flask.render_template(
                        "login.html",
                        clientid=config["twitch_clientid"],
                        scope=' '.join(SPECIAL_USERS[user_name]),
                        redirect_uri=flask.url_for(".login", _external=True),
                        nonce=flask.session['login_nonce'],
                        session=await load_session(include_url=False),
                        special_user=user_name,
                        remember_me=remember_me)

            # Store the user to the database
            user = twitch.get_user(user_name)
            user["id"] = user["_id"]
            user["twitch_oauth"] = access_token
            with server.db.engine.begin() as conn:
                query = insert(users)
                query = query.on_conflict_do_update(
                    index_elements=[users.c.id],
                    set_={
                        'name': query.excluded.name,
                        'display_name': query.excluded.display_name,
                    },
                )
                conn.execute(query, user)

            # Store the user ID into the session
            flask.session['id'] = user["_id"]
            flask.session.permanent = remember_me

            return_to = flask.session.pop('login_return_to', None)
            return flask.render_template("login_response.html",
                                         success=True,
                                         return_to=return_to,
                                         session=await
                                         load_session(include_url=False))
        except utils.PASSTHROUGH_EXCEPTIONS:
            raise
        except Exception:
            server.app.logger.exception("Exception in login")
            return flask.render_template("login_response.html",
                                         success=False,
                                         session=await
                                         load_session(include_url=False))
Example #4
0
async def load_session(include_url=True, include_header=True):
    """
	Get the login session information from the cookies.

	Includes all the information needed by the master.html template.
	"""
    user_id = flask.session.get('id')
    user_name = flask.session.get('user')
    if user_id is None and user_name is not None:
        # Upgrade old session
        with server.db.engine.begin() as conn:
            query = insert(users) \
             .values(id=sqlalchemy.bindparam("_id")) \
             .returning(users.c.id)
            query = query.on_conflict_do_update(
                index_elements=[users.c.id],
                set_={
                    'name': query.excluded.name,
                    'display_name': query.excluded.display_name,
                },
            )
            user_id, = conn.execute(query, twitch.get_user(user_name)).first()
        flask.session["id"] = user_id
    if 'user' in flask.session:
        del flask.session["user"]
    if 'apipass' in flask.request.values and flask.request.values[
            'apipass'] in from_apipass:
        user_id = from_apipass[flask.request.values["apipass"]]

    session = {}
    if include_url:
        session['url'] = flask.request.url
    else:
        session['url'] = None
    if include_header:
        session['header'] = await common.rpc.bot.get_header_info()
        if 'current_game' in session['header']:
            games = server.db.metadata.tables["games"]
            shows = server.db.metadata.tables["shows"]
            stats = server.db.metadata.tables["stats"]
            game_per_show_data = server.db.metadata.tables[
                "game_per_show_data"]
            game_stats = server.db.metadata.tables["game_stats"]
            game_votes = server.db.metadata.tables["game_votes"]
            disabled_stats = server.db.metadata.tables["disabled_stats"]
            with server.db.engine.begin() as conn:
                game_id = session['header']['current_game']['id']
                show_id = session['header']['current_show']['id']
                session['header']['current_game']['display'], = conn.execute(
                    sqlalchemy.select([
                        sqlalchemy.func.coalesce(
                            game_per_show_data.c.display_name, games.c.name),
                    ]).select_from(
                        games.outerjoin(
                            game_per_show_data,
                            (game_per_show_data.c.game_id == games.c.id) &
                            (game_per_show_data.c.show_id == show_id))).where(
                                games.c.id == game_id)).first()

                session['header']['current_show']['name'], = conn.execute(
                    sqlalchemy.select([
                        shows.c.name,
                    ]).where(shows.c.id == show_id)).first()

                good = sqlalchemy.cast(
                    sqlalchemy.func.sum(
                        sqlalchemy.cast(game_votes.c.vote,
                                        sqlalchemy.Integer)),
                    sqlalchemy.Numeric)
                rating = conn.execute(
                    sqlalchemy.select([
                        (100 * good /
                         sqlalchemy.func.count(game_votes.c.vote)),
                        good,
                        sqlalchemy.func.count(game_votes.c.vote),
                    ]).where(game_votes.c.game_id == game_id).where(
                        game_votes.c.show_id == show_id)).first()
                if rating[0] is not None and rating[1] is not None:
                    session['header']['current_game']["rating"] = {
                        'perc': rating[0],
                        'good': rating[1],
                        'total': rating[2],
                    }
                stats_query = sqlalchemy.select([
                 game_stats.c.count,
                 game_data.stat_plural(stats, game_stats.c.count)
                ]).select_from(game_stats
                 .join(stats, stats.c.id == game_stats.c.stat_id)
                ).where(game_stats.c.game_id == game_id) \
                 .where(game_stats.c.show_id == show_id) \
                 .where(~sqlalchemy.exists(sqlalchemy.select([1])
                  .where(disabled_stats.c.stat_id == game_stats.c.stat_id)
                  .where(disabled_stats.c.show_id == game_stats.c.show_id)
                 )) \
                 .order_by(game_stats.c.count.desc())
                session['header']['current_game']['stats'] = [{
                    'count': count,
                    'type': type,
                } for count, type in conn.execute(stats_query)]

        if not session['header']['is_live']:
            session['header'][
                'nextstream'] = googlecalendar.get_next_event_text(
                    googlecalendar.CALENDAR_LRL)

    if user_id is not None:
        users = server.db.metadata.tables["users"]
        patreon_users = server.db.metadata.tables["patreon_users"]
        with server.db.engine.begin() as conn:
            query = sqlalchemy.select([
                users.c.name,
                sqlalchemy.func.coalesce(users.c.display_name, users.c.name),
                users.c.twitch_oauth, users.c.is_sub, users.c.is_mod,
                users.c.autostatus, users.c.patreon_user_id
            ]).where(users.c.id == user_id)
            name, display_name, token, is_sub, is_mod, autostatus, patreon_user_id = conn.execute(
                query).first()
            session['user'] = {
                "id": user_id,
                "name": name,
                "display_name": display_name,
                "twitch_oauth": token,
                "is_sub": is_sub,
                "is_mod": is_mod,
                "autostatus": autostatus,
                "patreon_user_id": patreon_user_id,
            }
    else:
        session['user'] = {
            "id": None,
            "name": None,
            "display_name": None,
            "twitch_oauth": None,
            "is_sub": False,
            "is_mod": False,
            "autostatus": False,
        }
    return session
Example #5
0
import common.rpc

with server.db.engine.begin() as conn:
    users = server.db.metadata.tables["users"]
    for key, name in from_apipass.items():
        query = insert(users) \
         .values(id=sqlalchemy.bindparam("_id")) \
         .returning(users.c.id)
        query = query.on_conflict_do_update(
            index_elements=[users.c.id],
            set_={
                'name': query.excluded.name,
                'display_name': query.excluded.display_name,
            },
        )
        from_apipass[key], = conn.execute(query, twitch.get_user(name)).first()

# See https://github.com/justintv/Twitch-API/blob/master/authentication.md#scopes
# We don't actually need, or want, any at present
REQUEST_SCOPES = []

SPECIAL_USERS = {}
SPECIAL_USERS.setdefault(config["username"], []).extend(
    ['chat_login', 'user_read', 'user_follows_edit'])
SPECIAL_USERS.setdefault(config["channel"],
                         []).extend(['channel_subscriptions'])


def with_session(func):
    """
	Pass the current login session information to the function
Example #6
0
async def load_session(include_url=True, include_header=True):
	"""
	Get the login session information from the cookies.

	Includes all the information needed by the master.html template.
	"""
	user_id = flask.session.get('id')
	user_name = flask.session.get('user')
	if user_id is None and user_name is not None:
		# Upgrade old session
		user_id = flask.session["id"] = twitch.get_user(name=user_name).id
	if 'user' in flask.session:
		del flask.session["user"]
	if 'apipass' in flask.request.values and flask.request.values['apipass'] in from_apipass:
		user_id = from_apipass[flask.request.values["apipass"]]

	session = {}
	if include_url:
		session['url'] = flask.request.url
	else:
		session['url'] = None
	if include_header:
		session['header'] = await common.rpc.bot.get_header_info()
		if 'current_game' in session['header']:
			games = server.db.metadata.tables["games"]
			shows = server.db.metadata.tables["shows"]
			game_per_show_data = server.db.metadata.tables["game_per_show_data"]
			with server.db.engine.begin() as conn:
				game_id = session['header']['current_game']['id']
				show_id = session['header']['current_show']['id']
				session['header']['current_game']['display'], = conn.execute(sqlalchemy.select([
					sqlalchemy.func.coalesce(game_per_show_data.c.display_name, games.c.name),
				]).select_from(games
					.outerjoin(game_per_show_data, (game_per_show_data.c.game_id == games.c.id) & (game_per_show_data.c.show_id == show_id))
				).where(games.c.id == game_id)).first()

				session['header']['current_show']['name'], = conn.execute(sqlalchemy.select([
					shows.c.name,
				]).where(shows.c.id == show_id)).first()

		if not session['header']['is_live']:
			session['header']['nextstream'] = googlecalendar.get_next_event_text(googlecalendar.CALENDAR_LRL)

	if user_id is not None:
		user_id = int(user_id)
		users = server.db.metadata.tables["users"]
		patreon_users = server.db.metadata.tables["patreon_users"]
		with server.db.engine.begin() as conn:
			query = sqlalchemy.select([
				users.c.name, sqlalchemy.func.coalesce(users.c.display_name, users.c.name), users.c.twitch_oauth,
				users.c.is_sub, users.c.is_mod, users.c.autostatus, users.c.patreon_user_id,
				users.c.stream_delay, users.c.chat_timestamps, users.c.chat_timestamps_24hr, users.c.chat_timestamps_secs
			]).where(users.c.id == user_id)
			name, display_name, token, is_sub, is_mod, autostatus, patreon_user_id, \
				stream_delay, chat_timestamps, chat_timestamps_24hr, chat_timestamps_secs = conn.execute(query).first()
			session['user'] = {
				"id": user_id,
				"name": name,
				"display_name": display_name,
				"twitch_oauth": token,
				"is_sub": is_sub,
				"is_mod": is_mod,
				"autostatus": autostatus,
				"patreon_user_id": patreon_user_id,
				"stream_delay": stream_delay,
				"chat_timestamps": chat_timestamps,
				"chat_timestamps_24hr": chat_timestamps_24hr,
				"chat_timestamps_secs": chat_timestamps_secs,
			}
	else:
		session['user'] = {
			"id": None,
			"name": None,
			"display_name": None,
			"twitch_oauth": None,
			"is_sub": False,
			"is_mod": False,
			"autostatus": False,
			"stream_delay": 10,
			"chat_timestamps": 0,
			"chat_timestamps_24hr": True,
			"chat_timestamps_secs": False,
		}
	return session
Example #7
0
import flask.json
import sqlalchemy
from sqlalchemy.dialects.postgresql import insert

import www.utils
from www import server
from common.config import config, from_apipass
from common import utils
from common import http
from common import twitch
from common import game_data
from common import googlecalendar
import common.rpc

for key, name in from_apipass.items():
	from_apipass[key] = twitch.get_user(name=name).id

# See https://dev.twitch.tv/docs/v5/guides/authentication/#scopes
# We don't actually need, or want, any at present
REQUEST_SCOPES = []

SPECIAL_USERS = {}
SPECIAL_USERS.setdefault(config["username"], list(REQUEST_SCOPES)).extend(['chat_login', 'user_read', 'user_follows_edit'])
SPECIAL_USERS.setdefault(config["channel"], list(REQUEST_SCOPES)).extend(['channel_subscriptions'])

def with_session(func):
	"""
	Pass the current login session information to the function

	Usage:
	@server.app.route('/path')
Example #8
0
async def load_session(include_url=True, include_header=True):
    """
	Get the login session information from the cookies.

	Includes all the information needed by the master.html template.
	"""
    user_id = flask.session.get('id')
    user_name = flask.session.get('user')
    if user_id is None and user_name is not None:
        # Upgrade old session
        user_id = flask.session["id"] = twitch.get_user(name=user_name).id
    if 'user' in flask.session:
        del flask.session["user"]
    if 'apipass' in flask.request.values and flask.request.values[
            'apipass'] in from_apipass:
        user_id = from_apipass[flask.request.values["apipass"]]

    session = {}
    if include_url:
        session['url'] = flask.request.url
    else:
        session['url'] = None
    if include_header:
        session['header'] = await common.rpc.bot.get_header_info()
        if 'current_game' in session['header']:
            games = server.db.metadata.tables["games"]
            shows = server.db.metadata.tables["shows"]
            game_per_show_data = server.db.metadata.tables[
                "game_per_show_data"]
            with server.db.engine.begin() as conn:
                game_id = session['header']['current_game']['id']
                show_id = session['header']['current_show']['id']
                session['header']['current_game']['display'], = conn.execute(
                    sqlalchemy.select([
                        sqlalchemy.func.coalesce(
                            game_per_show_data.c.display_name, games.c.name),
                    ]).select_from(
                        games.outerjoin(
                            game_per_show_data,
                            (game_per_show_data.c.game_id == games.c.id) &
                            (game_per_show_data.c.show_id == show_id))).where(
                                games.c.id == game_id)).first()

                session['header']['current_show']['name'], = conn.execute(
                    sqlalchemy.select([
                        shows.c.name,
                    ]).where(shows.c.id == show_id)).first()

        if not session['header']['is_live']:
            session['header'][
                'nextstream'] = googlecalendar.get_next_event_text(
                    googlecalendar.CALENDAR_LRL)

    if user_id is not None:
        user_id = int(user_id)
        users = server.db.metadata.tables["users"]
        patreon_users = server.db.metadata.tables["patreon_users"]
        with server.db.engine.begin() as conn:
            query = sqlalchemy.select([
                users.c.name,
                sqlalchemy.func.coalesce(users.c.display_name, users.c.name),
                users.c.twitch_oauth, users.c.is_sub, users.c.is_mod,
                users.c.autostatus, users.c.patreon_user_id,
                users.c.stream_delay, users.c.chat_timestamps,
                users.c.chat_timestamps_24hr, users.c.chat_timestamps_secs
            ]).where(users.c.id == user_id)
            name, display_name, token, is_sub, is_mod, autostatus, patreon_user_id, \
             stream_delay, chat_timestamps, chat_timestamps_24hr, chat_timestamps_secs = conn.execute(query).first()
            session['user'] = {
                "id": user_id,
                "name": name,
                "display_name": display_name,
                "twitch_oauth": token,
                "is_sub": is_sub,
                "is_mod": is_mod,
                "autostatus": autostatus,
                "patreon_user_id": patreon_user_id,
                "stream_delay": stream_delay,
                "chat_timestamps": chat_timestamps,
                "chat_timestamps_24hr": chat_timestamps_24hr,
                "chat_timestamps_secs": chat_timestamps_secs,
            }
    else:
        session['user'] = {
            "id": None,
            "name": None,
            "display_name": None,
            "twitch_oauth": None,
            "is_sub": False,
            "is_mod": False,
            "autostatus": False,
            "stream_delay": 10,
            "chat_timestamps": 0,
            "chat_timestamps_24hr": True,
            "chat_timestamps_secs": False,
        }
    return session
Example #9
0
import flask.json
import sqlalchemy
from sqlalchemy.dialects.postgresql import insert

import www.utils
from www import server
from common.config import config, from_apipass
from common import utils
from common import http
from common import twitch
from common import game_data
from common import googlecalendar
import common.rpc

for key, name in from_apipass.items():
    from_apipass[key] = twitch.get_user(name=name).id

# See https://dev.twitch.tv/docs/v5/guides/authentication/#scopes
# We don't actually need, or want, any at present
REQUEST_SCOPES = []

SPECIAL_USERS = {}
SPECIAL_USERS.setdefault(config["username"], list(REQUEST_SCOPES)).extend(
    ['chat_login', 'user_read', 'user_follows_edit'])
SPECIAL_USERS.setdefault(config["channel"], list(REQUEST_SCOPES)).extend(
    ['channel_subscriptions'])


def with_session(func):
    """
	Pass the current login session information to the function
Example #10
0
async def login(return_to=None):
	if 'code' not in flask.request.values:
		if return_to is None:
			return_to = flask.request.values.get('return_to')
		flask.session['login_return_to'] = return_to

		if 'as' in flask.request.values:
			if flask.request.values['as'] not in SPECIAL_USERS:
				return www.utils.error_page("Not a recognised user name: %s" % flask.request.values['as'])
			scope = SPECIAL_USERS[flask.request.values['as']]
		else:
			scope = REQUEST_SCOPES

		# Generate a random nonce so we can verify that the user who comes back is the same user we sent away
		flask.session['login_nonce'] = uuid.uuid4().hex

		return flask.render_template("login.html", clientid=config["twitch_clientid"], scope=' '.join(scope), redirect_uri=REDIRECT_URI, nonce=flask.session['login_nonce'], session=await load_session(include_url=False))
	else:
		try:
			# Check that we're expecting the user to be logging in...
			expected_nonce = flask.session.pop('login_nonce', None)
			if not expected_nonce:
				raise Exception("Not expecting a login here")

			twitch_state = flask.request.values.get('state', '')
			# We have to pack the "remember me" flag into the state parameter we send via twitch, since that's where the form points... awkward
			if ':' in twitch_state:
				twitch_nonce, remember_me = twitch_state.split(':')
				remember_me = bool(int(remember_me))
			else:
				# User didn't have JS turned on, so remember me option not available
				twitch_nonce = twitch_state
				remember_me = False
			if expected_nonce != twitch_nonce:
				raise Exception("Nonce mismatch: %s vs %s" % (expected_nonce, twitch_nonce))

			# Call back to Twitch to get our access token
			oauth_params = {
				'client_id': config["twitch_clientid"],
				'client_secret': config["twitch_clientsecret"],
				'grant_type': 'authorization_code',
				'redirect_uri': REDIRECT_URI,
				'code': flask.request.values['code'],
			}
			res_json = urllib.request.urlopen("https://api.twitch.tv/kraken/oauth2/token", urllib.parse.urlencode(oauth_params).encode()).read().decode()
			res_object = flask.json.loads(res_json)
			if not res_object.get('access_token'):
				raise Exception("No access token from Twitch: %s" % res_json)
			access_token = res_object['access_token']
			granted_scopes = res_object["scope"]

			# Use that access token to get basic information about the user
			req = urllib.request.Request("https://api.twitch.tv/kraken/")
			req.add_header("Authorization", "OAuth %s" % access_token)
			res_json = urllib.request.urlopen(req).read().decode()
			res_object = flask.json.loads(res_json)
			if not res_object.get('token', {}).get('valid'):
				raise Exception("User object not valid: %s" % res_json)
			if not res_object.get('token', {}).get('user_name'):
				raise Exception("No user name from Twitch: %s" % res_json)
			user_name = res_object['token']['user_name'].lower()

			# If one of our special users logged in *without* using the "as" flag,
			# Twitch *might* remember them and give us the same permissions anyway
			# but if not, then we don't have the permissions we need to do our thing
			# so bounce them back to the login page with the appropriate scopes.
			if user_name in SPECIAL_USERS:
				if any(i not in granted_scopes for i in SPECIAL_USERS[user_name]):
					server.app.logger.error("User %s has not granted us the required permissions" % user_name)
					flask.session['login_nonce'] = uuid.uuid4().hex
					return flask.render_template("login.html", clientid=config["twitch_clientid"], scope=' '.join(SPECIAL_USERS[user_name]), redirect_uri=REDIRECT_URI, nonce=flask.session['login_nonce'], session=await load_session(include_url=False), special_user=user_name, remember_me=remember_me)

			# Store the user to the database
			user = twitch.get_user(user_name)
			user["id"] = user["_id"]
			user["twitch_oauth"] = access_token
			with server.db.engine.begin() as conn:
				conn.execute(users.insert(postgresql_on_conflict="update"), user)

			# Store the user ID into the session
			flask.session['id'] = user["_id"]
			flask.session.permanent = remember_me

			return_to = flask.session.pop('login_return_to', None)
			return flask.render_template("login_response.html", success=True, return_to=return_to, session=await load_session(include_url=False))
		except utils.PASSTHROUGH_EXCEPTIONS:
			raise
		except Exception:
			server.app.logger.exception("Exception in login")
			return flask.render_template("login_response.html", success=False, session=await load_session(include_url=False))
Example #11
0
async def load_session(include_url=True, include_header=True):
	"""
	Get the login session information from the cookies.

	Includes all the information needed by the master.html template.
	"""
	user_id = flask.session.get('id')
	user_name = flask.session.get('user')
	if user_id is None and user_name is not None:
		# Upgrade old session
		with server.db.engine.begin() as conn:
			user_id, = conn.execute(
				users.insert(postgresql_on_conflict="update")
					.values(id=sqlalchemy.bindparam("_id"))
					.returning(users.c.id),
				twitch.get_user(user_name)
			).first()
		flask.session["id"] = user_id
	if 'user' in flask.session:
		del flask.session["user"]
	if 'apipass' in flask.request.values and flask.request.values['apipass'] in from_apipass:
		user_id = from_apipass[flask.request.values["apipass"]]

	session = {}
	if include_url:
		session['url'] = flask.request.url
	else:
		session['url'] = None
	if include_header:
		session['header'] = await common.rpc.bot.get_header_info()
		if 'current_game' in session['header']:
			games = server.db.metadata.tables["games"]
			shows = server.db.metadata.tables["shows"]
			stats = server.db.metadata.tables["stats"]
			game_per_show_data = server.db.metadata.tables["game_per_show_data"]
			game_stats = server.db.metadata.tables["game_stats"]
			game_votes = server.db.metadata.tables["game_votes"]
			disabled_stats = server.db.metadata.tables["disabled_stats"]
			with server.db.engine.begin() as conn:
				game_id = session['header']['current_game']['id']
				show_id = session['header']['current_show']['id']
				session['header']['current_game']['display'], = conn.execute(sqlalchemy.select([
					sqlalchemy.func.coalesce(game_per_show_data.c.display_name, games.c.name),
				]).select_from(games
					.outerjoin(game_per_show_data, (game_per_show_data.c.game_id == games.c.id) & (game_per_show_data.c.show_id == show_id))
				).where(games.c.id == game_id)).first()

				session['header']['current_show']['name'], = conn.execute(sqlalchemy.select([
					shows.c.name,
				]).where(shows.c.id == show_id)).first()

				good = sqlalchemy.cast(
					sqlalchemy.func.sum(sqlalchemy.cast(game_votes.c.vote, sqlalchemy.Integer)),
					sqlalchemy.Numeric
				)
				rating = conn.execute(sqlalchemy.select([
					(100 * good / sqlalchemy.func.count(game_votes.c.vote)),
					good,
					sqlalchemy.func.count(game_votes.c.vote),
				]).where(game_votes.c.game_id == game_id).where(game_votes.c.show_id == show_id)).first()
				if rating[0] is not None and rating[1] is not None:
					session['header']['current_game']["rating"] = {
						'perc': rating[0],
						'good': rating[1],
						'total': rating[2],
					}
				stats_query = sqlalchemy.select([
					game_stats.c.count,
					game_data.stat_plural(stats, game_stats.c.count)
				]).select_from(game_stats
					.join(stats, stats.c.id == game_stats.c.stat_id)
				).where(game_stats.c.game_id == game_id) \
					.where(game_stats.c.show_id == show_id) \
					.where(~sqlalchemy.exists(sqlalchemy.select([1])
						.where(disabled_stats.c.stat_id == game_stats.c.stat_id)
						.where(disabled_stats.c.show_id == game_stats.c.show_id)
					)) \
					.order_by(game_stats.c.count.desc())
				session['header']['current_game']['stats'] = [
					{
						'count': count,
						'type': type,
					}
					for count, type in conn.execute(stats_query)
				]

	if user_id is not None:
		users = server.db.metadata.tables["users"]
		patreon_users = server.db.metadata.tables["patreon_users"]
		with server.db.engine.begin() as conn:
			query = sqlalchemy.select([
				users.c.name, sqlalchemy.func.coalesce(users.c.display_name, users.c.name), users.c.twitch_oauth,
				users.c.is_sub, users.c.is_mod, users.c.autostatus, users.c.patreon_user
			]).where(users.c.id == user_id)
			name, display_name, token, is_sub, is_mod, autostatus, patreon_user = conn.execute(query).first()
			session['user'] = {
				"id": user_id,
				"name": name,
				"display_name": display_name,
				"twitch_oauth": token,
				"is_sub": is_sub,
				"is_mod": is_mod,
				"autostatus": autostatus,
				"patreon_user": patreon_user,
			}
	else:
		session['user'] = {
			"id": None,
			"name": None,
			"display_name": None,
			"twitch_oauth": None,
			"is_sub": False,
			"is_mod": False,
			"autostatus": False,
		}
	return session
Example #12
0
import www.utils
from www import server
from common.config import config, from_apipass
from common import utils
from common import twitch
from common import game_data
import common.rpc

with server.db.engine.begin() as conn:
	users = server.db.metadata.tables["users"]
	from_apipass = {
		key: conn.execute(
				users.insert(postgresql_on_conflict="update")
					.values(id=sqlalchemy.bindparam("_id"))
					.returning(users.c.id),
			twitch.get_user(name)
		).first()[0]
		for key, name in from_apipass.items()
	}

# See https://github.com/justintv/Twitch-API/blob/master/authentication.md#scopes
# We don't actually need, or want, any at present
REQUEST_SCOPES = []

SPECIAL_USERS = {
	config["username"]: ['chat_login', 'user_read', 'user_follows_edit'],
	config["channel"]: ['channel_subscriptions'],
}

# Needs to be the URI of this script, and also the registered URI for the app
REDIRECT_URI = 'https://lrrbot.mrphlip.com/login'
Example #13
0
import www.utils
from www import server
from common.config import config, from_apipass
from common import utils
from common import twitch
from common import game_data
import common.rpc

with server.db.engine.begin() as conn:
    users = server.db.metadata.tables["users"]
    from_apipass = {
        key: conn.execute(
            users.insert(postgresql_on_conflict="update").values(
                id=sqlalchemy.bindparam("_id")).returning(users.c.id),
            twitch.get_user(name)).first()[0]
        for key, name in from_apipass.items()
    }

# See https://github.com/justintv/Twitch-API/blob/master/authentication.md#scopes
# We don't actually need, or want, any at present
REQUEST_SCOPES = []

SPECIAL_USERS = {
    config["username"]: ['chat_login', 'user_read', 'user_follows_edit'],
    config["channel"]: ['channel_subscriptions'],
}

# Needs to be the URI of this script, and also the registered URI for the app
REDIRECT_URI = 'https://lrrbot.mrphlip.com/login'
#REDIRECT_URI = 'http://localhost:5000/login'