Implement sending rich embeds

This commit is contained in:
Jeremy Zhang 2019-11-06 13:45:48 -08:00
parent 8dec93d087
commit aa49b2d473
15 changed files with 529 additions and 53 deletions

View File

@ -0,0 +1,30 @@
"""Add send_rich_embed fields to guilds and cosmetics
Revision ID: 08f6b59be038
Revises: ecf3e6bf950e
Create Date: 2019-11-06 11:54:01.324095
"""
# revision identifiers, used by Alembic.
revision = '08f6b59be038'
down_revision = 'ecf3e6bf950e'
branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('cosmetics', sa.Column('send_rich_embed', sa.Boolean(), server_default=sa.text('false'), nullable=False))
op.add_column('guilds', sa.Column('send_rich_embed', sa.Boolean(), server_default='0', nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('guilds', 'send_rich_embed')
op.drop_column('cosmetics', 'send_rich_embed')
# ### end Alembic commands ###

View File

@ -49,6 +49,7 @@ def cosmetics_post():
css = request.form.get("css", None)
css_limit = int(request.form.get("css_limit", 0))
guest_icon = request.form.get("guest_icon", None)
send_rich_embed = request.form.get("send_rich_embed", None)
badges = request.form.get("badges", None)
entry = db.session.query(Cosmetics).filter(Cosmetics.user_id == user_id).first()
if entry:
@ -62,6 +63,9 @@ def cosmetics_post():
if guest_icon is not None:
guest_icon = guest_icon.lower() == "true"
user.guest_icon = guest_icon
if send_rich_embed:
send_rich_embed = send_rich_embed.lower() == "true"
user.send_rich_embed = send_rich_embed
if badges is not None:
badges = badges.split(",")
if badges == [""]:
@ -93,6 +97,7 @@ def cosmetics_patch():
css = request.form.get("css", None)
css_limit = request.form.get("css_limit", None)
guest_icon = request.form.get("guest_icon", None)
send_rich_embed = request.form.get("send_rich_embed", None)
badges = request.form.get("badges", None)
entry = db.session.query(Cosmetics).filter(Cosmetics.user_id == user_id).first()
if not entry:
@ -105,6 +110,9 @@ def cosmetics_patch():
if guest_icon:
guest_icon = guest_icon.lower() == "true"
entry.guest_icon = guest_icon
if send_rich_embed:
send_rich_embed = send_rich_embed.lower() == "true"
entry.send_rich_embed = send_rich_embed
if badges is not None:
badges = badges.split(",")
if badges == [""]:
@ -195,6 +203,7 @@ def administrate_guild(guild_id):
"autorole_unauth": db_guild.autorole_unauth,
"autorole_discord": db_guild.autorole_discord,
"file_upload": db_guild.file_upload,
"send_rich_embed": db_guild.send_rich_embed,
}
return render_template("administrate_guild.html.j2", guild=dbguild_dict, members=users, permissions=permissions, cosmetics=cosmetics)
@ -216,6 +225,7 @@ def update_administrate_guild(guild_id):
db_guild.autorole_unauth = request.form.get("autorole_unauth", db_guild.autorole_unauth, type=int)
db_guild.autorole_discord = request.form.get("autorole_discord", db_guild.autorole_discord, type=int)
db_guild.file_upload = request.form.get("file_upload", db_guild.file_upload) in ["true", True]
db_guild.send_rich_embed = request.form.get("send_rich_embed", db_guild.send_rich_embed) in ["true", True]
invite_link = request.form.get("invite_link", db_guild.invite_link)
if invite_link != None and invite_link.strip() == "":
invite_link = None
@ -254,6 +264,7 @@ def update_administrate_guild(guild_id):
autorole_unauth=db_guild.autorole_unauth,
autorole_discord=db_guild.autorole_discord,
file_upload=db_guild.file_upload,
send_rich_embed=db_guild.send_rich_embed,
)
@admin.route("/guilds")

View File

