mirror of
				https://github.com/TitanEmbeds/Titan.git
				synced 2025-11-03 23:37:09 +01:00 
			
		
		
		
	Implemented Cosmetics and User Custom CSS, closes #7
This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
			
		||||
from flask import Blueprint, render_template, abort, redirect, url_for, session
 | 
			
		||||
from flask import Blueprint, render_template, abort, redirect, url_for, session, request
 | 
			
		||||
from titanembeds.utils import check_guild_existance, guild_query_unauth_users_bool
 | 
			
		||||
from titanembeds.oauth import generate_guild_icon_url, generate_avatar_url
 | 
			
		||||
from titanembeds.database import db, Guilds
 | 
			
		||||
from titanembeds.database import db, Guilds, UserCSS
 | 
			
		||||
from config import config
 | 
			
		||||
import random
 | 
			
		||||
 | 
			
		||||
@@ -20,6 +20,12 @@ def get_logingreeting():
 | 
			
		||||
    ]
 | 
			
		||||
    return random.choice(greetings)
 | 
			
		||||
 | 
			
		||||
def get_custom_css():
 | 
			
		||||
    css = request.args.get("css", None)
 | 
			
		||||
    if css:
 | 
			
		||||
        css = db.session.query(UserCSS).filter(UserCSS.id == css).first()
 | 
			
		||||
    return css
 | 
			
		||||
 | 
			
		||||
@embed.route("/<string:guild_id>")
 | 
			
		||||
def guild_embed(guild_id):
 | 
			
		||||
    if check_guild_existance(guild_id):
 | 
			
		||||
@@ -35,7 +41,8 @@ def guild_embed(guild_id):
 | 
			
		||||
            guild_id=guild_id, guild=guild_dict,
 | 
			
		||||
            generate_guild_icon=generate_guild_icon_url,
 | 
			
		||||
            unauth_enabled=guild_query_unauth_users_bool(guild_id),
 | 
			
		||||
            client_id=config['client-id']
 | 
			
		||||
            client_id=config['client-id'],
 | 
			
		||||
            css=get_custom_css()
 | 
			
		||||
        )
 | 
			
		||||
    abort(404)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
from flask import Blueprint, request, redirect, jsonify, abort, session, url_for, render_template
 | 
			
		||||
from config import config
 | 
			
		||||
from titanembeds.decorators import discord_users_only
 | 
			
		||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans
 | 
			
		||||
from titanembeds.database import db, Guilds, UnauthenticatedUsers, UnauthenticatedBans, Cosmetics, UserCSS
 | 
			
		||||
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
 | 
			
		||||
@@ -66,7 +66,90 @@ def dashboard():
 | 
			
		||||
        redir = session['redirect']
 | 
			
		||||
        session['redirect'] = None
 | 
			
		||||
        return redirect(redir)
 | 
			
		||||
    return render_template("dashboard.html.j2", servers=guilds, icon_generate=generate_guild_icon_url)
 | 
			
		||||
    cosmetics = db.session.query(Cosmetics).filter(Cosmetics.user_id == session['user_id']).first()
 | 
			
		||||
    css_list = None
 | 
			
		||||
    if cosmetics and cosmetics.css:
 | 
			
		||||
        css_list = db.session.query(UserCSS).filter(UserCSS.user_id == session['user_id']).all()
 | 
			
		||||
    return render_template("dashboard.html.j2", servers=guilds, icon_generate=generate_guild_icon_url, cosmetics=cosmetics, css_list=css_list)
 | 
			
		||||
 | 
			
		||||
@user.route("/custom_css/new", methods=["GET"])
 | 
			
		||||
@discord_users_only()
 | 
			
		||||
def new_custom_css_get():
 | 
			
		||||
    cosmetics = db.session.query(Cosmetics).filter(Cosmetics.user_id == session['user_id']).first()
 | 
			
		||||
    if not cosmetics or not cosmetics.css:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return render_template("usercss.html.j2", new=True)
 | 
			
		||||
 | 
			
		||||
@user.route("/custom_css/new", methods=["POST"])
 | 
			
		||||
@discord_users_only()
 | 
			
		||||
