Rework error system a bit to remove a bunch of duplicated code (#434)
This commit is contained in:
parent
08602b4279
commit
0c632d73b7
28 changed files with 197 additions and 350 deletions
|
@ -161,10 +161,10 @@ def before_request():
|
||||||
app.config['SETTINGS'] = json.load(f)
|
app.config['SETTINGS'] = json.load(f)
|
||||||
|
|
||||||
if request.host != app.config["SERVER_NAME"]:
|
if request.host != app.config["SERVER_NAME"]:
|
||||||
return {"error": "Unauthorized host provided."}, 401
|
return {"error": "Unauthorized host provided."}, 403
|
||||||
|
|
||||||
if not app.config['SETTINGS']['Bots'] and request.headers.get("Authorization"):
|
if not app.config['SETTINGS']['Bots'] and request.headers.get("Authorization"):
|
||||||
abort(503)
|
abort(403, "Bots are currently not allowed")
|
||||||
|
|
||||||
g.db = db_session()
|
g.db = db_session()
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ function post_toast3(t, url, button1, button2) {
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -148,6 +149,7 @@ function delete_commentModal(id) {
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -185,6 +187,7 @@ function post_reply(id){
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
|
@ -227,6 +230,7 @@ function comment_edit(id){
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
|
@ -314,6 +318,7 @@ function post_comment(fullname,id,level = 1){
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
|
@ -396,6 +401,7 @@ function handle_action(type, cid, thing) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
else document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ function delete_postModal(id) {
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,6 +108,7 @@ function post_toast(t, url, reload, data) {
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
@ -30,6 +30,7 @@ function post_toast2(t, url, button1, button2) {
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
document.getElementById('toast-post-error-text').innerText = "Error, please try again later."
|
||||||
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show();
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
@ -169,7 +169,8 @@ function submitFormAjax(e) {
|
||||||
let data=JSON.parse(xhr.response);
|
let data=JSON.parse(xhr.response);
|
||||||
var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error'));
|
var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error'));
|
||||||
myToast.show();
|
myToast.show();
|
||||||
document.getElementById('toast-post-error-text').innerText = data["error"];
|
if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"];
|
||||||
|
if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"];
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success'));
|
var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success'));
|
||||||
myToast.hide();
|
myToast.hide();
|
||||||
|
|
|
@ -42,14 +42,40 @@ PUSHER_KEY = environ.get("PUSHER_KEY", "").strip()
|
||||||
DEFAULT_COLOR = environ.get("DEFAULT_COLOR", "fff").strip()
|
DEFAULT_COLOR = environ.get("DEFAULT_COLOR", "fff").strip()
|
||||||
COLORS = {'ff66ac','805ad5','62ca56','38a169','80ffff','2a96f3','eb4963','ff0000','f39731','30409f','3e98a7','e4432d','7b9ae4','ec72de','7f8fa6', 'f8db58','8cdbe6', DEFAULT_COLOR}
|
COLORS = {'ff66ac','805ad5','62ca56','38a169','80ffff','2a96f3','eb4963','ff0000','f39731','30409f','3e98a7','e4432d','7b9ae4','ec72de','7f8fa6', 'f8db58','8cdbe6', DEFAULT_COLOR}
|
||||||
|
|
||||||
|
ERROR_MESSAGES = {
|
||||||
|
400: "That request was bad and you should feel bad",
|
||||||
|
401: "You need an account for this. Please make one!",
|
||||||
|
403: "You don't have access to this page.",
|
||||||
|
404: "That page doesn't exist. If you got here from a link on the website, please report this issue. Thanks!",
|
||||||
|
405: "Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!",
|
||||||
|
409: "There's a conflict between what you're trying to do and what you or someone else has done and because of that you can't do what you're trying to do.",
|
||||||
|
413: "Max file size is 8 MB",
|
||||||
|
422: "Something is wrong about your request. If you keep getting this unexpectedly, please report it!",
|
||||||
|
429: "Are you hammering the site? Stop that, yo.",
|
||||||
|
500: "Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!",
|
||||||
|
}
|
||||||
|
|
||||||
LOGGEDIN_ACTIVE_TIME = 15 * 60
|
LOGGEDIN_ACTIVE_TIME = 15 * 60
|
||||||
|
|
||||||
|
WERKZEUG_ERROR_DESCRIPTIONS = {
|
||||||
|
400: "The browser (or proxy) sent a request that this server could not understand.",
|
||||||
|
401: "The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.",
|
||||||
|
403: "You don't have the permission to access the requested resource. It is either read-protected or not readable by the server.",
|
||||||
|
404: "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.",
|
||||||
|
405: "The method is not allowed for the requested URL.",
|
||||||
|
409: "A conflict happened while processing the request. The resource might have been modified while the request was being processed.",
|
||||||
|
413: "The data value transmitted exceeds the capacity limit.",
|
||||||
|
415: "The server does not support the media type transmitted in the request.",
|
||||||
|
422: "The request was well-formed but was unable to be followed due to semantic errors.",
|
||||||
|
429: "This user has exceeded an allotted request count. Try again later.",
|
||||||
|
500: "The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.",
|
||||||
|
}
|
||||||
|
|
||||||
IMAGE_FORMATS = ['png','gif','jpg','jpeg','webp']
|
IMAGE_FORMATS = ['png','gif','jpg','jpeg','webp']
|
||||||
VIDEO_FORMATS = ['mp4','webm','mov','avi','mkv','flv','m4v','3gp']
|
VIDEO_FORMATS = ['mp4','webm','mov','avi','mkv','flv','m4v','3gp']
|
||||||
AUDIO_FORMATS = ['mp3','wav','ogg','aac','m4a','flac']
|
AUDIO_FORMATS = ['mp3','wav','ogg','aac','m4a','flac']
|
||||||
NO_TITLE_EXTENSIONS = IMAGE_FORMATS + VIDEO_FORMATS + AUDIO_FORMATS
|
NO_TITLE_EXTENSIONS = IMAGE_FORMATS + VIDEO_FORMATS + AUDIO_FORMATS
|
||||||
|
|
||||||
|
|
||||||
AWARDS = {
|
AWARDS = {
|
||||||
"lootbox": {
|
"lootbox": {
|
||||||
"kind": "lootbox",
|
"kind": "lootbox",
|
||||||
|
|
|
@ -118,7 +118,7 @@ def is_not_permabanned(f):
|
||||||
check_ban_evade(v)
|
check_ban_evade(v)
|
||||||
|
|
||||||
if v.is_suspended_permanently:
|
if v.is_suspended_permanently:
|
||||||
return {"error": "Forbidden: you are permabanned."}, 403
|
abort(403, "You are permanently banned")
|
||||||
|
|
||||||
return make_response(f(*args, v=v, **kwargs))
|
return make_response(f(*args, v=v, **kwargs))
|
||||||
|
|
||||||
|
|
|
@ -279,7 +279,8 @@ def club_allow(v, username):
|
||||||
|
|
||||||
if not u: abort(404)
|
if not u: abort(404)
|
||||||
|
|
||||||
if u.admin_level >= v.admin_level: return {"error": "noob"}
|
if u.admin_level >= v.admin_level:
|
||||||
|
abort(403, "Can't target users with admin level higher than you")
|
||||||
|
|
||||||
u.club_allowed = True
|
u.club_allowed = True
|
||||||
g.db.add(u)
|
g.db.add(u)
|
||||||
|
@ -307,7 +308,8 @@ def club_ban(v, username):
|
||||||
|
|
||||||
if not u: abort(404)
|
if not u: abort(404)
|
||||||
|
|
||||||
if u.admin_level >= v.admin_level: return {"error": "noob"}
|
if u.admin_level >= v.admin_level:
|
||||||
|
abort(403, "Can't target users with admin level higher than you")
|
||||||
|
|
||||||
u.club_allowed = False
|
u.club_allowed = False
|
||||||
|
|
||||||
|
@ -502,7 +504,7 @@ def change_settings(v, setting):
|
||||||
site_settings[setting] = int(new_value)
|
site_settings[setting] = int(new_value)
|
||||||
else:
|
else:
|
||||||
# 422ing for any other types for now, feel free to add some more types if needed
|
# 422ing for any other types for now, feel free to add some more types if needed
|
||||||
abort(422)
|
abort(422, "Not a valid config value type")
|
||||||
else:
|
else:
|
||||||
site_settings[setting] = not site_settings[setting]
|
site_settings[setting] = not site_settings[setting]
|
||||||
if site_settings[setting]: word = 'enabled'
|
if site_settings[setting]: word = 'enabled'
|
||||||
|
@ -555,7 +557,7 @@ def purge_cache(v):
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
if response == "<Response [200]>": return {"message": "Cache purged!"}
|
if response == "<Response [200]>": return {"message": "Cache purged!"}
|
||||||
return {"error": "Failed to purge cache."}
|
abort(500, "Failed to purge cache.")
|
||||||
|
|
||||||
|
|
||||||
@app.post("/admin/under_attack")
|
@app.post("/admin/under_attack")
|
||||||
|
@ -574,7 +576,7 @@ def under_attack(v):
|
||||||
|
|
||||||
response = str(requests.patch(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, data='{"value":"medium"}', timeout=5))
|
response = str(requests.patch(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, data='{"value":"medium"}', timeout=5))
|
||||||
if response == "<Response [200]>": return {"message": "Under attack mode disabled!"}
|
if response == "<Response [200]>": return {"message": "Under attack mode disabled!"}
|
||||||
return {"error": "Failed to disable under attack mode."}
|
abort(500, "Failed to disable under attack mode.")
|
||||||
else:
|
else:
|
||||||
ma = ModAction(
|
ma = ModAction(
|
||||||
kind="enable_under_attack",
|
kind="enable_under_attack",
|
||||||
|
@ -585,7 +587,7 @@ def under_attack(v):
|
||||||
|
|
||||||
response = str(requests.patch(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, data='{"value":"under_attack"}', timeout=5))
|
response = str(requests.patch(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, data='{"value":"under_attack"}', timeout=5))
|
||||||
if response == "<Response [200]>": return {"message": "Under attack mode enabled!"}
|
if response == "<Response [200]>": return {"message": "Under attack mode enabled!"}
|
||||||
return {"error": "Failed to enable under attack mode."}
|
abort(500, "Failed to enable under attack mode.")
|
||||||
|
|
||||||
@app.get("/admin/badge_grant")
|
@app.get("/admin/badge_grant")
|
||||||
@limiter.exempt
|
@limiter.exempt
|
||||||
|
@ -1307,7 +1309,7 @@ def sticky_post(post_id, v):
|
||||||
if v.admin_level > 1:
|
if v.admin_level > 1:
|
||||||
post.stickied = v.username
|
post.stickied = v.username
|
||||||
post.stickied_utc = int(time.time()) + 3600
|
post.stickied_utc = int(time.time()) + 3600
|
||||||
else: return {"error": "Can't exceed 3 pinned posts limit!"}, 403
|
else: abort(403, "Can't exceed 3 pinned posts limit!")
|
||||||
else: post.stickied = v.username
|
else: post.stickied = v.username
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
|
|
||||||
|
@ -1332,7 +1334,7 @@ def unsticky_post(post_id, v):
|
||||||
|
|
||||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
||||||
if post and post.stickied:
|
if post and post.stickied:
|
||||||
if post.stickied.endswith('(pin award)'): return {"error": "Can't unpin award pins!"}, 403
|
if post.stickied.endswith('(pin award)'): abort(403, "Can't unpin award pins!")
|
||||||
|
|
||||||
post.stickied = None
|
post.stickied = None
|
||||||
post.stickied_utc = None
|
post.stickied_utc = None
|
||||||
|
@ -1386,7 +1388,7 @@ def unsticky_comment(cid, v):
|
||||||
comment = get_comment(cid, v=v)
|
comment = get_comment(cid, v=v)
|
||||||
|
|
||||||
if comment.is_pinned:
|
if comment.is_pinned:
|
||||||
if comment.is_pinned.endswith("(pin award)"): return {"error": "Can't unpin award pins!"}, 403
|
if comment.is_pinned.endswith("(pin award)"): abort(403, "Can't unpin award pins!")
|
||||||
|
|
||||||
comment.is_pinned = None
|
comment.is_pinned = None
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
|
@ -36,10 +36,10 @@ def buy(v, award):
|
||||||
abort(404) # disable entirely pending possible future use of coins
|
abort(404) # disable entirely pending possible future use of coins
|
||||||
|
|
||||||
if award == 'benefactor' and not request.values.get("mb"):
|
if award == 'benefactor' and not request.values.get("mb"):
|
||||||
return {"error": "You can only buy the Benefactor award with marseybux."}, 403
|
abort(403, "You can only buy the Benefactor award with marseybux.")
|
||||||
|
|
||||||
if award == 'ghost' and v.admin_level < 2:
|
if award == 'ghost' and v.admin_level < 2:
|
||||||
return {"error": "Only admins can buy that award."}, 403
|
abort(403, "Only admins can buy that award.")
|
||||||
|
|
||||||
AWARDS = deepcopy(AWARDS2)
|
AWARDS = deepcopy(AWARDS2)
|
||||||
|
|
||||||
|
@ -49,11 +49,11 @@ def buy(v, award):
|
||||||
price = int(og_price * v.discount)
|
price = int(og_price * v.discount)
|
||||||
|
|
||||||
if request.values.get("mb"):
|
if request.values.get("mb"):
|
||||||
if v.procoins < price: return {"error": "Not enough marseybux."}, 400
|
if v.procoins < price: abort(400, "Not enough marseybux.")
|
||||||
if award == "grass": return {"error": "You can't buy the grass award with marseybux."}, 403
|
if award == "grass": abort(403, "You can't buy the grass award with marseybux.")
|
||||||
v.procoins -= price
|
v.procoins -= price
|
||||||
else:
|
else:
|
||||||
if v.coins < price: return {"error": "Not enough coins."}, 400
|
if v.coins < price: abort(400, "Not enough coins.")
|
||||||
v.coins -= price
|
v.coins -= price
|
||||||
v.coins_spent += price
|
v.coins_spent += price
|
||||||
if v.coins_spent >= 1000000 and not v.has_badge(73):
|
if v.coins_spent >= 1000000 and not v.has_badge(73):
|
||||||
|
@ -129,7 +129,7 @@ def award_post(pid, v):
|
||||||
kind = request.values.get("kind", "").strip()
|
kind = request.values.get("kind", "").strip()
|
||||||
|
|
||||||
if kind not in AWARDS:
|
if kind not in AWARDS:
|
||||||
return {"error": "That award doesn't exist."}, 404
|
abort(404, "That award doesn't exist.")
|
||||||
|
|
||||||
post_award = g.db.query(AwardRelationship).filter(
|
post_award = g.db.query(AwardRelationship).filter(
|
||||||
AwardRelationship.kind == kind,
|
AwardRelationship.kind == kind,
|
||||||
|
@ -139,12 +139,12 @@ def award_post(pid, v):
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
if not post_award:
|
if not post_award:
|
||||||
return {"error": "You don't have that award."}, 404
|
abort(404, "You don't have that award.")
|
||||||
|
|
||||||
post = g.db.query(Submission).filter_by(id=pid).one_or_none()
|
post = g.db.query(Submission).filter_by(id=pid).one_or_none()
|
||||||
|
|
||||||
if not post:
|
if not post:
|
||||||
return {"error": "That post doesn't exist."}, 404
|
abort(404, "That post doesn't exist.")
|
||||||
|
|
||||||
post_award.submission_id = post.id
|
post_award.submission_id = post.id
|
||||||
g.db.add(post_award)
|
g.db.add(post_award)
|
||||||
|
@ -154,7 +154,7 @@ def award_post(pid, v):
|
||||||
author = post.author
|
author = post.author
|
||||||
|
|
||||||
if kind == "benefactor" and author.id == v.id:
|
if kind == "benefactor" and author.id == v.id:
|
||||||
return {"error": "You can't use this award on yourself."}, 400
|
abort(400, "You can't use this award on yourself.")
|
||||||
|
|
||||||
if v.id != author.id:
|
if v.id != author.id:
|
||||||
msg = f"@{v.username} has given your [post]({post.shortlink}) the {AWARDS[kind]['title']} Award!"
|
msg = f"@{v.username} has given your [post]({post.shortlink}) the {AWARDS[kind]['title']} Award!"
|
||||||
|
@ -231,7 +231,7 @@ def award_comment(cid, v):
|
||||||
kind = request.values.get("kind", "").strip()
|
kind = request.values.get("kind", "").strip()
|
||||||
|
|
||||||
if kind not in AWARDS:
|
if kind not in AWARDS:
|
||||||
return {"error": "That award doesn't exist."}, 404
|
abort(404, "That award doesn't exist.")
|
||||||
|
|
||||||
comment_award = g.db.query(AwardRelationship).filter(
|
comment_award = g.db.query(AwardRelationship).filter(
|
||||||
AwardRelationship.kind == kind,
|
AwardRelationship.kind == kind,
|
||||||
|
@ -241,12 +241,12 @@ def award_comment(cid, v):
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
if not comment_award:
|
if not comment_award:
|
||||||
return {"error": "You don't have that award."}, 404
|
abort(404, "You don't have that award.")
|
||||||
|
|
||||||
c = g.db.query(Comment).filter_by(id=cid).one_or_none()
|
c = g.db.query(Comment).filter_by(id=cid).one_or_none()
|
||||||
|
|
||||||
if not c:
|
if not c:
|
||||||
return {"error": "That comment doesn't exist."}, 404
|
abort(404, "That comment doesn't exist.")
|
||||||
|
|
||||||
comment_award.comment_id = c.id
|
comment_award.comment_id = c.id
|
||||||
g.db.add(comment_award)
|
g.db.add(comment_award)
|
||||||
|
@ -261,7 +261,7 @@ def award_comment(cid, v):
|
||||||
send_repeatable_notification(author.id, msg)
|
send_repeatable_notification(author.id, msg)
|
||||||
|
|
||||||
if kind == "benefactor" and author.id == v.id:
|
if kind == "benefactor" and author.id == v.id:
|
||||||
return {"error": "You can't use this award on yourself."}, 400
|
abort(400, "You can't use this award on yourself.")
|
||||||
|
|
||||||
if kind == "ban":
|
if kind == "ban":
|
||||||
link = f"[this comment]({c.shortlink})"
|
link = f"[this comment]({c.shortlink})"
|
||||||
|
@ -372,7 +372,7 @@ def admin_userawards_post(v):
|
||||||
for key, value in notify_awards.items():
|
for key, value in notify_awards.items():
|
||||||
note += f"{value} {AWARDS[key]['title']}, "
|
note += f"{value} {AWARDS[key]['title']}, "
|
||||||
|
|
||||||
if len(note) > 256: return {"error": "You're giving too many awards at the same time!"}
|
if len(note) > 256: abort(400, "You're giving too many awards at the same time!")
|
||||||
|
|
||||||
ma=ModAction(
|
ma=ModAction(
|
||||||
kind="grant_awards",
|
kind="grant_awards",
|
||||||
|
|
|
@ -144,7 +144,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
|
||||||
@limiter.limit("1/second;20/minute;200/hour;1000/day")
|
@limiter.limit("1/second;20/minute;200/hour;1000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def api_comment(v):
|
def api_comment(v):
|
||||||
if v.is_suspended: return {"error": "You can't perform this action while banned."}, 403
|
if v.is_suspended: abort(403, "You can't perform this action while banned.")
|
||||||
|
|
||||||
parent_fullname = request.values.get("parent_fullname").strip()
|
parent_fullname = request.values.get("parent_fullname").strip()
|
||||||
|
|
||||||
|
@ -166,11 +166,11 @@ def api_comment(v):
|
||||||
if not parent_post: abort(404) # don't allow sending comments to the ether
|
if not parent_post: abort(404) # don't allow sending comments to the ether
|
||||||
level = 1 if isinstance(parent, Submission) else parent.level + 1
|
level = 1 if isinstance(parent, Submission) else parent.level + 1
|
||||||
sub = parent_post.sub
|
sub = parent_post.sub
|
||||||
if sub and v.exiled_from(sub): return {"error": f"You're exiled from /h/{sub}"}, 403
|
if sub and v.exiled_from(sub): abort(403, f"You're exiled from /h/{sub}")
|
||||||
|
|
||||||
body = request.values.get("body", "").strip()[:10000]
|
body = request.values.get("body", "").strip()[:10000]
|
||||||
|
|
||||||
if not body and not request.files.get('file'): return {"error":"You need to actually write something!"}, 400
|
if not body and not request.files.get('file'): abort(400, "You need to actually write something!")
|
||||||
|
|
||||||
if request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
|
if request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
|
||||||
files = request.files.getlist('file')[:4]
|
files = request.files.getlist('file')[:4]
|
||||||
|
@ -180,7 +180,7 @@ def api_comment(v):
|
||||||
file.save(oldname)
|
file.save(oldname)
|
||||||
image = process_image(oldname)
|
image = process_image(oldname)
|
||||||
if image == "":
|
if image == "":
|
||||||
return {"error":"Image upload failed"}
|
abort(500, "Image upload failed")
|
||||||
|
|
||||||
if app.config['MULTIMEDIA_EMBEDDING_ENABLED']:
|
if app.config['MULTIMEDIA_EMBEDDING_ENABLED']:
|
||||||
body += f"\n\n"
|
body += f"\n\n"
|
||||||
|
@ -190,18 +190,18 @@ def api_comment(v):
|
||||||
file.save("video.mp4")
|
file.save("video.mp4")
|
||||||
with open("video.mp4", 'rb') as f:
|
with open("video.mp4", 'rb') as f:
|
||||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
except requests.Timeout: abort(500, "Video upload timed out, please try again!")
|
||||||
try: url = req['link']
|
try: url = req['link']
|
||||||
except:
|
except:
|
||||||
error = req['error']
|
error = req['error']
|
||||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||||
return {"error": error}, 400
|
abort(400, error)
|
||||||
if url.endswith('.'): url += 'mp4'
|
if url.endswith('.'): url += 'mp4'
|
||||||
if app.config['MULTIMEDIA_EMBEDDING_ENABLED']:
|
if app.config['MULTIMEDIA_EMBEDDING_ENABLED']:
|
||||||
body += f"\n\n{url}"
|
body += f"\n\n{url}"
|
||||||
else:
|
else:
|
||||||
body += f'\n\n<a href="{url}">{url}</a>'
|
body += f'\n\n<a href="{url}">{url}</a>'
|
||||||
else: return {"error": "Image/Video files only"}, 400
|
else: abort(400, "Image/Video files only")
|
||||||
|
|
||||||
body_html = sanitize(body, comment=True)
|
body_html = sanitize(body, comment=True)
|
||||||
|
|
||||||
|
@ -214,10 +214,10 @@ def api_comment(v):
|
||||||
).one_or_none()
|
).one_or_none()
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
return {"error": f"You already made that comment: /comment/{existing.id}"}, 409
|
abort(409, f"You already made that comment: /comment/{existing.id}")
|
||||||
|
|
||||||
if parent.author.any_block_exists(v) and v.admin_level < 2:
|
if parent.author.any_block_exists(v) and v.admin_level < 2:
|
||||||
return {"error": "You can't reply to users who have blocked you, or users you have blocked."}, 403
|
abort(403, "You can't reply to users who have blocked you, or users you have blocked.")
|
||||||
|
|
||||||
is_bot = bool(request.headers.get("Authorization"))
|
is_bot = bool(request.headers.get("Authorization"))
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ def api_comment(v):
|
||||||
)
|
)
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
return {"error": "Too much spam!"}, 403
|
abort(403, "Too much spam!")
|
||||||
|
|
||||||
if len(body_html) > 20000: abort(400)
|
if len(body_html) > 20000: abort(400)
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ def edit_comment(cid, v):
|
||||||
body = request.values.get("body", "").strip()[:10000]
|
body = request.values.get("body", "").strip()[:10000]
|
||||||
|
|
||||||
if len(body) < 1 and not (request.files.get("file") and request.headers.get("cf-ipcountry") != "T1"):
|
if len(body) < 1 and not (request.files.get("file") and request.headers.get("cf-ipcountry") != "T1"):
|
||||||
return {"error":"You have to actually type something!"}, 400
|
abort(400, "You have to actually type something!")
|
||||||
|
|
||||||
if body != c.body or request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
|
if body != c.body or request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
|
||||||
body_html = sanitize(body, edit=True)
|
body_html = sanitize(body, edit=True)
|
||||||
|
@ -406,7 +406,7 @@ def edit_comment(cid, v):
|
||||||
comment.ban_reason = "AutoJanny"
|
comment.ban_reason = "AutoJanny"
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
||||||
return {"error": "Too much spam!"}, 403
|
abort(403, "Too much spam!")
|
||||||
# End Spam Checking
|
# End Spam Checking
|
||||||
|
|
||||||
if request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
|
if request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
|
||||||
|
@ -421,15 +421,15 @@ def edit_comment(cid, v):
|
||||||
file.save("video.mp4")
|
file.save("video.mp4")
|
||||||
with open("video.mp4", 'rb') as f:
|
with open("video.mp4", 'rb') as f:
|
||||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
except requests.Timeout: abort(500, "Video upload timed out, please try again!")
|
||||||
try: url = req['link']
|
try: url = req['link']
|
||||||
except:
|
except:
|
||||||
error = req['error']
|
error = req['error']
|
||||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||||
return {"error": error}, 400
|
abort(400, error)
|
||||||
if url.endswith('.'): url += 'mp4'
|
if url.endswith('.'): url += 'mp4'
|
||||||
body += f"\n\n{url}"
|
body += f"\n\n{url}"
|
||||||
else: return {"error": "Image/Video files only"}, 400
|
else: abort(400, "Image/Video files only")
|
||||||
|
|
||||||
body_html = sanitize(body, edit=True)
|
body_html = sanitize(body, edit=True)
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ def unpin_comment(cid, v):
|
||||||
if v.id != comment.post.author_id: abort(403)
|
if v.id != comment.post.author_id: abort(403)
|
||||||
|
|
||||||
if not comment.is_pinned.endswith(" (OP)"):
|
if not comment.is_pinned.endswith(" (OP)"):
|
||||||
return {"error": "You can only unpin comments you have pinned!"}
|
abort(403, "You can only unpin comments you have pinned!")
|
||||||
|
|
||||||
comment.is_pinned = None
|
comment.is_pinned = None
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
|
@ -1,70 +1,41 @@
|
||||||
from files.helpers.wrappers import *
|
from files.helpers.wrappers import *
|
||||||
from flask import *
|
from flask import request, session
|
||||||
from urllib.parse import quote, urlencode
|
from urllib.parse import quote, urlencode
|
||||||
import time
|
import time
|
||||||
from files.__main__ import app, limiter
|
from files.__main__ import app
|
||||||
|
from http.client import responses
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(400)
|
@app.errorhandler(400)
|
||||||
def error_400(e):
|
@app.errorhandler(401)
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "400 Bad Request"}, 400
|
@app.errorhandler(403)
|
||||||
else: return render_template('errors/400.html', err=True), 400
|
@app.errorhandler(404)
|
||||||
|
@app.errorhandler(405)
|
||||||
|
@app.errorhandler(413)
|
||||||
|
@app.errorhandler(422)
|
||||||
|
@app.errorhandler(429)
|
||||||
|
def error(e):
|
||||||
|
title = responses.get(e.code, "Internal Server Error")
|
||||||
|
description = ERROR_MESSAGES.get(e.code, e.code)
|
||||||
|
details = None if e.description == WERKZEUG_ERROR_DESCRIPTIONS.get(e.code, e.code) else e.description
|
||||||
|
|
||||||
|
if request.headers.get("Authorization") or request.headers.get("xhr"):
|
||||||
|
return {"code": e.code, "description": description, "details": details, "error": title}, e.code
|
||||||
|
|
||||||
|
return render_template('errors/error.html', err=True, code=e.code, error=title, description=description, details=details), e.code
|
||||||
|
|
||||||
@app.errorhandler(401)
|
@app.errorhandler(401)
|
||||||
def error_401(e):
|
def error_401(e):
|
||||||
|
if request.headers.get("Authorization") or request.headers.get("xhr"): return error(e)
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "401 Not Authorized"}, 401
|
|
||||||
else:
|
|
||||||
path = request.path
|
path = request.path
|
||||||
qs = urlencode(dict(request.values))
|
qs = urlencode(dict(request.values))
|
||||||
argval = quote(f"{path}?{qs}", safe='')
|
argval = quote(f"{path}?{qs}", safe='')
|
||||||
return redirect(f"/login?redirect={argval}")
|
return redirect(f"/login?redirect={argval}")
|
||||||
|
|
||||||
@app.errorhandler(403)
|
|
||||||
def error_403(e):
|
|
||||||
|
|
||||||
description = e.description
|
|
||||||
if description == "You don't have the permission to access the requested resource. It is either read-protected or not readable by the server.": description = ''
|
|
||||||
|
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"):
|
|
||||||
if not description: description = "403 Forbidden"
|
|
||||||
return {"error": description}, 403
|
|
||||||
else:
|
|
||||||
if not description: description = "You don't have access to this page."
|
|
||||||
return render_template('errors/403.html', description=description, err=True), 403
|
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(404)
|
|
||||||
def error_404(e):
|
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "404 Not Found"}, 404
|
|
||||||
else: return render_template('errors/404.html', err=True), 404
|
|
||||||
|
|
||||||
@app.errorhandler(405)
|
|
||||||
def error_405(e):
|
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "405 Method Not Allowed"}, 405
|
|
||||||
else: return render_template('errors/405.html', err=True), 405
|
|
||||||
|
|
||||||
@app.errorhandler(413)
|
|
||||||
def error_413(e):
|
|
||||||
return {"error": "Max file size is 8 MB (16 MB for paypigs)"}, 413
|
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"):
|
|
||||||
return {"error": "Max file size is 8 MB (16 MB for paypigs)"}, 413
|
|
||||||
else: return render_template('errors/413.html', err=True), 413
|
|
||||||
|
|
||||||
@app.errorhandler(429)
|
|
||||||
def error_429(e):
|
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "429 Too Many Requests"}, 429
|
|
||||||
else: return render_template('errors/429.html', err=True), 429
|
|
||||||
|
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
def error_500(e):
|
def error_500(e):
|
||||||
g.db.rollback()
|
g.db.rollback()
|
||||||
|
return error(e)
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "500 Internal Server Error"}, 500
|
|
||||||
else: return render_template('errors/500.html', err=True), 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/allow_nsfw")
|
@app.post("/allow_nsfw")
|
||||||
def allow_nsfw():
|
def allow_nsfw():
|
||||||
|
|
|
@ -179,7 +179,7 @@ def logout(v):
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def sign_up_get(v):
|
def sign_up_get(v):
|
||||||
if not app.config['SETTINGS']['Signups']:
|
if not app.config['SETTINGS']['Signups']:
|
||||||
return {"error": "New account registration is currently closed. Please come back later."}, 403
|
abort(403, "New account registration is currently closed. Please come back later.")
|
||||||
|
|
||||||
if v: return redirect(SITE_FULL)
|
if v: return redirect(SITE_FULL)
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ def sign_up_get(v):
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def sign_up_post(v):
|
def sign_up_post(v):
|
||||||
if not app.config['SETTINGS']['Signups']:
|
if not app.config['SETTINGS']['Signups']:
|
||||||
return {"error": "New account registration is currently closed. Please come back later."}, 403
|
abort(403, "New account registration is currently closed. Please come back later.")
|
||||||
|
|
||||||
if v: abort(403)
|
if v: abort(403)
|
||||||
|
|
||||||
|
@ -254,7 +254,6 @@ def sign_up_post(v):
|
||||||
username = username.strip()
|
username = username.strip()
|
||||||
|
|
||||||
def signup_error(error):
|
def signup_error(error):
|
||||||
|
|
||||||
args = {"error": error}
|
args = {"error": error}
|
||||||
if request.values.get("referred_by"):
|
if request.values.get("referred_by"):
|
||||||
user = g.db.query(User).filter_by(id=request.values.get("referred_by")).one_or_none()
|
user = g.db.query(User).filter_by(id=request.values.get("referred_by")).one_or_none()
|
||||||
|
|
|
@ -38,20 +38,19 @@ MAX_TITLE_LENGTH = 500
|
||||||
MAX_URL_LENGTH = 2048
|
MAX_URL_LENGTH = 2048
|
||||||
MAX_BODY_LENGTH = 20000
|
MAX_BODY_LENGTH = 20000
|
||||||
|
|
||||||
# Get request value `val` and ensure it is within length constraints
|
|
||||||
# : Returns an either tuple (good_value, error)
|
def guarded_value(val, min_len, max_len) -> str:
|
||||||
# : TODO it may make sense to do more sanitisation here
|
'''
|
||||||
def guarded_value(val, min_len, max_len):
|
Get request value `val` and ensure it is within length constraints
|
||||||
|
Requires a request context and either aborts early or returns a good value
|
||||||
|
'''
|
||||||
raw = request.values.get(val, '').strip()
|
raw = request.values.get(val, '').strip()
|
||||||
raw = raw.replace('\u200e', '')
|
raw = raw.replace('\u200e', '')
|
||||||
|
|
||||||
if len(raw) < min_len:
|
if len(raw) < min_len: abort(400, f"Minimum length for {val} is {min_len}")
|
||||||
return (None, ({"error": f"Minimum length for {val} is {min_len}"}, 403))
|
if len(raw) > max_len: abort(400, f"Maximum length for {val} is {max_len}")
|
||||||
|
# TODO: it may make sense to do more sanitisation here
|
||||||
if len(raw) > max_len:
|
return raw
|
||||||
return (None, ({"error": f"Maximum length for {val} is {max_len}"}, 403))
|
|
||||||
|
|
||||||
return (raw, None)
|
|
||||||
|
|
||||||
@app.post("/toggle_club/<pid>")
|
@app.post("/toggle_club/<pid>")
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ -130,7 +129,7 @@ def post_id(pid, anything=None, v=None, sub=None):
|
||||||
post = get_post(pid, v=v)
|
post = get_post(pid, v=v)
|
||||||
|
|
||||||
if post.over_18 and not (v and v.over_18) and session.get('over_18', 0) < int(time.time()):
|
if post.over_18 and not (v and v.over_18) and session.get('over_18', 0) < int(time.time()):
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error":"Must be 18+ to view"}, 451
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, "Must be 18+ to view")
|
||||||
return render_template("errors/nsfw.html", v=v)
|
return render_template("errors/nsfw.html", v=v)
|
||||||
|
|
||||||
if v: defaultsortingcomments = v.defaultsortingcomments
|
if v: defaultsortingcomments = v.defaultsortingcomments
|
||||||
|
@ -441,11 +440,8 @@ def edit_post(pid, v):
|
||||||
|
|
||||||
if p.author_id != v.id and not (v.admin_level > 1 and v.admin_level > 2): abort(403)
|
if p.author_id != v.id and not (v.admin_level > 1 and v.admin_level > 2): abort(403)
|
||||||
|
|
||||||
title, err = guarded_value("title", 1, MAX_TITLE_LENGTH)
|
title = guarded_value("title", 1, MAX_TITLE_LENGTH)
|
||||||
if err: return err
|
body = guarded_value("body", 0, MAX_BODY_LENGTH)
|
||||||
|
|
||||||
body, err = guarded_value("body", 0, MAX_BODY_LENGTH)
|
|
||||||
if err: return err
|
|
||||||
|
|
||||||
if title != p.title:
|
if title != p.title:
|
||||||
p.title = title
|
p.title = title
|
||||||
|
@ -467,24 +463,24 @@ def edit_post(pid, v):
|
||||||
file.save("video.mp4")
|
file.save("video.mp4")
|
||||||
with open("video.mp4", 'rb') as f:
|
with open("video.mp4", 'rb') as f:
|
||||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
except requests.Timeout: abort(500, "Video upload timed out, please try again!")
|
||||||
try: url = req['link']
|
try: url = req['link']
|
||||||
except:
|
except:
|
||||||
error = req['error']
|
error = req['error']
|
||||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||||
return {"error": error}, 400
|
abort(400, error)
|
||||||
if url.endswith('.'): url += 'mp4'
|
if url.endswith('.'): url += 'mp4'
|
||||||
if app.config['MULTIMEDIA_EMBEDDING_ENABLED']:
|
if app.config['MULTIMEDIA_EMBEDDING_ENABLED']:
|
||||||
body += f"\n\n"
|
body += f"\n\n"
|
||||||
else:
|
else:
|
||||||
body += f'\n\n<a href="{url}">{url}</a>'
|
body += f'\n\n<a href="{url}">{url}</a>'
|
||||||
else: return {"error": "Image/Video files only"}, 400
|
else: abort(400, "Image/Video files only")
|
||||||
|
|
||||||
body_html = sanitize(body, edit=True)
|
body_html = sanitize(body, edit=True)
|
||||||
|
|
||||||
p.body = body
|
p.body = body
|
||||||
|
|
||||||
if len(body_html) > 40000: return {"error":"Submission body_html too long! (max 40k characters)"}, 400
|
if len(body_html) > 40000: abort(400, "Submission body_html too long! (max 40k characters)")
|
||||||
|
|
||||||
p.body_html = body_html
|
p.body_html = body_html
|
||||||
|
|
||||||
|
@ -711,19 +707,14 @@ def api_is_repost():
|
||||||
def submit_post(v, sub=None):
|
def submit_post(v, sub=None):
|
||||||
|
|
||||||
def error(error):
|
def error(error):
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": error}, 403
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(400, error)
|
||||||
|
|
||||||
SUBS = [x[0] for x in g.db.query(Sub.name).order_by(Sub.name).all()]
|
SUBS = [x[0] for x in g.db.query(Sub.name).order_by(Sub.name).all()]
|
||||||
return render_template("submit.html", SUBS=SUBS, v=v, error=error, title=title, url=url, body=body), 400
|
return render_template("submit.html", SUBS=SUBS, v=v, error=error, title=title, url=url, body=body), 400
|
||||||
|
|
||||||
title, err = guarded_value("title", 1, MAX_TITLE_LENGTH)
|
title = guarded_value("title", 1, MAX_TITLE_LENGTH)
|
||||||
if err: return error(err[0]["error"])
|
url = guarded_value("url", 0, MAX_URL_LENGTH)
|
||||||
|
body = guarded_value("body", 0, MAX_BODY_LENGTH)
|
||||||
url, err = guarded_value("url", 0, MAX_URL_LENGTH)
|
|
||||||
if err: return error(err[0]["error"])
|
|
||||||
|
|
||||||
body, err = guarded_value("body", 0, MAX_BODY_LENGTH)
|
|
||||||
if err: return error(err[0]["error"])
|
|
||||||
|
|
||||||
sub = request.values.get("sub")
|
sub = request.values.get("sub")
|
||||||
if sub: sub = sub.replace('/h/','').replace('s/','')
|
if sub: sub = sub.replace('/h/','').replace('s/','')
|
||||||
|
@ -1125,10 +1116,8 @@ def unsave_post(pid, v):
|
||||||
@app.post("/pin/<post_id>")
|
@app.post("/pin/<post_id>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def api_pin_post(post_id, v):
|
def api_pin_post(post_id, v):
|
||||||
|
post = get_post(post_id)
|
||||||
post = g.db.query(Submission).filter_by(id=post_id).one_or_none()
|
if v.id != post.author_id: abort(403, "Only the post author's can do that!")
|
||||||
if post:
|
|
||||||
if v.id != post.author_id: return {"error": "Only the post author's can do that!"}
|
|
||||||
post.is_pinned = not post.is_pinned
|
post.is_pinned = not post.is_pinned
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
|
|
||||||
|
@ -1137,7 +1126,6 @@ def api_pin_post(post_id, v):
|
||||||
g.db.commit()
|
g.db.commit()
|
||||||
if post.is_pinned: return {"message": "Post pinned!"}
|
if post.is_pinned: return {"message": "Post pinned!"}
|
||||||
else: return {"message": "Post unpinned!"}
|
else: return {"message": "Post unpinned!"}
|
||||||
return {"error": "Post not found!"}
|
|
||||||
|
|
||||||
@app.get("/submit/title")
|
@app.get("/submit/title")
|
||||||
@limiter.limit("6/minute")
|
@limiter.limit("6/minute")
|
||||||
|
@ -1148,7 +1136,6 @@ def get_post_title(v):
|
||||||
if not url or '\\' in url: abort(400)
|
if not url or '\\' in url: abort(400)
|
||||||
url = url.strip()
|
url = url.strip()
|
||||||
if not url.startswith('http'): abort(400)
|
if not url.startswith('http'): abort(400)
|
||||||
|
|
||||||
checking_url = url.lower().split('?')[0].split('%3F')[0]
|
checking_url = url.lower().split('?')[0].split('%3F')[0]
|
||||||
if any((checking_url.endswith(f'.{x}') for x in NO_TITLE_EXTENSIONS)):
|
if any((checking_url.endswith(f'.{x}') for x in NO_TITLE_EXTENSIONS)):
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
|
@ -69,10 +69,9 @@ def searchposts(v):
|
||||||
if 'author' in criteria:
|
if 'author' in criteria:
|
||||||
posts = posts.filter(Submission.ghost == False)
|
posts = posts.filter(Submission.ghost == False)
|
||||||
author = get_user(criteria['author'])
|
author = get_user(criteria['author'])
|
||||||
if not author: return {"error": "User not found"}
|
|
||||||
if author.is_private and (not v or (author.id != v.id and v.admin_level < 2)):
|
if author.is_private and (not v or (author.id != v.id and v.admin_level < 2)):
|
||||||
if request.headers.get("Authorization"):
|
if request.headers.get("Authorization"):
|
||||||
return {"error": f"@{author.username}'s profile is private; You can't use the 'author' syntax on them"}
|
abort(403, f"@{author.username}'s profile is private; You can't use the 'author' syntax on them")
|
||||||
return render_template("search.html",
|
return render_template("search.html",
|
||||||
v=v,
|
v=v,
|
||||||
query=query,
|
query=query,
|
||||||
|
@ -195,10 +194,9 @@ def searchcomments(v):
|
||||||
if 'author' in criteria:
|
if 'author' in criteria:
|
||||||
comments = comments.filter(Comment.ghost == False)
|
comments = comments.filter(Comment.ghost == False)
|
||||||
author = get_user(criteria['author'])
|
author = get_user(criteria['author'])
|
||||||
if not author: return {"error": "User not found"}
|
|
||||||
if author.is_private and (not v or (author.id != v.id and v.admin_level < 2)):
|
if author.is_private and (not v or (author.id != v.id and v.admin_level < 2)):
|
||||||
if request.headers.get("Authorization"):
|
if request.headers.get("Authorization"):
|
||||||
return {"error": f"@{author.username}'s profile is private; You can't use the 'author' syntax on them"}
|
abort(403, f"@{author.username}'s profile is private; You can't use the 'author' syntax on them")
|
||||||
|
|
||||||
return render_template("search_comments.html", v=v, query=query, total=0, page=page, comments=[], sort=sort, t=t, next_exists=False, error=f"@{author.username}'s profile is private; You can't use the 'author' syntax on them.")
|
return render_template("search_comments.html", v=v, query=query, total=0, page=page, comments=[], sort=sort, t=t, next_exists=False, error=f"@{author.username}'s profile is private; You can't use the 'author' syntax on them.")
|
||||||
|
|
||||||
|
|
|
@ -177,16 +177,16 @@ def settings_profile_post(v):
|
||||||
file.save("video.mp4")
|
file.save("video.mp4")
|
||||||
with open("video.mp4", 'rb') as f:
|
with open("video.mp4", 'rb') as f:
|
||||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
except requests.Timeout: abort(500, "Video upload timed out, please try again!")
|
||||||
try: url = req['link']
|
try: url = req['link']
|
||||||
except:
|
except:
|
||||||
error = req['error']
|
error = req['error']
|
||||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||||
return {"error": error}, 400
|
abort(400, error)
|
||||||
if url.endswith('.'): url += 'mp4'
|
if url.endswith('.'): url += 'mp4'
|
||||||
bio += f"\n\n{url}"
|
bio += f"\n\n{url}"
|
||||||
else:
|
else:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "Image/Video files only"}, 400
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(400, "Image/Video files only")
|
||||||
return render_template("settings_profile.html", v=v, error="Image/Video files only."), 400
|
return render_template("settings_profile.html", v=v, error="Image/Video files only."), 400
|
||||||
|
|
||||||
bio_html = sanitize(bio)
|
bio_html = sanitize(bio)
|
||||||
|
@ -240,7 +240,7 @@ def settings_profile_post(v):
|
||||||
if theme:
|
if theme:
|
||||||
if theme in THEMES:
|
if theme in THEMES:
|
||||||
if theme == "transparent" and not v.background:
|
if theme == "transparent" and not v.background:
|
||||||
return {"error": "You need to set a background to use the transparent theme!"}
|
abort(400, "You need to set a background to use the transparent theme!")
|
||||||
v.theme = theme
|
v.theme = theme
|
||||||
if theme == "win98": v.themecolor = "30409f"
|
if theme == "win98": v.themecolor = "30409f"
|
||||||
updated = True
|
updated = True
|
||||||
|
@ -266,7 +266,7 @@ def settings_profile_post(v):
|
||||||
return {"message": "Your settings have been updated."}
|
return {"message": "Your settings have been updated."}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return {"error": "You didn't change anything."}, 400
|
abort(400, "You didn't change anything.")
|
||||||
|
|
||||||
|
|
||||||
@app.post("/settings/filters")
|
@app.post("/settings/filters")
|
||||||
|
@ -453,7 +453,7 @@ def settings_log_out_others(v):
|
||||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_images_profile(v):
|
def settings_images_profile(v):
|
||||||
if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403
|
if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
file = request.files["profile"]
|
file = request.files["profile"]
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ def settings_images_profile(v):
|
||||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_images_banner(v):
|
def settings_images_banner(v):
|
||||||
if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403
|
if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
file = request.files["banner"]
|
file = request.files["banner"]
|
||||||
|
|
||||||
|
@ -552,16 +552,16 @@ def settings_block_user(v):
|
||||||
|
|
||||||
user = get_user(request.values.get("username"), graceful=True)
|
user = get_user(request.values.get("username"), graceful=True)
|
||||||
|
|
||||||
if not user: return {"error": "That user doesn't exist."}, 404
|
if not user: abort(404, "That user doesn't exist.")
|
||||||
|
|
||||||
if user.id == v.id:
|
if user.id == v.id:
|
||||||
return {"error": "You can't block yourself."}, 409
|
abort(409, "You can't block yourself.")
|
||||||
|
|
||||||
if v.is_blocking(user):
|
if v.is_blocking(user):
|
||||||
return {"error": f"You have already blocked @{user.username}."}, 409
|
abort(409, f"You have already blocked @{user.username}.")
|
||||||
|
|
||||||
if user.id == NOTIFICATIONS_ID:
|
if user.id == NOTIFICATIONS_ID:
|
||||||
return {"error": "You can't block this user."}, 409
|
abort(409, "You can't block this user.")
|
||||||
|
|
||||||
new_block = UserBlock(user_id=v.id,
|
new_block = UserBlock(user_id=v.id,
|
||||||
target_id=user.id,
|
target_id=user.id,
|
||||||
|
|
|
@ -310,15 +310,15 @@ def submit_contact(v):
|
||||||
file.save("video.mp4")
|
file.save("video.mp4")
|
||||||
with open("video.mp4", 'rb') as f:
|
with open("video.mp4", 'rb') as f:
|
||||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
except requests.Timeout: abort(500, "Video upload timed out, please try again!")
|
||||||
try: url = req['link']
|
try: url = req['link']
|
||||||
except:
|
except:
|
||||||
error = req['error']
|
error = req['error']
|
||||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||||
return {"error": error}, 400
|
abort(400, error)
|
||||||
if url.endswith('.'): url += 'mp4'
|
if url.endswith('.'): url += 'mp4'
|
||||||
html += f"<p>{url}</p>"
|
html += f"<p>{url}</p>"
|
||||||
else: return {"error": "Image/Video files only"}, 400
|
else: abort(400, "Image/Video files only")
|
||||||
|
|
||||||
new_comment = Comment(author_id=v.id if v else NOTIFICATIONS_ID,
|
new_comment = Comment(author_id=v.id if v else NOTIFICATIONS_ID,
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
|
|
|
@ -74,12 +74,6 @@ def unexile(v, sub, uid):
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"message": "User unexiled successfully!"}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"message": "User unexiled successfully!"}
|
||||||
return redirect(f'/h/{sub}/exilees')
|
return redirect(f'/h/{sub}/exilees')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/h/<sub>/block")
|
@app.post("/h/<sub>/block")
|
||||||
@auth_required
|
@auth_required
|
||||||
def block_sub(v, sub):
|
def block_sub(v, sub):
|
||||||
|
@ -87,7 +81,7 @@ def block_sub(v, sub):
|
||||||
if not sub: abort(404)
|
if not sub: abort(404)
|
||||||
sub = sub.name
|
sub = sub.name
|
||||||
|
|
||||||
if v.mods(sub): return {"error": "You can't block subs you mod!"}
|
if v.mods(sub): abort(409, "You can't block subs you mod!")
|
||||||
|
|
||||||
existing = g.db.query(SubBlock).filter_by(user_id=v.id, sub=sub).one_or_none()
|
existing = g.db.query(SubBlock).filter_by(user_id=v.id, sub=sub).one_or_none()
|
||||||
|
|
||||||
|
@ -337,7 +331,7 @@ def get_sub_css(sub):
|
||||||
@limiter.limit("1/second;10/day")
|
@limiter.limit("1/second;10/day")
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
def sub_banner(v, sub):
|
def sub_banner(v, sub):
|
||||||
if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403
|
if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
sub = g.db.query(Sub).filter_by(name=sub.lower().strip()).one_or_none()
|
sub = g.db.query(Sub).filter_by(name=sub.lower().strip()).one_or_none()
|
||||||
if not sub: abort(404)
|
if not sub: abort(404)
|
||||||
|
@ -364,7 +358,7 @@ def sub_banner(v, sub):
|
||||||
@limiter.limit("1/second;10/day")
|
@limiter.limit("1/second;10/day")
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
def sub_sidebar(v, sub):
|
def sub_sidebar(v, sub):
|
||||||
if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403
|
if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
sub = g.db.query(Sub).filter_by(name=sub.lower().strip()).one_or_none()
|
sub = g.db.query(Sub).filter_by(name=sub.lower().strip()).one_or_none()
|
||||||
if not sub: abort(404)
|
if not sub: abort(404)
|
||||||
|
|
|
@ -347,15 +347,15 @@ def transfer_coins(v, username):
|
||||||
|
|
||||||
receiver = g.db.query(User).filter_by(username=username).one_or_none()
|
receiver = g.db.query(User).filter_by(username=username).one_or_none()
|
||||||
|
|
||||||
if receiver is None: return {"error": "That user doesn't exist."}, 404
|
if receiver is None: abort(404, "That user doesn't exist.")
|
||||||
|
|
||||||
if receiver.id != v.id:
|
if receiver.id != v.id:
|
||||||
amount = request.values.get("amount", "").strip()
|
amount = request.values.get("amount", "").strip()
|
||||||
amount = int(amount) if amount.isdigit() else None
|
amount = int(amount) if amount.isdigit() else None
|
||||||
|
|
||||||
if amount is None or amount <= 0: return {"error": "Invalid amount of coins."}, 400
|
if amount is None or amount <= 0: abort(400, "Invalid amount of coins.")
|
||||||
if v.coins < amount: return {"error": "You don't have enough coins."}, 400
|
if v.coins < amount: abort(400, "You don't have enough coins.")
|
||||||
if amount < 100: return {"error": "You have to gift at least 100 coins."}, 400
|
if amount < 100: abort(400, "You have to gift at least 100 coins.")
|
||||||
|
|
||||||
if not v.patron and not receiver.patron and not v.alts_patron and not receiver.alts_patron: tax = math.ceil(amount*0.03)
|
if not v.patron and not receiver.patron and not v.alts_patron and not receiver.alts_patron: tax = math.ceil(amount*0.03)
|
||||||
else: tax = 0
|
else: tax = 0
|
||||||
|
@ -383,15 +383,15 @@ def transfer_bux(v, username):
|
||||||
|
|
||||||
receiver = g.db.query(User).filter_by(username=username).one_or_none()
|
receiver = g.db.query(User).filter_by(username=username).one_or_none()
|
||||||
|
|
||||||
if not receiver: return {"error": "That user doesn't exist."}, 404
|
if not receiver: abort(404, "That user doesn't exist.")
|
||||||
|
|
||||||
if receiver.id != v.id:
|
if receiver.id != v.id:
|
||||||
amount = request.values.get("amount", "").strip()
|
amount = request.values.get("amount", "").strip()
|
||||||
amount = int(amount) if amount.isdigit() else None
|
amount = int(amount) if amount.isdigit() else None
|
||||||
|
|
||||||
if not amount or amount < 0: return {"error": "Invalid amount of marseybux."}, 400
|
if not amount or amount < 0: abort(400, "Invalid amount of marseybux.")
|
||||||
if v.procoins < amount: return {"error": "You don't have enough marseybux"}, 400
|
if v.procoins < amount: abort(400, "You don't have enough marseybux")
|
||||||
if amount < 100: return {"error": "You have to gift at least 100 marseybux."}, 400
|
if amount < 100: abort(400, "You have to gift at least 100 marseybux.")
|
||||||
|
|
||||||
log_message = f"@{v.username} has transferred {amount} Marseybux to @{receiver.username}"
|
log_message = f"@{v.username} has transferred {amount} Marseybux to @{receiver.username}"
|
||||||
send_repeatable_notification(GIFT_NOTIF_ID, log_message)
|
send_repeatable_notification(GIFT_NOTIF_ID, log_message)
|
||||||
|
@ -537,18 +537,18 @@ def reportbugs(v):
|
||||||
@auth_required
|
@auth_required
|
||||||
def message2(v, username):
|
def message2(v, username):
|
||||||
if v.is_suspended_permanently:
|
if v.is_suspended_permanently:
|
||||||
return {"error": "You have been permabanned and cannot send messages; " + \
|
abort(403, "You have been permabanned and cannot send messages; " + \
|
||||||
"contact modmail if you think this decision was incorrect."}, 403
|
"contact modmail if you think this decision was incorrect.")
|
||||||
|
|
||||||
user = get_user(username, v=v)
|
user = get_user(username, v=v)
|
||||||
if hasattr(user, 'is_blocking') and user.is_blocking: return {"error": "You're blocking this user."}, 403
|
if hasattr(user, 'is_blocking') and user.is_blocking: abort(403, "You're blocking this user.")
|
||||||
|
|
||||||
if v.admin_level <= 1 and hasattr(user, 'is_blocked') and user.is_blocked:
|
if v.admin_level <= 1 and hasattr(user, 'is_blocked') and user.is_blocked:
|
||||||
return {"error": "This user is blocking you."}, 403
|
abort(403, "This user is blocking you.")
|
||||||
|
|
||||||
message = request.values.get("message", "").strip()[:10000].strip()
|
message = request.values.get("message", "").strip()[:10000].strip()
|
||||||
|
|
||||||
if not message: return {"error": "Message is empty!"}
|
if not message: abort(400, "Message is empty!")
|
||||||
|
|
||||||
body_html = sanitize(message)
|
body_html = sanitize(message)
|
||||||
|
|
||||||
|
@ -557,7 +557,7 @@ def message2(v, username):
|
||||||
Comment.body_html == body_html,
|
Comment.body_html == body_html,
|
||||||
).one_or_none()
|
).one_or_none()
|
||||||
|
|
||||||
if existing: return {"error": "Message already exists."}, 403
|
if existing: abort(403, "Message already exists.")
|
||||||
|
|
||||||
c = Comment(author_id=v.id,
|
c = Comment(author_id=v.id,
|
||||||
parent_submission=None,
|
parent_submission=None,
|
||||||
|
@ -595,7 +595,7 @@ def messagereply(v):
|
||||||
|
|
||||||
message = request.values.get("body", "").strip()[:10000].strip()
|
message = request.values.get("body", "").strip()[:10000].strip()
|
||||||
|
|
||||||
if not message and not request.files.get("file"): return {"error": "Message is empty!"}
|
if not message and not request.files.get("file"): abort(400, "Message is empty!")
|
||||||
|
|
||||||
id = int(request.values.get("parent_id"))
|
id = int(request.values.get("parent_id"))
|
||||||
parent = get_comment(id, v=v)
|
parent = get_comment(id, v=v)
|
||||||
|
@ -617,15 +617,15 @@ def messagereply(v):
|
||||||
file.save("video.mp4")
|
file.save("video.mp4")
|
||||||
with open("video.mp4", 'rb') as f:
|
with open("video.mp4", 'rb') as f:
|
||||||
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
try: req = requests.request("POST", "https://api.imgur.com/3/upload", headers={'Authorization': f'Client-ID {IMGUR_KEY}'}, files=[('video', f)], timeout=5).json()['data']
|
||||||
except requests.Timeout: return {"error": "Video upload timed out, please try again!"}
|
except requests.Timeout: abort(500, "Video upload timed out, please try again!")
|
||||||
try: url = req['link']
|
try: url = req['link']
|
||||||
except:
|
except:
|
||||||
error = req['error']
|
error = req['error']
|
||||||
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
if error == 'File exceeds max duration': error += ' (60 seconds)'
|
||||||
return {"error": error}, 400
|
abort(400, error)
|
||||||
if url.endswith('.'): url += 'mp4'
|
if url.endswith('.'): url += 'mp4'
|
||||||
body_html += f"<p>{url}</p>"
|
body_html += f"<p>{url}</p>"
|
||||||
else: return {"error": "Image/Video files only"}, 400
|
else: abort(400, "Image/Video files only")
|
||||||
|
|
||||||
|
|
||||||
c = Comment(author_id=v.id,
|
c = Comment(author_id=v.id,
|
||||||
|
@ -781,7 +781,7 @@ def u_username(username, v=None):
|
||||||
return redirect(SITE_FULL + request.full_path.replace(username, u.username)[:-1])
|
return redirect(SITE_FULL + request.full_path.replace(username, u.username)[:-1])
|
||||||
|
|
||||||
if u.reserved:
|
if u.reserved:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": f"That username is reserved for: {u.reserved}"}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, f"That username is reserved for: {u.reserved}")
|
||||||
return render_template("userpage_reserved.html", u=u, v=v)
|
return render_template("userpage_reserved.html", u=u, v=v)
|
||||||
|
|
||||||
if v and v.id != u.id and (u.patron or u.admin_level > 1):
|
if v and v.id != u.id and (u.patron or u.admin_level > 1):
|
||||||
|
@ -795,17 +795,17 @@ def u_username(username, v=None):
|
||||||
|
|
||||||
|
|
||||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2)):
|
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2)):
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "That userpage is private"}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, "That userpage is private")
|
||||||
return render_template("userpage_private.html", u=u, v=v)
|
return render_template("userpage_private.html", u=u, v=v)
|
||||||
|
|
||||||
|
|
||||||
if v and hasattr(u, 'is_blocking') and u.is_blocking:
|
if v and hasattr(u, 'is_blocking') and u.is_blocking:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": f"You are blocking @{u.username}."}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, f"You are blocking @{u.username}.")
|
||||||
return render_template("userpage_blocking.html", u=u, v=v)
|
return render_template("userpage_blocking.html", u=u, v=v)
|
||||||
|
|
||||||
|
|
||||||
if v and v.admin_level < 2 and hasattr(u, 'is_blocked') and u.is_blocked:
|
if v and v.admin_level < 2 and hasattr(u, 'is_blocked') and u.is_blocked:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "This person is blocking you."}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, "This person is blocking you.")
|
||||||
return render_template("userpage_blocked.html", u=u, v=v)
|
return render_template("userpage_blocked.html", u=u, v=v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -866,22 +866,22 @@ def u_username_comments(username, v=None):
|
||||||
u = user
|
u = user
|
||||||
|
|
||||||
if u.reserved:
|
if u.reserved:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": f"That username is reserved for: {u.reserved}"}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, f"That username is reserved for: {u.reserved}")
|
||||||
return render_template("userpage_reserved.html",
|
return render_template("userpage_reserved.html",
|
||||||
u=u,
|
u=u,
|
||||||
v=v)
|
v=v)
|
||||||
|
|
||||||
|
|
||||||
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2)):
|
if u.is_private and (not v or (v.id != u.id and v.admin_level < 2)):
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "That userpage is private"}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, "That userpage is private")
|
||||||
return render_template("userpage_private.html", u=u, v=v)
|
return render_template("userpage_private.html", u=u, v=v)
|
||||||
|
|
||||||
if v and hasattr(u, 'is_blocking') and u.is_blocking:
|
if v and hasattr(u, 'is_blocking') and u.is_blocking:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": f"You are blocking @{u.username}."}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, f"You are blocking @{u.username}.")
|
||||||
return render_template("userpage_blocking.html", u=u, v=v)
|
return render_template("userpage_blocking.html", u=u, v=v)
|
||||||
|
|
||||||
if v and v.admin_level < 2 and hasattr(u, 'is_blocked') and u.is_blocked:
|
if v and v.admin_level < 2 and hasattr(u, 'is_blocked') and u.is_blocked:
|
||||||
if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "This person is blocking you."}
|
if request.headers.get("Authorization") or request.headers.get("xhr"): abort(403, "This person is blocking you.")
|
||||||
return render_template("userpage_blocked.html", u=u, v=v)
|
return render_template("userpage_blocked.html", u=u, v=v)
|
||||||
|
|
||||||
|
|
||||||
|
@ -949,9 +949,9 @@ def u_username_info(username, v=None):
|
||||||
user=get_user(username, v=v)
|
user=get_user(username, v=v)
|
||||||
|
|
||||||
if hasattr(user, 'is_blocking') and user.is_blocking:
|
if hasattr(user, 'is_blocking') and user.is_blocking:
|
||||||
return {"error": "You're blocking this user."}, 401
|
abort(401, "You're blocking this user.")
|
||||||
elif hasattr(user, 'is_blocked') and user.is_blocked:
|
elif hasattr(user, 'is_blocked') and user.is_blocked:
|
||||||
return {"error": "This user is blocking you."}, 403
|
abort(403, "This user is blocking you.")
|
||||||
|
|
||||||
return user.json
|
return user.json
|
||||||
|
|
||||||
|
@ -962,9 +962,9 @@ def u_user_id_info(id, v=None):
|
||||||
user=get_account(id, v=v)
|
user=get_account(id, v=v)
|
||||||
|
|
||||||
if hasattr(user, 'is_blocking') and user.is_blocking:
|
if hasattr(user, 'is_blocking') and user.is_blocking:
|
||||||
return {"error": "You're blocking this user."}, 401
|
abort(401, "You're blocking this user.")
|
||||||
elif hasattr(user, 'is_blocked') and user.is_blocked:
|
elif hasattr(user, 'is_blocked') and user.is_blocked:
|
||||||
return {"error": "This user is blocking you."}, 403
|
abort(403, "This user is blocking you.")
|
||||||
|
|
||||||
return user.json
|
return user.json
|
||||||
|
|
||||||
|
@ -975,7 +975,7 @@ def follow_user(username, v):
|
||||||
|
|
||||||
target = get_user(username)
|
target = get_user(username)
|
||||||
|
|
||||||
if target.id==v.id: return {"error": "You can't follow yourself!"}, 400
|
if target.id==v.id: abort(400, "You can't follow yourself!")
|
||||||
|
|
||||||
if g.db.query(Follow).filter_by(user_id=v.id, target_id=target.id).one_or_none(): return {"message": "User followed!"}
|
if g.db.query(Follow).filter_by(user_id=v.id, target_id=target.id).one_or_none(): return {"message": "User followed!"}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ def api_vote_post(post_id, new, v):
|
||||||
if request.headers.get("Authorization"): abort(403)
|
if request.headers.get("Authorization"): abort(403)
|
||||||
|
|
||||||
# make sure new is valid
|
# make sure new is valid
|
||||||
if new == "-1" and environ.get('DISABLE_DOWNVOTES') == '1': return {"error": "forbidden."}, 403
|
if new == "-1" and environ.get('DISABLE_DOWNVOTES') == '1': abort(403, "forbidden.")
|
||||||
if new not in ["-1", "0", "1"]: abort(400)
|
if new not in ["-1", "0", "1"]: abort(400)
|
||||||
new = int(new)
|
new = int(new)
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ def api_vote_comment(comment_id, new, v):
|
||||||
if request.headers.get("Authorization"): abort(403)
|
if request.headers.get("Authorization"): abort(403)
|
||||||
|
|
||||||
# make sure new is valid
|
# make sure new is valid
|
||||||
if new == "-1" and environ.get('DISABLE_DOWNVOTES') == '1': return {"error": "forbidden."}, 403
|
if new == "-1" and environ.get('DISABLE_DOWNVOTES') == '1': abort(403, "forbidden.")
|
||||||
if new not in ["-1", "0", "1"]: abort(400)
|
if new not in ["-1", "0", "1"]: abort(400)
|
||||||
new = int(new)
|
new = int(new)
|
||||||
|
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>400 Bad Request</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-400{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>400</h1>
|
|
||||||
<h5>Bad Request</h5>
|
|
||||||
<p class="text-muted mb-5">That request was bad and you should feel bad</p>
|
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,21 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>401 Not Authorized</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-401{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>401</h1>
|
|
||||||
<h5>Not Authorized</h5>
|
|
||||||
<p class="text-muted mb-5">You need an account for this. Please make one!</p>
|
|
||||||
<div><a href="/signup" class="btn btn-primary mb-2">Create an account</a></div>
|
|
||||||
<div><a href="/login" class="text-muted text-small">Or sign in</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>404 Page Not Found</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-404{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>404</h1>
|
|
||||||
<h5>Page Not Found</h5>
|
|
||||||
<p class="text-muted mb-5">That page doesn't exist. If you got here from a link on the website, please report this issue. Thanks!</p>
|
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>405 Method Not Allowed</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-405{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>405</h1>
|
|
||||||
<h5>Method Not Allowed</h5>
|
|
||||||
<p class="text-muted mb-5">Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!</p>
|
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>Max file size is 8 MB</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-413{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>413</h1>
|
|
||||||
<h5>Payload Too Large</h5>
|
|
||||||
<p class="text-muted mb-5">Max file size is 8 MB</p>
|
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,19 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>429 Too Many Requests</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-429{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>429</h1>
|
|
||||||
<h5>Too Many Requests</h5>
|
|
||||||
<p class="text-muted mb-5">Are you hammering the site? Stop that, yo.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,20 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
<title>500 Internal Server Error</title>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block pagetype %}error-500{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-10 col-md-5">
|
|
||||||
<div class="text-center px-3 my-8">
|
|
||||||
<h1>500</h1>
|
|
||||||
<h5>Internal Server Error</h5>
|
|
||||||
<p class="text-muted mb-5">Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!</p>
|
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,18 +1,18 @@
|
||||||
{% extends "default.html" %}
|
{% extends "default.html" %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
<title>403 Forbidden</title>
|
<title>{{code}} {{error}}</title>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
{% block pagetype %}error-{{code}}{% endblock %}
|
||||||
{% block pagetype %}error-403{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-10 col-md-5">
|
<div class="col-10 col-md-5">
|
||||||
<div class="text-center px-3 my-8">
|
<div class="text-center px-3 my-8">
|
||||||
<h1>403</h1>
|
<h1>{{code}}</h1>
|
||||||
<h5>Forbidden</h5>
|
<h5>{{error}}</h5>
|
||||||
<p class="text-muted mb-5">{{description}}</p>
|
<p class="text-muted mb-5">{{description}}</p>
|
||||||
|
{% if details -%}
|
||||||
|
<blockquote class="error-details mb-5 py-2">{{details|safe}}</blockquote>
|
||||||
|
{%- endif %}
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Add table
Add a link
Reference in a new issue