Basic embed interface + login to embed client

This commit is contained in:
Jeremy Zhang 2017-04-04 05:53:27 +00:00
parent 7ec1ac6760
commit 90179c495a
12 changed files with 955 additions and 28 deletions

View File

@ -0,0 +1,286 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="//fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/css/materialize.min.css" integrity="sha256-6DQKO56c9MZL0LAc7QNtxqJyqSa3rS9Gq5FVcIhtA+w=" crossorigin="anonymous" media="screen,projection"/>
<style>
html {
background-color: #455a64;
color: white;
}
main {
min-height: calc(100vh - 80px);
}
footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 50px;
background-color: #37474f;
}
nav {
background-color: #263238;
background: linear-gradient(rgba(38, 50, 56, 1), rgba(255,0,0,0));
box-shadow: none;
}
nav .brand-logo {
font-size: 1.5rem;
}
@media only screen and (min-width: 993px) {
.container {
width: 85%;
}
}
.side-nav {
color: white;
background-color: #607d8b;
}
.side-nav .userView .name {
font-size: 20px;
}
.side-nav li>a {
color: #eceff1;
}
.side-nav .subheader {
color: #cfd8dc;
font-variant: small-caps;
}
.divider {
background-color: #90a4ae;
}
.channel-hash {
font-size: 95%;
color: #b0bec5;
}
.membercircle {
margin-top: 5px;
height: 40px;
}
.membername {
position: absolute;
padding-left: 10px;
}
.chatcontent {
padding-left: 1%;
padding-top: 1%;
padding-bottom: 40px;
}
@media only screen and (min-width: 601px) {
nav a.button-collapse {
display: block;
}
}
.chatusername {
font-weight: bold;
color: #eceff1;
}
.chattimestamp {
font-size: 10px;
color: #90a4ae;
}
.footercontainer {
width: 100%;
position: relative;
margin: 10px;
}
.currentuserchip {
display: inline-block;
position: relative;
top: -6px;
padding: 6px;
padding-right: 9px;
background-color: #455a64;
}
.currentuserimage {
width: 30px;
}
.currentusername {
position: relative;
top: 7px;
left: 5px;
}
.input-field {
position: relative;
top: -19px;
}
.left {
float: left;
}
.modal {
background-color: #546e7a;
}
</style>
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Embed - Titan Embeds for Discord</title>
</head>
<body>
<div class="navbar-fixed">
<nav>
<div class="nav-wrapper">
<a href="#" data-activates="guild-nav" class="button-collapse" id="guild-btn"><i class="material-icons">menu</i></a>
<div class="container">
<a href="#" class="brand-logo"><b>Titan</b>Embeds</a>
</div>
<a href="#" data-activates="members-nav" class="button-collapse right" id="members-btn"><i class="material-icons">person</i></a>
</div>
</nav>
</div>
<main>
<div class="chatcontent">
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> adfsadfsdfas</p>
</div>
</main>
<ul id="guild-nav" class="side-nav">
<li>
<div class="userView">
<img class="circle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg">
<span class="name">Guild Name</span>
</div>
</li>
<li><a class="subheader">Actions</a></li>
<li><a href="#!" class="waves-effect">Manage Guild Embed</a></li>
<li><a href="#!" class="waves-effect">Open Server on Discordapp</a></li>
<li><div class="divider"></div></li>
<li><a class="subheader">Channels</a></li>
<li><a class="waves-effect truncate" href="#!"><span class="channel-hash">#</span> channel-1</a></li>
<li><a class="waves-effect truncate" href="#!"><span class="channel-hash">#</span> channel-2</a></li>
<li><a class="waves-effect truncate" href="#!"><span class="channel-hash">#</span> channel-3</a></li>
</ul>
<ul id="members-nav" class="side-nav">
<li><a class="subheader">Online Server Members</a></li>
<li><a class="waves-effect truncate" href="#!"><img class="circle membercircle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg"> <span class="membername">EndenDragon</span></a></li>
<li><a class="waves-effect truncate" href="#!"><img class="circle membercircle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg"> <span class="membername">EndenDragon</span></a></li>
<li><a class="waves-effect truncate" href="#!"><img class="circle membercircle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg"> <span class="membername">EndenDragon</span></a></li>
<li><div class="divider"></div></li>
<li><a class="subheader">Authenticated Embed Users</a></li>
<li><a class="waves-effect truncate" href="#!"><img class="circle membercircle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg"> <span class="membername">EndenDragon</span></a></li>
<li><a class="waves-effect truncate" href="#!"><img class="circle membercircle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg"> <span class="membername">EndenDragon</span></a></li>
<li><a class="waves-effect truncate" href="#!"><img class="circle membercircle" src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg"> <span class="membername">EndenDragon</span></a></li>
<li><a class="subheader">Guest Embed Users</a></li>
<li><a class="waves-effect truncate" href="#!"><span class="membername">EndenDragon#6969</span></a></li>
<li><a class="waves-effect truncate" href="#!"><span class="membername">EndenDragon#1234</span></a></li>
<li><a class="waves-effect truncate" href="#!"><span class="membername">EndenDragon#3333</span></a></li>
</ul>
<div id="loginmodal" class="modal">
<div class="modal-content">
<h4>Let's get to know each other! My name is Titan, what's yours?</h4>
<p class="flow-text">Please choose one of the following methods to login!</p>
<div class="row">
<div class="col s1 m4">
<a class="waves-effect waves-light btn-large">Login with Discord</a>
</div>
<div class="col s1 m8">
<p>Of course, you also have the option to login by picking a temporary username.</p>
<input id="custom_username_field" type="text">
<label class="active" for="custom_username_field">Username</label>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="footercontainer">
<div class="currentuserchip left" id="nameplate">
<div class="left"><img src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg" class="circle left currentuserimage"></div>
<div class="currentusername left">EndenDragon#4151</div>
</div>
<div id="messageboxouter" class="input-field inline"><textarea placeholder="Enter message" id="messagebox" type="text" class="materialize-textarea"></textarea></div>
</div>
</footer>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/js/materialize.min.js" integrity="sha256-ToPQhpo/E89yaCd7+V8LUCjobNRkjilRXfho6x3twLU=" crossorigin="anonymous"></script>
<script>
function resize_messagebox() {
var namebox_width = $("#nameplate").outerWidth(true);
var screen_width = $(document).width();
$("#messageboxouter").width(screen_width - namebox_width - 40);
}
$(function(){
resize_messagebox()
$("#loginmodal").modal({
dismissible: false, // Modal can be dismissed by clicking outside of the modal
opacity: .5, // Opacity of modal background
inDuration: 300, // Transition in duration
outDuration: 200, // Transition out duration
startingTop: '4%', // Starting top style attribute
endingTop: '10%', // Ending top style attribute
}
);
$('#loginmodal').modal('open');
});
$(window).resize(function() {
resize_messagebox()
});
$('#guild-btn').sideNav({
menuWidth: 300, // Default is 300
edge: 'left', // Choose the horizontal origin
closeOnClick: true, // Closes side-nav on <a> clicks, useful for Angular/Meteor
draggable: true // Choose whether you can drag to open on touch screens
}
);
$('#members-btn').sideNav({
menuWidth: 300, // Default is 300
edge: 'right', // Choose the horizontal origin
draggable: true // Choose whether you can drag to open on touch screens
}
);
</script>
</body>
</html>

