From a9bdbf800c12ef2a6c6180c739f6d03f425163ec Mon Sep 17 00:00:00 2001 From: Sleepingpirates <32914211+Sleepingpirates@users.noreply.github.com> Date: Wed, 17 Jun 2020 21:23:10 -0400 Subject: [PATCH] Add files via upload --- Dockerfile | 7 ++ app/app/__init__.py | 19 ++++ app/app/bot/Invitarr.py | 194 ++++++++++++++++++++++++++++++++++ app/app/bot/db.py | 83 +++++++++++++++ app/app/configHandler.py | 56 ++++++++++ app/app/forms.py | 52 +++++++++ app/app/models.py | 15 +++ app/app/routes.py | 120 +++++++++++++++++++++ app/app/static/favicon.ico | Bin 0 -> 12059 bytes app/app/static/img/logo.svg | 45 ++++++++ app/app/static/main.css | 86 +++++++++++++++ app/app/templates/bot.html | 194 ++++++++++++++++++++++++++++++++++ app/app/templates/index.html | 131 +++++++++++++++++++++++ app/app/templates/layout.html | 42 ++++++++ app/app/templates/login.html | 105 ++++++++++++++++++ app/app/templates/plex.html | 155 +++++++++++++++++++++++++++ app/requirements.txt | 33 ++++++ app/run.py | 17 +++ app/setup.py | 14 +++ app/uwsgi.ini | 4 + 20 files changed, 1372 insertions(+) create mode 100644 Dockerfile create mode 100644 app/app/__init__.py create mode 100644 app/app/bot/Invitarr.py create mode 100644 app/app/bot/db.py create mode 100644 app/app/configHandler.py create mode 100644 app/app/forms.py create mode 100644 app/app/models.py create mode 100644 app/app/routes.py create mode 100644 app/app/static/favicon.ico create mode 100644 app/app/static/img/logo.svg create mode 100644 app/app/static/main.css create mode 100644 app/app/templates/bot.html create mode 100644 app/app/templates/index.html create mode 100644 app/app/templates/layout.html create mode 100644 app/app/templates/login.html create mode 100644 app/app/templates/plex.html create mode 100644 app/requirements.txt create mode 100644 app/run.py create mode 100644 app/setup.py create mode 100644 app/uwsgi.ini diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9918e0d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine +RUN apk update && apk add gcc libc-dev make git libffi-dev openssl-dev python3-dev libxml2-dev libxslt-dev +ENV LISTEN_PORT 5001 +EXPOSE 5001 +COPY ./app /app +RUN pip install -r requirements.txt && python3 setup.py +ENV STATIC_PATH /app/app/static diff --git a/app/app/__init__.py b/app/app/__init__.py new file mode 100644 index 0000000..82a6914 --- /dev/null +++ b/app/app/__init__.py @@ -0,0 +1,19 @@ +import os +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_bcrypt import Bcrypt +from flask_login import LoginManager + +app = Flask(__name__) + +SECRET_KEY = os.urandom(32) +app.config['SECRET_KEY'] = SECRET_KEY +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///bot/app.db' + +db = SQLAlchemy(app) +bcrypt = Bcrypt(app) +login_manager = LoginManager(app) +login_manager.login_view = 'login' +login_manager.login_message_category = 'info' + +from app import routes diff --git a/app/app/bot/Invitarr.py b/app/app/bot/Invitarr.py new file mode 100644 index 0000000..9f38538 --- /dev/null +++ b/app/app/bot/Invitarr.py @@ -0,0 +1,194 @@ +#Copyright 2020 Sleepingpirate. +import os +from os import environ +import discord +from discord.ext import commands +import asyncio +from plexapi.myplex import MyPlexAccount +from discord import Webhook, AsyncWebhookAdapter +import aiohttp +from dotenv import load_dotenv +import configparser +CONFIG_PATH = 'app/config/config.ini' +BOT_SECTION = 'bot_envs' + +try: + config = configparser.ConfigParser() + config.read(CONFIG_PATH) +except: + print("Cannot find config") + +# settings +Discord_bot_token = config.get(BOT_SECTION, 'discord_bot_token') +roleid = int(config.get(BOT_SECTION, 'role_id')) +PLEXUSER = config.get(BOT_SECTION, 'plex_user') +PLEXPASS = config.get(BOT_SECTION, 'plex_pass') +PLEX_SERVER_NAME = config.get(BOT_SECTION, 'plex_server_name') +Plex_LIBS = config.get(BOT_SECTION, 'plex_libs') +chan = int(config.get(BOT_SECTION, 'channel_id')) +ownerid = int(config.get(BOT_SECTION, 'owner_id')) +auto_remove_user = config.get(BOT_SECTION, 'auto_remove_user') if config.get(BOT_SECTION, 'auto_remove_user') else False + +li = list(Plex_LIBS.split(',')) +Plex_LIBS = li + +#rolenames = list(roleid.split(',')) + +if auto_remove_user: + print("auto remove user = True") + import db as db + +account = MyPlexAccount(PLEXUSER, PLEXPASS) +plex = account.resource(PLEX_SERVER_NAME).connect() # returns a PlexServer instance + +def plexadd(plexname): + try: + plex.myPlexAccount().inviteFriend(user=plexname, server=plex, sections=Plex_LIBS, allowSync=False, + allowCameraUpload=False, allowChannels=False, filterMovies=None, + filterTelevision=None, filterMusic=None) + + except Exception as e: + print(e) + return False + else: + print(plexname +' has been added to plex (☞ຈل͜ຈ)☞') + return True + + +def plexremove(plexname): + try: + plex.myPlexAccount().removeFriend(user=plexname) + except Exception as e: + print(e) + return False + else: + print(plexname +' has been removed from plex (☞ຈل͜ຈ)☞') + return True + +class MyClient(discord.Client): + async def on_ready(self): + print('Made by Sleepingpirate https://github.com/Sleepingpirates/') + print('Logged in as') + print(self.user.name) + print(self.user.id) + print('------') + await client.change_presence(activity=discord.Game(name="Do -help in {}".format(client.get_channel(chan)))) + + async def on_member_update(self, before, after): + role = after.guild.get_role(roleid) + secure = client.get_channel(chan) + if (role in after.roles and role not in before.roles): + await after.send('Welcome To '+ PLEX_SERVER_NAME +'. Just reply with your email so we can add you to Plex!') + await after.send('I will wait 10 minutes for your message, if you do not send it by then I will cancel the command.') + def check(m): + return m.author == after and not m.guild + try: + email = await client.wait_for('message', timeout=600, check=check) + except asyncio.TimeoutError: + await after.send('Timed Out. Message Server Admin So They Can Add You Manually.') + else: + await asyncio.sleep(5) + await after.send('Got it we will be processing your email shortly') + print(email.content) #make it go to a log channel + plexname = str(email.content) + if plexadd(plexname): + if auto_remove_user: + db.save_user(str(after.id), email.content) + await asyncio.sleep(20) + await after.send('You have Been Added To Plex!') + await secure.send(plexname + ' ' + after.mention + ' was added to plex') + else: + await after.send('There was an error adding this email address. Message Server Admin.') + elif(role not in after.roles and role in before.roles): + if auto_remove_user: + try: + user_id = after.id + email = db.get_useremail(user_id) + plexremove(email) + deleted = db.delete_user(user_id) + if deleted: + print("Removed {} from db".format(email)) + await secure.send(plexname + ' ' + after.mention + ' was removed from plex') + else: + print("Cannot remove this user from db.") + except: + print("Cannot remove this user from plex.") + + + async def on_message(self, message): + secure = client.get_channel(chan) + if message.author.id == self.user.id: + return + + if message.author.id == ownerid: + if message.content.startswith('-db add'): + mgs = message.content.replace('-db add ','') + try: + mgs = mgs.split(' ') + email = mgs[0] + bad_chars = ['<','>','@','!'] + user_id = mgs[1] + for i in bad_chars: + user_id = user_id.replace(i, '') + db.save_user(user_id, email) + await secure.send(email + ' ' + mgs[1] + ' was added to plex') + except: + await message.channel.send('Cannot add this user to db.') + print("Cannot add this user to db.") + await message.delete() + + if str(message.channel) == str(secure): + if message.content.startswith('-db ls') or message.content.startswith('-db rm'): + embed = discord.Embed(title='Invitarr Database.') + all = db.read_useremail() + for index, peoples in enumerate(all): + index = index + 1 + id = int(peoples[1]) + dbuser = client.get_user(id) + dbemail = peoples[2] + embed.add_field(name=f"**{index}. {dbuser.name}**", value=dbemail+'\n', inline=False) + if message.content.startswith('-db ls'): + await secure.send(embed = embed) + else: + try: + position = message.content.replace("-db rm", "") + position = int(position) - 1 + id = all[position][1] + email = db.get_useremail(id) + deleted = db.delete_user(id) + if deleted: + print("Removed {} from db".format(email)) + await secure.send("Removed {} from db".format(email)) + else: + print("Cannot remove this user from db.") + except Exception as e: + print(e) + + if message.content.startswith('-help'): + embed = discord.Embed(title='Invitarr Bot Commands', description='Made by [Sleepingpirates](https://github.com/Sleepingpirates/Invitarr), [Join Discord Server](https://discord.gg/vcxCytN)') + embed.add_field(name='-plexadd ', value='This command is used to add an email to plex', inline=False) + embed.add_field(name='-plexrm ', value='This command is used to remove an email from plex', inline=False) + embed.add_field(name='-db ls', value='This command is used list Invitarrs database', inline=False) + embed.add_field(name='-db add <@user>', value='This command is used add exsisting users email and discord id to the DB.', inline=False) + embed.add_field(name='-db rm ', value='This command is used remove a record from the Db. Use -db ls to determine record position. ex: -db rm 1', inline=False) + await secure.send(embed = embed) + + + async def on_member_remove(self, member): + if auto_remove_user: + try: + user_id = member.id ## not there + email = db.get_useremail(user_id) + plexremove(email) + deleted = db.delete_user(user_id) + if deleted: + print("Removed {} from db".format(email)) + secure = client.get_channel(chan) + await secure.send(email + ' ' + member.mention + 'was removed from plex because they left the server') + else: + print("Cannot remove this user from db.") + except: + print("Cannot remove this user from plex.") + +client = MyClient() +client.run(Discord_bot_token) diff --git a/app/app/bot/db.py b/app/app/bot/db.py new file mode 100644 index 0000000..b982f0b --- /dev/null +++ b/app/app/bot/db.py @@ -0,0 +1,83 @@ +import sqlite3 + +DB_URL = 'app/config/app.db' + +def create_connection(db_file): + """ create a database connection to a SQLite database """ + conn = None + try: + conn = sqlite3.connect(db_file) + print("Connected to db") + except Error as e: + print("error in connecting to db") + finally: + if conn: + return conn + +def checkTableExists(dbcon, tablename): + dbcur = dbcon.cursor() + dbcur.execute("""SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='{0}';""".format(tablename.replace('\'', '\'\''))) + if dbcur.fetchone()[0] == 1: + dbcur.close() + return True + dbcur.close() + return False + +conn = create_connection(DB_URL) + +# Checking if table exists +if checkTableExists(conn, 'clients'): + print('Table exists.') +else: + conn.execute(''' + CREATE TABLE "clients" ( + "id" INTEGER NOT NULL UNIQUE, + "discord_username" TEXT NOT NULL UNIQUE, + "email" TEXT NOT NULL, + PRIMARY KEY("id" AUTOINCREMENT) + ); + ''') + +def save_user(username, email): + if username and email: + conn.execute("INSERT INTO clients (discord_username, email) VALUES ('"+ username +"', '" + email + "')"); + conn.commit() + print("User added to db.") + else: + return "Username or email cannot be empty" + +def get_useremail(username): + if username: + try: + cursor = conn.execute('SELECT discord_username, email from clients where discord_username="{}";'.format(username)) + for row in cursor: + email = row[1] + if email: + return email + else: + return "No users found" + except: + return "error in fetching from db" + else: + return "username cannot be empty" + +def delete_user(username): + if username: + try: + conn.execute('DELETE from clients where discord_username="{}";'.format(username)) + conn.commit() + return True + except: + return False + else: + return "username cannot be empty" + +def read_useremail(): + cur = conn.cursor() + cur.execute("SELECT * FROM clients") + rows = cur.fetchall() + all = [] + for row in rows: + #print(row[1]+' '+row[2]) + all.append(row) + return all diff --git a/app/app/configHandler.py b/app/app/configHandler.py new file mode 100644 index 0000000..ede8fc6 --- /dev/null +++ b/app/app/configHandler.py @@ -0,0 +1,56 @@ +import configparser + +config = configparser.ConfigParser() + +CONFIG_PATH = 'app/config/config.ini' +BOT_SECTION = 'bot_envs' +CONFIG_KEYS = ['username', 'password', 'discord_bot_token', 'plex_user', 'plex_pass', + 'role_id', 'plex_server_name', 'plex_libs', 'owner_id', 'channel_id', + 'auto_remove_user'] + +def get_config(): + """ + Function to return current config + """ + try: + config.read(CONFIG_PATH) + return config + except Exception as e: + print(e) + print('error in reading config') + return None + + +def change_config(key, value): + """ + Function to change the key, value pair in config + """ + try: + config = configparser.ConfigParser() + config.read(CONFIG_PATH) + except Exception as e: + print(e) + print("Cannot Read config.") + + try: + config.set(BOT_SECTION, key, str(value)) + except Exception as e: + config.add_section(BOT_SECTION) + config.set(BOT_SECTION, key, str(value)) + + try: + with open(CONFIG_PATH, 'w') as configfile: + config.write(configfile) + except Exception as e: + print(e) + print("Cannot write to config.") + +def change_config_form(form_output): + """ + Function to change config on the basis of form_output from web + """ + for key in CONFIG_KEYS: + try: + change_config(key, form_output[key].data) + except: + pass diff --git a/app/app/forms.py b/app/app/forms.py new file mode 100644 index 0000000..047dfa9 --- /dev/null +++ b/app/app/forms.py @@ -0,0 +1,52 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, SubmitField, BooleanField, IntegerField +from wtforms.validators import DataRequired + +class LoginForm(FlaskForm): + + username = StringField('Username', + validators=[DataRequired()]) + + password = PasswordField('Password', + validators=[DataRequired()]) + + submit = SubmitField('Save Changes') + +class GeneralForm(FlaskForm): + + username = StringField('Username', + validators=[DataRequired()]) + + password = PasswordField('Password', + validators=[DataRequired()]) + + submit = SubmitField('Save Changes') + +class BotForm(FlaskForm): + + discord_bot_token = StringField('Discord Bot Token', + validators=[DataRequired()]) + + role_id = IntegerField('Role Id', + validators=[DataRequired()]) + + channel_id = IntegerField('Channel Id', + validators=[DataRequired()]) + owner_id = IntegerField('Owner Id', + validators=[DataRequired()]) + # Auto Remove User + auto_remove_user = BooleanField('On') + + submit = SubmitField('Save Changes') + +class PlexForm(FlaskForm): + + plex_user = StringField('Plex User', + validators=[DataRequired()]) + plex_pass = StringField('Plex Pass', + validators=[DataRequired()]) + plex_server_name = StringField('Plex Server Name', + validators=[DataRequired()]) + plex_libs = StringField('Plex Libs', + validators=[DataRequired()]) + submit = SubmitField('Save Changes') \ No newline at end of file diff --git a/app/app/models.py b/app/app/models.py new file mode 100644 index 0000000..ea10fbd --- /dev/null +++ b/app/app/models.py @@ -0,0 +1,15 @@ +from app import db, login_manager +from flask_login import UserMixin + +@login_manager.user_loader +def load_user(user_id): + return User.query.get(int(user_id)) + + +class User(db.Model, UserMixin): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(20), unique=True, nullable=False) + password = db.Column(db.String(60), nullable=False) + + def __repr__(self): + return f"User('{self.username}')" diff --git a/app/app/routes.py b/app/app/routes.py new file mode 100644 index 0000000..bf1dead --- /dev/null +++ b/app/app/routes.py @@ -0,0 +1,120 @@ +from flask import render_template, flash, request, redirect, url_for +from flask_login import login_user, current_user, logout_user, login_required +import subprocess + +from app import app, db, bcrypt +from app.models import User +from app.forms import LoginForm, GeneralForm, BotForm, PlexForm +from app import configHandler + +db.create_all() +BOT_SECTION = 'bot_envs' +proc = None + +def manage_bot(option): + global proc + if option == 'start': + proc = subprocess.Popen(["python", "app/bot/Invitarr.py"]) + elif option == 'kill': + if proc: + proc.terminate() + +try: + manage_bot('start') +except: + print("Some error in starting bot. Please check the config vars") + +@app.route("/login", methods=['GET', 'POST']) +def login(): + if current_user.is_authenticated: + return redirect(url_for('home')) + form = LoginForm() + if form.validate_on_submit(): + user = User.query.filter_by(username=form.username.data).first() + if user and bcrypt.check_password_hash(user.password, form.password.data): + login_user(user, remember=True) + next_page = request.args.get('next') + return redirect(next_page) if next_page else redirect(url_for('home')) + else: + flash('Login Unsuccessful. Please check email and password') + return render_template('login.html', title='Login', form=form) + +@app.route('/logout') +@login_required +def logout(): + flash('Logged out.') + logout_user() + return redirect(url_for('login')) + +@app.route('/', methods=['GET', 'POST']) +@login_required +def home(): + form = GeneralForm() + if request.method == 'GET': + user = User.query.all()[0] + form.username.data = user.username + form.password.data = user.password + elif request.method == 'POST': + if form.validate_on_submit(): + user = User.query.all()[0] + user.username = form.username.data + hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8') + user.password = hashed_password + db.session.commit() + logout_user() + flash('Details updated.') + return redirect(url_for('login')) + return render_template('index.html', form=form) + +@app.route('/bot', methods=['GET', 'POST']) +@login_required +def bot(): + form = BotForm() + if request.method == 'GET': + try: + config = configHandler.get_config() + form.discord_bot_token.data = config.get(BOT_SECTION, 'discord_bot_token') + form.role_id.data = config.get(BOT_SECTION, 'role_id') + form.channel_id.data = config.get(BOT_SECTION, 'channel_id') + form.owner_id.data = config.get(BOT_SECTION, 'owner_id') + form.auto_remove_user.data = config.get(BOT_SECTION, 'auto_remove_user') + except: + pass + elif request.method == 'POST': + if form.validate_on_submit(): + try: + configHandler.change_config_form(form) + flash('Settings updated.') + manage_bot('kill') + manage_bot('start') + except: + flash('Some error in updating settings') + return render_template('bot.html', form = form) + +@app.route('/plex', methods=['GET', 'POST']) +@login_required +def plex(): + form = PlexForm() + if request.method == 'GET': + try: + config = configHandler.get_config() + form.plex_user.data = config.get(BOT_SECTION, 'plex_user') + form.plex_pass.data = config.get(BOT_SECTION, 'plex_pass') + form.plex_server_name.data = config.get(BOT_SECTION, 'plex_server_name') + form.plex_libs.data = config.get(BOT_SECTION, 'plex_libs') + except: + pass + elif request.method == 'POST': + if form.validate_on_submit(): + try: + configHandler.change_config_form(form) + flash('Settings updated.') + except: + flash('Some error in updating settings') + try: + manage_bot('kill') + manage_bot('start') + except Exception as e: + raise Exception(e) + + return render_template('plex.html', form = form) diff --git a/app/app/static/favicon.ico b/app/app/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e9fb8300d13f6956eb22da46707e1d9b88602057 GIT binary patch literal 12059 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 + + + + + + + + + + + + + + + + + diff --git a/app/app/static/main.css b/app/app/static/main.css new file mode 100644 index 0000000..3a5495e --- /dev/null +++ b/app/app/static/main.css @@ -0,0 +1,86 @@ +/* Universal */ +:root { + --main-bg-color: #000000; + --content-background: #17151C; + --secondary-content-background: #2A2731; + --primary-text-color: #FFFFFF; +} + +body{ + background-color: var(--main-bg-color); + color: var(--primary-text-color); +} + +/* Header */ +h3{ + font-weight: bold; + display: inline-block; + margin: 0.5em 0 1.5em 0.25em; + padding-top: 0.5em; +} + +.header img{ + vertical-align: middle; +} + +a.nav-link{ + color: var(--primary-text-color); +} + +.header button{ + max-height: 50px; + /* margin: 1em 0.5em; */ +} + +/* Form */ +.form-container{ + padding: 1.5em; + padding-top: 2em; + border-radius: 0 0 10px 10px; + background-color: var(--content-background); +} + +.form-stringfield{ + background-color: var(--secondary-content-background); + color: var(--primary-text-color); +} + +.form-stringfield:focus{ + background-color: var(--secondary-content-background); + color: var(--primary-text-color); +} + +.custom-checkbox{ + padding-left: 3em; +} + +/* Modal */ +.modal-content{ + background-color: var(--secondary-content-background); + padding: 1em !important; +} + +.modal-body{ + text-align: center; +} + +.modal-header{ + padding: 1em; + border-bottom: none; +} + +.modal-header h4{ + color: var(--primary-text-color) +} + +/* Login Page */ +.login{ + margin: auto; + margin-top: 5em; + text-align: center; +} + +.login h2{ + margin-top: 1em; + font-weight: bold; +} diff --git a/app/app/templates/bot.html b/app/app/templates/bot.html new file mode 100644 index 0000000..7e0f399 --- /dev/null +++ b/app/app/templates/bot.html @@ -0,0 +1,194 @@ +{%extends 'layout.html'%} +{% block content %} +
+ +

