mirror of
https://github.com/TitanEmbeds/Titan.git
synced 2024-12-24 14:07:03 +01:00
Add user cards and badges, Closes #25
This commit is contained in:
parent
3af5dc703a
commit
204858d011
@ -0,0 +1,28 @@
|
||||
"""Added badges column to cosmetics
|
||||
|
||||
Revision ID: 66971a97040e
|
||||
Revises: 16b4fdbbe155
|
||||
Create Date: 2017-12-07 04:30:25.639794
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '66971a97040e'
|
||||
down_revision = '16b4fdbbe155'
|
||||
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('badges', sa.String(length=255), server_default='[]', nullable=False))
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('cosmetics', 'badges')
|
||||
# ### end Alembic commands ###
|
@ -8,6 +8,9 @@ def init_debug():
|
||||
|
||||
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' # Testing oauthlib
|
||||
|
||||
app.jinja_env.auto_reload = True
|
||||
app.config['TEMPLATES_AUTO_RELOAD'] = True
|
||||
|
||||
# Session viewer https://gist.github.com/babldev/502364a3f7c9bafaa6db
|
||||
def decode_flask_cookie(secret_key, cookie_str):
|
||||
import hashlib
|
||||
|
@ -4,6 +4,7 @@ from functools import wraps
|
||||
from titanembeds.database import db, get_administrators_list, Cosmetics, Guilds, UnauthenticatedUsers, UnauthenticatedBans, TitanTokens, TokenTransactions, get_titan_token, set_titan_token
|
||||
from titanembeds.oauth import generate_guild_icon_url
|
||||
import datetime
|
||||
import json
|
||||
|
||||
admin = Blueprint("admin", __name__)
|
||||
|
||||
@ -39,6 +40,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)
|
||||
badges = request.form.get("badges", None)
|
||||
entry = db.session.query(Cosmetics).filter(Cosmetics.user_id == user_id).first()
|
||||
if entry:
|
||||
abort(409)
|
||||
@ -51,6 +53,11 @@ def cosmetics_post():
|
||||
if guest_icon is not None:
|
||||
guest_icon = guest_icon.lower() == "true"
|
||||
user.guest_icon = guest_icon
|
||||
if badges is not None:
|
||||
badges = badges.split(",")
|
||||
if badges == [""]:
|
||||
badges = []
|
||||
user.badges = json.dumps(badges)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
return ('', 204)
|
||||
@ -77,6 +84,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)
|
||||
badges = request.form.get("badges", None)
|
||||
entry = db.session.query(Cosmetics).filter(Cosmetics.user_id == user_id).first()
|
||||
if not entry:
|
||||
abort(409)
|
||||
@ -88,8 +96,14 @@ def cosmetics_patch():
|
||||
if guest_icon:
|
||||
guest_icon = guest_icon.lower() == "true"
|
||||
entry.guest_icon = guest_icon
|
||||
if badges is not None:
|
||||
badges = badges.split(",")
|
||||
if badges == [""]:
|
||||
badges = []
|
||||
entry.badges = json.dumps(badges)
|
||||
db.session.commit()
|
||||
return ('', 204)
|
||||
|
||||
def prepare_guild_members_list(members, bans):
|
||||
all_users = []
|
||||
ip_pool = []
|
||||
|
@ -1,4 +1,4 @@
|
||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers, KeyValueProperties, GuildMembers, Messages, get_channel_messages, list_all_guild_members, get_guild_member, get_administrators_list
|
||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, AuthenticatedUsers, KeyValueProperties, GuildMembers, Messages, get_channel_messages, list_all_guild_members, get_guild_member, get_administrators_list, get_badges
|
||||
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, user_unauthenticated, checkUserRevoke, checkUserBanned, update_user_status, check_user_in_guild, get_guild_channels, guild_webhooks_enabled, guild_unauthcaptcha_enabled
|
||||
from titanembeds.oauth import user_has_permission, generate_avatar_url, check_user_can_administrate_guild
|
||||
@ -429,6 +429,10 @@ def create_authenticated_user():
|
||||
response.status_code = 403
|
||||
return response
|
||||
|
||||
@api.route("/badges/<user_id>")
|
||||
def badges(user_id):
|
||||
return jsonify(get_badges(user_id))
|
||||
|
||||
def canCleanupDB():
|
||||
canclean = False
|
||||
if request.form.get("secret", None) == config['app-secret']:
|
||||
@ -437,6 +441,7 @@ def canCleanupDB():
|
||||
if session['user_id'] in get_administrators_list():
|
||||
canclean = True
|
||||
return canclean
|
||||
|
||||
@api.route("/cleanup-db", methods=["DELETE"])
|
||||
def cleanup_keyval_db():
|
||||
if canCleanupDB():
|
||||
|
@ -3,7 +3,7 @@ from flask import current_app as app
|
||||
from flask_socketio import emit
|
||||
from config import config
|
||||
from titanembeds.decorators import discord_users_only
|
||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, Cosmetics, UserCSS, Patreon, set_titan_token, get_titan_token
|
||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, Cosmetics, UserCSS, Patreon, set_titan_token, get_titan_token, add_badge
|
||||
from titanembeds.oauth import authorize_url, token_url, make_authenticated_session, get_current_authenticated_user, get_user_managed_servers, check_user_can_administrate_guild, check_user_permission, generate_avatar_url, generate_guild_icon_url, generate_bot_invite_url
|
||||
import time
|
||||
import datetime
|
||||
@ -431,6 +431,7 @@ def donate_confirm():
|
||||
action = "PAYPAL {}".format(trans_id)
|
||||
set_titan_token(session["user_id"], tokens, action)
|
||||
session["tokens"] = get_titan_token(session["user_id"])
|
||||
add_badge(session["user_id"], "supporter")
|
||||
return redirect(url_for('user.donate_thanks', transaction=trans_id))
|
||||
else:
|
||||
return redirect(url_for('index'))
|
||||
@ -555,6 +556,7 @@ def patreon_sync_post():
|
||||
db.session.add(dbpatreon)
|
||||
db.session.commit()
|
||||
set_titan_token(session["user_id"], usr["titan"]["eligible_tokens"], "PATREON {} [{}]".format(usr["attributes"]["full_name"], usr["id"]))
|
||||
add_badge(session["user_id"], "supporter")
|
||||
session["tokens"] = get_titan_token(session["user_id"])
|
||||
return ('', 204)
|
||||
|
||||
|
@ -9,7 +9,7 @@ from .authenticated_users import AuthenticatedUsers
|
||||
from .guild_members import GuildMembers, list_all_guild_members, get_guild_member
|
||||
from .keyvalue_properties import KeyValueProperties, set_keyvalproperty, get_keyvalproperty, getexpir_keyvalproperty, setexpir_keyvalproperty, ifexists_keyvalproperty, delete_keyvalproperty
|
||||
from .messages import Messages, get_channel_messages
|
||||
from .cosmetics import Cosmetics
|
||||
from .cosmetics import Cosmetics, set_badges, get_badges, add_badge, remove_badge
|
||||
from .user_css import UserCSS
|
||||
from .administrators import Administrators, get_administrators_list
|
||||
from .titan_tokens import TitanTokens, get_titan_token
|
||||
|
@ -1,4 +1,5 @@
|
||||
from titanembeds.database import db
|
||||
import json
|
||||
|
||||
class Cosmetics(db.Model):
|
||||
__tablename__ = "cosmetics"
|
||||
@ -7,6 +8,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
|
||||
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):
|
||||
self.user_id = user_id
|
||||
@ -25,3 +27,34 @@ class Cosmetics(db.Model):
|
||||
self.guest_icon = kwargs["guest_icon"]
|
||||
else:
|
||||
self.guest_icon = False
|
||||
|
||||
if "badges" in kwargs:
|
||||
self.badges = json.dumps(kwargs["badges"])
|
||||
else:
|
||||
self.badges = "[]"
|
||||
|
||||
def set_badges(user_id, badges):
|
||||
usr = db.session.query(Cosmetics).filter(Cosmetics.user_id == user_id).first()
|
||||
if not usr:
|
||||
usr = Cosmetics(user_id)
|
||||
usr.badges = json.dumps(badges)
|
||||
db.session.add(usr)
|
||||
db.session.commit()
|
||||
|
||||
def get_badges(user_id):
|
||||
usr = db.session.query(Cosmetics).filter(Cosmetics.user_id == user_id).first()
|
||||
if usr:
|
||||
return json.loads(usr.badges)
|
||||
return []
|
||||
|
||||
def add_badge(user_id, name):
|
||||
bgs = get_badges(user_id)
|
||||
if name not in bgs:
|
||||
bgs.append(name)
|
||||
set_badges(user_id, bgs)
|
||||
|
||||
def remove_badge(user_id, name):
|
||||
bgs = get_badges(user_id)
|
||||
if name in bgs:
|
||||
bgs.remove(name)
|
||||
set_badges(user_id, bgs)
|
@ -679,6 +679,73 @@ p.mentioned span.chatmessage {
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
#usercard .identity {
|
||||
display: inline;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
#usercard .identity .hash, #usercard .identity .discriminator {
|
||||
font-size: 1.30rem;
|
||||
}
|
||||
|
||||
#usercard .bottag {
|
||||
background-color: #5DADE2;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
font-weight: bold;
|
||||
margin-left: 7px;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
#usercard .role .bubble {
|
||||
color: #cacbce;
|
||||
border: 1px solid;
|
||||
border-color: inherit;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#usercard .role .text, #usercard .role .color {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#usercard .role .color {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background-color: #cacbce;
|
||||
margin-right: 0;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
#usercard .role .text {
|
||||
color: lightgray;
|
||||
}
|
||||
|
||||
#usercard .game {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#usercard .game .text {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#usercard .badges .star {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
#usercard .badges .supporter {
|
||||
color: limegreen;
|
||||
}
|
||||
|
||||
#usercard .badges .administrator {
|
||||
color: hotpink;
|
||||
}
|
||||
|
||||
#usercard .badges .partner {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
#google-recaptcha {
|
||||
margin: 0 auto;
|
||||
width: 302px;
|
||||
|
@ -1,13 +1,13 @@
|
||||
/* global $, Materialize, location */
|
||||
|
||||
function postForm(user_id, css, css_limit, guest_icon) {
|
||||
function postForm(user_id, css, css_limit, guest_icon, 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}
|
||||
data: {"user_id": user_id, "css": css, "css_limit": css_limit, "guest_icon": guest_icon, "badges": badges}
|
||||
});
|
||||
return funct.promise();
|
||||
}
|
||||
@ -32,6 +32,7 @@ function patchForm(user_id, param) {
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$('select').material_select();
|
||||
$("#new_submit").click(function () {
|
||||
var user_id = $("#new_user_id").val();
|
||||
if (user_id.length < 1) {
|
||||
@ -41,7 +42,8 @@ $(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 formPost = postForm(user_id, css_checked, css_limit, guest_icon_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);
|
||||
formPost.done(function (data) {
|
||||
location.reload();
|
||||
});
|
||||
@ -115,3 +117,18 @@ function update_guest_icon_switch(user_id, element) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function update_badges(user_id, element) {
|
||||
var badges = $(element).val().join();
|
||||
var formPatch = patchForm(user_id, {"badges": badges});
|
||||
formPatch.done(function (data) {
|
||||
Materialize.toast('Badges 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 badges!', 10000);
|
||||
}
|
||||
});
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
|
||||
(function () {
|
||||
const theme_options = ["DiscordDark", "BetterTitan"]; // All the avaliable theming names
|
||||
const badges_options = ["administrator", "partner", "supporter", "star"]; // All badges avaliable
|
||||
|
||||
var user_def_css; // Saves the user defined css
|
||||
var has_already_been_initially_resized = false; // keep track if the embed initially been resized
|
||||
@ -134,6 +135,14 @@
|
||||
return funct.promise();
|
||||
}
|
||||
|
||||
function api_badges(user_id) {
|
||||
var funct = $.ajax({
|
||||
dataType: "json",
|
||||
url: "/api/badges/" + user_id,
|
||||
});
|
||||
return funct.promise();
|
||||
}
|
||||
|
||||
$(function() {
|
||||
if ($("#user-defined-css").length > 0) {
|
||||
user_def_css = $("#user-defined-css").text();
|
||||
@ -165,6 +174,9 @@
|
||||
inDuration: 400,
|
||||
outDuration: 400,
|
||||
});
|
||||
$("#usercard").modal({
|
||||
opacity: .5,
|
||||
});
|
||||
|
||||
$("#nameplate").click(function () {
|
||||
$("#userembedmodal").modal("open");
|
||||
@ -607,7 +619,7 @@
|
||||
var rendered_user = Mustache.render(template_user, {"id": member.id.toString() + "d", "username": member_name, "avatar": member.avatar_url});
|
||||
$("#discord-members").append(rendered_user);
|
||||
$( "#discorduser-" + member.id.toString() + "d").click({"member_id": member.id.toString()}, function(event) {
|
||||
mention_member(event.data.member_id);
|
||||
openUserCard(event.data.member_id);
|
||||
});
|
||||
if (member.color) {
|
||||
$( "#discorduser-" + member.id.toString() + "d").css("color", "#" + member.color);
|
||||
@ -631,7 +643,7 @@
|
||||
var rendered = Mustache.render(template, {"id": member.id.toString() + "a", "username": username, "avatar": member.avatar_url});
|
||||
$("#embed-discord-members").append(rendered);
|
||||
$( "#discorduser-" + member.id.toString() + "a").click({"member_id": member.id.toString()}, function(event) {
|
||||
mention_member(event.data.member_id);
|
||||
openUserCard(event.data.member_id);
|
||||
});
|
||||
}
|
||||
authenticated_users_list = users;
|
||||
@ -679,6 +691,60 @@
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function openUserCard(user_id) {
|
||||
var bgs = api_badges(user_id);
|
||||
bgs.done(function (data) {
|
||||
for (var i = 0; i < badges_options.length; i++) {
|
||||
var badge = badges_options[i];
|
||||
if (data.indexOf(badge) != -1) {
|
||||
$(`#usercard .badges .${badge}`).show();
|
||||
} else {
|
||||
$(`#usercard .badges .${badge}`).hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < discord_users_list.length; i++) {
|
||||
var usr = discord_users_list[i];
|
||||
if (usr.id == user_id) {
|
||||
$("#usercard .avatar").attr("src", usr.avatar_url);
|
||||
$("#usercard .identity .username").text(usr.username);
|
||||
$("#usercard .identity .discriminator").text(usr.discriminator);
|
||||
if (usr.bot) {
|
||||
$("#usercard .bottag").show();
|
||||
} else {
|
||||
$("#usercard .bottag").hide();
|
||||
}
|
||||
if (usr.status == "offline") {
|
||||
$("#usercard .offline-text").show();
|
||||
} else {
|
||||
$("#usercard .offline-text").hide();
|
||||
}
|
||||
if (usr["hoist-role"]) {
|
||||
$("#usercard .role").show();
|
||||
$("#usercard .role .text").text(usr["hoist-role"].name);
|
||||
if (usr.color) {
|
||||
$("#usercard .role .bubble").css("color", "#" + usr.color);
|
||||
$("#usercard .role .color").css("background-color", "#" + usr.color);
|
||||
}
|
||||
} else {
|
||||
$("#usercard .role").hide();
|
||||
}
|
||||
if (usr.game) {
|
||||
$("#usercard .game").show();
|
||||
$("#usercard .game .text").text(usr.game.name);
|
||||
} else {
|
||||
$("#usercard .game").hide();
|
||||
}
|
||||
$("#usercard-mention-btn").off("click");
|
||||
$("#usercard-mention-btn").click(function () {
|
||||
mention_member(user_id);
|
||||
$("#usercard").modal('close');
|
||||
});
|
||||
}
|
||||
}
|
||||
$("#usercard").modal('open');
|
||||
}
|
||||
|
||||
function flashElement(element) {
|
||||
var opacity = element.css("opacity");
|
||||
for (var i = 0; i < 3; i++) {
|
||||
@ -966,7 +1032,7 @@
|
||||
$("#chatcontent .chatusername").last().click(function () {
|
||||
var discordid = $(this).parent().attr("discord_userid");
|
||||
if (discordid) {
|
||||
mention_member(discordid);
|
||||
openUserCard(discordid);
|
||||
}
|
||||
});
|
||||
$("#chatcontent p:last-child").find(".channellink").click(function () {
|
||||
|
@ -15,6 +15,7 @@
|
||||
<th>CSS</th>
|
||||
<th>CSS Limit</th>
|
||||
<th>Guest Icon</th>
|
||||
<th>Badges</th>
|
||||
<th>Submit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -50,6 +51,17 @@
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="input-field col s12">
|
||||
<select multiple id="new_badges">
|
||||
<option value="" disabled>Choose your option</option>
|
||||
<option value="administrator">TitanEmbeds Administrators</option>
|
||||
<option value="partner">TitanEmbeds Partner</option>
|
||||
<option value="supporter">TitanEmbeds Supporter</option>
|
||||
<option value="star">GitHub Stargazer</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a class="waves-effect waves-light btn" id="new_submit">Submit</a>
|
||||
</td>
|
||||
@ -69,6 +81,7 @@
|
||||
<th>CSS</th>
|
||||
<th>CSS Limit</th>
|
||||
<th>Guest Icon</th>
|
||||
<th>Badges</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -101,6 +114,17 @@
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="input-field col s12">
|
||||
<select multiple id="new_badges" onchange="update_badges('{{ cosmetic.user_id }}', this)">
|
||||
<option value="" disabled>Choose your option</option>
|
||||
<option value="administrator" {% if "administrator" in cosmetic.badges %}selected{% endif %}>TitanEmbeds Administrators</option>
|
||||
<option value="partner" {% if "partner" in cosmetic.badges %}selected{% endif %}>TitanEmbeds Partner</option>
|
||||
<option value="supporter" {% if "supporter" in cosmetic.badges %}selected{% endif %}>TitanEmbeds Supporter</option>
|
||||
<option value="star" {% if "star" in cosmetic.badges %}selected{% endif %}>GitHub Stargazer</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -175,6 +175,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="usercard" class="modal bottom-sheet">
|
||||
<div class="modal-content">
|
||||
<div class="row">
|
||||
<div class="col s12 m1">
|
||||
<img class="circle avatar" src="">
|
||||
<br>
|
||||
<a class="waves-effect waves-light btn" id="usercard-mention-btn">Mention</a>
|
||||
</div>
|
||||
<div class="col s12 m11">
|
||||
<h4 class="identity"><span class="username"></span><span class="hash">#</span><span class="discriminator"></span></h4> <span class="bottag">BOT</span>
|
||||
<div class="badges">
|
||||
<a class="administrator tooltipped" data-tooltip="TitanEmbeds Administrator" data-position="top" href="https://titanembeds.com/" target="_blank"><i class="material-icons">gavel</i></a>
|
||||
<a class="partner tooltipped" data-tooltip="TitanEmbeds Partner" data-position="top" href="https://titanembeds.com/about" target="_blank"><i class="material-icons">person_pin</i></a>
|
||||
<a class="supporter tooltipped" data-tooltip="TitanEmbeds Supporter" data-position="top" href="https://titanembeds.com/user/donate" target="_blank"><i class="material-icons">attach_money</i></a>
|
||||
<a class="star tooltipped" data-tooltip="GitHub Stargazer" data-position="top" href="https://github.com/TitanEmbeds/Titan" target="_blank"><i class="material-icons">star</i></a>
|
||||
</div>
|
||||
<p class="offline-text">User is Offline.</p>
|
||||
<p class="game">Playing <span class="text"></span></p>
|
||||
<p class="role">Highest Role: <span class="bubble"><span class="color"></span> <span class="text"></span></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="emoji-picker">
|
||||
<div id="emoji-picker-content">
|
||||
<div class="row">
|
||||
|
Loading…
Reference in New Issue
Block a user