View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/css/materialize.min.css" integrity="sha256-6DQKO56c9MZL0LAc7QNtxqJyqSa3rS9Gq5FVcIhtA+w=" crossorigin="anonymous" media="screen,projection"/>
<style>
html {
background-color: #7986cb;
color: white;
}
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
nav {
background-color: #3f51b5;
background: linear-gradient(rgba(63, 81, 181, 1), rgba(255,0,0,0));
box-shadow: none;
}
.page-footer {
background-color: transparent;
}
@media only screen and (max-width: 992px) {
nav .brand-logo {
left: 10%;
}
}
.btn {
background-color: #303f9f;
}
.btn:hover {
background-color: #3f51b5;
}
.btn:focus {
background-color: #536dfe;
}
.avatar_menu {
background-size: contain;
}
.center_content {
display: block;
margin-left: auto;
margin-right: auto;
}
</style>
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Index - Titan Embeds for Discord</title>
</head>
<body>
<main>
<ul id="menu_dropdown" class="dropdown-content">
<li><a href="#!">Servers</a></li>
<li class="divider"></li>
<li><a href="#!">Logout</a></li>
</ul>
<nav>
<div class="nav-wrapper container">
<a href="#" class="brand-logo"><b>Titan</b>Embeds</a>
<ul id="nav-mobile" class="right">
<li><a href="#" class="waves-effect btn z-depth-3">Visit Us!</a></li>
<li><a href="#" class="waves-effect btn z-depth-3">Login</a></li>
<li><a id="menu_drop" data-activates="menu_dropdown" class="waves-effect btn z-depth-3 btn-floating dropdown-button avatar_menu" style='background-image: url("https://cdn.discordapp.com/attachments/213843114123722752/292181315665657857/unknown.png")'></a></li>
</ul>
</div>
</nav>
<div class="container">
<h1 class="center-align">Embed Discord chats like a <br>true Titan</h1>
<p class="flow-text center-align">Add <strong>Titan</strong> to your discord server to create your own personalized chat embed!</p>
<a class="waves-effect waves-light btn btn-large center_content">Start here!</a>
<br /><br />
<div style="display: flex;align-items: center;">
<video preload="true" loop="" style="width:100%; border-radius: 10px;">
<source src="http://mee6.xyz/static/mee6.mp4" type="video/mp4">
<source src="http://mee6.xyz/static/mee6.webm" type="video/webm; codecs=vp8, vorbis">
<source type="video/ogg; codecs=theora, vorbis" src="http://mee6.xyz/static/mee6.ogg">
Your browser does not support the video tag.
</video>
</div>
</div>
</main>
<footer class="page-footer">
<div class="footer-copyright">
<div class="container">
A project by EndenDragon
<a class="grey-text text-lighten-4 right" href="https://github.com/EndenDragon/Titan">GitHub Repo</a>
</div>
</div>
</footer>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/js/materialize.min.js" integrity="sha256-ToPQhpo/E89yaCd7+V8LUCjobNRkjilRXfho6x3twLU=" crossorigin="anonymous"></script>
</body>
</html>