def new_custom_css_post():
 | 
			
		||||
    cosmetics = db.session.query(Cosmetics).filter(Cosmetics.user_id == session['user_id']).first()
 | 
			
		||||
    if not cosmetics or not cosmetics.css:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    
 | 
			
		||||
    name = request.form.get("name", None)
 | 
			
		||||
    user_id = session["user_id"]
 | 
			
		||||
    css = request.form.get("css","")
 | 
			
		||||
    if not name:
 | 
			
		||||
        abort(400)
 | 
			
		||||
    else:
 | 
			
		||||
        name = name.strip()
 | 
			
		||||
        css = css.strip()
 | 
			
		||||
    css = UserCSS(name, user_id, css)
 | 
			
		||||
    db.session.add(css)
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return jsonify({"id": css.id})
 | 
			
		||||
 | 
			
		||||
@user.route("/custom_css/edit/<css_id>", methods=["GET"])
 | 
			
		||||
@discord_users_only()
 | 
			
		||||
def edit_custom_css_get(css_id):
 | 
			
		||||
    cosmetics = db.session.query(Cosmetics).filter(Cosmetics.user_id == session['user_id']).first()
 | 
			
		||||
    if not cosmetics or not cosmetics.css:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    css = db.session.query(UserCSS).filter(UserCSS.id == css_id).first()
 | 
			
		||||
    if not css:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if css.user_id != session['user_id']:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    return render_template("usercss.html.j2", new=False, css=css)
 | 
			
		||||
 | 
			
		||||
@user.route("/custom_css/edit/<css_id>", methods=["POST"])
 | 
			
		||||
@discord_users_only()
 | 
			
		||||
def edit_custom_css_post(css_id):
 | 
			
		||||
    cosmetics = db.session.query(Cosmetics).filter(Cosmetics.user_id == session['user_id']).first()
 | 
			
		||||
    if not cosmetics or not cosmetics.css:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    dbcss = db.session.query(UserCSS).filter(UserCSS.id == css_id).first()
 | 
			
		||||
    if not dbcss:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if dbcss.user_id != session['user_id']:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    name = request.form.get("name", None)
 | 
			
		||||
    css = request.form.get("css", "")
 | 
			
		||||
    if not name:
 | 
			
		||||
        abort(400)
 | 
			
		||||
    else:
 | 
			
		||||
        name = name.strip()
 | 
			
		||||
        css = css.strip()
 | 
			
		||||
    dbcss.name = name
 | 
			
		||||
    dbcss.css = css
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return jsonify({"id": dbcss.id})
 | 
			
		||||
 | 
			
		||||
@user.route("/custom_css/edit/<css_id>", methods=["DELETE"])
 | 
			
		||||
@discord_users_only()
 | 
			
		||||
def edit_custom_css_delete(css_id):
 | 
			
		||||
    cosmetics = db.session.query(Cosmetics).filter(Cosmetics.user_id == session['user_id']).first()
 | 
			
		||||
    if not cosmetics or not cosmetics.css:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    dbcss = db.session.query(UserCSS).filter(UserCSS.id == css_id).first()
 | 
			
		||||
    if not dbcss:
 | 
			
		||||
        abort(404)
 | 
			
		||||
    if dbcss.user_id != session['user_id']:
 | 
			
		||||
        abort(403)
 | 
			
		||||
    db.session.delete(dbcss)
 | 
			
		||||
    db.session.commit()
 | 
			
		||||
    return jsonify({})
 | 
			
		||||
 | 
			
		||||
@user.route("/administrate_guild/<guild_id>", methods=["GET"])
 | 
			
		||||
@discord_users_only()
 | 
			
		||||
 
 | 
			
		||||
@@ -9,3 +9,5 @@ from authenticated_users import AuthenticatedUsers
 | 
			
		||||
from guild_members import GuildMembers, list_all_guild_members
 | 
			
		||||
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 user_css import UserCSS
 | 
			
		||||
							
								
								
									
										7
									
								
								webapp/titanembeds/database/cosmetics.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								webapp/titanembeds/database/cosmetics.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
from titanembeds.database import db
 | 
			
		||||
 | 
			
		||||
class Cosmetics(db.Model):
 | 
			
		||||
    __tablename__ = "cosmetics"
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)    # Auto increment id
 | 
			
		||||
    user_id = db.Column(db.String(255))             # Discord user id of user of cosmetics
 | 
			
		||||
    css = db.Column(db.Boolean())                   # If they can create/edit custom CSS
 | 
			
		||||
							
								
								
									
										13
									
								
								webapp/titanembeds/database/user_css.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								webapp/titanembeds/database/user_css.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