@ -303,6 +303,9 @@ def post():
file = request.files["file"]
if file and file.filename == "":
file = None
rich_embed = request.form.get("richembed", None)
if rich_embed:
rich_embed = json.loads(rich_embed)
if "user_id" in session:
dbUser = redisqueue.get_guild_member(guild_id, session["user_id"])
else:
@ -322,7 +325,7 @@ def post():
chan = filter_guild_channel(guild_id, channel_id)
if not chan.get("write") or chan["channel"]["type"] != "text":
status_code = 401
elif file and not chan.get("attach_files"):
elif (file and not chan.get("attach_files")) or (rich_embed and not chan.get("embed_links")):
status_code = 406
elif not illegal_post:
userid = session["user_id"]
@ -354,10 +357,10 @@ def post():
username = username[:25]
username = username + "#" + str(session['discriminator'])
avatar = session['avatar']
message = discord_api.execute_webhook(webhook.get("id"), webhook.get("token"), username, avatar, content, file)
message = discord_api.execute_webhook(webhook.get("id"), webhook.get("token"), username, avatar, content, file, rich_embed)
delete_webhook_if_too_much(webhook)
else:
message = discord_api.create_message(channel_id, content, file)
message = discord_api.create_message(channel_id, content, file, rich_embed)
status_code = message['code']
db.session.commit()
response = jsonify(message=message.get('content', message), status=status, illegal_reasons=illegal_reasons)

View File

@ -233,6 +233,7 @@ def administrate_guild(guild_id):
"autorole_unauth": db_guild.autorole_unauth,
"autorole_discord": db_guild.autorole_discord,
"file_upload": db_guild.file_upload,
"send_rich_embed": db_guild.send_rich_embed,
}
return render_template("administrate_guild.html.j2", guild=dbguild_dict, members=users, permissions=permissions, cosmetics=cosmetics, disabled=(guild_id in list_disabled_guilds()))
@ -262,6 +263,7 @@ def update_administrate_guild(guild_id):
db_guild.autorole_unauth = request.form.get("autorole_unauth", db_guild.autorole_unauth, type=int)
db_guild.autorole_discord = request.form.get("autorole_discord", db_guild.autorole_discord, type=int)
db_guild.file_upload = request.form.get("file_upload", db_guild.file_upload) in ["true", True]
db_guild.send_rich_embed = request.form.get("send_rich_embed", db_guild.send_rich_embed) in ["true", True]
invite_link = request.form.get("invite_link", db_guild.invite_link)
if invite_link != None and invite_link.strip() == "":
@ -304,6 +306,7 @@ def update_administrate_guild(guild_id):
autorole_unauth=db_guild.autorole_unauth,
autorole_discord=db_guild.autorole_discord,
file_upload=db_guild.file_upload,
send_rich_embed=db_guild.send_rich_embed,
)
@user.route("/add-bot/<guild_id>")

View File

@ -7,6 +7,7 @@ class Cosmetics(db.Model):
css = db.Column(db.Boolean(), nullable=False) # If they can create/edit custom CSS
css_limit = db.Column(db.Integer, nullable=False, server_default="0") # Custom CSS Limit
guest_icon = db.Column(db.Boolean(), nullable=False, server_default=db.false()) # If they can set the guest icon for all guilds
send_rich_embed = db.Column(db.Boolean(), nullable=False, server_default=db.false()) # If they can set the send rich embed for all guilds
badges = db.Column(db.String(255), nullable=False, server_default="[]") # JSON list of all the badges the user has
def __init__(self, user_id, **kwargs):
@ -27,6 +28,11 @@ class Cosmetics(db.Model):
else:
self.guest_icon = False
if "send_rich_embed" in kwargs:
self.send_rich_embed = kwargs["send_rich_embed"]
else:
self.send_rich_embed = False
if "badges" in kwargs:
self.badges = json.dumps(kwargs["badges"])
else:

View File

@ -20,6 +20,7 @@ class Guilds(db.Model):
autorole_unauth = db.Column(db.BigInteger, nullable=True, server_default=None) # Automatic Role inherit for unauthenticated users
autorole_discord = db.Column(db.BigInteger, nullable=True, server_default=None) # Automatic Role inherit for discord users
file_upload = db.Column(db.Boolean(), nullable=False, server_default="0") # Allow file uploading for server
send_rich_embed = db.Column(db.Boolean(), nullable=False, server_default="0") # Allow sending rich embed messages
def __init__(self, guild_id):
self.guild_id = guild_id

View File