View File

@ -12,6 +12,7 @@ os.chdir(config['app-location'])
app = Flask(__name__, static_folder="static")
app.config['SQLALCHEMY_DATABASE_URI'] = config['database-uri']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Suppress the warning/no need this on for now.
app.config['RATELIMIT_HEADERS_ENABLED'] = True
app.secret_key = config['app-secret']
db.init_app(app)

View File

@ -1,6 +1,6 @@
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers
from titanembeds.decorators import valid_session_required, discord_users_only
from titanembeds.utils import get_client_ipaddr, discord_api, rate_limiter, channel_ratelimit_key, guild_ratelimit_key, cache, make_guildchannels_cache_key
from titanembeds.utils import check_guild_existance, guild_query_unauth_users_bool, get_client_ipaddr, discord_api, rate_limiter, channel_ratelimit_key, guild_ratelimit_key, cache, make_guildchannels_cache_key
from titanembeds.oauth import user_has_permission, generate_avatar_url
from flask import Blueprint, abort, jsonify, session, request
from sqlalchemy import and_
@ -49,16 +49,6 @@ def checkUserBanned(guild_id, ip_address=None):
return True
return banned
def check_guild_existance(guild_id):
dbGuild = Guilds.query.filter_by(guild_id=guild_id).first()
if not dbGuild:
return False
guilds = discord_api.get_all_guilds()
for guild in guilds:
if guild_id == guild['id']:
return True
return False
def update_user_status(guild_id, username, user_key=None):
if user_unauthenticated():
ip_address = get_client_ipaddr()
@ -88,7 +78,7 @@ def update_user_status(guild_id, username, user_key=None):
}
if status['banned'] or status['revoked']:
return status
dbUser = db.session.query(AuthenticatedUsers).filter(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == status['user_id']).first()
dbUser = db.session.query(AuthenticatedUsers).filter(and_(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == status['user_id'])).first()
dbUser.bumpTimestamp()
return status
@ -144,17 +134,14 @@ def get_online_embed_users(guild_id):
client_id = user.client_id
u = discord_api.get_guild_member(guild_id, client_id)['content']['user']
meta = {
'id': u['id'],
'username': u['username'],
'discriminator': u['discriminator'],
'avatar': generate_avatar_url(u['id'], u['avatar']),
'avatar_url': generate_avatar_url(u['id'], u['avatar']),
}
users['authenticated'].append(meta)
return users
def guild_query_unauth_users_bool(guild_id):
dbGuild = Guilds.query.filter_by(guild_id=guild_id).first()
return dbGuild.unauth_users
@api.route("/fetch", methods=["GET"])
@valid_session_required(api=True)
@rate_limiter.limit("2500/hour")
@ -174,7 +161,7 @@ def fetch():
messages = discord_api.get_channel_messages(channel_id, after_snowflake)
status_code = messages['code']
response = jsonify(messages=messages.get('content', messages), status=status)
resonse.status_code = status_code
response.status_code = status_code
return response
@api.route("/post", methods=["POST"])
@ -194,7 +181,7 @@ def post():
status_code = 401
else:
message = discord_api.create_message(channel_id, content)
status_code = messages['code']
status_code = message['code']
response = jsonify(message=message.get('content', message), status=status)
response.status_code = status_code
return response
@ -255,7 +242,7 @@ def create_authenticated_user():
if not check_guild_existance(guild_id):
abort(404)
if not checkUserBanned(guild_id):
db_user = db.session.query(AuthenticatedUsers).filter(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == session['user_id']).first()
db_user = db.session.query(AuthenticatedUsers).filter(and_(AuthenticatedUsers.guild_id == guild_id, AuthenticatedUsers.client_id == session['user_id'])).first()
if not db_user:
db_user = AuthenticatedUsers(guild_id, session['user_id'])
db.session.add(db_user)
@ -263,7 +250,7 @@ def create_authenticated_user():
if not check_user_in_guild(guild_id):
discord_api.add_guild_member(guild_id, session['user_id'], session['user_keys']['access_token'])
status = update_user_status(guild_id, session['username'])
return jsonify(error=False)
return jsonify(status=status)
else:
status = {'banned': True}
response = jsonify(status=status)

