master
Aevann1 2021-07-31 06:48:47 +02:00
parent 0dae9d133f
commit 920ac8adfa
31 changed files with 112 additions and 815 deletions

View File

@ -226,7 +226,7 @@ def validate_formkey(f):
def wrapper(*args, v, **kwargs):
if not request.path.startswith("/api/v1"):
if not request.headers.get("Authorization"):
submitted_key = request.values.get("formkey", None)
@ -261,53 +261,4 @@ def no_cors(f):
return resp
wrapper.__name__ = f.__name__
return wrapper
# wrapper for api-related things that discriminates between an api url
# and an html url for the same content
# f should return {'api':lambda:some_func(), 'html':lambda:other_func()}
def api(*scopes, no_ban=False):
def wrapper_maker(f):
def wrapper(*args, **kwargs):
if request.path.startswith(('/api/v1','/api/v2')):
v = kwargs.get('v')
result = f(*args, **kwargs)
if isinstance(result, dict):
resp = result['api']()
else:
resp = result
if not isinstance(resp, RespObj):
resp = make_response(resp)
return resp
else:
result = f(*args, **kwargs)
if not isinstance(result, dict):
return result
try:
if request.path.startswith('/inpage/'):
return result['inpage']()
elif request.path.startswith(('/api/vue/','/test/')):
return result['api']()
else:
return result['html']()
except KeyError:
return result
wrapper.__name__ = f.__name__
return wrapper
return wrapper_maker
return wrapper

View File

@ -51,7 +51,7 @@ def send_verification_email(user, email=None):
)
@app.post("/api/verify_email")
@app.post("/verify_email")
@is_not_banned
def api_verify_email(v):

View File

@ -62,7 +62,6 @@ def flagged_posts(v):
@app.get("/admin/image_posts")
@admin_level_required(3)
@api("read")
def image_posts_listing(v):
page = int(request.args.get('page', 1))
@ -650,7 +649,7 @@ def admin_title_change(user_id, v):
return (redirect(user.url), user)
@app.post("/api/ban_user/<user_id>")
@app.post("/ban_user/<user_id>")
@admin_level_required(6)
@validate_formkey
def ban_user(user_id, v):
@ -707,7 +706,7 @@ def ban_user(user_id, v):
return jsonify({"message": f"@{user.username} was banned"})
@app.post("/api/unban_user/<user_id>")
@app.post("/unban_user/<user_id>")
@admin_level_required(6)
@validate_formkey
def unban_user(user_id, v):
@ -738,7 +737,7 @@ def unban_user(user_id, v):
if request.args.get("notoast"): return (redirect(user.url), user)
return jsonify({"message": f"@{user.username} was unbanned"})
@app.post("/api/ban_post/<post_id>")
@app.post("/ban_post/<post_id>")
@admin_level_required(3)
@validate_formkey
def ban_post(post_id, v):
@ -777,7 +776,7 @@ def ban_post(post_id, v):
return "", 204
@app.post("/api/unban_post/<post_id>")
@app.post("/unban_post/<post_id>")
@admin_level_required(3)
@validate_formkey
def unban_post(post_id, v):
@ -805,7 +804,7 @@ def unban_post(post_id, v):
return "", 204
@app.post("/api/distinguish/<post_id>")
@app.post("/distinguish/<post_id>")
@admin_level_required(1)
@validate_formkey
def api_distinguish_post(post_id, v):
@ -828,7 +827,7 @@ def api_distinguish_post(post_id, v):
return "", 204
@app.post("/api/sticky/<post_id>")
@app.post("/sticky/<post_id>")
@admin_level_required(3)
def api_sticky_post(post_id, v):
@ -842,7 +841,7 @@ def api_sticky_post(post_id, v):
return "", 204
@app.post("/api/pin/<post_id>")
@app.post("/pin/<post_id>")
@auth_required
def api_pin_post(post_id, v):
@ -853,7 +852,7 @@ def api_pin_post(post_id, v):
return "", 204
@app.post("/api/ban_comment/<c_id>")
@app.post("/ban_comment/<c_id>")
@admin_level_required(1)
def api_ban_comment(c_id, v):
@ -874,7 +873,7 @@ def api_ban_comment(c_id, v):
return "", 204
@app.post("/api/unban_comment/<c_id>")
@app.post("/unban_comment/<c_id>")
@admin_level_required(1)
def api_unban_comment(c_id, v):
@ -898,10 +897,8 @@ def api_unban_comment(c_id, v):
return "", 204
@app.post("/api/distinguish_comment/<c_id>")
@app.post("/api/v1/distinguish_comment/<c_id>")
@app.post("/distinguish_comment/<c_id>")
@auth_required
@api("read")
def admin_distinguish_comment(c_id, v):
if v.admin_level == 0: abort(403)
@ -1029,7 +1026,7 @@ def admin_nunuke_user(v):
return redirect(user.url)
@app.route("/api/user_stat_data", methods=['GET'])
@app.route("/user_stat_data", methods=['GET'])
@admin_level_required(2)
@cache.memoize(timeout=60)
def user_stat_data(v):

View File

@ -33,7 +33,7 @@ ALLOW_MULTIPLE = (
)
@app.get("/api/awards")
@app.get("/awards")
@auth_required
def get_awards(v):
@ -46,7 +46,7 @@ def get_awards(v):
return jsonify(return_value)
@app.put("/api/post/<pid>/awards")
@app.put("/post/<pid>/awards")
@auth_required
@validate_formkey
def award_post(pid, v):
@ -108,7 +108,7 @@ def award_post(pid, v):
return "", 204
@app.put("/api/comment/<cid>/awards")
@app.put("/comment/<cid>/awards")
@auth_required
@validate_formkey
def award_comment(cid, v):

View File

@ -19,19 +19,9 @@ beams_client = PushNotifications(
secret_key=PUSHER_KEY,
)
@app.get("/api/v1/post/<pid>/comment/<cid>")
def comment_cid_api_redirect(cid=None, pid=None):
redirect(f'/api/v1/comment/<cid>')
@app.get("/comment/<cid>")
@app.get("/comment/<cid>")
@app.get("/post_short/<pid>/<cid>")
@app.get("/post_short/<pid>/<cid>/")
@app.get("/api/v1/comment/<cid>")
@app.get("/post/<pid>/<anything>/<cid>")
@app.get("/api/vue/comment/<cid>")
@auth_desired
@api("read")
def post_pid_comment_cid(cid, pid=None, anything=None, v=None):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
@ -198,12 +188,10 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None):
'api': lambda: top_comment.json
}
@app.post("/api/comment")
@app.post("/api/v1/comment")
@app.post("/comment")
@limiter.limit("6/minute")
@is_not_banned
@validate_formkey
@api("create")
def api_comment(v):
parent_submission = request.form.get("submission")
@ -604,7 +592,6 @@ def api_comment(v):
@app.post("/edit_comment/<cid>")
@is_not_banned
@validate_formkey
@api("edit")
def edit_comment(cid, v):
c = get_comment(cid, v=v)
@ -793,10 +780,8 @@ def edit_comment(cid, v):
return jsonify({"html": c.body_html})
@app.post("/delete/comment/<cid>")
@app.post("/api/v1/delete/comment/<cid>")
@auth_required
@validate_formkey
@api("delete")
def delete_comment(cid, v):
c = g.db.query(Comment).filter_by(id=cid).first()
@ -818,10 +803,8 @@ def delete_comment(cid, v):
"api": lambda: ("", 204)}
@app.post("/undelete/comment/<cid>")
@app.post("/api/v1/undelete/comment/<cid>")
@auth_required
@validate_formkey
@api("delete")
def undelete_comment(cid, v):
c = g.db.query(Comment).filter_by(id=cid).first()
@ -841,24 +824,6 @@ def undelete_comment(cid, v):
return {"html": lambda: ("", 204),
"api": lambda: ("", 204)}
@app.get("/embed/comment/<cid>")
@app.get("/embed/post/<pid>/comment/<cid>")
@app.get("/api/v1/embed/comment/<cid>")
@app.get("/api/v1/embed/post/<pid>/comment/<cid>")
def embed_comment_cid(cid, pid=None):
comment = get_comment(int(cid))
if not comment.parent:
abort(403)
if comment.is_banned or comment.deleted_utc > 0:
return {'html': lambda: render_template("embeds/comment_removed.html", c=comment),
'api': lambda: {'error': f'Comment {cid} has been removed'}
}
return render_template("embeds/comment.html", c=comment)
@app.post("/comment_pin/<cid>")
@auth_required
@validate_formkey

View File

