Sorted online discord server members by roles and color. fixed caching a bit

This commit is contained in:
Jeremy Zhang 2017-04-13 23:10:13 -07:00
parent 789341ace9
commit b040f614c2
5 changed files with 147 additions and 50 deletions

View File

@ -186,8 +186,8 @@ def get_guild_channels(guild_id):
result["read"] = False result["read"] = False
result["write"] = False result["write"] = False
#if result["read"]: if result["read"]:
result_channels.append(result) result_channels.append(result)
return sorted(result_channels, key=lambda k: k['channel']['position']) return sorted(result_channels, key=lambda k: k['channel']['position'])
def filter_guild_channel(guild_id, channel_id): def filter_guild_channel(guild_id, channel_id):
@ -199,6 +199,28 @@ def filter_guild_channel(guild_id, channel_id):
def get_online_discord_users(guild_id): def get_online_discord_users(guild_id):
embed = discord_api.get_widget(guild_id) embed = discord_api.get_widget(guild_id)
apimembers = discord_api.list_all_guild_members(guild_id)
apimembers_filtered = {}
for member in apimembers:
apimembers_filtered[member["user"]["id"]] = member
guild_roles = discord_api.get_guild_roles(guild_id)["content"]
guildroles_filtered = {}
for role in guild_roles:
guildroles_filtered[role["id"]] = role
for member in embed['members']:
apimem = apimembers_filtered.get(member["id"])
member["hoist-role"] = None
member["color"] = None
if apimem:
for roleid in reversed(apimem["roles"]):
role = guildroles_filtered[roleid]
if role["color"] != 0:
member["color"] = '{0:02x}'.format(role["color"]) #int to hex
if role["hoist"]:
member["hoist-role"] = {}
member["hoist-role"]["name"] = role["name"]
member["hoist-role"]["id"] = role["id"]
member["hoist-role"]["position"] = role["position"]
return embed['members'] return embed['members']
def get_online_embed_users(guild_id): def get_online_embed_users(guild_id):
@ -287,7 +309,7 @@ def create_unauthenticated_user():
username = username.strip() username = username.strip()
if len(username) < 2 or len(username) > 32: if len(username) < 2 or len(username) > 32:
abort(406) abort(406)
if not all(x.isalnum() or x.isspace() or "-" == x or "_" == x for x in username): if not all(x.isalpha() or x.isspace() or "-" == x or "_" == x for x in username):
abort(406) abort(406)
if not check_guild_existance(guild_id): if not check_guild_existance(guild_id):
abort(404) abort(404)

View File

@ -2,10 +2,12 @@ import requests
import sys import sys
import time import time
import json import json
from functools import partial
from cachetools import cached, TTLCache from cachetools import cached, TTLCache
from cachetools.keys import hashkey
_DISCORD_API_BASE = "https://discordapp.com/api/v6" _DISCORD_API_BASE = "https://discordapp.com/api/v6"
cache = TTLCache(200, 300) cache = TTLCache(200, 200)
def json_or_text(response): def json_or_text(response):
text = response.text text = response.text
@ -120,7 +122,7 @@ class DiscordREST:
r = self.request("GET", _endpoint) r = self.request("GET", _endpoint)
return r return r
@cached(cache) @cached(cache, key=partial(hashkey, 'get_guild_member'))
def get_guild_member(self, guild_id, user_id): def get_guild_member(self, guild_id, user_id):
_endpoint = "/guilds/{guild_id}/members/{user_id}".format(guild_id=guild_id, user_id=user_id) _endpoint = "/guilds/{guild_id}/members/{user_id}".format(guild_id=guild_id, user_id=user_id)
r = self.request("GET", _endpoint) r = self.request("GET", _endpoint)
@ -158,11 +160,30 @@ class DiscordREST:
r = self.request("GET", _endpoint) r = self.request("GET", _endpoint)
return r return r
@cached(cache, key=partial(hashkey, 'list_all_guild_members'))
def list_all_guild_members(self, guild_id):
_endpoint = "/guilds/{guild_id}/members".format(guild_id=guild_id)
count = 1
last_usrid = ""
users = []
params = {"limit": 1000}
while count > 0:
r = self.request("GET", _endpoint, params=params)
if r["success"] == True:
content = r["content"]
count = len(content)
users.extend(content)
if count > 0:
params["after"] = content[-1]["user"]["id"]
else:
count = 0
return users
##################### #####################
# User # User
##################### #####################
@cached(cache) @cached(cache, key=partial(hashkey, 'get_all_guilds'))
def get_all_guilds(self): def get_all_guilds(self):
_endpoint = "/users/@me/guilds" _endpoint = "/users/@me/guilds"
params = {} params = {}
@ -185,7 +206,7 @@ class DiscordREST:
# Widget Handler # Widget Handler
##################### #####################
@cached(cache) @cached(cache, key=partial(hashkey, 'get_widget'))
def get_widget(self, guild_id): def get_widget(self, guild_id):
_endpoint = _DISCORD_API_BASE + "/servers/{guild_id}/widget.json".format(guild_id=guild_id) _endpoint = _DISCORD_API_BASE + "/servers/{guild_id}/widget.json".format(guild_id=guild_id)
embed = self.get_guild_embed(guild_id) embed = self.get_guild_embed(guild_id)