View File

@ -1,7 +1,40 @@
from flask import Blueprint
from flask import Blueprint, render_template, abort, redirect, url_for, session
from titanembeds.utils import check_guild_existance, discord_api, guild_query_unauth_users_bool
from titanembeds.oauth import generate_guild_icon_url, generate_avatar_url, check_user_can_administrate_guild
import random
embed = Blueprint("embed", __name__)
@embed.route("/<guild_id>")
def get_logingreeting():
greetings = [
"Let's get to know each other! My name is Titan, what's yours?",
"Hello and welcome!",
"What brings you here today?",
"....what do you expect this text to say?",
"Aha! ..made you look!",
"Initiating launch sequence...",
"Captain, what's your option?",
"Alright, here's the usual~",
]
return random.choice(greetings)
@embed.route("/<string:guild_id>")
def guild_embed(guild_id):
return guild_id
print guild_id
if check_guild_existance(guild_id):
guild = discord_api.get_guild(guild_id)['content']
return render_template("embed.html.j2",
login_greeting=get_logingreeting(),
guild_id=guild_id, guild=guild,
generate_guild_icon=generate_guild_icon_url,
unauth_enabled=guild_query_unauth_users_bool(guild_id)
)
abort(404)
@embed.route("/signin_complete")
def signin_complete():
return render_template("signin_complete.html.j2")
@embed.route("/login_discord")
def login_discord():
return redirect(url_for("user.login_authenticated", redirect=url_for("embed.signin_complete", _external=True)))

