mirror of
				https://github.com/TitanEmbeds/Titan.git
				synced 2025-10-31 13:59:08 +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