from titanembeds.database import db
 | 
			
		||||
 | 
			
		||||
class UserCSS(db.Model):
 | 
			
		||||
    __tablename__ = "user_css"
 | 
			
		||||
    id = db.Column(db.Integer, primary_key=True)    # Auto increment id
 | 
			
		||||
    name = db.Column(db.String(255))                # CSS Name
 | 
			
		||||
    user_id = db.Column(db.String(255))             # Discord client ID of the owner of the css (can edit)
 | 
			
		||||
    css = db.Column(db.Text())                      # CSS contents
 | 
			
		||||
 | 
			
		||||
    def __init__(self, name, user_id, css=None):
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.user_id = user_id
 | 
			
		||||
        self.css = css
 | 
			
		||||
							
								
								
									
										57
									
								
								webapp/titanembeds/static/js/usercss.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								webapp/titanembeds/static/js/usercss.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
/*global $, ace, Materialize, newCSS*/
 | 
			
		||||
(function () {
 | 
			
		||||
    var editor = ace.edit("css_editor");
 | 
			
		||||
    
 | 
			
		||||
    function postForm() {
 | 
			
		||||
        var name = $('#css_name').val();
 | 
			
		||||
        var css = editor.getValue();
 | 
			
		||||
        var funct = $.ajax({
 | 
			
		||||
            dataType: "json",
 | 
			
		||||
            method: "POST",
 | 
			
		||||
            data: {"name": name, "css": css}
 | 
			
		||||
        });
 | 
			
		||||
        return funct.promise();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $(function(){
 | 
			
		||||
        editor.getSession().setMode("ace/mode/css");
 | 
			
		||||
        editor.setTheme("ace/theme/chrome");
 | 
			
		||||
        $("#submit-btn").click(submitForm);
 | 
			
		||||
        
 | 
			
		||||
        if (!newCSS) {
 | 
			
		||||
            $("#delete-btn").click(delete_css);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    function submitForm() {
 | 
			
		||||
        var formPost = postForm();
 | 
			
		||||
        formPost.done(function (data) {
 | 
			
		||||
            if (newCSS) {
 | 
			
		||||
                window.location.href = "edit/" + data.id;
 | 
			
		||||
            } else {
 | 
			
		||||
                Materialize.toast('CSS Updated!', 10000);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        formPost.fail(function () {
 | 
			
		||||
            Materialize.toast('Oh no! Something has failed posting your CSS!', 10000);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function delete_css() {
 | 
			
		||||
        var candelete = confirm("Do you really want to delete this css???");
 | 
			
		||||
        if (!candelete) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        $.ajax({
 | 
			
		||||
          type: 'DELETE',
 | 
			
		||||
          success: function() {
 | 
			
		||||
              alert("You have successfully deleted the CSS!");
 | 
			
		||||
              window.location.href = "/user/dashboard";
 | 
			
		||||
          },
 | 
			
		||||
          error: function() {
 | 
			
		||||
              Materialize.toast('Oh no! Something has failed deleting your CSS!', 10000);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
})();
 | 
			
		||||
@@ -29,4 +29,35 @@
 | 
			
		||||
  </div>
 | 
			
		||||
  {% endfor %}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<hr>
 | 
			
		||||
 | 
			
		||||
{% if cosmetics is none %}
 | 
			
		||||
<div class="row">
 | 
			
		||||
  <div class="col s12">
 | 
			
		||||
    <div class="card-panel indigo lighten-5 z-depth-3 hoverable black-text">
 | 
			
		||||
      <h4>Cosmetics!</h4>
 | 
			
		||||
      <p class="flow-text">Would you like to have <strong>cosmetics</strong> such as <em>custom CSS</em> for your embed?</p>
 | 
			
		||||
      <a class="waves-effect waves-light btn" href="https://discord.io/Titan">Talk to us!</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% if css_list is not none %}
 | 
			
		||||
<p class="flow-text">
 | 
			
		||||
  Create or modify your custom CSS.
 | 
			
		||||
  <a class="waves-effect waves-light btn" href="{{ url_for("user.new_custom_css_get") }}">New</a>
 | 
			
		||||
</p>
 | 
			
		||||
<div class="row">
 | 
			
		||||
  {% for css in css_list %}
 | 
			
		||||
  <div class="col l4 m6 s12">
 | 
			
		||||
    <div class="card-panel indigo lighten-5 z-depth-3 hoverable black-text">
 | 
			
		||||
      <p class="flow-text truncate"><code>#{{ css.id }}</code> {{ css.name }}</p>
 | 
			
		||||
      <a class="waves-effect waves-light btn" href="{{ url_for("user.edit_custom_css_get", css_id=css.id) }}">Modify</a>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  {% endfor %}
 | 
			
		||||
</div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,10 @@
 | 
			
		||||
 | 
			
		||||
    <title>{{ guild['name'] }} - Embed - Titan Embeds for Discord</title>
 | 
			
		||||
    {% include 'google_analytics.html.j2' %}
 | 
			
		||||
    
 | 
			
		||||
    {% if css is not none %}
 | 
			
		||||
    <style>{{ css.css }}</style>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <div class="navbar-fixed">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										65
									
								
								webapp/titanembeds/templates/usercss.html.j2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								webapp/titanembeds/templates/usercss.html.j2
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
{% extends 'site_layout.html.j2' %}
 | 
			
		||||
{% block title %}{% if new %}New{% else %}Editing {{ css.name }} -{% endif %} User CSS{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<h1>{% if new %}New{% else %}Editing {{ css.name }}{% endif %} - User Defined CSS</h1>
 | 
			
		||||
<p><strong>Note:</strong> This feature is only used for CSS. Any attempts to enter HTML or malicious CSS code
 | 
			
		||||
will have CSS cosmetic privilages removed, if caught. Please don't, we check the databases often. Thanks!</p>
 | 
			
		||||
 | 
			
		||||
{% if not new %}
 | 
			
		||||
<div class="card-panel indigo lighten-5 z-depth-3 hoverable black-text">
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col s12">
 | 
			
		||||
        <p class="flow-text">Using your custom CSS</p>
 | 
			
		||||
        <p><strong>This user defined CSS has a unique ID of <em style="font-size: 130%;">{{ css.id }}</em>.</strong></p>
 | 
			
		||||
        <p>To use this CSS in the embed, you must apped a <code>?css={{ css.id }}</code> to the embed URL.</p>
 | 
			
		||||
        <p>Something like this will work:</p>
 | 
			
		||||
        <input readonly value="https://titanembeds.tk/embed/1234567890987654321?css={{ css.id }}" id="disabled" type="text" onClick="this.setSelectionRange(48, this.value.length)">
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
<div class="card-panel indigo lighten-5 z-depth-3 hoverable black-text">
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col s12">
 | 
			
		||||
        <p class="flow-text">Give your CSS a name</p>
 | 
			
		||||
        <input placeholder="Some Lit CSS" id="css_name" type="text" {% if not new %}value="{{ css.name }}"{% endif %}>
 | 
			
		||||
        <label for="css_name">Name</label>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col s12">
 | 
			
		||||
        <p class="flow-text">Edit your CSS code here</p>
 | 
			
		||||
        <div style="position: relative; height: 40vh;">
 | 
			
		||||
            <div id="css_editor">{% if new %}/* Enter your CSS code here! */{% else %}{{ css.css }}{% endif %}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <br>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="col s12">
 | 
			
		||||
        <a id="submit-btn" class="waves-effect waves-light btn">Submit</a>
 | 
			
		||||
        {% if not new %}<a id="delete-btn" class="waves-effect waves-light btn red">Delete</a>{% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block script %}
 | 
			
		||||
<script src="//cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js" integrity="sha256-xrr4HH5eSY+cFz4SH7ja/LaAi9qcEdjMpeMP49/iOLs=" crossorigin="anonymous"></script>
 | 
			
		||||
<script>
 | 
			
		||||
    const newCSS = {% if new %}true{% else %}false{% endif %};
 | 
			
		||||
</script>
 | 
			
		||||
<script type="text/javascript" src="{{ url_for('static', filename='js/usercss.js') }}"></script>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block additional_head_elements %}
 | 
			
		||||
<style>
 | 
			
		||||
    #css_editor { 
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
        left: 0;
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user