View File

@ -39,7 +39,7 @@ def callback():
session['avatar'] = generate_avatar_url(user['id'], user['avatar'])
if session["redirect"]:
redir = session["redirect"]
session.pop('redirect', None)
session['redirect'] = None
return redirect(redir)
return redirect(url_for("user.dashboard"))

View File

@ -7,7 +7,7 @@ def valid_session_required(api=False):
def decorated_function(*args, **kwargs):
if 'unauthenticated' not in session or 'user_id' not in session or 'username' not in session:
if api:
return jsonify(error=True, message="Unauthenticated session"), 403
return jsonify(error=True, message="Unauthenticated session"), 401
redirect(url_for('user.logout'))
if session['unauthenticated'] and 'user_keys' not in session:
session['user_keys'] = {}
@ -21,7 +21,7 @@ def discord_users_only(api=False):
def decorated_function(*args, **kwargs):
if 'unauthenticated' not in session or session['unauthenticated']:
if api:
return jsonify(error=True, message="Not logged in as a discord user"), 403
return jsonify(error=True, message="Not logged in as a discord user"), 401
return redirect(url_for("user.login_authenticated"))
return f(*args, **kwargs)
return decorated_function

View File

@ -0,0 +1,130 @@
html {
background-color: #455a64;
color: white;
}
main {
min-height: calc(100vh - 80px);
}
footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 50px;
background-color: #37474f;
}
nav {
background-color: #263238;
background: linear-gradient(rgba(38, 50, 56, 1), rgba(255,0,0,0));
box-shadow: none;
}
nav .brand-logo {
font-size: 1.5rem;
}
@media only screen and (min-width: 993px) {
.container {
width: 85%;
}
}
.side-nav {
color: white;
background-color: #607d8b;
}
.side-nav .userView .name {
font-size: 20px;
}
.side-nav li>a {
color: #eceff1;
}
.side-nav .subheader {
color: #cfd8dc;
font-variant: small-caps;
}
.divider {
background-color: #90a4ae;
}
.channel-hash {
font-size: 95%;
color: #b0bec5;
}
.membercircle {
margin-top: 5px;
height: 40px;
}
.membername {
position: absolute;
padding-left: 10px;
}
.chatcontent {
padding-left: 1%;
padding-top: 1%;
padding-bottom: 40px;
}
@media only screen and (min-width: 601px) {
nav a.button-collapse {
display: block;
}
}
.chatusername {
font-weight: bold;
color: #eceff1;
}
.chattimestamp {
font-size: 10px;
color: #90a4ae;
}
.footercontainer {
width: 100%;
position: relative;
margin: 10px;
}
.currentuserchip {
display: inline-block;
position: relative;
top: -6px;
padding: 6px;
padding-right: 9px;
background-color: #455a64;
}
.currentuserimage {
width: 30px;
}
.currentusername {
position: relative;
top: 7px;
left: 5px;
}
.input-field {
position: relative;
top: -19px;
}
.left {
float: left;
}
.modal {
background-color: #546e7a;
}

View File

