diff --git a/discordbot/titanembeds/database/guilds.py b/discordbot/titanembeds/database/guilds.py
index b391b74..06f0040 100644
--- a/discordbot/titanembeds/database/guilds.py
+++ b/discordbot/titanembeds/database/guilds.py
@@ -7,6 +7,7 @@ class Guilds(Base):
name = db.Column(db.String(255)) # Name
unauth_users = db.Column(db.Boolean()) # If allowed unauth users
visitor_view = db.Column(db.Boolean()) # If users are automatically "signed in" and can view chat
+ webhook_messages = db.Column(db.Boolean()) # Use webhooks to send messages instead of the bot
chat_links = db.Column(db.Boolean()) # If users can post links
bracket_links = db.Column(db.Boolean()) # If appending brackets to links to prevent embed
mentions_limit = db.Column(db.Integer) # If there is a limit on the number of mentions in a msg
@@ -23,6 +24,7 @@ class Guilds(Base):
self.name = name
self.unauth_users = True # defaults to true
self.visitor_view = False
+ self.webhook_messages = False
self.chat_links = True
self.bracket_links = True
self.mentions_limit = -1 # -1 = unlimited mentions
diff --git a/webapp/alembic/versions/dadcb876cdd9_added_webhook_messages_boolean_column_.py b/webapp/alembic/versions/dadcb876cdd9_added_webhook_messages_boolean_column_.py
new file mode 100644
index 0000000..f51ad78
--- /dev/null
+++ b/webapp/alembic/versions/dadcb876cdd9_added_webhook_messages_boolean_column_.py
@@ -0,0 +1,144 @@
+"""Added webhook messages boolean column to guilds
+
+Revision ID: dadcb876cdd9
+Revises: 2a2f32ac91d6
+Create Date: 2017-08-27 20:01:30.874376
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'dadcb876cdd9'
+down_revision = '2a2f32ac91d6'
+branch_labels = None
+depends_on = None
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.alter_column('cosmetics', 'css',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False)
+ op.alter_column('guild_members', 'active',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('guild_members', 'banned',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False,
+ existing_server_default=sa.text("'0'"))
+ op.add_column('guilds', sa.Column('webhook_messages', sa.Boolean(), nullable=False))
+ op.alter_column('guilds', 'bracket_links',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('guilds', 'channels',
+ existing_type=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ type_=sa.Text(length=4294967295),
+ existing_nullable=False)
+ op.alter_column('guilds', 'chat_links',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('guilds', 'emojis',
+ existing_type=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ type_=sa.Text(length=4294967295),
+ existing_nullable=False)
+ op.alter_column('guilds', 'roles',
+ existing_type=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ type_=sa.Text(length=4294967295),
+ existing_nullable=False)
+ op.alter_column('guilds', 'unauth_users',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('guilds', 'visitor_view',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False)
+ op.alter_column('guilds', 'webhooks',
+ existing_type=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ type_=sa.Text(length=4294967295),
+ existing_nullable=False)
+ op.alter_column('unauthenticated_users', 'revoked',
+ existing_type=mysql.TINYINT(display_width=1),
+ type_=sa.Boolean(),
+ existing_nullable=False,
+ existing_server_default=sa.text("'0'"))
+ op.alter_column('user_css', 'css',
+ existing_type=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ type_=sa.Text(length=4294967295),
+ existing_nullable=True)
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.alter_column('user_css', 'css',
+ existing_type=sa.Text(length=4294967295),
+ type_=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ existing_nullable=True)
+ op.alter_column('unauthenticated_users', 'revoked',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False,
+ existing_server_default=sa.text("'0'"))
+ op.alter_column('guilds', 'webhooks',
+ existing_type=sa.Text(length=4294967295),
+ type_=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ existing_nullable=False)
+ op.alter_column('guilds', 'visitor_view',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False)
+ op.alter_column('guilds', 'unauth_users',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('guilds', 'roles',
+ existing_type=sa.Text(length=4294967295),
+ type_=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ existing_nullable=False)
+ op.alter_column('guilds', 'emojis',
+ existing_type=sa.Text(length=4294967295),
+ type_=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ existing_nullable=False)
+ op.alter_column('guilds', 'chat_links',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('guilds', 'channels',
+ existing_type=sa.Text(length=4294967295),
+ type_=mysql.LONGTEXT(collation='utf8mb4_unicode_ci'),
+ existing_nullable=False)
+ op.alter_column('guilds', 'bracket_links',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.drop_column('guilds', 'webhook_messages')
+ op.alter_column('guild_members', 'banned',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False,
+ existing_server_default=sa.text("'0'"))
+ op.alter_column('guild_members', 'active',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False,
+ existing_server_default=sa.text("'1'"))
+ op.alter_column('cosmetics', 'css',
+ existing_type=sa.Boolean(),
+ type_=mysql.TINYINT(display_width=1),
+ existing_nullable=False)
+ # ### end Alembic commands ###
diff --git a/webapp/titanembeds/blueprints/admin/admin.py b/webapp/titanembeds/blueprints/admin/admin.py
index 22712c9..e773718 100644
--- a/webapp/titanembeds/blueprints/admin/admin.py
+++ b/webapp/titanembeds/blueprints/admin/admin.py
@@ -135,6 +135,7 @@ def administrate_guild(guild_id):
"name": db_guild.name,
"unauth_users": db_guild.unauth_users,
"visitor_view": db_guild.visitor_view,
+ "webhook_messages": db_guild.webhook_messages,
"chat_links": db_guild.chat_links,
"bracket_links": db_guild.bracket_links,
"mentions_limit": db_guild.mentions_limit,
@@ -149,6 +150,7 @@ def update_administrate_guild(guild_id):
db_guild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first()
db_guild.unauth_users = request.form.get("unauth_users", db_guild.unauth_users) in ["true", True]
db_guild.visitor_view = request.form.get("visitor_view", db_guild.visitor_view) in ["true", True]
+ db_guild.webhook_messages = request.form.get("webhook_messages", db_guild.webhook_messages) in ["true", True]
db_guild.chat_links = request.form.get("chat_links", db_guild.chat_links) in ["true", True]
db_guild.bracket_links = request.form.get("bracket_links", db_guild.bracket_links) in ["true", True]
db_guild.mentions_limit = request.form.get("mentions_limit", db_guild.mentions_limit)
@@ -161,6 +163,8 @@ def update_administrate_guild(guild_id):
id=db_guild.id,
guild_id=db_guild.guild_id,
unauth_users=db_guild.unauth_users,
+ visitor_view=db_guild.visitor_view,
+ webhook_messages=db_guild.webhook_messages,
chat_links=db_guild.chat_links,
bracket_links=db_guild.bracket_links,
mentions_limit=db_guild.mentions_limit,
diff --git a/webapp/titanembeds/blueprints/api/api.py b/webapp/titanembeds/blueprints/api/api.py
index 2002dae..f28d4e1 100644
--- a/webapp/titanembeds/blueprints/api/api.py
+++ b/webapp/titanembeds/blueprints/api/api.py
@@ -2,7 +2,7 @@ from titanembeds.database import db, Guilds, UnauthenticatedUsers, Unauthenticat
from titanembeds.decorators import valid_session_required, discord_users_only
from titanembeds.utils import check_guild_existance, guild_accepts_visitors, guild_query_unauth_users_bool, get_client_ipaddr, discord_api, rate_limiter, channel_ratelimit_key, guild_ratelimit_key
from titanembeds.oauth import user_has_permission, generate_avatar_url, check_user_can_administrate_guild
-from titanembeds.userbookkeeping import user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels
+from titanembeds.userbookkeeping import user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels, guild_webhooks_enabled
from flask import Blueprint, abort, jsonify, session, request, url_for
from flask_socketio import emit
from sqlalchemy import and_
@@ -50,7 +50,7 @@ def format_post_content(guild_id, channel_id, message, dbUser):
mention = "<@" + match[2: len(match) - 1] + ">"
message = message.replace(match, mention, 1)
- if not get_channel_webhook_url(guild_id, channel_id):
+ if not guild_webhooks_enabled(guild_id):
if (session['unauthenticated']):
message = u"**[{}#{}]** {}".format(session['username'], session['user_id'], message)
else:
@@ -137,15 +137,23 @@ def get_guild_emojis(guild_id):
# Returns webhook url if exists and can post w/webhooks, otherwise None
def get_channel_webhook_url(guild_id, channel_id):
+ if not guild_webhooks_enabled(guild_id):
+ return None
dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first()
guild_webhooks = json.loads(dbguild.webhooks)
+ name = "[Titan] "
+ if user_unauthenticated():
+ name = name + session["username"] + "#" + str(session["user_id"])
+ else:
+ name = name + session["username"] + "#" + str(session["discriminator"])
for webhook in guild_webhooks:
- if channel_id == webhook["channel_id"] and (webhook["name"].lower().startswith("titan") or webhook["name"].lower().startswith("[titan]")):
+ if channel_id == webhook["channel_id"] and webhook["name"] == name:
return {
"id": webhook["id"],
"token": webhook["token"]
}
- return None
+ webhook = discord_api.create_webhook(channel_id, name)
+ return webhook["content"]
@api.route("/fetch", methods=["GET"])
@valid_session_required(api=True)
diff --git a/webapp/titanembeds/blueprints/gateway/gateway.py b/webapp/titanembeds/blueprints/gateway/gateway.py
index 946483e..57ca873 100644
--- a/webapp/titanembeds/blueprints/gateway/gateway.py
+++ b/webapp/titanembeds/blueprints/gateway/gateway.py
@@ -1,10 +1,11 @@
-from titanembeds.utils import socketio, guild_accepts_visitors, get_client_ipaddr
-from titanembeds.userbookkeeping import check_user_in_guild, get_guild_channels, update_user_status
-from titanembeds.database import db, GuildMembers, get_guild_member
+from titanembeds.utils import socketio, guild_accepts_visitors, get_client_ipaddr, discord_api
+from titanembeds.userbookkeeping import check_user_in_guild, get_guild_channels, update_user_status, guild_webhooks_enabled
+from titanembeds.database import db, GuildMembers, get_guild_member, Guilds
from flask_socketio import Namespace, emit, disconnect, join_room, leave_room
import functools
from flask import request, session
import time
+import json
class Gateway(Namespace):
def on_connect(self):
@@ -48,6 +49,17 @@ class Gateway(Namespace):
else:
msg = {"unauthenticated": False, "id": session["user_id"]}
emit("embed_user_disconnect", msg, room="GUILD_"+guild_id)
+ if guild_webhooks_enabled(guild_id): # Delete webhooks
+ dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first()
+ guild_webhooks = json.loads(dbguild.webhooks)
+ name = "[Titan] "
+ if session["unauthenticated"]:
+ name = name + session["username"] + "#" + str(session["user_id"])
+ else:
+ name = name + session["username"] + "#" + str(session["discriminator"])
+ for webhook in guild_webhooks:
+ if webhook["name"] == name:
+ discord_api.delete_webhook(webhook["id"], webhook["token"])
def on_heartbeat(self, data):
guild_id = data["guild_id"]
diff --git a/webapp/titanembeds/blueprints/user/user.py b/webapp/titanembeds/blueprints/user/user.py
index 4024a22..9a2b216 100644
--- a/webapp/titanembeds/blueprints/user/user.py
+++ b/webapp/titanembeds/blueprints/user/user.py
@@ -181,6 +181,7 @@ def administrate_guild(guild_id):
"name": db_guild.name,
"unauth_users": db_guild.unauth_users,
"visitor_view": db_guild.visitor_view,
+ "webhook_messages": db_guild.webhook_messages,
"chat_links": db_guild.chat_links,
"bracket_links": db_guild.bracket_links,
"mentions_limit": db_guild.mentions_limit,
@@ -199,6 +200,7 @@ def update_administrate_guild(guild_id):
abort(400)
db_guild.unauth_users = request.form.get("unauth_users", db_guild.unauth_users) in ["true", True]
db_guild.visitor_view = request.form.get("visitor_view", db_guild.visitor_view) in ["true", True]
+ db_guild.webhook_messages = request.form.get("webhook_messages", db_guild.webhook_messages) in ["true", True]
db_guild.chat_links = request.form.get("chat_links", db_guild.chat_links) in ["true", True]
db_guild.bracket_links = request.form.get("bracket_links", db_guild.bracket_links) in ["true", True]
db_guild.mentions_limit = request.form.get("mentions_limit", db_guild.mentions_limit)
@@ -212,6 +214,8 @@ def update_administrate_guild(guild_id):
id=db_guild.id,
guild_id=db_guild.guild_id,
unauth_users=db_guild.unauth_users,
+ visitor_view=db_guild.visitor_view,
+ webhook_messages=db_guild.webhook_messages,
chat_links=db_guild.chat_links,
bracket_links=db_guild.bracket_links,
mentions_limit=db_guild.mentions_limit,
diff --git a/webapp/titanembeds/database/guilds.py b/webapp/titanembeds/database/guilds.py
index 10ff3bd..72db66a 100644
--- a/webapp/titanembeds/database/guilds.py
+++ b/webapp/titanembeds/database/guilds.py
@@ -7,6 +7,7 @@ class Guilds(db.Model):
name = db.Column(db.String(255), nullable=False) # Name
unauth_users = db.Column(db.Boolean(), nullable=False, default=1) # If allowed unauth users
visitor_view = db.Column(db.Boolean(), nullable=False, default=0) # If users are automatically "signed in" and can view chat
+ webhook_messages = db.Column(db.Boolean(), nullable=False, default=0) # Use webhooks to send messages instead of the bot
chat_links = db.Column(db.Boolean(), nullable=False, default=1) # If users can post links
bracket_links = db.Column(db.Boolean(), nullable=False, default=1) # If appending brackets to links to prevent embed
mentions_limit = db.Column(db.Integer, nullable=False, default=11) # If there is a limit on the number of mentions in a msg
@@ -23,6 +24,7 @@ class Guilds(db.Model):
self.name = name
self.unauth_users = True # defaults to true
self.visitor_view = False
+ self.webhook_messages = False
self.chat_links = True
self.bracket_links = True
self.mentions_limit = -1 # -1 = unlimited mentions
diff --git a/webapp/titanembeds/discordrest.py b/webapp/titanembeds/discordrest.py
index 3afc03b..c3490af 100644
--- a/webapp/titanembeds/discordrest.py
+++ b/webapp/titanembeds/discordrest.py
@@ -145,6 +145,16 @@ class DiscordREST:
# Webhook
#####################
+ def create_webhook(self, channel_id, name, avatar=None):
+ _endpoint = "/channels/{channel_id}/webhooks".format(channel_id=channel_id)
+ payload = {
+ "name": name,
+ }
+ if avatar:
+ payload["avatar"] = avatar
+ r = self.request("POST", _endpoint, data=payload, json=True)
+ return r
+
def execute_webhook(self, webhook_id, webhook_token, username, avatar, content, wait=True):
_endpoint = "/webhooks/{id}/{token}".format(id=webhook_id, token=webhook_token)
if wait:
@@ -155,4 +165,9 @@ class DiscordREST:
'username': username
}
r = self.request("POST", _endpoint, data=payload)
+ return r
+
+ def delete_webhook(self, webhook_id, webhook_token):
+ _endpoint = "/webhooks/{id}/{token}".format(id=webhook_id, token=webhook_token)
+ r = self.request("DELETE", _endpoint)
return r
\ No newline at end of file
diff --git a/webapp/titanembeds/static/js/administrate_guild.js b/webapp/titanembeds/static/js/administrate_guild.js
index 78c3b1b..c189827 100644
--- a/webapp/titanembeds/static/js/administrate_guild.js
+++ b/webapp/titanembeds/static/js/administrate_guild.js
@@ -16,6 +16,15 @@ $('#visitor_view').change(function() {
});
});
+$('#webhook_messages').change(function() {
+ var pathname = window.location.pathname;
+ var checked = $(this).is(':checked')
+ var payload = {"webhook_messages": checked}
+ $.post(pathname, payload, function(data) {
+ Materialize.toast('Updated webhook messages setting!', 2000)
+ });
+});
+
$('#chat_links').change(function() {
var pathname = window.location.pathname;
var checked = $(this).is(':checked')
diff --git a/webapp/titanembeds/templates/administrate_guild.html.j2 b/webapp/titanembeds/templates/administrate_guild.html.j2
index 27578c2..9353c27 100644
--- a/webapp/titanembeds/templates/administrate_guild.html.j2
+++ b/webapp/titanembeds/templates/administrate_guild.html.j2
@@ -62,6 +62,19 @@
+
+
+
Toggle Webhooks Messages
+Instead of sending user messages directly from the Titan bot, webhook messages allows Titan to take advantage of the built-in webhooks to create messages that looks more real. Reading messages in Discord can be 20% more cooler!
+Chat Links
diff --git a/webapp/titanembeds/userbookkeeping.py b/webapp/titanembeds/userbookkeeping.py index 576a161..13954af 100644 --- a/webapp/titanembeds/userbookkeeping.py +++ b/webapp/titanembeds/userbookkeeping.py @@ -176,4 +176,8 @@ def get_guild_channels(guild_id, force_everyone=False): result["mention_everyone"] = False result_channels.append(result) - return sorted(result_channels, key=lambda k: k['channel']['position']) \ No newline at end of file + return sorted(result_channels, key=lambda k: k['channel']['position']) + +def guild_webhooks_enabled(guild_id): + dbguild = db.session.query(Guilds).filter(Guilds.guild_id == guild_id).first() + return dbguild.webhook_messages \ No newline at end of file