@ -109,12 +109,20 @@ class DiscordREST:
# Channel
#####################
def create_message(self, channel_id, content, file=None):
def create_message(self, channel_id, content, file=None, richembed=None):
_endpoint = "/channels/{channel_id}/messages".format(channel_id=channel_id)
payload = {'content': content}
is_json = False
if file:
payload = {"payload_json": (None, json.dumps(payload)), "file": (file.filename, file.read(), 'application/octet-stream')}
r = self.request("POST", _endpoint, data=payload)
if richembed:
if richembed.get("type"):
del richembed["type"]
payload["embed"] = richembed
if not content:
del payload["content"]
is_json = True
r = self.request("POST", _endpoint, data=payload, json=is_json)
return r
#####################
@ -172,10 +180,11 @@ class DiscordREST:
r = self.request("POST", _endpoint, data=payload, json=True)
return r
def execute_webhook(self, webhook_id, webhook_token, username, avatar, content, file=None, wait=True):
def execute_webhook(self, webhook_id, webhook_token, username, avatar, content, file=None, richembed=None, wait=True):
_endpoint = "/webhooks/{id}/{token}".format(id=webhook_id, token=webhook_token)
if wait:
_endpoint += "?wait=true"
is_json = False
payload = {
'content': content,
'avatar_url': avatar,
@ -183,7 +192,14 @@ class DiscordREST:
}
if file:
payload = {"payload_json": (None, json.dumps(payload)), "file": (file.filename, file.read(), 'application/octet-stream')}
r = self.request("POST", _endpoint, data=payload)
if richembed:
if richembed.get("type"):
del richembed["type"]
payload["embeds"] = [richembed]
if not content:
del payload["content"]
is_json = True
r = self.request("POST", _endpoint, data=payload, json=is_json)
return r
def delete_webhook(self, webhook_id, webhook_token):

View File

@ -927,6 +927,10 @@ p.mentioned span.chatmessage {
display: none;
}
#send-rich-embed-btn {
display: none;
}
#upload-file-btn {
display: none;
}
@ -941,6 +945,10 @@ p.mentioned span.chatmessage {
display: block;
}
#send-rich-embed-btn {
display: block;
}
#upload-file-btn {
display: block;
}
@ -963,6 +971,19 @@ p.mentioned span.chatmessage {
color: white;
}
#send-rich-embed-btn {
position: absolute;
bottom: 5px;
right: 91px;
color: gray;
padding: 1px;
transition: .3s ease-out;
}
#send-rich-embed-btn:hover {
color: white;
}
#send-msg-btn {
position: absolute;
bottom: 7px;
@ -980,6 +1001,11 @@ p.mentioned span.chatmessage {
display: none;
}
#richembedmodal {
width: 80%;
max-height: 89vh;
}
@media only screen and (min-width: 500px) {
#filemodal-body {
display: flex;
@ -996,14 +1022,37 @@ p.mentioned span.chatmessage {
max-height: 100px;
}
#messagebox-filemodal {
#messagebox-filemodal, #messagebox-richembedmodal, #richembedmodal-left input {
background-color: rgba(0, 0, 0, 0.07);
}
#messagebox-filemodal::placeholder {
#messagebox-filemodal::placeholder, #messagebox-richembedmodal::placeholder, #richembedmodal-left input::placeholder {
color: #90a4ae;
}
#richembedmodal-left .input-field label {
color: white;
}
#richembedmodal-left input[type=text] {
height: 25px;
margin-bottom: 5px;
}
#richembedmodal-fields .input-field {
margin-top: 25px;
}
#richembedmodal-fields .delete-field {
padding-left: 0;
padding-right: 0;
color: #F5B7D0;
}
#richembedmodal-fields > div {
margin-bottom: 0;
}
#mention-picker {
color: black;
position: fixed;

View File