@ -0,0 +1,216 @@
/* global $ */
/* global Materialize */
/* global Mustache */
/* global guild_id */
var logintimer; // timer to keep track of user inactivity after hitting login
function resize_messagebox() {
var namebox_width = $("#nameplate").outerWidth(true);
var screen_width = $(document).width();
$("#messageboxouter").width(screen_width - namebox_width - 40);
}
function query_guild() {
var funct = $.ajax({
dataType: "json",
url: "/api/query_guild",
data: {"guild_id": guild_id}
});
return funct.promise();
}
function create_authenticated_user() {
var funct = $.ajax({
method: "POST",
dataType: "json",
url: "/api/create_authenticated_user",
data: {"guild_id": guild_id}
});
return funct.promise();
}
function create_unauthenticated_user(username) {
var funct = $.ajax({
method: "POST",
dataType: "json",
url: "/api/create_unauthenticated_user",
data: {"username": username, "guild_id": guild_id}
});
return funct.promise();
}
function fetch(channel_id, after=null) {
var funct = $.ajax({
method: "GET",
dataType: "json",
url: "/api/fetch",
data: {"channel_id": channel_id, "after": after}
});
return funct.promise();
}
$(function(){
resize_messagebox();
$("#loginmodal").modal({
dismissible: false, // Modal can be dismissed by clicking outside of the modal
opacity: .5, // Opacity of modal background
inDuration: 300, // Transition in duration
outDuration: 200, // Transition out duration
startingTop: '4%', // Starting top style attribute
endingTop: '10%', // Ending top style attribute
}
);
var guild = query_guild();
guild.fail(function() {
$('#loginmodal').modal('open');
});
guild.done(function(data) {
initialize_embed(data);
//$('#loginmodal').modal('open');
});
});
function lock_login_fields() {
$("#loginProgress").show();
$("#discordlogin_btn").attr("disabled",true);
$("#custom_username_field").prop("disabled",true);
logintimer = setTimeout(function() {
unlock_login_fields();
}, 60000);
}
function unlock_login_fields() {
$("#loginProgress").hide();
$("#discordlogin_btn").attr("disabled",false);
$("#custom_username_field").prop("disabled",false);
clearTimeout(logintimer);
}
function initialize_embed(guildobj) {
$('#loginmodal').modal('close');
unlock_login_fields();
if (guildobj === undefined) {
var guild = query_guild();
guild.done(function(data) {
prepare_guild(data);
});
} else {
prepare_guild(guildobj);
}
}
function prepare_guild(guildobj) {
console.log(guildobj);
fill_channels(guildobj.channels);
fill_discord_members(guildobj.discordmembers);
fill_authenticated_users(guildobj.embedmembers.authenticated);
fill_unauthenticated_users(guildobj.embedmembers.unauthenticated);
}
function fill_channels(channels) {
var template = $('#mustache_channellistings').html();
Mustache.parse(template);
$("#channels-list").empty();
for (var i = 0; i < channels.length; i++) {
var chan = channels[i];
var rendered = Mustache.render(template, {"channelid": chan.id, "channelname": chan.name});
$("#channels-list").append(rendered);
}
}
function fill_discord_members(discordmembers) {
var template = $('#mustache_authedusers').html();
Mustache.parse(template);
$("#discord-members").empty();
for (var i = 0; i < discordmembers.length; i++) {
var member = discordmembers[i];
var rendered = Mustache.render(template, {"id": member.id, "username": member.username, "avatar": member.avatar_url});
$("#discord-members").append(rendered);
}
}
function fill_authenticated_users(users) {
var template = $('#mustache_authedusers').html();
Mustache.parse(template);
$("#embed-discord-members").empty();
for (var i = 0; i < users.length; i++) {
var member = users[i];
var rendered = Mustache.render(template, {"id": member.id, "username": member.username, "avatar": member.avatar_url});
$("#embed-discord-members").append(rendered);
}
}
function fill_unauthenticated_users(users) {
var template = $('#mustache_unauthedusers').html();
Mustache.parse(template);
$("#embed-unauth-users").empty();
for (var i = 0; i < users.length; i++) {
var member = users[i];
var rendered = Mustache.render(template, {"username": member.username, "discriminator": member.discriminator});
$("#embed-unauth-users").append(rendered);
}
}
function wait_for_discord_login() {
_wait_for_discord_login(0);
}
function _wait_for_discord_login(index) {
setTimeout(function() {
var usr = create_authenticated_user();
usr.done(function(data) {
initialize_embed();
return;
});
usr.fail(function(data) {
if (data.status == 403) {
Materialize.toast('Authentication error! You have been banned.', 10000);
} else if (index < 10) {
_wait_for_discord_login(index + 1);
}
});
}, 5000);
}
$("#discordlogin_btn").click(function() {
lock_login_fields();
wait_for_discord_login();
});
$("#custom_username_field").keyup(function(event){
if(event.keyCode == 13 && $(this).val().length >= 2 && $(this).val().length <= 32) {
lock_login_fields();
var usr = create_unauthenticated_user($(this).val());
usr.done(function(data) {
initialize_embed();
});
usr.fail(function(data) {
if (data.status == 403) {
Materialize.toast('Authentication error! You have been banned.', 10000);
}
})
}
});
$(window).resize(function() {
resize_messagebox();
});
$('#guild-btn').sideNav({
menuWidth: 300, // Default is 300
edge: 'left', // Choose the horizontal origin
closeOnClick: true, // Closes side-nav on <a> clicks, useful for Angular/Meteor
draggable: true // Choose whether you can drag to open on touch screens
}
);
$('#members-btn').sideNav({
menuWidth: 300, // Default is 300
edge: 'right', // Choose the horizontal origin
draggable: true // Choose whether you can drag to open on touch screens
}
);