Invitarr Configuration

+ +
+ +
+ +
+ {{ form.hidden_tag() }} +
+
+
+ {{ form.discord_bot_token.label(class="form-control-label")}} +
+
+
+ {% if form.discord_bot_token.errors %} + {{ form.discord_bot_token(class="form-control form-stringfield")}} + Some text describing this field +
+ {% for error in form.discord_bot_token.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.discord_bot_token(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.role_id.label(class="form-control-label")}} +
+
+
+ {% if form.role_id.errors %} + {{ form.role_id(class="form-control form-stringfield")}} +
+ {% for error in form.role_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.role_id(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.channel_id.label(class="form-control-label")}} +
+
+
+ {% if form.channel_id.errors %} + {{ form.channel_id(class="form-control form-stringfield")}} +
+ {% for error in form.channel_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.channel_id(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.owner_id.label(class="form-control-label")}} +
+
+
+ {% if form.owner_id.errors %} + {{ form.owner_id(class="form-control form-stringfield")}} +
+ {% for error in form.owner_id.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.owner_id(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+

Auto Remove User

+
+
+
+ {% if form.auto_remove_user.errors %} + {{ form.auto_remove_user(class="custom-control-input form-stringfield", id="removeSwitch")}} + {{ form.auto_remove_user.label(class="custom-control-label", for="removeSwitch")}} +
+ {% for error in form.auto_remove_user.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.auto_remove_user(class="custom-control-input form-stringfield", id="removeSwitch")}} + {{ form.auto_remove_user.label(class="custom-control-label", for="removeSwitch")}} + {% endif %} +
+
+
+
+ {{ form.submit(class="btn btn-primary submit-btn") }} +
+
+
+ +{% endblock content %} + +{% block script %} + +{% endblock script %} diff --git a/app/app/templates/index.html b/app/app/templates/index.html new file mode 100644 index 0000000..bc0f08b --- /dev/null +++ b/app/app/templates/index.html @@ -0,0 +1,131 @@ +{%extends 'layout.html'%} +{% block content %} +
+ +

Invitarr Configuration

+
+ +
+ +
+ {{ form.hidden_tag() }} +
+
+
+ {{ form.username.label(class="form-control-label")}} +
+
+
+ {% if form.username.errors %} + {{ form.username(class="form-control form-stringfield")}} + Some text describing this field +
+ {% for error in form.username.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.username(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.password.label(class="form-control-label")}} +
+
+
+ {% if form.password.errors %} + {{ form.password(class="form-control form-stringfield")}} +
+ {% for error in form.password.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.password(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+ {{ form.submit(class="btn btn-primary submit-btn") }} +
+
+
+ +{% endblock content %} + +{% block script %} + +{% endblock script %} diff --git a/app/app/templates/layout.html b/app/app/templates/layout.html new file mode 100644 index 0000000..2b3982d --- /dev/null +++ b/app/app/templates/layout.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + {% if title %} + {{ title }} - Invitarr + {% else %} + Invitarr + {% endif %} + + +
+ {% block content %}{% endblock %} +
+ + + + + + + {% block script %}{% endblock %} + + + + diff --git a/app/app/templates/login.html b/app/app/templates/login.html new file mode 100644 index 0000000..fb8576e --- /dev/null +++ b/app/app/templates/login.html @@ -0,0 +1,105 @@ +{%extends 'layout.html'%} +{% block content %} + + +{% endblock content %} + + +{% block script %} + +{% endblock script %} \ No newline at end of file diff --git a/app/app/templates/plex.html b/app/app/templates/plex.html new file mode 100644 index 0000000..91d23f9 --- /dev/null +++ b/app/app/templates/plex.html @@ -0,0 +1,155 @@ +{%extends 'layout.html'%} +{% block content %} +
+ +

Invitarr Configuration

+
+ +
+ +
+ {{ form.hidden_tag() }} +
+
+
+ {{ form.plex_user.label(class="form-control-label")}} +
+
+
+ {% if form.plex_user.errors %} + {{ form.plex_user(class="form-control form-stringfield")}} + Some text describing this field +
+ {% for error in form.plex_user.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.plex_user(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.plex_pass.label(class="form-control-label")}} +
+
+
+ {% if form.plex_pass.errors %} + {{ form.plex_pass(class="form-control form-stringfield")}} +
+ {% for error in form.plex_pass.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.plex_pass(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.plex_server_name.label(class="form-control-label")}} +
+
+
+ {% if form.plex_server_name.errors %} + {{ form.plex_server_name(class="form-control form-stringfield")}} +
+ {% for error in form.plex_server_name.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.plex_server_name(class="form-control form-stringfield")}} + {% endif %} +
+
+
+
+
+
+ {{ form.plex_libs.label(class="form-control-label")}} +
+
+
+ {% if form.plex_libs.errors %} + {{ form.plex_libs(class="form-control form-stringfield")}} +
+ {% for error in form.plex_libs.errors %} + {{ error }} + {% endfor %} +
+ {% else %} + {{ form.plex_libs(class="form-control form-stringfield")}} + {% endif %} + Enter comma seperated values +
+
+
+
+ {{ form.submit(class="btn btn-primary submit-btn") }} +
+
+
+ +{% endblock content %} + +{% block script %} + +{% endblock script %} diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..2c13823 --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1,33 @@ +aiohttp==3.6.2 +async-timeout==3.0.1 +attrs==19.3.0 +bcrypt==3.1.7 +certifi==2020.4.5.2 +cffi==1.14.0 +chardet==3.0.4 +click==7.1.2 +discord.py==1.3.3 +Flask==1.1.2 +Flask-Bcrypt==0.7.1 +Flask-Login==0.5.0 +Flask-SQLAlchemy==2.4.3 +Flask-WTF==0.14.3 +idna==2.9 +idna-ssl==1.1.0 +itsdangerous==1.1.0 +Jinja2==2.11.2 +MarkupSafe==1.1.1 +multidict==4.7.6 +plex.py==0.9.0 +PlexAPI==4.0.0 +pycparser==2.20 +python-dotenv==0.13.0 +requests==2.23.0 +six==1.15.0 +SQLAlchemy==1.3.17 +typing-extensions==3.7.4.2 +urllib3==1.25.9 +websockets==8.1 +Werkzeug==1.0.1 +WTForms==2.3.1 +yarl==1.4.2 diff --git a/app/run.py b/app/run.py new file mode 100644 index 0000000..b40771f --- /dev/null +++ b/app/run.py @@ -0,0 +1,17 @@ +from app import app +from app import db, bcrypt +from app.models import User +from os import path +''' +if path.exists("app.config.app.db") is False: + db.create_all() + try: + hashed_password = bcrypt.generate_password_hash(DEFAULT_PASS).decode('utf-8') + user = User(username=DEFAULT_USER, password=hashed_password) + db.session.add(user) + db.session.commit() + except: + print("Some error in setting up.") +''' +if __name__ == "__main__": + app.run(debug=True) diff --git a/app/setup.py b/app/setup.py new file mode 100644 index 0000000..8707b15 --- /dev/null +++ b/app/setup.py @@ -0,0 +1,14 @@ +from app import db, bcrypt +from app.models import User + +DEFAULT_USER = "admin" +DEFAULT_PASS = "admin" +db.create_all() + +try: + hashed_password = bcrypt.generate_password_hash(DEFAULT_PASS).decode('utf-8') + user = User(username=DEFAULT_USER, password=hashed_password) + db.session.add(user) + db.session.commit() +except: + print("Some error in setting up.") diff --git a/app/uwsgi.ini b/app/uwsgi.ini new file mode 100644 index 0000000..c4a31cb --- /dev/null +++ b/app/uwsgi.ini @@ -0,0 +1,4 @@ +[uwsgi] +module = run +callable = app +enable-threads = true