@ -1,13 +1,13 @@
/* global $, Materialize, location */
function postForm(user_id, css, css_limit, guest_icon, badges) {
function postForm(user_id, css, css_limit, guest_icon, send_rich_embed, badges) {
if (css_limit == "") {
css_limit = 0;
}
var funct = $.ajax({
dataType: "json",
method: "POST",
data: {"user_id": user_id, "css": css, "css_limit": css_limit, "guest_icon": guest_icon, "badges": badges}
data: {"user_id": user_id, "css": css, "css_limit": css_limit, "guest_icon": guest_icon, "send_rich_embed": send_rich_embed, "badges": badges}
});
return funct.promise();
}
@ -42,8 +42,9 @@ $(function() {
var css_checked = $("#new_css_switch").is(':checked');
var css_limit = $("#new_css_limit").val();
var guest_icon_checked = $("#new_guest_icon_switch").is(':checked');
var send_rich_embed_checked = $("#new_send_rich_embed_switch").is(":checked");
var badges = $("#new_badges > option:selected").map(function(){ return this.value }).get().join();
var formPost = postForm(user_id, css_checked, css_limit, guest_icon_checked, badges);
var formPost = postForm(user_id, css_checked, css_limit, guest_icon_checked, send_rich_embed_checked, badges);
formPost.done(function (data) {
location.reload();
});
@ -118,6 +119,21 @@ function update_guest_icon_switch(user_id, element) {
});
}
function update_send_rich_embed_switch(user_id, element) {
var send_rich_checked = $(element).is(':checked');
var formPatch = patchForm(user_id, {"send_rich_embed": send_rich_checked});
formPatch.done(function (data) {
Materialize.toast('Send Rich Embed updated!', 10000);
});
formPatch.fail(function (data) {
if (data.status == 409) {
Materialize.toast('This user id does not exists!', 10000);
} else {
Materialize.toast('Oh no! Something has failed changing the send rich embed toggle!', 10000);
}
});
}
function update_badges(user_id, element) {
var badges = $(element).val().join();
var formPatch = patchForm(user_id, {"badges": badges});

View File

@ -182,6 +182,15 @@ $('#file_upload').change(function() {
});
});
$('#send_rich_embed').change(function() {
var pathname = window.location.pathname;
var checked = $(this).is(':checked')
var payload = {"send_rich_embed": checked}
$.post(pathname, payload, function(data) {
Materialize.toast('Updated send rich embed setting!', 2000)
});
});
function initiate_ban(guild_id, user_id) {
var reason = prompt("Please enter your reason for ban");
var payload = {

View File

@ -155,7 +155,7 @@
return funct.promise();
}
function post(channel_id, content, file) {
function post(channel_id, content, file, richembed) {
if (content == "") {
content = null;
}
@ -188,6 +188,11 @@
}
return myXhr;
}
} else if (richembed) {
data = {"guild_id": guild_id, "channel_id": channel_id, "richembed": richembed};
if (content) {
data["content"] = content;
}
} else {
data = {"guild_id": guild_id, "channel_id": channel_id, "content": content};
}
@ -290,6 +295,7 @@
}
}
$("#send-rich-embed-btn").hide();
$("#upload-file-btn").hide();
$("#send-msg-btn").hide();
@ -332,6 +338,14 @@
outDuration: 400,
complete: function () { $("#fileinput").val(""); }
});
$("#richembedmodal").modal({
dismissible: true,
opacity: .3,
inDuration: 400,
outDuration: 400,
endingTop: '4%',
complete: function () { }
});
$("#usercard").modal({
opacity: .5,
});
@ -374,6 +388,10 @@
$("#messagebox-filemodal").trigger(jQuery.Event("keydown", { keyCode: 13 } ));
});
$("#proceed_richembedmodal_btn").click(function () {
$("#messagebox-richembedmodal").trigger(jQuery.Event("keydown", { keyCode: 13 } ));
});
$("#fileinput").change(function (e){
var files = e.target.files;
if (files && files.length > 0) {
@ -404,6 +422,52 @@
}
});
$("#send-rich-embed-btn").click(function () {
$("#richembedmodal").modal("open");
$("#messagebox-richembedmodal").val($("#messagebox").val());
$("#richembedform-color").val("#6BABDA");
$("#richembedform-title").val("");
$("#richembedform-description").val("");
$("#richembedform-url").val("");
$("#richembedform-thumbnailurl").val("");
$("#richembedform-authorname").val("");
$("#richembedform-authorurl").val("");
$("#richembedform-authoricon").val("");
$("#richembedform-footertext").val("");
$("#richembedmodal-fields").empty();
$("#richembedmodal-preview").empty();
});
$("#richembedmodal-left input").keyup(function () {
genPreviewPopulateRichEmbed();
});
$("#richembedmodal_addfield_btn").click(function () {
var count = $("#richembedmodal-fields > .row").length;
if (count >= 10) {
$("#richembedmodal_addfield_btn").addClass("disabled");
return;
}
var template = $($("#mustache_richembedfieldinput").html());
$("#richembedmodal-fields").append(template);
template.find("input.name").keyup(function () {
genPreviewPopulateRichEmbed();
});
template.find("input.value").keyup(function () {
genPreviewPopulateRichEmbed();
});
template.find(".delete-field").click(function () {
$(this).closest(".row").remove();
$("#richembedmodal_addfield_btn").removeClass("disabled");
});
count = $("#richembedmodal-fields > .row").length;
if (count >= 10) {
$("#richembedmodal_addfield_btn").addClass("disabled");
return;
}
});
$( "#theme-selector" ).change(function () {
var theme = $("#theme-selector option:selected").val();
var keep_custom_css = $("#overwrite_theme_custom_css_checkbox").is(':checked');
@ -621,6 +685,7 @@
$("#messagebox").hide();
$("#emoji-tray-toggle").hide();
$(".wdt-emoji-picker").hide();
$("#send-rich-embed-btn").hide();
$("#upload-file-btn").hide();
$("#send-msg-btn").hide();
} else {
@ -628,6 +693,7 @@
$("#messagebox").show();
$("#emoji-tray-toggle").show();
$(".wdt-emoji-picker").show();
$("#send-rich-embed-btn").show();
$("#upload-file-btn").show();
$("#send-msg-btn").show();
}
@ -834,6 +900,7 @@
if (curr_default_channel == null) {
$("#messagebox").prop('disabled', true);
$("#messagebox").prop('placeholder', "NO TEXT CHANNELS");
$("#send-rich-embed-btn").hide();
$("#upload-file-btn").hide();
$("#send-msg-btn").hide();
Materialize.toast("You find yourself in a strange place. You don't have access to any text channels, or there are none in this server.", 20000);
@ -845,12 +912,14 @@
if (this_channel.write) {
$("#messagebox").prop('disabled', false);
$("#messagebox").prop('placeholder', "Enter message");
$("#send-rich-embed-btn").show();
$("#upload-file-btn").show();
$("#send-msg-btn").show();
$(".wdt-emoji-picker").show();
} else {
$("#messagebox").prop('disabled', true);
$("#messagebox").prop('placeholder', "Messaging is disabled in this channel.");
$("#send-rich-embed-btn").hide();
$("#upload-file-btn").hide();
$("#send-msg-btn").hide();
$(".wdt-emoji-picker").hide();
@ -860,6 +929,11 @@
} else {
$("#upload-file-btn").hide();
}
if (this_channel.embed_links) {
$("#send-rich-embed-btn").show();
} else {
$("#send-rich-embed-btn").hide();
}
$("#channeltopic").text(this_channel.channel.topic);
$("#channel-"+selected_channel).parent().addClass("active");
}
@ -1110,6 +1184,107 @@
$("#usercard").modal('open');
}
function generatePreviewRichEmbed() {
var richembed = generateRichEmbedObjFromModalForm();
var rendered = render_embed(richembed);
$("#richembedmodal-preview").html(rendered);
}
function genPreviewPopulateRichEmbed() {
generatePreviewRichEmbed();
var richembed = generateRichEmbedObjFromModalForm();
$("#richembedmodal-object").val("");
if (Object.keys(richembed).length > 2) {
if (richembed.fields && richembed.fields.length == 0) {
return;
}
$("#richembedmodal-object").val(JSON.stringify(richembed));
}
}
function generateRichEmbedObjFromModalForm() {
var color = $("#richembedform-color").val();
var title = $("#richembedform-title").val();
var description = $("#richembedform-description").val();
var url = $("#richembedform-url").val();
var thumbnailurl = $("#richembedform-thumbnailurl").val();
var authorname = $("#richembedform-authorname").val();
var authorurl = $("#richembedform-authorurl").val();
var authoricon = $("#richembedform-authoricon").val();
var footertext = $("#richembedform-footertext").val();
var output = {
"type": "rich"
};
if (color.startsWith("#")) {
color = color.substr(1);
}
color = "0x" + color;
color = parseInt(color, 16);
output["color"] = color;
if (title) {
output["title"] = title;
}
if (description) {
output["description"] = description;
}
if (url) {
output["url"] = url;
}
if (thumbnailurl) {
output["thumbnail"] = {
"url": thumbnailurl,
"proxy_url": thumbnailurl,
};
}
if (authorname || authorurl || authoricon) {
output["author"] = {};
}
if (authorname) {
output["author"]["name"] = authorname;
}
if (authorurl) {
output["author"]["url"] = authorurl;
}
if (authoricon) {
output["author"]["icon_url"] = authoricon;
output["author"]["proxy_icon_url"] = authoricon;
}
if (footertext) {
output["footer"] = {
"text": footertext
}
}
var fieldRows = $("#richembedmodal-fields > .row");
if (fieldRows.length) {
output["fields"] = [];
}
for (var i = 0; i < Math.min(fieldRows.length, 10); i++) {
var fieldRow = $(fieldRows[i]);
var fieldName = fieldRow.find("input.name").val().trim();
var fieldValue = fieldRow.find("input.value").val().trim();
if (fieldName && fieldValue) {
output["fields"].push({
"name": fieldName,
"value": fieldValue,
"inline": false,
});
}
}
return output;
}
function flashElement(element) {
var opacity = element.css("opacity");
for (var i = 0; i < 3; i++) {
@ -1378,48 +1553,51 @@
// if ($.inArray(disembed.type, ["rich", "link", "video"]) == -1) {
// continue;
// }
if (disembed.type == "image") {
var img = "<img class=\"image attachment materialboxed\" src=\"" + disembed.thumbnail.proxy_url + "\">";
emb.push(img);
continue;
}
disembed.isVideo = false;
if (disembed.type == "video") {
disembed.isVideo = true;
if (disembed.video) {
var url = new URL(disembed.video.url);
if (url.hostname.endsWith("twitch.tv")) {
if (url.searchParams.has("autoplay")) {
url.searchParams.set("autoplay", "false");
disembed.video.url = url.toString();
}
}
}
}
disembed.toRenderFooter = false;
if (disembed.footer) {
disembed.toRenderFooter = true;
} else if (disembed.timestamp) {
disembed.toRenderFooter = true;
}
disembed.footerVerticalBar = disembed.footer && disembed.timestamp;
if (disembed.timestamp) {
disembed.formatted_timestamp = moment(disembed.timestamp).format('ddd MMM Do, YYYY [at] h:mm A');
}
if (disembed.color) {
disembed.hexColor = "#" + disembed.color.toString(16);
}
var template = $('#mustache_richembed').html();
Mustache.parse(template);
var rendered = Mustache.render(template, disembed);
var rendered = render_embed(disembed);
emb.push(rendered);
}
}
return emb;
}
function render_embed(disembed) {
if (disembed.type == "image") {
var img = "<img class=\"image attachment materialboxed\" src=\"" + disembed.thumbnail.proxy_url + "\">";
return img;
}
disembed.isVideo = false;
if (disembed.type == "video") {
disembed.isVideo = true;
if (disembed.video) {
var url = new URL(disembed.video.url);
if (url.hostname.endsWith("twitch.tv")) {
if (url.searchParams.has("autoplay")) {
url.searchParams.set("autoplay", "false");
disembed.video.url = url.toString();
}
}
}
}
disembed.toRenderFooter = false;
if (disembed.footer) {
disembed.toRenderFooter = true;
} else if (disembed.timestamp) {
disembed.toRenderFooter = true;
}
disembed.footerVerticalBar = disembed.footer && disembed.timestamp;
if (disembed.timestamp) {
disembed.formatted_timestamp = moment(disembed.timestamp).format('ddd MMM Do, YYYY [at] h:mm A');
}
if (disembed.color) {
disembed.hexColor = "#" + disembed.color.toString(16);
}
var template = $('#mustache_richembed').html();
Mustache.parse(template);
var rendered = Mustache.render(template, disembed);
return rendered;
}
function parse_message_reactions(reactions) {
var reacts = []
var template = $("#mustache_reactionchip").html();
@ -2010,12 +2188,15 @@
if (event.keyCode == 16) {
shift_pressed = true;
}
if(event.keyCode == 13 && !shift_pressed && ($(this).val().length >= 1 || $("#fileinput").val().length >= 1)) {
if(event.keyCode == 13 && !shift_pressed && ($(this).val().length >= 1 || $("#fileinput").val().length >= 1 || $("#richembedmodal-object").val().length >= 1)) {
$(this).val($.trim($(this).val()));
$(this).blur();
$("#messagebox-richembedmodal").attr('readonly', true);
$("#messagebox-filemodal").attr('readonly', true);
$("#proceed_fileupload_btn").attr("disabled", true);
$("#proceed_richembedmodal_btn").attr("disabled", true);
$("#messagebox").attr('readonly', true);
$("#richembedmodal-left input").attr('readonly', true);
$("#send-msg-btn").attr("disabled", true);
var emojiConvertor = new EmojiConvertor();
emojiConvertor.init_env();
@ -2028,12 +2209,18 @@
file = $("#fileinput")[0].files[0];
}
$("#filemodalprogress").show();
var funct = post(selected_channel, messageInput, file);
var richembed = $("#richembedmodal-object").val();
if (!richembed) {
richembed = null;
}
var funct = post(selected_channel, messageInput, file, richembed);
funct.done(function(data) {
$("#messagebox").val("");
$("#messagebox-filemodal").val("");
$("#fileinput").val("");
$("#richembedmodal-object").val("");
$("#filemodal").modal("close");
$("#richembedmodal").modal("close");
});
funct.fail(function(data) {
Materialize.toast('Failed to send message.', 10000);
@ -2055,6 +2242,9 @@
$("#messagebox-filemodal").attr('readonly', false);
$("#proceed_fileupload_btn").attr("disabled", false);
$("#filemodalprogress").hide();
$("#messagebox-richembedmodal").attr('readonly', false);
$("#proceed_richembedmodal_btn").attr("disabled", false);
$("#richembedmodal-left input").attr('readonly', false);
$("#send-msg-btn").attr("disabled", false);
if ($("#filemodal").is(":visible")) {
$("#messagebox-filemodal").focus();
@ -2087,6 +2277,28 @@
}
});
$("#messagebox-richembedmodal").keyup(function (event) {
if (event.keyCode == 16) {
shift_pressed = false;
}
});
$("#messagebox-richembedmodal").keydown(function (event) {
if ($(this).val().length == 1) {
$(this).val($.trim($(this).val()));
}
if (event.keyCode == 16) {
shift_pressed = true;
}
if(event.keyCode == 13 && !shift_pressed) {
$(this).val($.trim($(this).val()));
$(this).blur();
$("#messagebox").val($(this).val());
$("#messagebox").trigger(jQuery.Event("keydown", { keyCode: 13 } ));
}
});
$("#send-msg-btn").click(function () {
$("#messagebox").focus();
$("#messagebox").trigger(jQuery.Event("keydown", { keyCode: 13 } ));

View File

@ -15,6 +15,7 @@
<th>CSS</th>
<th>CSS Limit</th>
<th>Guest Icon</th>
<th>Send Rich Embed</th>
<th>Badges</th>
<th>Submit</th>
</tr>
@ -51,6 +52,16 @@
</label>
</div>
</td>
<td>
<div class="switch">
<label>
Off
<input type="checkbox" id="new_send_rich_embed_switch">
<span class="lever"></span>
On
</label>
</div>
</td>
<td>
<div class="input-field col s12">
<select multiple id="new_badges">
@ -80,6 +91,7 @@
<th>CSS</th>
<th>CSS Limit</th>
<th>Guest Icon</th>
<th>Send Rich Embed</th>
<th>Badges</th>
</tr>
</thead>
@ -113,6 +125,16 @@
</label>
</div>
</td>
<td>
<div class="switch">
<label>
Off
<input type="checkbox" {% if cosmetic.send_rich_embed %}checked{% endif %} onchange="update_send_rich_embed_switch('{{ cosmetic.user_id }}', this)">
<span class="lever"></span>
On
</label>
</div>
</td>
<td>
<div class="input-field col s12">
<select multiple id="new_badges" onchange="update_badges('{{ cosmetic.user_id }}', this)">

View File

@ -227,6 +227,22 @@
</label>
</div>
<br>
<p class="flow-text">Send Rich Embed</p>
<p>Allow users to send rich embedded messages (both the bot & user need "embed links" permission)</p>
{% if not cosmetics.send_rich_embed %}
<p class="red lighten-4"><strong>Your user account does not have access to change send rich embed. Please visit the Titan Tokens shop to activate this cosmetic item.</strong></p>
{% endif %}
<div class="switch">
<label>
Disable
<input type="checkbox" id="send_rich_embed" name="send_rich_embed" {% if guild['send_rich_embed'] %}checked{% endif %} {% if not cosmetics.send_rich_embed %}disabled{% endif %} >
<span class="lever"></span>
Enable
</label>
</div>
</div>
</div>
</div>

View File

@ -83,6 +83,7 @@
<div id="messageboxouter" class="input-field inline">
<textarea placeholder="Enter message" id="messagebox" type="text" class="materialize-textarea wdt-emoji-open-on-colon" rows="1"></textarea>
<span id="visitor_mode_message" style="display:none;"><span id="visitor_mode_message_note">{{ _("Please login to post a message.") }}</span> <a id="visitor_login_btn" class="waves-effect waves-light btn">{{ _("Login") }}</a></span>
<a id="send-rich-embed-btn" class="btn-flat"><i class="material-icons">queue</i></a>
<a id="upload-file-btn" class="btn-flat"><i class="material-icons">file_upload</i></a>
<a id="send-msg-btn" class="btn-floating btn-large waves-effect waves-light"><i class="material-icons">send</i></a>
</div>
@ -298,6 +299,67 @@
</div>
</div>
<div id="richembedmodal" class="modal">
<div class="modal-content">
<h4 class="center-align">Send a Rich Embed Message</h4>
<p>Add a comment (optional)</p>
<p class="center-align">
<textarea placeholder="Enter message" id="messagebox-richembedmodal" type="text" class="materialize-textarea" rows="1"></textarea>
</p>
<div id="richembedmodal-body" class="row">
<div id="richembedmodal-left" class="col s12 m5">
<div class="input-field">
<span>Color</span>
<input id="richembedform-color" type="color" value="#6BABDA">
</div>
<div class="input-field">
<input placeholder="title" id="richembedform-title" type="text" data-length="100" maxlength="100">
<label for="richembedform-title">Title</label>
</div>
<div class="input-field">
<input placeholder="description" id="richembedform-description" type="text" data-length="100" maxlength="100">
<label for="richembedform-description">Description</label>
</div>
<div class="input-field">
<input placeholder="link url" id="richembedform-url" type="text" data-length="100" maxlength="100">
<label for="richembedform-url">Link URL</label>
</div>
<div class="input-field">
<input placeholder="thumbnail url" id="richembedform-thumbnailurl" type="text" data-length="100" maxlength="100">
<label for="richembedform-thumbnailurl">Thumbnail URL (must begin with http(s))</label>
</div>
<div class="input-field">
<input placeholder="author name" id="richembedform-authorname" type="text" data-length="100" maxlength="100">
<label for="richembedform-authorname">Author Name</label>
</div>
<div class="input-field">
<input placeholder="author link url" id="richembedform-authorurl" type="text" data-length="100" maxlength="100">
<label for="richembedform-authorurl">Author Link URL (must begin with http(s))</label>
</div>
<div class="input-field">
<input placeholder="author icon url" id="richembedform-authoricon" type="text" data-length="100" maxlength="100">
<label for="richembedform-authoricon">Author Icon URL (must begin with http(s))</label>
</div>
<div class="input-field">
<input placeholder="footer text" id="richembedform-footertext" type="text" data-length="100" maxlength="100">
<label for="richembedform-footertext">Footer Text</label>
</div>
<span>Fields:</span>
<div id="richembedmodal-fields"></div>
<a id="richembedmodal_addfield_btn" class="waves-effect waves-light btn">+ Field</a>
</div>
<div id="richembedmodal-right" class="col s12 m7">
<div id="richembedmodal-preview"></div>
<span>Preview</span>
</div>
</div>
<input type="hidden" value="" id="richembedmodal-object">
<p class="right-align">
<a id="proceed_richembedmodal_btn" class="waves-effect waves-light btn">Send</a>
</p>
</div>
</div>
<div id="usercard" class="modal bottom-sheet">
<div class="modal-content">
<div class="row">
@ -545,6 +607,20 @@
<script id="mustache_reactionchip" type="text/template">
<span class="reaction tooltipped" data-position="top" data-delay="200" data-tooltip="{{#emoji.id}}:{{/emoji.id}}{{emoji.name}}{{#emoji.id}}:{{/emoji.id}}"><img src="{{img_url}}"> <span class="count">{{count}}</span></span>
</script>
<script id="mustache_richembedfieldinput" type="text/template">
<div class="row">
<div class="input-field col s5">
<input placeholder="Name" type="text" data-length="100" class="name" maxlength="100">
</div>
<div class="input-field col s5">
<input placeholder="Value" type="text" data-length="100" class="value" maxlength="100">
</div>
<div class="col s2">
<a class="btn-flat delete-field"><i class="material-icons">delete_forever</i></a>
</div>
</div>
</script>
{% endraw %}
<script>

View File

@ -233,11 +233,13 @@ def get_guild_channels(guild_id, force_everyone=False, forced_role=0):
result["mention_everyone"] = False
if not bot_result["attach_files"] or not db_guild.file_upload or not result["write"]:
result["attach_files"] = False
if not bot_result["embed_links"] or not db_guild.send_rich_embed or not result["write"]:
result["embed_links"] = False
result_channels.append(result)
return sorted(result_channels, key=lambda k: k['channel']['position'])
def get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_roles, user_id=None, force_everyone=False):
result = {"channel": channel, "read": False, "write": False, "mention_everyone": False, "attach_files": False}
result = {"channel": channel, "read": False, "write": False, "mention_everyone": False, "attach_files": False, "embed_links": False}
if not user_id:
user_id = str(session.get("user_id"))
if guild_owner == user_id:
@ -245,6 +247,7 @@ def get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_r
result["write"] = True
result["mention_everyone"] = True
result["attach_files"] = True
result["embed_links"] = True
return result
channel_perm = 0
@ -272,6 +275,7 @@ def get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_r
result["write"] = True
result["mention_everyone"] = True
result["attach_files"] = True
result["embed_links"] = True
return result
denies = 0
@ -295,6 +299,7 @@ def get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_r
result["write"] = user_has_permission(channel_perm, 11)
result["mention_everyone"] = user_has_permission(channel_perm, 17)
result["attach_files"] = user_has_permission(channel_perm, 15)
result["embed_links"] = user_has_permission(channel_perm, 14)
# If you cant read channel, you cant write in it
if not user_has_permission(channel_perm, 10):
@ -302,6 +307,7 @@ def get_channel_permission(channel, guild_id, guild_owner, guild_roles, member_r
result["write"] = False
result["mention_everyone"] = False
result["attach_files"] = False
result["embed_links"] = False
return result
def get_forced_role(guild_id):