View File

@ -0,0 +1,135 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="//fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/css/materialize.min.css" integrity="sha256-6DQKO56c9MZL0LAc7QNtxqJyqSa3rS9Gq5FVcIhtA+w=" crossorigin="anonymous" media="screen,projection"/>
<link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='css/embedstyle.css') }}">
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{{ guild['name'] }} - Embed - Titan Embeds for Discord</title>
</head>
<body>
<div class="navbar-fixed">
<nav>
<div class="nav-wrapper">
<a href="#" data-activates="guild-nav" class="button-collapse" id="guild-btn"><i class="material-icons">menu</i></a>
<div class="container">
<a href="#" class="brand-logo"><b>Titan</b>Embeds</a>
</div>
<a href="#" data-activates="members-nav" class="button-collapse right" id="members-btn"><i class="material-icons">person</i></a>
</div>
</nav>
</div>
<main>
<div class="chatcontent">
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> adfsadfsdfas</p>
</div>
</main>
<ul id="guild-nav" class="side-nav">
<li>
<div class="userView">
{% if guild['icon'] %}
<img class="circle" src="{{ generate_guild_icon( guild['id'], guild['icon'] ) }}">
{% endif %}
<span class="name">{{ guild['name'] }}</span>
</div>
</li>
<li><a class="subheader">Actions</a></li>
<li><a href="{{ url_for("user.administrate_guild", guild_id=guild['id']) }}" class="waves-effect" target="_blank" id="administrate_link" style="display: none;">Manage Guild Embed</a></li>
<li><a href="https://discordapp.com/channels/{{ guild['id'] }}/" class="waves-effect" target="_blank">Open Server on Discordapp</a></li>
<li><div class="divider"></div></li>
<li><a class="subheader">Channels</a></li>
<span id="channels-list"></span>
</ul>
<ul id="members-nav" class="side-nav">
<li><a class="subheader">Online Server Members</a></li>
<span id="discord-members"></span>
<li><div class="divider"></div></li>
<li><a class="subheader">Authenticated Embed Users</a></li>
<span id="embed-discord-members"></span>
<li><a class="subheader">Guest Embed Users</a></li>
<span id="embed-unauth-users"></span>
</ul>
<div id="loginmodal" class="modal">
<div class="modal-content">
<h4>{{ login_greeting }}</h4>
<p class="flow-text">Please choose one of the following methods to authenticate!</p>
<div class="progress" id="loginProgress" style="display: none;">
<div class="indeterminate"></div>
</div>
<div class="row">
<div class="col s1 m4">
<a id="discordlogin_btn" href="{{ url_for("embed.login_discord", _external=True) }}" class="waves-effect waves-light btn-large" target="_blank">Login with Discord</a>
</div>
{% if unauth_enabled %}
<div class="col s1 m8">
<p>Of course, you also have the option to login by picking a temporary username.</p>
<input id="custom_username_field" type="text">
<label class="active" for="custom_username_field">Username</label>
</div>
{% endif %}
</div>
</div>
</div>
<footer class="footer">
<div class="footercontainer">
<div class="currentuserchip left" id="nameplate">
<div class="left"><img src="https://cdn.discordapp.com/icons/213459805048668160/14aa7c0ad94e3c80d2eeef3a83cae1c1.jpg" class="circle left currentuserimage"></div>
<div class="currentusername left">EndenDragon#4151</div>
</div>
<div id="messageboxouter" class="input-field inline"><textarea placeholder="Enter message" id="messagebox" type="text" class="materialize-textarea"></textarea></div>
</div>
</footer>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.1/js/materialize.min.js" integrity="sha256-ToPQhpo/E89yaCd7+V8LUCjobNRkjilRXfho6x3twLU=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js" integrity="sha256-iaqfO5ue0VbSGcEiQn+OeXxnxAMK2+QgHXIDA5bWtGI=" crossorigin="anonymous"></script>
{% raw %}
<script id="mustache_channellistings" type="text/template">
<li><a class="waves-effect truncate" id="channel-{{channelid}}"><span class="channel-hash">#</span> {{channelname}}</a></li>
</script>
<script id="mustache_authedusers" type="text/template">
<li><a class="waves-effect truncate" id="discorduser-{{id}}"><img class="circle membercircle" src="{{avatar}}"> <span class="membername">{{username}}</span></a></li>
</script>
<script id="mustache_unauthedusers" type="text/template">
<li><a class="waves-effect truncate"><span class="membername">{{username}}#{{discriminator}}</span></a></li>
</script>
<script id="mustache_usermessage" type="text/template">
<p><span title="March 31, 2017 3:30PM" class="chattimestamp">3:30PM</span> <span class="chatusername">EndenDragon#69420</span> Hello everyone!</p>
</script>
{% endraw %}
<script>
var guild_id = "{{ guild_id }}";
</script>
<script type="text/javascript" src="{{ url_for('static', filename='js/embed.js') }}"></script>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>Sign in completed - Titan Embeds</title>
</head>
<body>
<p>Sign in complete! You may now close the window.</p>
<script>
window.close()
</script>
</body>
</html>

View File

@ -1,3 +1,4 @@
from titanembeds.database import db, Guilds
from titanembeds.discordrest import DiscordREST
from flask import request, session
from flask.ext.cache import Cache
@ -51,5 +52,18 @@ def guild_ratelimit_key():
guild_id = request.args.get('guild_id', "0")
return (sess + guild_id).encode('utf-8')
def check_guild_existance(guild_id):
dbGuild = Guilds.query.filter_by(guild_id=guild_id).first()
if not dbGuild:
return False
guilds = discord_api.get_all_guilds()
for guild in guilds:
if guild_id == guild['id']:
return True
return False
rate_limiter = Limiter(key_func=get_client_ipaddr) # Default limit by ip address
def guild_query_unauth_users_bool(guild_id):
dbGuild = db.session.query(Guilds).filter(Guilds.guild_id==guild_id).first()
return dbGuild.unauth_users
rate_limiter = Limiter(key_func=get_client_ipaddr) # Default limit by ip address