@ -13,7 +13,6 @@ from drama.__main__ import app
@app.errorhandler(400)
@auth_desired
@api()
def error_400(e, v):
return{"html": lambda: (render_template('errors/400.html', v=v), 400),
"api": lambda: (jsonify({"error": "400 Bad Request"}), 400 )
@ -28,15 +27,12 @@ def error_401(e):
argval = quote(f"{path}?{qs}", safe='')
output = f"/login?redirect={argval}"
if request.path.startswith("/api/v1/"):
return jsonify({"error": "401 Not Authorized"}), 401
else:
return redirect(output)
if request.headers.get("Authorization"): return jsonify({"error": "401 Not Authorized"}), 401
else: return redirect(output)
@app.errorhandler(403)
@auth_desired
@api()
def error_403(e, v):
return{"html": lambda: (render_template('errors/403.html', v=v), 403),
"api": lambda: (jsonify({"error": "403 Forbidden"}), 403)
@ -45,7 +41,6 @@ def error_403(e, v):
@app.errorhandler(404)
@auth_desired
@api()
def error_404(e, v):
return{"html": lambda: (render_template('errors/404.html', v=v), 404),
"api": lambda: (jsonify({"error": "404 Not Found"}), 404)
@ -54,7 +49,6 @@ def error_404(e, v):
@app.errorhandler(405)
@auth_desired
@api()
def error_405(e, v):
return{"html": lambda: (render_template('errors/405.html', v=v), 405),
"api": lambda: (jsonify({"error": "405 Method Not Allowed"}), 405)
@ -63,7 +57,6 @@ def error_405(e, v):
@app.errorhandler(409)
@auth_desired
@api()
def error_409(e, v):
return{"html": lambda: (render_template('errors/409.html', v=v), 409),
"api": lambda: (jsonify({"error": "409 Conflict"}), 409)
@ -72,7 +65,6 @@ def error_409(e, v):
@app.errorhandler(410)
@auth_desired
@api()
def error_410(e, v):
return{"html": lambda: (render_template('errors/410.html', v=v), 410),
"api": lambda: (jsonify({"error": "410 Request Payload Too Large"}), 410)
@ -80,7 +72,6 @@ def error_410(e, v):
@app.errorhandler(413)
@auth_desired
@api()
def error_413(e, v):
return{"html": lambda: (render_template('errors/413.html', v=v), 413),
"api": lambda: (jsonify({"error": "413 Image Size Too Large"}), 413)
@ -88,7 +79,6 @@ def error_413(e, v):
@app.errorhandler(418)
@auth_desired
@api()
def error_418(e, v):
return{"html": lambda: (render_template('errors/418.html', v=v), 418),
"api": lambda: (jsonify({"error": "418 I'm A Teapot"}), 418)
@ -97,7 +87,6 @@ def error_418(e, v):
@app.errorhandler(422)
@auth_desired
@api()
def error_422(e, v):
return{"html": lambda: (render_template('errors/422.html', v=v), 422),
"api": lambda: (jsonify({"error": "422 Unprocessable Entity"}), 422)
@ -106,7 +95,6 @@ def error_422(e, v):
@app.errorhandler(429)
@auth_desired
@api()
def error_429(e, v):
return{"html": lambda: (render_template('errors/429.html', v=v), 429),
"api": lambda: (jsonify({"error": "429 Too Many Requests"}), 429)
@ -115,7 +103,6 @@ def error_429(e, v):
@app.errorhandler(451)
@auth_desired
@api()
def error_451(e, v):
return{"html": lambda: (render_template('errors/451.html', v=v), 451),
"api": lambda: (jsonify({"error": "451 Unavailable For Legal Reasons"}), 451)
@ -124,7 +111,6 @@ def error_451(e, v):
@app.errorhandler(500)
@auth_desired
@api()
def error_500(e, v):
try:
g.db.rollback()
@ -138,7 +124,6 @@ def error_500(e, v):
@app.errorhandler(502)
@auth_desired
@api()
def error_502(e, v):
return{"html": lambda: (render_template('errors/502.html', v=v), 502),
"api": lambda: (jsonify({"error": "502 Bad Gateway"}), 502)
@ -147,7 +132,6 @@ def error_502(e, v):
@app.errorhandler(503)
@auth_desired
@api()
def error_503(e, v):
return{"html": lambda: (render_template('errors/503.html', v=v), 503),
"api": lambda: (jsonify({"error": "503 Service Unavailable"}), 503)

View File

@ -4,7 +4,7 @@ from flask import g
from drama.__main__ import app
@app.post("/api/flag/post/<pid>")
@app.post("/flag/post/<pid>")
@auth_desired
def api_flag_post(pid, v):
@ -30,7 +30,7 @@ def api_flag_post(pid, v):
return "", 204
@app.post("/api/flag/comment/<cid>")
@app.post("/flag/comment/<cid>")
@auth_desired
def api_flag_comment(cid, v):

View File

@ -289,9 +289,7 @@ def changeloglist(v=None, sort="new", page=1 ,t="all", **kwargs):
return posts
@app.get("/changelog")
@app.get("/api/v1/changelog")
@auth_desired
@api("read")
def changelog(v):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
@ -405,9 +403,7 @@ def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all", **kwargs):
return comments[:26]
@app.get("/comments")
@app.get("/api/v1/front/comments")
@auth_desired
@api("read")
def all_comments(v):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")

View File

@ -274,11 +274,9 @@ def edit_oauth_app(v, aid):
return redirect('/settings/apps')
@app.route("/api/v1/identity")
@app.route("/identity")
@auth_required
@api("identity")
def api_v1_identity(v):
return jsonify(v.json)
@ -443,9 +441,8 @@ def oauth_rescind_app(aid, v):
return jsonify({"message": f"{auth.application.app_name} Revoked"})
@app.post("/api/v1/release")
@app.post("/release")
@auth_required
@api()
def oauth_release_auth(v):
token=request.headers.get("Authorization").split()[1]
@ -462,9 +459,8 @@ def oauth_release_auth(v):
return jsonify({"message":"Authorization released"})
@app.post("/api/v1/kill")
@app.post("/kill")
@auth_required
@api()
def oauth_kill_auth(v):
token=request.headers.get("Authorization").split()[1]

View File

@ -22,7 +22,7 @@ from .front import frontlist
with open("snappy.txt", "r") as f:
snappyquotes = f.read().split("{[para]}")
@app.post("/api/publish/<pid>")
@app.post("/publish/<pid>")
@is_not_banned
@validate_formkey
def publish(pid, v):
@ -44,11 +44,8 @@ def submit_get(v):
v=v)
@app.get("/post/<pid>")
@app.get("/post/<pid>/")
@app.get("/post/<pid>/<anything>")
@app.get("/api/v1/post/<pid>")
@auth_desired
@api("read")
def post_id(pid, anything=None, v=None):
try: pid = int(pid)
except Exception as e: pass
@ -514,12 +511,9 @@ def archiveorg(url):
@app.post("/submit")
@app.post("/api/v1/submit")
@app.post("/api/vue/submit")
@limiter.limit("6/minute")
@is_not_banned
@validate_formkey
@api("create")
def submit_post(v):
@ -1009,9 +1003,7 @@ def submit_post(v):
@app.post("/delete_post/<pid>")
@app.post("/api/v1/delete_post/<pid>")
@auth_required
@api("delete")
@validate_formkey
def delete_post_pid(pid, v):
@ -1030,9 +1022,7 @@ def delete_post_pid(pid, v):
return "", 204
@app.post("/undelete_post/<pid>")
@app.post("/api/v1/undelete_post/<pid>")
@auth_required
@api("delete")
@validate_formkey
def undelete_post_pid(pid, v):
post = get_post(pid)
@ -1054,10 +1044,8 @@ def embed_post_pid(pid):
return render_template("embeds/submission.html", p=post)
@app.post("/api/toggle_comment_nsfw/<cid>")
@app.post("/api/v1/toggle_comment_nsfw/<cid>")
@app.post("/toggle_comment_nsfw/<cid>")
@is_not_banned
@api("update")
@validate_formkey
def toggle_comment_nsfw(cid, v):
@ -1067,10 +1055,8 @@ def toggle_comment_nsfw(cid, v):
g.db.add(comment)
return "", 204
@app.post("/api/toggle_post_nsfw/<pid>")
@app.post("/api/v1/toggle_post_nsfw/<pid>")
@app.post("/toggle_post_nsfw/<pid>")
@is_not_banned
@api("update")
@validate_formkey
def toggle_post_nsfw(pid, v):

View File

@ -197,10 +197,7 @@ def searchcommentlisting(criteria, v=None, page=1, t="None", sort="top"):
return total, [x.id for x in comments]
@app.get("/search/posts")
@app.get("/api/v1/search")
@app.route("/api/vue/search")
@auth_desired
@api("read")
def searchposts(v, search_type="posts"):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
@ -243,10 +240,7 @@ def searchposts(v, search_type="posts"):
}
@app.get("/search/comments")
@app.get("/api/v1/search/comments")
@app.route("/api/vue/search/comments")
@auth_desired
@api("read")
def searchcomments(v):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
@ -280,10 +274,7 @@ def searchcomments(v):
}
@app.get("/search/users")
@app.get("/api/v1/search/users")
@app.route("/api/vue/search/users")
@auth_desired
@api("read")
def searchusers(v, search_type="posts"):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")

View File

@ -11,10 +11,7 @@ def patrons(v):
return render_template("patrons.html", v=v, users=users)
@app.get("/badmins")
@app.route("/api/vue/admins", methods=["GET"])
@app.get("/api/v1/admins")
@auth_desired
@api("read")
def badmins(v):
badmins = g.db.query(User).filter_by(admin_level=6).order_by(User.dramacoins.desc()).all()
return {
@ -23,9 +20,7 @@ def badmins(v):
}
@app.get("/log")
@app.get("/api/v1/mod_log")
@auth_desired
@api("read")
def log(v):
page=int(request.args.get("page",1))

View File

@ -31,13 +31,6 @@ def suicide(v, username):
g.db.add(v)
return "", 204
@app.get("/api/v1/user/<username>")
@auth_desired
@api("read")
def user_info(v, username):
user = get_user(username, v=v)
return jsonify(user.json)
@app.get("/leaderboard")
@auth_desired
def leaderboard(v):
@ -179,10 +172,8 @@ def mfa_qr(secret, v):
return send_file(mem, mimetype="image/png", as_attachment=False)
@app.get("/api/is_available/<name>")
@app.get("/api/v1/is_available/<name>")
@app.get("/is_available/<name>")
@auth_desired
@api("read")
def api_is_available(name, v):
name=name.strip()
@ -212,18 +203,6 @@ def user_id(id):
user = get_account(int(id))
return redirect(user.url)
# Allow Id of user to be queryied, and then redirect the bot to the
# actual user api endpoint.
# So they get the data and then there will be no need to reinvent
# the wheel.
@app.get("/api/v1/uid/<uid>")
@auth_desired
@api("read")
def user_by_uid(uid, v=None):
user=get_account(uid)
return redirect(f'/api/v1/user/{user.username}/info')
@app.get("/u/<username>")
def redditor_moment_redirect(username):
@ -254,9 +233,7 @@ def visitors(v):
return render_template("viewers.html", v=v, viewers=viewers)
@app.get("/@<username>")
@app.get("/api/v1/user/<username>/listing")
@auth_desired
@api("read")
def u_username(username, v=None):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
@ -381,9 +358,7 @@ def u_username(username, v=None):
@app.get("/@<username>/comments")
@app.get("/api/v1/user/<username>/comments")
@auth_desired
@api("read")
def u_username_comments(username, v=None):
if v and v.is_banned and not v.unban_utc: return render_template("seized.html")
@ -472,9 +447,8 @@ def u_username_comments(username, v=None):
"api": lambda: jsonify({"data": [c.json for c in listing]})
}
@app.get("/api/v1/user/<username>/info")
@app.get("/@<username>/info")
@auth_desired
@api("read")
def u_username_info(username, v=None):
user=get_user(username, v=v)
@ -487,7 +461,7 @@ def u_username_info(username, v=None):
return jsonify(user.json)
@app.post("/api/follow/<username>")
@app.post("/follow/<username>")
@auth_required
def follow_user(username, v):
@ -509,7 +483,7 @@ def follow_user(username, v):
return "", 204
@app.post("/api/unfollow/<username>")
@app.post("/unfollow/<username>")
@auth_required
def unfollow_user(username, v):
@ -545,9 +519,7 @@ def user_profile_uid(uid):
@app.get("/@<username>/saved/posts")
@app.get("/api/v1/saved/posts")
@auth_required
@api("read")
def saved_posts(v, username):
page=int(request.args.get("page",1))
@ -572,9 +544,7 @@ def saved_posts(v, username):
@app.get("/@<username>/saved/comments")
@app.get("/api/v1/saved/comments")
@auth_required
@api("read")
def saved_comments(v, username):
page=int(request.args.get("page",1))

View File

@ -62,10 +62,8 @@ def admin_vote_info_get(v):
@app.post("/api/v1/vote/post/<post_id>/<new>")
@app.post("/api/vote/post/<post_id>/<new>")
@app.post("/vote/post/<post_id>/<new>")
@is_not_banned
@api("vote")
@validate_formkey
def api_vote_post(post_id, new, v):
@ -107,10 +105,8 @@ def api_vote_post(post_id, new, v):
g.db.add(post)
return "", 204
@app.post("/api/v1/vote/comment/<comment_id>/<new>")
@app.post("/api/vote/comment/<comment_id>/<new>")
@app.post("/vote/comment/<comment_id>/<new>")
@is_not_banned
@api("vote")
@validate_formkey
def api_vote_comment(comment_id, new, v):

View File

@ -11,7 +11,7 @@
<h4>&nbsp;Admin Tools</h4>
{% filter markdown %}
* [Grant User Award](/admin/user_award)
* [Advanced Stats](/api/user_stat_data)
* [Advanced Stats](/user_stat_data)
* [Ban Domain](/admin/domain/enter%20domain%20here)
* [Shadowbanned Users](/admin/shadowbanned)
* [Users with Agendaposter Theme](/admin/agendaposters)

View File

@ -0,0 +1,5 @@
{% extends "default.html" %}
{% block title %}
words words words
{% endblock %}

View File

@ -140,7 +140,7 @@
}
},
mounted() {
fetch('/api/awards')
fetch('/awards')
.then(response => response.json())
.then(json => {
this.awards = json;

View File

@ -256,7 +256,7 @@
aria-hidden="true"></i><span class="d-none d-md-inline-block">Reply</span></a></li>
{% if v.id!=c.author_id %}
<li class="list-inline-item text-muted"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/api/comment/{{c.id}}/awards')"><i class="fas fa-gift"
<li class="list-inline-item text-muted"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/comment/{{c.id}}/awards')"><i class="fas fa-gift"
aria-hidden="true"></i><span class="d-none d-md-inline-block">Give Award</span></a></li>
{% endif %}
@ -300,15 +300,15 @@
{% if v and v.admin_level==6 and v.id != c.author_id %}
{% if c.author.is_banned %}
<li class="list-inline-item text-muted d-none d-md-inline-block"><a id="unexile-comment-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-slash fa-fw text-danger"></i>Unban user</a></li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a id="unexile-comment-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/unban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-slash fa-fw text-danger"></i>Unban user</a></li>
{% else %}
<li class="list-inline-item text-muted d-none d-md-inline-block"><a id="exile-comment-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/api/ban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-slash fa-fw text-danger"></i>Ban user</a></li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a id="exile-comment-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/ban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-slash fa-fw text-danger"></i>Ban user</a></li>
{% endif %}
{% endif %}
{% if v and c.parent_submission and (c.author_id==v.id or v.admin_level > 0) %}
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" onclick="post('/api/toggle_comment_nsfw/{{c.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil fa-fw text-danger"></i>Toggle +18</a></li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" onclick="post('/toggle_comment_nsfw/{{c.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil fa-fw text-danger"></i>Toggle +18</a></li>
{% endif %}
{% if v and v.admin_level >=4 and c.oauth_app %}
@ -343,7 +343,7 @@
<div id="reply-to-{{c.id}}" class="d-none">
<div id="comment-form-space-{{c.fullname}}" class="comment-write collapsed child">
<form id="reply-to-t3_{{c.id}}" action="/api/comment" method="post" class="input-group" enctype="multipart/form-data">
<form id="reply-to-t3_{{c.id}}" action="/comment" method="post" class="input-group" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="parent_fullname" value="{{c.fullname}}">
<input id="reply-form-submission-{{c.fullname}}" type="hidden" name="submission" value="{{c.post.id}}">
@ -437,7 +437,7 @@
{% endif %}
{% if v and c.parent_submission and (c.author_id==v.id or v.admin_level > 0) %}
<li class="list-group-item"><a class="d-block" href="javascript:void(0)" onclick="post('/api/toggle_comment_nsfw/{{c.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil text-danger"></i>Toggle +18</a></li>
<li class="list-group-item"><a class="d-block" href="javascript:void(0)" onclick="post('/toggle_comment_nsfw/{{c.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil text-danger"></i>Toggle +18</a></li>
{% endif %}
{% if v %}
@ -468,9 +468,9 @@
{% if v and (c.post and v.admin_level == 6) %}
{% if c.author_id != v.id %}
{% if c.author.is_banned %}
<li class="list-group-item"><a class="d-block text-danger" id="unexile-comment2-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-minus fa-fw text-danger"></i>Unban user</a></li>
<li class="list-group-item"><a class="d-block text-danger" id="unexile-comment2-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/unban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-minus fa-fw text-danger"></i>Unban user</a></li>
{% else %}
<li class="list-group-item"><a class="d-block text-danger" id="exile-comment2-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/api/ban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-minus fa-fw text-danger"></i>Ban user</a></li>
<li class="list-group-item"><a class="d-block text-danger" id="exile-comment2-{{c.id}}" href="javascript:void(0)" onclick="post_toast('/ban_user/{{c.author_id}}?toast=1')"><i class="fas fa-user-minus fa-fw text-danger"></i>Ban user</a></li>
{% endif %}
{% endif %}
{% endif %}

View File

@ -131,7 +131,7 @@
//comment modding
function removeComment(post_id) {
url="/api/ban_comment/"+post_id
url="/ban_comment/"+post_id
callback=function(){
document.getElementById("comment-"+post_id+"-only").classList.add("banned");
@ -144,7 +144,7 @@
};
function approveComment(post_id) {
url="/api/unban_comment/"+post_id
url="/unban_comment/"+post_id
callback=function(){
document.getElementById("comment-"+post_id+"-only").classList.remove("banned");
@ -161,7 +161,7 @@
var xhr = new XMLHttpRequest();
xhr.open("post", "/api/distinguish_comment/"+cid);
xhr.open("post", "/distinguish_comment/"+cid);
var form = new FormData();
@ -276,7 +276,7 @@
this.innerHTML='<span class="spinner-border spinner-border-sm mr-2" role="status" aria-hidden="true"></span>Reporting comment';
this.disabled = true;
var xhr = new XMLHttpRequest();
xhr.open("POST", '/api/flag/comment/'+id, true);
xhr.open("POST", '/flag/comment/'+id, true);
var form = new FormData()
form.append("formkey", formkey());
form.append("reason", document.getElementById("reason-comment").value);
@ -326,7 +326,7 @@
this.disabled = true;
var xhr = new XMLHttpRequest();
xhr.open("POST", '/api/flag/post/'+id, true);
xhr.open("POST", '/flag/post/'+id, true);
var form = new FormData()
form.append("formkey", formkey());
form.append("reason", document.getElementById("reason").value);
@ -495,7 +495,7 @@
form.append('body', document.getElementById('reply-form-body-'+fullname).value);
form.append('file', document.getElementById('file-upload-reply-'+fullname).files[0]);
var xhr = new XMLHttpRequest();
xhr.open("post", "/api/comment");
xhr.open("post", "/comment");
xhr.withCredentials=true;
xhr.onload=function(){
if (xhr.status==200) {
@ -691,7 +691,7 @@
}
}
post_toast("/api/vote/" + type + "/" + id + "/" + voteDirection);
post_toast("/vote/" + type + "/" + id + "/" + voteDirection);
}
@ -741,7 +741,7 @@
}
}
post_toast("/api/vote/" + type + "/" + id + "/" + voteDirection);
post_toast("/vote/" + type + "/" + id + "/" + voteDirection);
}

View File

@ -1,121 +0,0 @@
{% extends "embeds/embed_default.html" %}
{% set score=c.score_fuzzed %}
{% block title %}
<title>@{{c.author.username}} comments on "{{c.post.title}}"</title>
<meta name="description" content="{{c.body}}">
{% endblock %}
{% block content %}
<div class="post-info font-weight-bold">
<span class="align-top"><a href="{{c.permalink}}">{{c.post.title | safe}}</a></span>
</div>
<div id="comment-{{c.id}}" class="comment">
<span class="mr-2 d-block d-md-none"><a href="{{c.author.permalink}}"><img src="{{c.author.profile_url}}" class="profile-pic-25"></a></span>
<span class="comment-collapse d-md-block d-none" onclick="collapse_comment('{{c.id}}')"></span>
<div class="comment-body">
<div id="comment-{{c.id}}-only">
<div class="user-info">{% if c.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}{% if c.author.title and c.author.title.is_before %}<span style="color:#{{c.author.title.color}}">{{c.author.title.text}}</span> {% endif %}<a href="{{c.author.permalink}}" class="user-name {% if c.post.author_id==c.author_id %}text-info{% endif %}">{{c.author.username}}</a>{% if c.author.title and not c.author.title.is_before %}<span style="color:#{{c.author.title.color}}">{{c.author.title.text}}</span>{% endif %}
{% if c.distinguish_level or c.author_id==c.post.author_id %}
<span> </span>
{% if c.distinguish_level %}
<i class="fas fa-shield text-admin" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Drama Badmin, speaking officially"></i>
{% endif %}
{% if c.post.author_id==c.author_id %}
<i class="fas fa-microphone-stand text-info" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Submitter"></i>
{% endif %}
<span> </span>
{% endif %}
<span class="time-stamp" data-toggle="tooltip" data-placement="bottom" title="{{c.created_datetime}}"><span>&#183;</span> {{c.age_string}}</span>
{% if c.edited_utc %}
<span class="time-edited" data-toggle="tooltip" data-placement="bottom" title="{{c.edited_datetime}}"><span>&#183;</span> <span class="font-italic">Edited {{c.edited_string}}</span></span>
{% endif %}
<span class="comment-collapse d-md-none" onclick="collapse_comment('{{c.id}}')"></span>
</div>
<div id="comment-text-{{c.id}}" class="comment-text">
{{c.body_html | safe}}
</div>
<div id="comment-{{c.id}}-actions" class="comment-actions">
<ul class="list-inline text-right text-md-left">
<li id="comment-{{c.id}}-up" class="list-inline-item arrow-up d-none d-md-inline-block mr-2">
</li>
<li class="list-inline-item d-none d-md-inline-block mr-2">
<span id="comment-{{c.id}}-score-none"class="d-none text-black">{{score}}</span> </li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0);" role="button" class="copy-link" data-clipboard-text="{{c.permalink | full_link}}"><i class="fas fa-link"></i><span>Copy link</span></a>
</li>
<li class="list-inline-item d-none d-md-inline-block">
<div class="dropdown show">
<a href="#" role="button" id="dropdownMoreLink" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="fas fa-ellipsis-h"></i>
</a>
<div class="dropdown-menu border-0 shadow" aria-labelledby="dropdownMoreLink">
<a class="dropdown-item" href="{{c.parent.permalink}}"><i class="fas fa-dna"></i>Parent</a>
<a class="dropdown-item d-none" href="#"><i class="fas fa-save"></i>Save</a>
</div>
</div>
</li>
<li class="list-inline-item d-inline-block d-md-none">
<a href="#" data-toggle="modal" data-target="#actionsModal-{{c.id}}" data-focus="false"><i class="fas fa-ellipsis-h"></i></a>
</li>
<li id="comment-{{c.id}}-up" class="list-inline-item arrow-up d-inline-block d-md-none mr-2">
</li>
<li class="list-inline-item d-inline-block d-md-none mr-2">
<span id="comment-{{c.id}}-score-none" class="d-none text-black">{{score}}</span>
</li>
<li id="comment-{{c.id}}-down" class="list-inline-item arrow-down d-inline-block d-md-none">
</li>
</ul>
</div>
</div>
<!-- Comment Actions Modal -->
<div class="modal fade d-md-none" id="actionsModal-{{c.id}}" tabindex="-1" role="dialog" aria-labelledby="actionsModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title h6">More options</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true"><i class="far fa-times"></i></span>
</button>
</div>
<div class="modal-body">
<ul class="list-group comment-actions">
<li class="list-group-item"><a href="javascript:void(0);" role="button" class="d-block copy-link" data-dismiss="modal" data-clipboard-text="{{c.permalink | full_link}}"><i class="fas fa-link"></i><span>Share</span></a>
<li class="list-group-item"><a class="d-block" href="{{c.parent.permalink}}"><i class="fas fa-dna"></i>Parent</a></li>
<li class="list-group-item d-none"><a href="#" class="d-block"><i class="fas fa-save"></i>Save</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,38 +0,0 @@
{% extends "embeds/embed_default.html" %}
{% block title %}
{<title>@{{c.author.username}} comments on "{{c.post.title}}"</title>
<meta name="description" content="{{c.body}}">
{% endblock %}
{% endblock %}
<div class="post-info font-weight-bold">
<span class="align-top"><a href="{{c.permalink}}">{{c.post.title | safe}}</a></span>
</div>
<div id="comment-{{c.id}}" class="comment">
<span class="comment-collapse"></span>
<div class="comment-body">
<div id="comment-{{c.id}}-only" class="">
<div class="user-info">{% if c.over_18 %}<span class="badge badge-danger">+18</span> {% endif %}
{% if c.is_banned %}[Removed by administrators]{% else %}[Deleted by author]{% endif %}
</div>
<div id="comment-banned-warning" class="comment-text text-danger text-small">
{% if c.is_banned and c.ban_reason %}Reason: {{c.ban_reason}}{% endif %}
</div>
</div>
</div>
</div>
{% block content %}

View File

@ -1,114 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="author" content="">
{% block title %}
<title>Drama</title>
<meta name="description" content="Dude bussy lmao">
{% endblock %}
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- Drama CSS -->
{% block stylesheets %}
{% if v %}
<link rel="stylesheet" href="/assets/style/{{v.theme}}_{{v.themecolor}}.css">
{% if v.agendaposter %}<link rel="stylesheet" href="/assets/style/agendaposter.css">{% elif v.css %}<link rel="stylesheet" href="/@{{v.username}}/css">{% endif %}
{% else %}
<link rel="stylesheet" href="/assets/style/dark_ff66ac.css">
{% endif %}
{% endblock %}
<!-- Font Awesome -->
<link href="/assets/style/fa.css" rel="stylesheet"> <!--load all styles -->
</head>
<body id="{% block pagetype %}frontpage{% endblock %}" class="p-1">
<div class="container">
<div class="row justify-content-around" id="main-content-row">
<div class="col" id="main-content-col">
{% block content %}
{% endblock %}
</div>
<!-- Clipboard Toast -->
<div class="toast clipboard" id="toast-success" role="alert" aria-live="assertive" aria-atomic="true" data-animation="true" data-autohide="true" data-delay="5000">
<div class="toast-body text-center">
<i class="fas fa-check-circle text-success mr-2"></i>Link copied to clipboard
</div>
</div>
<div class="toast clipboard" id="toast-error" role="alert" aria-live="assertive" aria-atomic="true" data-animation="true" data-autohide="true" data-delay="5000">
<div class="toast-body text-center">
<i class="fas fa-exclamation-circle text-danger mr-2"></i>Unable to copy link
</div>
</div>
{% include "bootstrap.html" %}
<!-- ClipboardJS -->
<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<!-- Instantiate clipboard by passing a string selector -->
<script type="text/javascript">
var clipboard = new ClipboardJS('.copy-link');
clipboard.on('success', function(e) {
jQuery(function($) {
$('#toast-success').toast('show');
})
console.log(e);
});
clipboard.on('error', function(e) {
jQuery(function($) {
$('#toast-error').toast('show');
})
console.log(e);
});
</script>
{% block enlargeThumbJS %}
{% endblock %}
{% block toggleView %}
{% endblock %}
{% block embedJS %}
{% endblock %}
{% block formatJS %}
{% endblock %}
<script src="/assets/js/all_js.js"></script>
</body>
</html>

View File

@ -1,145 +0,0 @@
{% extends "embeds/embed_default.html" %}
{% set score=p.score_fuzzed %}
{% block title %}
<title>{{p.title | safe}}</title>
<meta name="description" content="posted {{p.age_string}} by @{{p.author.username}}">
{% endblock %}
{% block pagetype %}thread{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<div id="post-{{p.id}}" class="card border-0 mt-3{% if p.is_banned %} banned{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}">
<div class="d-flex flex-row-reverse flex-nowrap justify-content-end">
{% if p.thumb_url %}
<div class="card-header bg-transparent border-0 d-none d-md-flex flex-row flex-nowrap p-0">
<a href="{{p.url}}" rel="nofollow"><img src="{{p.thumb_url}}" class="post-img d-none d-md-block" alt="Unable to anonymously load image"></a>
</div>
{% endif %}
<div class="card-block w-100 my-md-auto">
<div class="post-meta text-left d-block d-md-none mb-2">{% if p.stickied %}<i class="fas fa-thumbtack text-success fa-rotate--45" data-toggle="tooltip" data-placement="bottom" title="Pinned post"></i> <span>&#183;</span> {% endif %}<span data-toggle="tooltip" data-placement="bottom" title="{{p.created_date}}">{{p.age_string}}</span> by {% if p.author.title and p.author.title.is_before %}<span style="color:#{{p.author.title.color}}">{{p.author.title.text}}</span> {% endif %}<a href="{{p.author.permalink}}" class="user-name">{{p.author.username}}</a>{% if p.author.title and not p.author.title.is_before %}<span style="color:#{{p.author.title.color}}">{{p.author.title.text}}</span>{% endif %}{% if p.distinguish_level %} <i class="fas fa-shield text-admin" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Drama Badmin, speaking officially"></i>{% endif %} <span>&#183;</span> ({{p.domain}}){% if p.edited_utc %} &#183; Edited <span data-toggle="tooltip" data-placement="bottom" title="{{edited_date}}">{{p.edited_string}}</span>{% endif %}</div>
<div class="post-meta text-left d-none d-md-block mb-md-2">{% if p.stickied %}<i class="fas fa-thumbtack text-success fa-rotate--45" data-toggle="tooltip" data-placement="bottom" title="Pinned post"></i> <span>&#183;</span> {% endif %}<span data-toggle="tooltip" data-placement="bottom" title="{{p.created_date}}">{{p.age_string}}</span> by {% if p.author.title and p.author.title.is_before %}<span style="color:#{{p.author.title.color}}">{{p.author.title.text}}</span> {% endif %}<a href="{{p.author.permalink}}" class="user-name">{{p.author.username}}</a>{% if p.author.title and not p.author.title.is_before %}<span style="color:#{{p.author.title.color}}">{{p.author.title.text}}</span>{% endif %}{% if p.distinguish_level %} <i class="fas fa-shield text-admin" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="Drama Badmin, speaking officially"></i>{% endif %} <span>&#183;</span> ({{p.domain}}){% if p.edited_utc %} &#183; Edited <span data-toggle="tooltip" data-placement="bottom" title="{{edited_date}}">{{p.edited_string}}</span>{% endif %}</div>
{% if p.url %}
<h1 class="card-title post-title text-left mb-2"><a target="_blank" href="{{p.url}}">{{p.title | safe}}</a></h1>
{% else %}
<h1 class="card-title post-title text-left mb-2">{{p.title | safe}}</h1>
{% endif %}
<div id="post-body" {% if p.body_html %}class="post-body mt-3"{% endif %}>
{{p.body_html | safe}}
</div>
<div class="post-actions mt-2 d-none d-md-block">
<ul class="list-inline text-right d-flex">
<li class="list-inline-item"><a href="{{p.permalink}}"><i class="fas fa-comment-dots"></i>{{p.comment_count}}</a></li>
<li class="list-inline-item"><a href="javascript:void(0);" role="button" class="copy-link" data-clipboard-text="{{p.permalink | full_link}}"><i class="fas fa-copy"></i>Copy link</a></li>
</ul>
</div>
</div>
<!-- Voting on "medium" devices or larger, hidden on smaller devices -->
<div id="voting" class="voting d-none d-md-block {% if p.body_html %} mb-auto {% else %} my-auto {% endif %} mr-3">
<div id="post-{{p.id}}-up" class="arrow-up mx-auto">
</div>
<span id="post-{{p.id}}-score-none" class="score text-muted">{{score}}</span>
<div id="post-{{p.id}}-down" class="arrow-down mx-auto">
</div>
</div>
</div>
<!-- Disable card-footer for now
<div class="card-footer d-none">
<div class="post-actions">
<ul class="list-inline text-right">
<li id="voting-{{p.id}}-mobile" class="voting list-inline-item d-md-none">
<span id="arrow-{{p.id}}-mobile-up" class="mr-2 arrow-mobile-up" onclick="vote('{{p.id}}','0')">
<i class="fas fa-chevron-up mx-0" aria-hidden="true"></i>
</span>
<span id="post-{{p.id}}-score-mobile-none" class="score text-muted">{{score}}</span>
<span id="arrow-{{p.id}}-mobile-down" class="arrow-mobile-down ml-2 my-0" onclick="vote('{{p.id}}','-1')">
<i class="fas fa-chevron-down mx-0" aria-hidden="true"></i>
</span>
</li>
</ul>
</div>
</div>
-->
</div>
</div>
<div class="row no-gutters mb-3 d-block d-md-none">
<div class="col">
<a target="_blank" href="{{p.url}}">{% if p.is_image %}<img src="{{p.url}}" class="img-fluid" alt="Unable to anonymously load image">
<div class="post-img-overlay d-block d-md-none">{{p.domain|truncate(30, True)}}<i class="fas fa-external-link-alt text-small ml-2"></i></div>
{% endif %}
</a>
</div>
</div>
</div>
<div class="row mb-3 d-block d-md-none">
<div class="col-12">
<div class="post-actions">
<ul class="list-inline text-right d-flex">
<li class="list-inline-item mr-auto"><a href="{{p.permalink}}"><i class="fas fa-comment-dots"></i>{{p.comment_count}}</a></li>
<li class="list-inline-item"><a href="javascript:void(0);" role="button" class="copy-link" data-clipboard-text="{{p.permalink | full_link}}"><i class="fas fa-link"></i>Share</a></li>
<li id="voting-{{p.id}}-mobile" class="voting list-inline-item d-md-none">
<span id="arrow-{{p.id}}-mobile-up" class="mr-2 arrow-mobile-up">
<i class="fas fa-arrow-alt-up mx-0" aria-hidden="true"></i>
</span>
<span id="post-{{p.id}}-score-mobile-none" class="score text-muted">{{score}}</span>
<span id="arrow-{{p.id}}-mobile-down" class="arrow-mobile-down ml-2 my-0">
<i class="fas fa-arrow-alt-down mx-0" aria-hidden="true"></i>
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,117 +0,0 @@
{% extends "default.html" %}
{% block title %}
<title>Drama - OAuth2</title>
<meta name="description" content="Drama OAuth2 Guide">
{% endblock %}
{% block content %}
{% filter markdown %}
# OAuth2
The OAuth2 authorization flow is used to enable users to authorize third-party applications to access their Drama account without having to provide their login information to the application.
This page explains how to obtain API application keys, how to prompt a user for authorization, and how to obtain and use access tokens.
## Step 1: Create your Application
In the [apps tab of Drama settings](/settings/apps), fill in and submit the form to request new API keys. You will need:
* an application name
* a Redirect URI, or a comma-separated list of redirect URIs. May not use HTTP unless using localhost (use HTTPS instead).
* a brief description of what your application is intended to do
Don't worry too much about accuracy; you will be able to change all of these later.
Drama administrators will review and approve or deny your request for API keys. You'll know when your request has been approved when a client ID and secret appear in your application information.
DO NOT reveal your Client Secret. Anyone with your Client Secret will be able to pretend to be you. You are responsible for keeping your Client Secret a secret!
## Step 2: Prompt Your User for Authorization
Send your user to `https://rdrama.net/oauth/authorize`, with the following URL parameters:
* `client_id` - Your application's Client ID
* `redirect_uri` - The redirect URI (or one of the URIs) specified in your application information. Must not use HTTP unless using localhost (use HTTPS instead).
* `state` - This is your own anti-cross-site-forgery token. We don't do anything with this, except give it to the user to pass back to you later. You are responsible for generating and validating the state token.
* `scope` - A comma-separated list of permission scopes that you are requesting. Valid scopes are: `identity`, `create`, `read`, `update`, `delete` and `vote`.
* `permanent` - optional. Set to `true` if you are requesting indefinite access. Omit if not.
If done correctly, the user will see that your application wants to access their Drama account, and be prompted to approve or deny the request.
## Step 3: Catch the redirect
The user clicks "Authorize". Drama will redirect the user's browser to GET the designated redirect URI. The following URL parameters will be included, which your server should process:
* `code` - a **single-use** authorization code.
* `state` - The state token from earlier.
Validate the state token. How you do this is up to you.
## Step 4: Exchange code for access token
Make a POST request to `https://rdrama.net/oauth/grant`. Include the following form parameters:
* `client_id` - Your application's Client ID
* `client_secret` - Your application's Client Secret
* `grant_type` - Set to the word "code"
* `code` - The `code` parameter that was given to you in the previous step.
Python example:
<pre>
import requests
import pprint
code=request.args.get("code")
headers={"User-Agent": "Porpl Reader v1 by @captainmeta4"}
url="/oauth/grant"
data={"client_id": my_client_id,
"client_secret": my_client_secret,
"grant_type": "code",
"code": code
}
r=requests.post(url, headers=headers, data=data)
pprint.pprint(r.json())
</pre>
If everything is good, we will respond with the following (example) JSON body:
<pre>
{
"access_token": #Access token
"scopes": #Comma-separated list of scopes included in authorization
"expires_at": #Unix epoch integer time at which access token expires
"token_type": "Bearer"
"refresh_token": #This key is omitted in temporary authorizations
}
</pre>
Store the access and refresh tokens. You should also store expiration timestamp and the scopes list, so that you pre-emptively avoid sending requests to Drama that won't be accepted.
## Step 5: Using the Access Token
To use the access token, include the following header in subsequent API requests to Drama: `Authorization: Bearer access_token_goes_here`
Python example, presuming that the application has obtained a valid `read` authorization:
<pre>
import requests
import pprint
headers={"Authorization": "Bearer " + access_token,
"User-Agent": "Drama Reader v1 by @carpathianflorist"}
url="/api/v1/front/listing"
r=requests.get(url, headers=headers)
pprint.pprint(r.json())
</pre>
The expected result of this would be a large JSON representation of the submissions that make up the user's personal front page.
{% endfilter %}
{% endblock %}

View File

@ -108,7 +108,7 @@
<input class="form-control" id="new_email" {% if v.email %}placeholder="{{v.email}}"{% else %}placeholder="Your email"{% endif %}
aria-describedby="new_email" type="email" name="new_email" required>
{% if v.email and not v.is_activated %}
<div class="text-danger text-small-extra mt-1" id="email-verify-text">Email not verified. You will not be able to recover your account with this email until you verify it. <u><a href="javascript:void(0)" onclick="post('/api/verify_email');emailVerifyText();" class="text-danger">Verify now.</a></u></div>
<div class="text-danger text-small-extra mt-1" id="email-verify-text">Email not verified. You will not be able to recover your account with this email until you verify it. <u><a href="javascript:void(0)" onclick="post('/verify_email');emailVerifyText();" class="text-danger">Verify now.</a></u></div>
{% elif not v.email %}
<div class="text-danger text-small-extra mt-1" id="email-verify-text">Add an email to secure your account in case you forget your password.</div>
{% endif %}

View File

@ -33,7 +33,7 @@
var id = document.getElementById("usernameHelpRegister");
var successID = document.getElementById("usernameHelpSuccess");
var dramaAPI = '/api/is_available/' + charCount;
var dramaAPI = '/is_available/' + charCount;
if (charCount.length >= 3) {

View File

@ -100,12 +100,12 @@
{% endif %}
{% if v and v.id==p.author_id %}
{% if p.private %}
<button class="btn btn-link btn-block btn-lg text-left text-muted"><a href="javascript:void(0)" onclick="post('/api/publish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-globe text-center text-muted mr-3"></i>Publish</a></button>
<button class="btn btn-link btn-block btn-lg text-left text-muted"><a href="javascript:void(0)" onclick="post('/publish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-globe text-center text-muted mr-3"></i>Publish</a></button>
{% endif %}
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-dismiss="modal" onclick="togglePostEdit('{{p.id}}')"><i class="far fa-edit text-center text-muted mr-3"></i>Edit</button>
<button class="btn btn-link btn-block btn-lg text-info text-left" id="pin-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/pin/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</button>
<button class="btn btn-link btn-block btn-lg text-info text-left" id="pin-post-{{p.id}}" href="javascript:void(0)" onclick="post('/pin/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</button>
{% if p.deleted_utc > 0 %}
<button class="btn btn-link btn-block btn-lg text-left text-muted" href="javascript:void(0)" onclick="post('/undelete_post/{{p.id}}', function(){window.location.reload(true);})"><i class="far fa-trash-alt text-center text-muted mr-3"></i>Undelete</button>
@ -117,7 +117,7 @@
<button class="btn btn-link btn-block btn-lg text-left text-muted"><a href="/votes?link=https://rdrama.net{{p.permalink}}"><i class="fas fa-arrows-v text-center text-muted mr-3"></i>Votes</a></button>
{% if v and v.id!=p.author_id %}
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-toggle="modal" data-dismiss="modal" data-target="#awardModal" onclick="awardModal('/api/post/{{p.id}}/awards')"><i class="fas fa-gift text-center text-muted mr-3"></i>Give Award</button>
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-toggle="modal" data-dismiss="modal" data-target="#awardModal" onclick="awardModal('/post/{{p.id}}/awards')"><i class="fas fa-gift text-center text-muted mr-3"></i>Give Award</button>
{% endif %}
{% if v and p.id in v.subscribed_idlist() %}
@ -133,18 +133,18 @@
{% endif %}
{% if v and (v.id==p.author_id or v.admin_level>=3) %}
<button class="btn btn-link btn-block btn-lg text-left text-muted" onclick="post('/api/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="far fa-eye-evil text-center text-muted mr-3"></i>Toggle +18</button>
<button class="btn btn-link btn-block btn-lg text-left text-muted" onclick="post('/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="far fa-eye-evil text-center text-muted mr-3"></i>Toggle +18</button>
{% endif %}
{% if v %}
{% if v.admin_level >=3 %}
<button class="btn btn-link btn-block btn-lg text-info text-left" id="sticky-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/sticky/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</button>
<button class="btn btn-link btn-block btn-lg text-info text-left" id="sticky-post-{{p.id}}" href="javascript:void(0)" onclick="post('/sticky/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</button>
{% if v==p.author %}
<button class="btn btn-link btn-block btn-lg text-left text-warning" id="distinguish-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/distinguish/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-crown text-center text-muted mr-3"></i>Distinguish</button>
<button class="btn btn-link btn-block btn-lg text-left text-warning" id="distinguish-post-{{p.id}}" href="javascript:void(0)" onclick="post('/distinguish/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-crown text-center text-muted mr-3"></i>Distinguish</button>
{% endif %}
<button class="btn btn-link btn-block btn-lg text-success text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-check text-center text-success mr-3"></i>Approve</button>
<button class="btn btn-link btn-block btn-lg text-danger text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-ban text-center text-danger mr-3"></i>Remove</button>
<button class="btn btn-link btn-block btn-lg text-success text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-check text-center text-success mr-3"></i>Approve</button>
<button class="btn btn-link btn-block btn-lg text-danger text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-ban text-center text-danger mr-3"></i>Remove</button>
{% endif %}
{% if v.admin_level >=4 and p.oauth_app %}
@ -162,9 +162,9 @@
{% if v and v.admin_level == 6 and v.id!=p.author_id %}
{% if p.author.is_banned %}
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{p.author_id}}?toast=1')"><i class="fas fa-user-minus mr-3 text-danger"></i>Unban user</a></button>
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/unban_user/{{p.author_id}}?toast=1')"><i class="fas fa-user-minus mr-3 text-danger"></i>Unban user</a></button>
{% else %}
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/api/ban_user/{{p.author_id}}?toast=1')"><i class="fas fa-user-minus mr-3 text-danger"></i>Ban user</a></button>
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/ban_user/{{p.author_id}}?toast=1')"><i class="fas fa-user-minus mr-3 text-danger"></i>Ban user</a></button>
{% endif %}
{% endif %}
@ -306,7 +306,7 @@
{% if v and v.id==p.author_id %}
{% if p.private %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/publish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-globe"></i>Publish</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/publish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-globe"></i>Publish</a></li>
{% endif %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="togglePostEdit('{{p.id}}')"><i class="fas fa-edit"></i>Edit</a></li>
{% endif %}
@ -314,7 +314,7 @@
<li class="list-inline-item"><a href="/votes?link=https://rdrama.net{{p.permalink}}"><i class="fas fa-arrows-v"></i>Votes</a></li>
{% if v and v.id!=p.author_id %}
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/api/post/{{p.id}}/awards')"><i class="fas fa-gift fa-fw"></i>Give Award</a></li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/post/{{p.id}}/awards')"><i class="fas fa-gift fa-fw"></i>Give Award</a></li>
{% endif %}
<li class="list-inline-item"><a href="javascript:void(0);" role="button" class="copy-link" data-clipboard-text="{{p.permalink | full_link}}"><i class="fas fa-copy"></i>Copy link</a></li>
@ -336,7 +336,7 @@
{% endif %}
{% if v and v.id==p.author_id %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/pin/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/pin/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</a></li>
{% if p.deleted_utc > 0 %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/undelete_post/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-trash-alt"></i>Undelete</a></li>
{% else %}
@ -345,21 +345,21 @@
{% endif %}
{% if v and v.admin_level>=3 %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/sticky/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/sticky/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</a></li>
{% if v==p.author %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/distinguish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-crown"></i>Distinguish</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/distinguish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-crown"></i>Distinguish</a></li>
{% endif %}
{% endif %}
{% if v %}
{% if v.id == p.author_id or v.admin_level >= 3 %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil text-danger"></i>Toggle +18</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil text-danger"></i>Toggle +18</a></li>
{% endif %}
{% if v.admin_level >=3 %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-check text-success"></i>Approve</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-ban text-danger"></i>Remove</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-check text-success"></i>Approve</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-ban text-danger"></i>Remove</a></li>
{% endif %}
{% if v.admin_level >= 4 and p.oauth_app %}
@ -382,10 +382,10 @@
{% if v.admin_level >=3 and v.id!=p.author_id %}
{% if p.author.is_banned %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{p.author_id}}')"
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post_toast('/unban_user/{{p.author_id}}')"
><i class="fas fa-user-slash"></i>Unban user</a></li>
{% else %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post_toast('/api/ban_user/{{p.author_id}}')"
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post_toast('/ban_user/{{p.author_id}}')"
><i class="fas fa-user-slash"></i>Ban user</a></li>
{% endif %}
{% endif %}
@ -525,7 +525,7 @@
</div>
<div id="comment-form-space-{{p.fullname}}" class="comment-write mb-3">
<form id="reply-to-{{p.fullname}}" class="input-group" action="/api/comment" method="post">
<form id="reply-to-{{p.fullname}}" class="input-group" action="/comment" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="parent_fullname" value="t2_{{p.id}}">
<input id="reply-form-submission-{{p.fullname}}" type="hidden" name="submission" value="{{p.id}}">

View File

@ -20,25 +20,25 @@
{% block adminpanel %}
{% if v.admin_level >=3 %}
<form action="/api/sticky/{{p.id}}" method="post">
<form action="/sticky/{{p.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="submit" value="{% if p.stickied %}Un-sticky{% else %}Pin{% endif %}">
</form>
{% endif %}
{% if v.admin_level >=3 and v.id==p.author_id %}
<form action="/api/distinguish/{{p.id}}" method="post">
<form action="/distinguish/{{p.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="submit" value="{% if p.distinguish_level %}Un-distinguish{% else %}Distinguish{% endif %}">
</form>
{% endif %}
{% if v.admin_level >=1 and v.admin_level > p.author.admin_level %}
{% if p.is_banned %}
<form action="/api/unban_post/{{p.id}}" method="post">
<form action="/unban_post/{{p.id}}" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="submit" value="Approve Post">
</form>
{% else %}
<form action="/api/ban_post/{{p.id}}", method="post">
<form action="/ban_post/{{p.id}}", method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<input type="submit" value="Remove Post">
</form>

View File

@ -134,7 +134,7 @@
<li class="list-inline-item"><a href="/votes?link=https://rdrama.net{{p.permalink}}"><i class="fas fa-arrows-v"></i>Votes</a></li>
{% if v and v.id!=p.author_id %}
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/api/post/{{p.id}}/awards')"><i class="fas fa-gift fa-fw"></i>Give Award</a></li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/post/{{p.id}}/awards')"><i class="fas fa-gift fa-fw"></i>Give Award</a></li>
{% endif %}
<li class="list-inline-item"><a href="javascript:void(0);" role="button" class="copy-link" data-clipboard-text="{{p.permalink | full_link}}"><i class="fas fa-copy"></i>Copy link</a></li>
@ -156,7 +156,7 @@
{% endif %}
{% if v and v.id==p.author_id %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/pin/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/pin/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</a></li>
{% if p.deleted_utc > 0 %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/undelete_post/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-trash-alt"></i>Undelete</a></li>
{% else %}
@ -166,9 +166,9 @@
{% if v and v.admin_level>=3 %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/sticky/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/sticky/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-thumbtack"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</a></li>
{% if v==p.author %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/distinguish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-crown"></i>Distinguish</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/distinguish/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-crown"></i>Distinguish</a></li>
{% endif %}
{% endif %}
@ -176,13 +176,13 @@
{% if v and (v.id==p.author_id or v.admin_level>=3) %}
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/api/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil text-danger"></i>Toggle +18</a></li>
<li class="list-inline-item"><a href="javascript:void(0)" onclick="post('/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="fas fa-eye-evil text-danger"></i>Toggle +18</a></li>
{% endif %}
{% if v.admin_level >=3 %}
<li class="list-inline-item"><a id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-check text-success"></i>Approve</a></li>
<li class="list-inline-item"><a id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-ban text-danger"></i>Remove</a></li>
<li class="list-inline-item"><a id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-check text-success"></i>Approve</a></li>
<li class="list-inline-item"><a id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-ban text-danger"></i>Remove</a></li>
{% endif %}
{% if v.admin_level >= 4 and p.oauth_app %}
@ -196,10 +196,10 @@
{% if v.admin_level >=3 and v.id!=p.author_id %}
{% if p.author.is_banned %}
<li class="list-inline-item"><a id="unexile2-user-{{p.id}}" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{p.author_id}}')"
<li class="list-inline-item"><a id="unexile2-user-{{p.id}}" href="javascript:void(0)" onclick="post_toast('/unban_user/{{p.author_id}}')"
><i class="fas fa-user-slash text-danger"></i>Unban user</a></li>
{% else %}
<li class="list-inline-item"><a id="exile2-user-{{p.id}}" href="javascript:void(0)" onclick="post_toast('/api/ban_user/{{p.author_id}}')"
<li class="list-inline-item"><a id="exile2-user-{{p.id}}" href="javascript:void(0)" onclick="post_toast('/ban_user/{{p.author_id}}')"
><i class="fas fa-user-slash text-danger"></i>Ban user</a></li>
{% endif %}
{% endif %}
@ -295,7 +295,7 @@
<button class="btn btn-link btn-block btn-lg text-left text-muted"><a href="/votes?link=https://rdrama.net{{p.permalink}}"><i class="fas fa-arrows-v text-center text-muted mr-3"></i>Votes</a></button>
{% if v and v.id!=p.author_id %}
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/api/post/{{p.id}}/awards')"><i class="fas fa-gift fa-fw"></i>Give Award</a></li>
<li class="list-inline-item text-muted d-none d-md-inline-block"><a href="javascript:void(0)" data-toggle="modal" data-target="#awardModal" onclick="awardModal('/post/{{p.id}}/awards')"><i class="fas fa-gift fa-fw"></i>Give Award</a></li>
{% endif %}
{% if v and p.id in v.subscribed_idlist() %}
@ -314,7 +314,7 @@
<button class="btn btn-link btn-block btn-lg text-left text-muted" data-toggle="modal" data-dismiss="modal" data-target="#reportPostModal" onclick="report_postModal('{{p.id}}','{{'@'+p.author.username}}')" class="d-block"><i class="far fa-flag text-center text-muted mr-3"></i>Report</button>
{% endif %}
{% if v and v.id==p.author_id %}
<button class="btn btn-link btn-block btn-lg text-info text-left" id="pin-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/pin/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</button>
<button class="btn btn-link btn-block btn-lg text-info text-left" id="pin-post-{{p.id}}" href="javascript:void(0)" onclick="post('/pin/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.is_pinned %}Unpin from your profile{% else %}Pin to your profile{% endif %}</button>
{% if p.deleted_utc > 0 %}
<button class="btn btn-link btn-block btn-lg text-left text-muted" href="javascript:void(0)" onclick="post('/undelete_post/{{p.id}}', function(){window.location.reload(true);})"><i class="far fa-trash-alt text-center text-muted mr-3"></i>Undelete</button>
{% else %}
@ -323,28 +323,28 @@
{% endif %}
{% if v and (v.id==p.author_id or v.admin_level>=3) %}
<button class="btn btn-link btn-block btn-lg text-left text-muted" onclick="post('/api/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="far fa-eye-evil text-center text-muted mr-3"></i>Toggle +18</button>
<button class="btn btn-link btn-block btn-lg text-left text-muted" onclick="post('/toggle_post_nsfw/{{p.id}}', function(){window.location.reload(true);})"><i class="far fa-eye-evil text-center text-muted mr-3"></i>Toggle +18</button>
{% endif %}
{% if v %}
{% if v.admin_level >=3 %}
{% if v.id!=p.author_id %}
{% if p.author.is_banned %}
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/api/unban_user/{{p.author_id}}')"><i class="fas fa-user-minus mr-3 text-danger"></i>Unban user</a></button>
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/unban_user/{{p.author_id}}')"><i class="fas fa-user-minus mr-3 text-danger"></i>Unban user</a></button>
{% else %}
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/api/ban_user/{{p.author_id}}')"><i class="fas fa-user-minus mr-3 text-danger"></i>Ban user</a></button>
<button class="btn btn-link btn-block btn-lg text-left" href="javascript:void(0)" onclick="post_toast('/ban_user/{{p.author_id}}')"><i class="fas fa-user-minus mr-3 text-danger"></i>Ban user</a></button>
{% endif %}
{% endif %}
<button class="btn btn-link btn-block btn-lg text-info text-left" id="sticky-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/sticky/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</button>
<button class="btn btn-link btn-block btn-lg text-info text-left" id="sticky-post-{{p.id}}" href="javascript:void(0)" onclick="post('/sticky/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-thumbtack text-center text-muted mr-3"></i>{% if p.stickied %}Unpin{% else %}Pin{% endif %}</button>
{% if v==p.author %}
<button class="btn btn-link btn-block btn-lg text-left text-warning" id="distinguish-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/distinguish/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-crown text-center text-muted mr-3"></i>Distinguish</button>
<button class="btn btn-link btn-block btn-lg text-left text-warning" id="distinguish-post-{{p.id}}" href="javascript:void(0)" onclick="post('/distinguish/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="fas fa-crown text-center text-muted mr-3"></i>Distinguish</button>
{% endif %}
<button class="btn btn-link btn-block btn-lg text-success text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-check text-center text-success mr-3"></i>Approve</button>
<button class="btn btn-link btn-block btn-lg text-danger text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/api/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-ban text-center text-danger mr-3"></i>Remove</button>
<button class="btn btn-link btn-block btn-lg text-success text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/unban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-check text-center text-success mr-3"></i>Approve</button>
<button class="btn btn-link btn-block btn-lg text-danger text-left" id="moderate-post-{{p.id}}" href="javascript:void(0)" onclick="post('/ban_post/{{p.id}}',callback=function(){window.location.reload(true);})"><i class="far fa-ban text-center text-danger mr-3"></i>Remove</button>
{% endif %}
{% if v.admin_level >=4 and p.oauth_app %}

View File

@ -13,8 +13,8 @@
{% if v %}
{% if v.id!=u.id and not u.is_private and not u.is_nofollow %}
<div id="button-sub-{{u.id}}" style="z-index: 2" class="{% if u.has_follower(v) %}d-none{% endif %}"><a class="btn btn-primary btn-sm" href="javascript:void(0)" onclick="post('/api/follow/{{u.username}}', callback=function(){document.getElementById('button-unsub-{{u.id}}').classList.toggle('d-none');document.getElementById('button-sub-{{u.id}}').classList.toggle('d-none');})">Follow</a></div>
<div id="button-unsub-{{u.id}}" style="z-index: 2" class="{% if not u.has_follower(v) %} d-none{% endif %}"><a class="btn btn-secondary btn-sm" href="javascript:void(0)" onclick="post('/api/unfollow/{{u.username}}', callback=function(){document.getElementById('button-unsub-{{u.id}}').classList.toggle('d-none');document.getElementById('button-sub-{{u.id}}').classList.toggle('d-none');})">Unfollow</a></div>
<div id="button-sub-{{u.id}}" style="z-index: 2" class="{% if u.has_follower(v) %}d-none{% endif %}"><a class="btn btn-primary btn-sm" href="javascript:void(0)" onclick="post('/follow/{{u.username}}', callback=function(){document.getElementById('button-unsub-{{u.id}}').classList.toggle('d-none');document.getElementById('button-sub-{{u.id}}').classList.toggle('d-none');})">Follow</a></div>
<div id="button-unsub-{{u.id}}" style="z-index: 2" class="{% if not u.has_follower(v) %} d-none{% endif %}"><a class="btn btn-secondary btn-sm" href="javascript:void(0)" onclick="post('/unfollow/{{u.username}}', callback=function(){document.getElementById('button-unsub-{{u.id}}').classList.toggle('d-none');document.getElementById('button-sub-{{u.id}}').classList.toggle('d-none');})">Unfollow</a></div>
{% endif %}
{% else %}
<div id="button-sub-{{u.id}}" style="z-index: 2" "><a class="btn btn-primary btn-sm" href="/signup?redirect={{request.path}}">Follow</a></div>

View File

@ -133,8 +133,8 @@
<div class="d-flex justify-content-between align-items-center">
<div>
{% if v and v.id != u.id %}
<a id="button-unsub" class="btn btn-secondary {% if not is_following %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/api/unfollow/{{u.username}}', callback=function(){document.getElementById('button-unsub').classList.toggle('d-none');document.getElementById('button-sub').classList.toggle('d-none');})">Unfollow</a>
<a id="button-sub" class="btn btn-primary {% if is_following or u.is_nofollow or u.is_blocked %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/api/follow/{{u.username}}', callback=function(){document.getElementById('button-sub').classList.toggle('d-none');document.getElementById('button-unsub').classList.toggle('d-none');})">Follow</a>
<a id="button-unsub" class="btn btn-secondary {% if not is_following %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/unfollow/{{u.username}}', callback=function(){document.getElementById('button-unsub').classList.toggle('d-none');document.getElementById('button-sub').classList.toggle('d-none');})">Unfollow</a>
<a id="button-sub" class="btn btn-primary {% if is_following or u.is_nofollow or u.is_blocked %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/follow/{{u.username}}', callback=function(){document.getElementById('button-sub').classList.toggle('d-none');document.getElementById('button-unsub').classList.toggle('d-none');})">Follow</a>
<a class="btn btn-primary" href="javascript:void(0)" onclick="document.getElementById('message').classList.toggle('d-none')">Message</a>
<a class="btn btn-primary" href="javascript:void(0)" onclick="post('/@{{u.username}}/suicide', function(){window.location.reload(true);})">Get them help</a>
@ -183,7 +183,7 @@
</div>
<pre></pre>
{% if u.is_banned %}
<form action="/api/unban_user/{{u.id}}/?notoast=1" method="post" action="">
<form action="/unban_user/{{u.id}}/?notoast=1" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<div class="custom-control custom-checkbox">
<input type="checkbox" id="alts-1-desktop" class="custom-control-input" name="alts" value="1">
@ -192,7 +192,7 @@
<input type="submit" class="btn btn-success" value="Unban user">
</form>
{% else %}
<form action="/api/ban_user/{{u.id}}?notoast=1" method="post" action="">
<form action="/ban_user/{{u.id}}?notoast=1" method="post" action="">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input style="font-size:11px;" type="text" class="form-control" name="reason" placeholder="Ban Reason" onchange="document.getElementById('user-ban-submit').disabled=false">
<input style="font-size:11px;" type="number" class="form-control" name="days" placeholder="Days (blank = permanent)">
@ -325,8 +325,8 @@
<a href="/views" class="btn btn-secondary btn-sm">Profile views</a>
{% endif %}
{% if v and v.id != u.id %}
<a id="button-unsub2" class="btn btn-secondary {% if not is_following %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/api/unfollow/{{u.username}}', callback=function(){document.getElementById('button-unsub2').classList.toggle('d-none');document.getElementById('button-sub2').classList.toggle('d-none');})">Unfollow</a>
<a id="button-sub2" class="btn btn-primary {% if is_following or u.is_nofollow or u.is_blocked %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/api/follow/{{u.username}}', callback=function(){document.getElementById('button-sub2').classList.toggle('d-none');document.getElementById('button-unsub2').classList.toggle('d-none');})">Follow</a>
<a id="button-unsub2" class="btn btn-secondary {% if not is_following %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/unfollow/{{u.username}}', callback=function(){document.getElementById('button-unsub2').classList.toggle('d-none');document.getElementById('button-sub2').classList.toggle('d-none');})">Unfollow</a>
<a id="button-sub2" class="btn btn-primary {% if is_following or u.is_nofollow or u.is_blocked %}d-none{% endif %}" href="javascript:void(0)" onclick="post('/follow/{{u.username}}', callback=function(){document.getElementById('button-sub2').classList.toggle('d-none');document.getElementById('button-unsub2').classList.toggle('d-none');})">Follow</a>
<a class="btn btn-primary" href="javascript:void(0)" onclick="document.getElementById('message-mobile').classList.toggle('d-none')">Message</a>
<a class="btn btn-primary" href="javascript:void(0)" onclick="post('/@{{u.username}}/suicide', function(){window.location.reload(true);})">Get them help</a>
@ -372,7 +372,7 @@
</div>
<pre></pre>
{% if u.is_banned %}
<form action="/api/unban_user/{{u.id}}/?notoast=1" method="post">
<form action="/unban_user/{{u.id}}/?notoast=1" method="post">
<input type="hidden" name="formkey", value="{{v.formkey}}">
<br />
<div class="custom-control custom-checkbox">
@ -383,7 +383,7 @@
<input type="submit" class="btn btn-success" value="Unban user">
</form>
{% else %}
<form action="/api/ban_user/{{u.id}}/?notoast=1" method="post">
<form action="/ban_user/{{u.id}}/?notoast=1" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input style="font-size:11px;" type="text" class="form-control" name="reason" placeholder="Ban Reason" onchange="document.getElementById('user-ban-submit2').disabled=false">
<input style="font-size:11px;" type="number" class="form-control" name="days" placeholder="Days (blank = permanent)">