View File

@ -51,6 +51,12 @@ color: #cfd8dc;
font-variant: small-caps; font-variant: small-caps;
} }
.role-title {
margin-bottom: -15px !important;
font-variant: normal !important;
font-size: 80% !important;
}
.divider { .divider {
background-color: #90a4ae; background-color: #90a4ae;
} }
@ -170,4 +176,4 @@ background-color: #546e7a;
a { a {
color: #82b1ff; color: #82b1ff;
} }

View File

@ -11,20 +11,20 @@
var last_message_id; // last message tracked var last_message_id; // last message tracked
var selected_channel = guild_id; // user selected channel, defaults to #general channel var selected_channel = guild_id; // user selected channel, defaults to #general channel
var guild_channels = {}; // all server channels used to highlight channels in messages var guild_channels = {}; // all server channels used to highlight channels in messages
function element_in_view(element, fullyInView) { function element_in_view(element, fullyInView) {
var pageTop = $(window).scrollTop(); var pageTop = $(window).scrollTop();
var pageBottom = pageTop + $(window).height(); var pageBottom = pageTop + $(window).height();
var elementTop = $(element).offset().top; var elementTop = $(element).offset().top;
var elementBottom = elementTop + $(element).height(); var elementBottom = elementTop + $(element).height();
if (fullyInView === true) { if (fullyInView === true) {
return ((pageTop < elementTop) && (pageBottom > elementBottom)); return ((pageTop < elementTop) && (pageBottom > elementBottom));
} else { } else {
return ((elementTop <= pageBottom) && (elementBottom >= pageTop)); return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
} }
} }
function query_guild() { function query_guild() {
var funct = $.ajax({ var funct = $.ajax({
dataType: "json", dataType: "json",
@ -33,7 +33,7 @@
}); });
return funct.promise(); return funct.promise();
} }
function create_authenticated_user() { function create_authenticated_user() {
var funct = $.ajax({ var funct = $.ajax({
method: "POST", method: "POST",
@ -43,7 +43,7 @@
}); });
return funct.promise(); return funct.promise();
} }
function create_unauthenticated_user(username) { function create_unauthenticated_user(username) {
var funct = $.ajax({ var funct = $.ajax({
method: "POST", method: "POST",
@ -53,7 +53,7 @@
}); });
return funct.promise(); return funct.promise();
} }
function fetch(channel_id, after=null) { function fetch(channel_id, after=null) {
var funct = $.ajax({ var funct = $.ajax({
method: "GET", method: "GET",
@ -63,7 +63,7 @@
}); });
return funct.promise(); return funct.promise();
} }
function post(channel_id, content) { function post(channel_id, content) {
var funct = $.ajax({ var funct = $.ajax({
method: "POST", method: "POST",
@ -73,7 +73,7 @@
}); });
return funct.promise(); return funct.promise();
} }
$(function(){ $(function(){
$("#loginmodal").modal({ $("#loginmodal").modal({
dismissible: false, // Modal can be dismissed by clicking outside of the modal dismissible: false, // Modal can be dismissed by clicking outside of the modal
@ -84,18 +84,18 @@
endingTop: '10%', // Ending top style attribute endingTop: '10%', // Ending top style attribute
} }
); );
var guild = query_guild(); var guild = query_guild();
guild.fail(function() { guild.fail(function() {
$('#loginmodal').modal('open'); $('#loginmodal').modal('open');
}); });
guild.done(function(data) { guild.done(function(data) {
initialize_embed(data); initialize_embed(data);
//$('#loginmodal').modal('open'); //$('#loginmodal').modal('open');
}); });
}); });
function lock_login_fields() { function lock_login_fields() {
$("#loginProgress").show(); $("#loginProgress").show();
$("#discordlogin_btn").attr("disabled",true); $("#discordlogin_btn").attr("disabled",true);
@ -104,14 +104,14 @@
unlock_login_fields(); unlock_login_fields();
}, 60000); }, 60000);
} }
function unlock_login_fields() { function unlock_login_fields() {
$("#loginProgress").hide(); $("#loginProgress").hide();
$("#discordlogin_btn").attr("disabled",false); $("#discordlogin_btn").attr("disabled",false);
$("#custom_username_field").prop("disabled",false); $("#custom_username_field").prop("disabled",false);
clearTimeout(logintimer); clearTimeout(logintimer);
} }
function initialize_embed(guildobj) { function initialize_embed(guildobj) {
$('#loginmodal').modal('close'); $('#loginmodal').modal('close');
unlock_login_fields(); unlock_login_fields();
@ -124,7 +124,7 @@
prepare_guild(guildobj); prepare_guild(guildobj);
} }
} }
function prepare_guild(guildobj) { function prepare_guild(guildobj) {
fill_channels(guildobj.channels); fill_channels(guildobj.channels);
fill_discord_members(guildobj.discordmembers); fill_discord_members(guildobj.discordmembers);
@ -132,7 +132,7 @@
fill_unauthenticated_users(guildobj.embedmembers.unauthenticated); fill_unauthenticated_users(guildobj.embedmembers.unauthenticated);
run_fetch_routine(); run_fetch_routine();
} }
function fill_channels(channels) { function fill_channels(channels) {
var template = $('#mustache_channellistings').html(); var template = $('#mustache_channellistings').html();
Mustache.parse(template); Mustache.parse(template);
@ -160,7 +160,7 @@
} }
$("#channel-"+selected_channel).parent().addClass("active"); $("#channel-"+selected_channel).parent().addClass("active");
} }
function mention_member(member_id) { function mention_member(member_id) {
if (!$('#messagebox').prop('disabled')) { if (!$('#messagebox').prop('disabled')) {
$('#messagebox').val( $('#messagebox').val() + "[@" + member_id + "] " ); $('#messagebox').val( $('#messagebox').val() + "[@" + member_id + "] " );
@ -168,21 +168,65 @@
$("#messagebox").focus(); $("#messagebox").focus();
} }
} }
function fill_discord_members(discordmembers) { function fill_discord_members(discordmembers) {
var template = $('#mustache_authedusers').html(); var template = $('#mustache_authedusers').html();
Mustache.parse(template); Mustache.parse(template);
$("#discord-members").empty(); $("#discord-members").empty();
var guild_members = {};
for (var i = 0; i < discordmembers.length; i++) { for (var i = 0; i < discordmembers.length; i++) {
var member = discordmembers[i]; var member = discordmembers[i];
var rendered = Mustache.render(template, {"id": member.id.toString() + "d", "username": member.username, "avatar": member.avatar_url}); if (member["hoist-role"]) {
$("#discord-members").append(rendered); if (!(member["hoist-role"]["id"] in guild_members)) {
guild_members[member["hoist-role"]["id"]] = {};
guild_members[member["hoist-role"]["id"]]["name"] = member["hoist-role"]["name"];
guild_members[member["hoist-role"]["id"]]["members"] = [];
guild_members[member["hoist-role"]["id"]]["position"] = member["hoist-role"]["position"]
}
guild_members[member["hoist-role"]["id"]]["members"].push(member);
} else {
if (!("0" in guild_members)) {
guild_members["0"] = {};
guild_members["0"]["name"] = null;
guild_members["0"]["members"] = [];
guild_members["0"]["position"] = 0;
}
guild_members["0"]["members"].push(member);
}
}
var guild_members_arr = [];
for (key in guild_members) {
guild_members_arr.push(guild_members[key]);
}
guild_members_arr.sort(function(a, b) {
return parseInt(b.position) - parseInt(a.position);
})
var template_role = $('#mustache_memberrole').html();
Mustache.parse(template_role);
var template_user = $('#mustache_authedusers').html();
Mustache.parse(template_user);
$("#discord-members").empty();
for (var i = 0; i < guild_members_arr.length; i++) {
var roleobj = guild_members_arr[i];
if (!roleobj["name"]) {
roleobj["name"] = "Uncategorized";
}
var rendered_role = Mustache.render(template_role, {"name": roleobj["name"]});
$("#discord-members").append(rendered_role);
for (var j = 0; j < roleobj.members.length; j++) {
var member = roleobj.members[j];
var rendered_user = Mustache.render(template_user, {"id": member.id.toString() + "d", "username": member.username, "avatar": member.avatar_url});
$("#discord-members").append(rendered_user);
$( "#discorduser-" + member.id.toString() + "d").click({"member_id": member.id.toString()}, function(event) { $( "#discorduser-" + member.id.toString() + "d").click({"member_id": member.id.toString()}, function(event) {
mention_member(event.data.member_id); mention_member(event.data.member_id);
}); });
if (member.color) {
$( "#discorduser-" + member.id.toString() + "d").css("color", "#" + member.color);
}
}
} }
} }
function fill_authenticated_users(users) { function fill_authenticated_users(users) {
var template = $('#mustache_authedusers').html(); var template = $('#mustache_authedusers').html();
Mustache.parse(template); Mustache.parse(template);
@ -196,7 +240,7 @@
}); });
} }
} }
function fill_unauthenticated_users(users) { function fill_unauthenticated_users(users) {
var template = $('#mustache_unauthedusers').html(); var template = $('#mustache_unauthedusers').html();
Mustache.parse(template); Mustache.parse(template);
@ -207,11 +251,11 @@
$("#embed-unauth-users").append(rendered); $("#embed-unauth-users").append(rendered);
} }
} }
function wait_for_discord_login() { function wait_for_discord_login() {
_wait_for_discord_login(0); _wait_for_discord_login(0);
} }
function _wait_for_discord_login(index) { function _wait_for_discord_login(index) {
setTimeout(function() { setTimeout(function() {
var usr = create_authenticated_user(); var usr = create_authenticated_user();
@ -228,7 +272,7 @@
}); });
}, 5000); }, 5000);
} }
function select_channel(channel_id) { function select_channel(channel_id) {
if (selected_channel != channel_id) { if (selected_channel != channel_id) {
selected_channel = channel_id; selected_channel = channel_id;
@ -239,7 +283,7 @@
run_fetch_routine(); run_fetch_routine();
} }
} }
function replace_message_mentions(message) { function replace_message_mentions(message) {
var mentions = message.mentions; var mentions = message.mentions;
for (var i = 0; i < mentions.length; i++) { for (var i = 0; i < mentions.length; i++) {
@ -250,11 +294,11 @@
} }
return message; return message;
} }
function getPosition(string, subString, index) { function getPosition(string, subString, index) {
return string.split(subString, index).join(subString).length; return string.split(subString, index).join(subString).length;
} }
function format_bot_message(message) { function format_bot_message(message) {
if (message.author.id == bot_client_id && (message.content.includes("**") && ( (message.content.includes("<")&&message.content.includes(">")) || (message.content.includes("[") && message.content.includes("]")) ))) { if (message.author.id == bot_client_id && (message.content.includes("**") && ( (message.content.includes("<")&&message.content.includes(">")) || (message.content.includes("[") && message.content.includes("]")) ))) {
var usernamefield = message.content.substring(getPosition(message.content, "**", 1)+3, getPosition(message.content, "**", 2)-1); var usernamefield = message.content.substring(getPosition(message.content, "**", 1)+3, getPosition(message.content, "**", 2)-1);
@ -264,14 +308,14 @@
} }
return message; return message;
} }
function parse_message_time(message) { function parse_message_time(message) {
var mome = moment(message.timestamp); var mome = moment(message.timestamp);
message.formatted_timestamp = mome.toDate().toString(); message.formatted_timestamp = mome.toDate().toString();
message.formatted_time = mome.format("h:mm A"); message.formatted_time = mome.format("h:mm A");
return message; return message;
} }
function parse_message_attachments(message) { function parse_message_attachments(message) {
for (var i = 0; i < message.attachments.length; i++) { for (var i = 0; i < message.attachments.length; i++) {
var attach = ""; var attach = "";
@ -283,7 +327,7 @@
} }
return message; return message;
} }
function handle_last_message_mention() { function handle_last_message_mention() {
var lastmsg = $("#chatcontent p:last-child"); var lastmsg = $("#chatcontent p:last-child");
var content = lastmsg.text().toLowerCase(); var content = lastmsg.text().toLowerCase();
@ -293,7 +337,7 @@
lastmsg.css( "font-weight", "bold" ); lastmsg.css( "font-weight", "bold" );
} }
} }
function escapeHtml(unsafe) { /* http://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript */ function escapeHtml(unsafe) { /* http://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript */
return unsafe return unsafe
.replace(/&/g, "&amp;") .replace(/&/g, "&amp;")
@ -302,12 +346,12 @@
.replace(/"/g, "&quot;") .replace(/"/g, "&quot;")
.replace(/'/g, "&#039;"); .replace(/'/g, "&#039;");
} }
function nl2br (str, is_xhtml) { /* http://stackoverflow.com/questions/2919337/jquery-convert-line-breaks-to-br-nl2br-equivalent/ */ function nl2br (str, is_xhtml) { /* http://stackoverflow.com/questions/2919337/jquery-convert-line-breaks-to-br-nl2br-equivalent/ */
var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>'; var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2'); return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
} }
function parse_channels_in_message(message) { function parse_channels_in_message(message) {
var channelids = Object.keys(guild_channels); var channelids = Object.keys(guild_channels);
for (var i = 0; i < channelids.length; i++) { for (var i = 0; i < channelids.length; i++) {
@ -316,7 +360,7 @@
} }
return message; return message;
} }
function fill_discord_messages(messages, jumpscroll) { function fill_discord_messages(messages, jumpscroll) {
if (messages.length == 0) { if (messages.length == 0) {
return last_message_id; return last_message_id;
@ -342,7 +386,7 @@
}); });
return last; return last;
} }
function run_fetch_routine() { function run_fetch_routine() {
var channel_id = selected_channel; var channel_id = selected_channel;
var fet; var fet;
@ -389,7 +433,7 @@
} }
}); });
} }
function update_embed_userchip(authenticated, avatar, username, userid, discrim=null) { function update_embed_userchip(authenticated, avatar, username, userid, discrim=null) {
if (authenticated) { if (authenticated) {
$("#currentuserimage").show(); $("#currentuserimage").show();
@ -400,12 +444,12 @@
$("#currentusername").text(username + "#" + userid); $("#currentusername").text(username + "#" + userid);
} }
} }
$("#discordlogin_btn").click(function() { $("#discordlogin_btn").click(function() {
lock_login_fields(); lock_login_fields();
wait_for_discord_login(); wait_for_discord_login();
}); });
$("#custom_username_field").keyup(function(event){ $("#custom_username_field").keyup(function(event){
if (event.keyCode == 13) { if (event.keyCode == 13) {
if (!(new RegExp(/^[a-z\d\-_\s]+$/i).test($(this).val()))) { if (!(new RegExp(/^[a-z\d\-_\s]+$/i).test($(this).val()))) {
@ -431,7 +475,7 @@
} }
} }
}); });
$("#messagebox").keyup(function(event){ $("#messagebox").keyup(function(event){
if ($(this).val().length == 1) { if ($(this).val().length == 1) {
$(this).val($.trim($(this).val())); $(this).val($.trim($(this).val()));
@ -459,7 +503,7 @@
}); });
} }
}); });
$('#guild-btn').sideNav({ $('#guild-btn').sideNav({
menuWidth: 300, // Default is 300 menuWidth: 300, // Default is 300
edge: 'left', // Choose the horizontal origin edge: 'left', // Choose the horizontal origin
@ -467,7 +511,7 @@
draggable: true // Choose whether you can drag to open on touch screens draggable: true // Choose whether you can drag to open on touch screens
} }
); );
$('#members-btn').sideNav({ $('#members-btn').sideNav({
menuWidth: 300, // Default is 300 menuWidth: 300, // Default is 300
edge: 'right', // Choose the horizontal origin edge: 'right', // Choose the horizontal origin

View File

@ -123,6 +123,10 @@
<script id="mustache_usermessage" type="text/template"> <script id="mustache_usermessage" type="text/template">
<p><span id="discordmessage_{{id}}" title="{{full_timestamp}}" class="chattimestamp">{{time}}</span> <span class="chatusername">{{username}}#{{discriminator}}</span> {{{content}}}</p> <p><span id="discordmessage_{{id}}" title="{{full_timestamp}}" class="chattimestamp">{{time}}</span> <span class="chatusername">{{username}}#{{discriminator}}</span> {{{content}}}</p>
</script> </script>
<script id="mustache_memberrole" type="text/template">
<li><a class="subheader role-title">{{name}}</a></li>
</script>
{% endraw %} {% endraw %}
<script> <script>