class Pagination_handler(Handler): __arguments_schema__ = good.Schema({ 'per_page': good.Any( good.All( [good.All(good.Coerce(int), good.Range(min=1))], good.Length(max=1), ), good.Default([constants.PER_PAGE]) ), 'page': good.Any( good.All( [good.All(good.Coerce(int), good.Range(min=1))], good.Length(max=1), ), good.Default([1]) ), }, default_keys=good.Required, extra_keys=good.Allow,) def get(self, *args, **kwargs): args = self.validate_arguments(Pagination_handler.__arguments_schema__) self.per_page = args.pop('per_page', [0])[0] self.page = args.pop('page', [0])[0] self.request.arguments.pop('per_page', None) self.request.arguments.pop('page', None)
class Handler(base.Handler): __schema__ = good.Schema( { 'subtitle_lang': good.Maybe(good.All(good.Lower(), good.Length(min=1, max=20))), 'audio_lang': good.Maybe(good.All(good.Lower(), good.Length(min=1, max=20))) }, default_keys=good.Optional) @authenticated(constants.LEVEL_USER) def get(self, show_id): data = models.User_show_subtitle_lang.get( user_id=self.current_user.id, show_id=show_id, ) if data: self.write_object(data) else: self.set_status(204) @authenticated(constants.LEVEL_USER) async def put(self, show_id): await self._put(show_id) self.set_status(204) @run_on_executor def _put(self, show_id): data = self.validate() with new_session() as session: d = models.User_show_subtitle_lang( user_id=self.current_user.id, show_id=show_id, subtitle_lang=data.get('subtitle_lang', None), audio_lang=data.get('audio_lang', None), ) session.merge(d) session.commit() @authenticated(constants.LEVEL_USER) async def patch(self, show_id): await self._patch(show_id) self.set_status(204) @run_on_executor def _patch(self, show_id): data = self.validate() with new_session() as session: d = models.User_show_subtitle_lang( user_id=self.current_user.id, show_id=show_id, ) if 'subtitle_lang' in data: d.subtitle_lang = data['subtitle_lang'] if 'audio_lang' in data: d.audio_lang = data['audio_lang'] session.merge(d) session.commit()
class Collection_handler(base.Handler): __schema__ = good.Schema({ 'name': good.All( str, good.Length(min=1, max=45), good.Match(re.compile(r'^[a-z0-9-_]+$', re.I), message='must only contain a-z, 0-9, _ and -')), 'email': good.All(str, good.Length(min=1, max=100), schemas.validate_email), 'password': good.All(str, good.Length(min=6)), }) async def get(self): users = await self.get_users() self.write_object(users) async def post(self, user_id=None): if user_id: raise exceptions.Parameter_restricted('user_id must not be set.') user = await self.create() self.set_status(201) self.write_object(user) @run_on_executor def get_users(self): username = self.get_argument('username') with new_session() as session: user = session.query(models.User).filter( models.User.name == username, ).first() if user: return [self.user_wrapper(user.serialize())] return [] @run_on_executor def create(self): user = self.validate() with new_session() as session: u = session.query(models.User.id).filter( models.User.email == user['email']).first() if u: raise exceptions.User_email_duplicate() u = session.query(models.User.id).filter( models.User.name == user['name']).first() if u: raise exceptions.User_username_duplicate() user = models.User( name=user['name'], email=user['email'], password=pbkdf2_sha256.encrypt(user['password']), ) session.add(user) session.commit() return user.serialize()
class Slots_handler(Api_handler): __schema__ = good.Schema({ 'emote_pool_size': good.All(good.Coerce(int), good.Range(min=2)), 'payout_percent': good.All(good.Coerce(int), good.Range(min=1)), 'min_bet': good.All(good.Coerce(int), good.Range(min=1)), 'max_bet': good.All(good.Coerce(int), good.Range(min=0)), 'emotes': [str], 'win_message': good.All(good.Coerce(str), good.Length(min=1, max=250)), 'allin_win_message': good.All(good.Coerce(str), good.Length(min=1, max=250)), 'lose_message': good.All(good.Coerce(str), good.Length(min=1, max=250)), 'allin_lose_message': good.All(good.Coerce(str), good.Length(min=1, max=250)), }) async def get(self, channel_id): settings = await self.db.fetchone( 'select * from twitch_gambling_slots_settings where channel_id=%s', (channel_id), ) if not settings: self.set_status(204) else: settings.pop('channel_id') settings['emotes'] = json.loads(settings['emotes']) self.write_object(settings) @Level(3) async def put(self, channel_id): data = self.validate() if 'emotes' in data: data['emotes'] = json.dumps(data['emotes']) fields = ','.join([f for f in data]) values = ','.join(['%s' for f in data]) dup = ','.join([f'{f}=VALUES({f})' for f in data]) await self.db.execute( f''' INSERT INTO twitch_gambling_slots_settings (channel_id, {fields}) VALUES (%s, {values}) ON DUPLICATE KEY UPDATE {dup} ''', ( channel_id, *data.values(), )) self.set_status(204)
class Handler(Api_handler): __schema__ = good.Schema({ 'message': good.All(str, good.Length(min=1, max=500)), 'webhook_url': good.Any(good.Url('https'), good.All(str, good.Length(max=0))), }) @Level(3) async def get(self, channel_id): r = await self.db.fetchone( 'SELECT webhook_url, message FROM twitch_discord_live_notification WHERE channel_id=%s', (channel_id, )) if not r: self.set_status(204) else: self.write_object({ 'webhook_url': r['webhook_url'], 'message': r['message'], }) @Level(3) async def put(self, channel_id): data = self.validate() r = await self.db.fetchone( 'SELECT webhook_url, message FROM twitch_discord_live_notification WHERE channel_id=%s', (channel_id, )) if not r: await self.db.execute( ''' INSERT INTO twitch_discord_live_notification (channel_id, webhook_url, message) VALUES (%s, %s, %s); ''', ( channel_id, data['webhook_url'], data['message'], )) else: await self.db.execute( ''' UPDATE twitch_discord_live_notification SET webhook_url=%s, message=%s WHERE channel_id=%s ''', ( data['webhook_url'], data['message'], channel_id, ))
class Handler(Api_handler): __schema__ = good.Schema({ str: [{ 'message': good.All(str, good.Length(min=0, max=200)), good.Optional('min_amount'): good.All(good.Coerce(int), good.Range(min=0, max=1000)), }], }, default_keys=good.Optional) @Level(1) async def get(self, channel_id): alerts = await self.db.fetchall( 'SELECT type, message, min_amount FROM twitch_chat_alerts WHERE channel_id=%s', (channel_id,) ) grouped_alerts = {} for a in alerts: l = grouped_alerts.setdefault(a['type'], []) l.append({ 'message': a['message'], 'min_amount': a['min_amount'] or 0, }) self.write_object(grouped_alerts) @Level(1) async def put(self, channel_id): data = self.validate() for key in data: ins = [] for d in data[key]: if d['message']: ins.append(( channel_id, key, d['message'], d.get('min_amount', 0), )) await self.db.execute( 'DELETE FROM twitch_chat_alerts WHERE channel_id=%s AND type=%s;', (channel_id, key,) ) if ins: await self.db.executemany(''' INSERT INTO twitch_chat_alerts (channel_id, type, message, min_amount) VALUES (%s, %s, %s, %s) ''', ins ) await self.get(channel_id)
class Banned_words_handler(Api_handler): __schema__ = good.Schema({ 'banned_words': good.All(str, good.Length(min=1, max=1000)), }) @Level(1) async def post(self, channel_id, filter_id): d = self.validate() c = await self.db.execute(''' INSERT INTO twitch_filter_banned_words (channel_id, filter_id, banned_words) VALUES (%s, %s, %s) ''', (channel_id, filter_id, d['banned_words'])) r = await self.redis.publish_json( 'tbot:server:commands', ['reload_filter_banned_words', channel_id, filter_id] ) self.set_status(201) self.write_object({ 'id': c.lastrowid, 'banned_words': d['banned_words'], }) @Level(1) async def put(self, channel_id, filter_id, id_): d = self.validate() await self.db.execute(''' UPDATE twitch_filter_banned_words SET banned_words=%s WHERE id=%s and channel_id=%s and filter_id=%s ''', (d['banned_words'], id_, channel_id, filter_id,)) r = await self.redis.publish_json( 'tbot:server:commands', ['reload_filter_banned_words', channel_id, filter_id] ) self.set_status(204) @Level(1) async def delete(self, channel_id, filter_id, id_): await self.db.execute(''' DELETE FROM twitch_filter_banned_words WHERE id=%s and channel_id=%s and filter_id=%s ''', (id_, channel_id, filter_id,)) r = await self.redis.publish_json( 'tbot:server:commands', ['reload_filter_banned_words', channel_id, filter_id] ) self.set_status(204)
class Change_password_handler(base.Handler): __schema__ = good.Schema({ 'password': str, 'new_password': good.All(str, good.Length(min=6)), }) @authenticated(constants.LEVEL_USER) async def post(self, user_id=None): user_id = user_id if user_id else self.current_user.id self.check_user_edit(user_id) await self.change_password(user_id) self.set_status(204) @run_on_executor def change_password(self, user_id): data = self.validate() if not models.User.login(int(user_id), data['password']): raise exceptions.Wrong_email_or_password_exception() with new_session() as session: models.User.change_password( user_id=user_id, new_password=data['new_password'], session=session, ) tokens = session.query(models.Token).filter( models.Token.user_id == user_id, or_( models.Token.expires >= datetime.utcnow(), models.Token.expires == None, )).all() for token in tokens: if token.token == self.access_token: continue session.delete(token) session.commit()
class Channel_admins(Api_handler): __schema__ = good.Schema({ 'user': good.All(str, good.Length(min=4, max=25)), 'level': good.All(good.Coerce(int), good.Range(min=1, max=3)), }) __update_schema__ = good.Schema({ 'level': good.All(good.Coerce(int), good.Range(min=1, max=3)), }) @Level(3) async def get(self, channel_id): admins = await self.db.fetchall( ''' SELECT user_id as id, user as name, level FROM twitch_channel_admins WHERE channel_id=%s ORDER BY level DESC ''', (channel_id, )) self.write_object(admins) @Level(3) async def post(self, channel_id): data = self.validate() url = 'https://api.twitch.tv/helix/users' users = await twitch_request(self.ahttp, url, { 'login': data['user'], }) if not users['data']: raise Api_exception(400, 'User does not exist on Twitch') user = users['data'][0] await self.db.execute( ''' INSERT INTO twitch_channel_admins (channel_id, user_id, user, level, created_at, updated_at) VALUES (%s, %s, %s, %s, now(), now()) ON DUPLICATE KEY UPDATE user=VALUES(user), level=VALUES(level), updated_at=VALUES(updated_at) ''', (channel_id, user['id'], user['display_name'], data['level'])) self.set_status(204) @Level(3) async def put(self, channel_id, user_id): data = self.validate(self.__update_schema__) await self.db.execute( 'UPDATE twitch_channel_admins SET level=%s WHERE channel_id=%s AND user_id=%s', (data['level'], channel_id, user_id)) @Level(3) async def delete(self, channel_id, user_id): await self.db.execute( 'DELETE FROM twitch_channel_admins WHERE channel_id=%s AND user_id=%s', (channel_id, user_id)) self.set_status(204)
good.Optional('user_level'): good.All(good.Coerce(int), good.Range(min=0, max=9)), good.Optional('enabled_status'): good.All(good.Coerce(int), good.Range(min=0, max=2)), good.Optional('global_cooldown'): good.All(good.Coerce(int), good.Range(min=0, max=86400)), good.Optional('user_cooldown'): good.All(good.Coerce(int), good.Range(min=0, max=86400)), good.Optional('mod_cooldown'): good.All(good.Coerce(int), good.Range(min=0, max=86400)), good.Optional('enabled'): good.All(good.Coerce(int), good.Range(min=0, max=1)), good.Optional('public'): good.All(good.Coerce(int), good.Range(min=0, max=1)), good.Optional('group_name'): good.Maybe(good.All(str, good.Length(min=0, max=50))), } class Collection_handler(Api_handler): __schema__ = good.Schema(_schema, default_keys=good.Required) @Level(1) async def get(self, channel_id): cmds = await self.db.fetchall( ''' SELECT * FROM twitch_commands WHERE channel_id=%s ORDER BY updated_at DESC
import good import sqlalchemy as sa from seplis.api.handlers import base from seplis.api.decorators import authenticated, new_session, run_on_executor from seplis.api import exceptions, constants, models from seplis import schemas _schema = { 'name': good.All(str, good.Length(min=1, max=45)), 'url': good.All(str, good.Length(min=1, max=200)), 'secret': good.All(str, good.Length(min=1, max=200)), } class Handler(base.Handler): '''Edit a play server. The user must be the owner.''' __schema__ = good.Schema(_schema, default_keys=good.Optional) @authenticated(0) async def get(self, id_): server = await self._get(id_) self.write_object(server) @authenticated(0) async def put(self, id_): ps = await self._put(id_) self.write_object(ps) @authenticated(0) async def delete(self, id_):
import logging, good, asyncio from ..base import Api_handler, Level, Api_exception from tbot import config, utils from datetime import datetime, timedelta __schema__ = { 'name': good.All(str, good.Length(min=1, max=100)), 'messages': good.All([good.All(str, good.Length(min=1, max=500))], good.Length(min=1, max=100)), good.Optional('enabled'): good.All(good.Coerce(int), good.Range(min=0, max=1)), good.Optional('enabled_status'): good.All(good.Coerce(int), good.Range(min=0, max=2)), good.Optional('interval'): good.All(good.Coerce(int), good.Range(min=1, max=10080)), good.Optional('send_message_order'): good.All(good.Coerce(int), good.Range(min=1, max=2)), } class Handler(Api_handler): __schema__ = good.Schema(__schema__, default_keys=good.Optional) @Level(1) async def put(self, channel_id, id_): data = self.validate() data['updated_at'] = datetime.utcnow() if 'interval' in data: data['next_run'] = datetime.utcnow()+timedelta(minutes=data['interval']) if 'messages' in data: data['messages'] = utils.json_dumps(data['messages']) fields = ', '.join(['`{}`=%s'.format(k) for k in data]) values = list(data.values()) values.append(channel_id) values.append(id_) await self.db.execute(
'url': good.Maybe(str), }, default_keys=good.Optional) _Episode_schema = { 'title': good.Maybe(str), good.Required('number'): good.All(good.Coerce(int), good.Range(min=1)), good.Optional('season'): good.Maybe(good.All(good.Coerce(int), good.Range(min=1))), good.Optional('episode'): good.Maybe(good.All(good.Coerce(int), good.Range(min=1))), 'air_date': good.Maybe(date_()), 'air_time': good.Maybe(time_()), 'air_datetime': good.Maybe(iso8601_to_utc()), 'description': good.Any(None, Description_schema), 'runtime': good.Maybe(good.Coerce(int)), } Episode_schema = good.Schema(_Episode_schema, default_keys=good.Optional) External_schema = good.Schema({ good.All(good.Length(min=1, max=45)):good.Any(None, good.All(good.Coerce(str), good.Length(min=1, max=45))) }, default_keys=good.Optional) Importer_schema = good.Schema( {key: good.Maybe(good.All(str, good.Length(min=1, max=45))) \ for key in constants.IMPORTER_TYPE_NAMES}, default_keys=good.Optional, ) _Show_schema = { 'title': good.Maybe(str), 'description': good.Maybe(Description_schema), 'premiered': good.Maybe(date_()), 'ended': good.Maybe(date_()), good.Optional('episodes'): [Episode_schema], 'externals': good.Any(None, External_schema), 'importers': good.Any(None, Importer_schema), 'status': good.Coerce(int),
class Points_settings_handler(Api_handler): __schema__ = good.Schema({ 'enabled': good.Boolean(), 'points_name': good.All(str, good.Length(min=1, max=45)), 'points_per_min': good.All(good.Coerce(int), good.Range(min=0)), 'points_per_min_sub_multiplier': good.All(good.Coerce(int), good.Range(min=0)), 'points_per_sub': good.All(good.Coerce(int), good.Range(min=0)), 'points_per_cheer': good.All(good.Coerce(int), good.Range(min=0)), 'ignore_users': [str], }) async def get(self, channel_id): settings = await self.db.fetchone( 'select * from twitch_channel_point_settings where channel_id=%s', (channel_id), ) if not settings: self.set_status(204) else: self.write_object({ 'enabled': True if settings['enabled'] == 1 else False, 'points_name': settings['points_name'], 'points_per_min': settings['points_per_min'], 'points_per_min_sub_multiplier': settings['points_per_min_sub_multiplier'], 'points_per_sub': settings['points_per_sub'], 'points_per_cheer': settings['points_per_cheer'], 'ignore_users': json.loads(settings['ignore_users']), }) @Level(3) async def put(self, channel_id): data = self.validate() if 'ignore_users' in data: data['ignore_users'] = json.dumps(data['ignore_users']) fields = ','.join([f for f in data]) values = ','.join(['%s' for f in data]) dup = ','.join([f'{f}=VALUES({f})' for f in data]) await self.db.execute( f''' INSERT INTO twitch_channel_point_settings (channel_id, {fields}) VALUES (%s, {values}) ON DUPLICATE KEY UPDATE {dup} ''', ( channel_id, *data.values(), )) self.set_status(204)
def Length(min=None, max=None, msg=None): return _wrapMsg(good.Length(min, max), msg)
class Handler(base.Handler): __schema__ = good.Schema({ 'key': str, 'new_password': good.All(str, good.Length(min=6)), }) __arguments_schema__ = good.Schema({ 'email': [str], }) async def get(self): args = self.validate_arguments() user_id = await self.get_user_id(args['email'][0]) if not user_id: self.set_status(204) return smtp = aiosmtplib.SMTP( hostname=config['smtp']['server'], port=int(config['smtp']['port']), use_tls=config['smtp']['use_tls'], loop=self.application.ioloop, ) await smtp.connect() if config['smtp']['user']: await smtp.login(config['smtp']['user'], config['smtp']['password']) url = await self.create_reset_url(user_id) message = MIMEText(''' <html> <body> Reset your SEPLIS password here: <a href="{0}">{0}</a> </body> </html> '''.format(url), 'html') message["From"] = config['smtp']['from'] message["To"] = args['email'][0] message["Subject"] = "Reset password" await smtp.send_message(message) self.set_status(204) async def post(self): await self.reset() self.set_status(204) @run_on_executor def get_user_id(self, email): with new_session() as session: u = session.query(models.User.id).filter( models.User.email == email, ).first() if u: return u.id @run_on_executor def create_reset_url(self, user_id): with new_session() as session: r = models.Reset_password( user_id=user_id, ) session.add(r) session.commit() return config['web']['url'] + '/reset-password/{}'.format(r.key) @run_on_executor def reset(self): data = self.validate() with new_session() as session: r = session.query(models.Reset_password.user_id).filter( models.Reset_password.key == data['key'], models.Reset_password.expires >= datetime.utcnow(), ).first() if not r: raise exceptions.Forbidden('Invalid reset key') session.query(models.Reset_password).filter( models.Reset_password.user_id == r.user_id, ).delete() user_id = r.user_id models.User.change_password( user_id=user_id, new_password=data['new_password'], session=session, ) tokens = session.query(models.Token).filter( models.Token.user_id == user_id, sa.or_( models.Token.expires >= datetime.utcnow(), models.Token.expires == None, ) ).all() for token in tokens: if token.token == self.access_token: continue session.delete(token) session.commit()