get rid of useless tabs and spaces

pull/83/head
Aevann 2023-01-01 13:36:20 +02:00
parent b0b70d2f0f
commit 044664a25e
108 changed files with 729 additions and 729 deletions

View File

@ -4,7 +4,7 @@ ARG DEBIAN_FRONTEND=noninteractive
RUN apt update RUN apt update
RUN apt -y upgrade RUN apt -y upgrade
RUN apt install -y supervisor RUN apt install -y supervisor
RUN apt install -y python3-pip RUN apt install -y python3-pip
RUN apt install -y ffmpeg RUN apt install -y ffmpeg
RUN apt install -y postgresql RUN apt install -y postgresql

View File

@ -174,7 +174,7 @@ blockquote {
} }
blockquote a { blockquote a {
color: skyblue; color: skyblue;
} }
.unread { .unread {

View File

@ -106,7 +106,7 @@ blockquote {
} }
.comment-collapse-icon::before { .comment-collapse-icon::before {
color: var(--gray-500) !important color: var(--gray-500) !important
} }
.text-admin { .text-admin {

View File

@ -6,7 +6,7 @@
--secondary: #c7c7c7; --secondary: #c7c7c7;
--gray: #c7c7c7; --gray: #c7c7c7;
--gray-300: #c7c7c7; --gray-300: #c7c7c7;
--gray-400: #cfcfcf; --gray-400: #cfcfcf;
--gray-500: #ffffff; --gray-500: #ffffff;
--gray-600: #ffffff; --gray-600: #ffffff;
--gray-700: #ffffff; --gray-700: #ffffff;

View File

@ -6574,7 +6574,7 @@ body > .container {
.emoji2 { .emoji2 {
/*background: None!important;*/ /*background: None!important;*/
width:60px; width:60px;
height: 85px; height: 85px;
overflow: hidden; overflow: hidden;
border: none border: none

View File

@ -35,7 +35,7 @@ body, .navbar-light, .navbar-dark, .card, .modal-content, .comment-write textare
} }
.modal .comment-actions .list-group-item { .modal .comment-actions .list-group-item {
background-color: var(--gray-600)!important; background-color: var(--gray-600)!important;
} }
.page-link { .page-link {

View File

@ -33,7 +33,7 @@ h1, h2, h3, h4, h5, h6 {
} }
.button { .button {
background-color: rgb(var(--background))!important; background-color: rgb(var(--background))!important;
background: 0 0; background: 0 0;
font-weight: 600; font-weight: 600;
font-size: 1rem; font-size: 1rem;

View File

@ -133,7 +133,7 @@
{"name":"oplus", "class":"Marsey Alphabet", "tags": ["⊕","xor","circled","sum"]}, {"name":"oplus", "class":"Marsey Alphabet", "tags": ["⊕","xor","circled","sum"]},
{"name":"otimes", "class":"Marsey Alphabet", "tags": ["⊗","tensor","circled","product"]}, {"name":"otimes", "class":"Marsey Alphabet", "tags": ["⊗","tensor","circled","product"]},
{"name":"trianglelefteq", "class":"Marsey Alphabet", "tags": ["⊴"]}, {"name":"trianglelefteq", "class":"Marsey Alphabet", "tags": ["⊴"]},
{"name":"marseyflagmaryland","class":"Marsey Flags"}, {"name":"marseyflagmaryland","class":"Marsey Flags"},
{"name":"marseyflagcalifornia","class":"Marsey Flags"}, {"name":"marseyflagcalifornia","class":"Marsey Flags"},
{"name":"marseyflagtexas","class":"Marsey Flags"}, {"name":"marseyflagtexas","class":"Marsey Flags"},

View File

@ -213,40 +213,40 @@ body {
background-color: #1f1f1f; background-color: #1f1f1f;
background-blend-mode: soft-light; background-blend-mode: soft-light;
} }
.color { .color {
width: 20%; width: 20%;
height: 100%; height: 100%;
float: left float: left
} }
.color p { .color p {
position: relative; position: relative;
z-index: 1231231; z-index: 1231231;
text-align: center; text-align: center;
line-height: 90vh; line-height: 90vh;
} }
.color:nth-child(1){ .color:nth-child(1){
background-color: #F5624D; background-color: #F5624D;
} }
.color:nth-child(2){ .color:nth-child(2){
background-color: #CC231E; background-color: #CC231E;
} }
.color:nth-child(3){ .color:nth-child(3){
background-color: #34A65F; background-color: #34A65F;
} }
.color:nth-child(4){ .color:nth-child(4){
background-color: #0F8A5F; background-color: #0F8A5F;
} }
.color:nth-child(5){ .color:nth-child(5){
background-color: #235E6F; background-color: #235E6F;
} }
#snow:not([data-nonce]) { #snow:not([data-nonce]) {
height: 100%; height: 100%;
color: #FFF; color: #FFF;

View File

@ -13,7 +13,7 @@
function snow(flakesMax) { function snow(flakesMax) {
// --- common properties --- // --- common properties ---
this.autoStart = true; // Whether the snow should start automatically or not. this.autoStart = true; // Whether the snow should start automatically or not.
this.excludeMobile = false; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) Enable at your own risk. this.excludeMobile = false; // Snow is likely to be bad news for mobile phones' CPUs (and batteries.) Enable at your own risk.
this.flakesMax = flakesMax; // Limit total amount of snow made (falling + sticking) this.flakesMax = flakesMax; // Limit total amount of snow made (falling + sticking)
@ -32,9 +32,9 @@ function snow(flakesMax) {
this.useTwinkleEffect = false; // Allow snow to randomly "flicker" in and out of view while falling this.useTwinkleEffect = false; // Allow snow to randomly "flicker" in and out of view while falling
this.usePositionFixed = false; // true = snow does not shift vertically when scrolling. May increase CPU load, disabled by default - if enabled, used only where supported this.usePositionFixed = false; // true = snow does not shift vertically when scrolling. May increase CPU load, disabled by default - if enabled, used only where supported
this.usePixelPosition = false; // Whether to use pixel values for snow top/left vs. percentages. Auto-enabled if body is position:relative or targetElement is specified. this.usePixelPosition = false; // Whether to use pixel values for snow top/left vs. percentages. Auto-enabled if body is position:relative or targetElement is specified.
// --- less-used bits --- // --- less-used bits ---
this.freezeOnBlur = true; // Only snow when the window is in focus (foreground.) Saves CPU. this.freezeOnBlur = true; // Only snow when the window is in focus (foreground.) Saves CPU.
this.flakeLeftOffset = 0; // Left margin/gutter space on edge of container (eg. browser window.) Bump up these values if seeing horizontal scrollbars. this.flakeLeftOffset = 0; // Left margin/gutter space on edge of container (eg. browser window.) Bump up these values if seeing horizontal scrollbars.
this.flakeRightOffset = 0; // Right margin/gutter space on edge of container this.flakeRightOffset = 0; // Right margin/gutter space on edge of container
@ -43,9 +43,9 @@ function snow(flakesMax) {
this.vMaxX = 5; // Maximum X velocity range for snow this.vMaxX = 5; // Maximum X velocity range for snow
this.vMaxY = 4; // Maximum Y velocity range for snow this.vMaxY = 4; // Maximum Y velocity range for snow
this.zIndex = 0; // CSS stacking order applied to each snowflake this.zIndex = 0; // CSS stacking order applied to each snowflake
// --- "No user-serviceable parts inside" past this point, yadda yadda --- // --- "No user-serviceable parts inside" past this point, yadda yadda ---
var storm = this, var storm = this,
features, features,
// UA sniffing and backCompat rendering mode checks for fixed position, etc. // UA sniffing and backCompat rendering mode checks for fixed position, etc.
@ -76,20 +76,20 @@ function snow(flakesMax) {
})(), })(),
didInit = false, didInit = false,
docFrag = document.createDocumentFragment(); docFrag = document.createDocumentFragment();
features = (function () { features = (function () {
var getAnimationFrame; var getAnimationFrame;
/** /**
* hat tip: paul irish * hat tip: paul irish
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/ * http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* https://gist.github.com/838785 * https://gist.github.com/838785
*/ */
function timeoutShim(callback) { function timeoutShim(callback) {
window.setTimeout(callback, 1000 / (storm.animationInterval || 20)); window.setTimeout(callback, 1000 / (storm.animationInterval || 20));
} }
var _animationFrame = var _animationFrame =
window.requestAnimationFrame || window.requestAnimationFrame ||
window.webkitRequestAnimationFrame || window.webkitRequestAnimationFrame ||
@ -97,24 +97,24 @@ function snow(flakesMax) {
window.oRequestAnimationFrame || window.oRequestAnimationFrame ||
window.msRequestAnimationFrame || window.msRequestAnimationFrame ||
timeoutShim; timeoutShim;
// apply to window, avoid "illegal invocation" errors in Chrome // apply to window, avoid "illegal invocation" errors in Chrome
getAnimationFrame = _animationFrame getAnimationFrame = _animationFrame
? function () { ? function () {
return _animationFrame.apply(window, arguments); return _animationFrame.apply(window, arguments);
} }
: null; : null;
var testDiv; var testDiv;
testDiv = document.createElement("div"); testDiv = document.createElement("div");
function has(prop) { function has(prop) {
// test for feature support // test for feature support
var result = testDiv.style[prop]; var result = testDiv.style[prop];
return result !== undefined ? prop : null; return result !== undefined ? prop : null;
} }
// note local scope. // note local scope.
var localFeatures = { var localFeatures = {
transform: { transform: {
@ -125,34 +125,34 @@ function snow(flakesMax) {
w3: has("transform"), w3: has("transform"),
prop: null // the normalized property value prop: null // the normalized property value
}, },
getAnimationFrame: getAnimationFrame getAnimationFrame: getAnimationFrame
}; };
localFeatures.transform.prop = localFeatures.transform.prop =
localFeatures.transform.w3 || localFeatures.transform.w3 ||
localFeatures.transform.moz || localFeatures.transform.moz ||
localFeatures.transform.webkit || localFeatures.transform.webkit ||
localFeatures.transform.ie || localFeatures.transform.ie ||
localFeatures.transform.opera; localFeatures.transform.opera;
testDiv = null; testDiv = null;
return localFeatures; return localFeatures;
})(); })();
this.timer = null; this.timer = null;
this.flakes = []; this.flakes = [];
this.disabled = false; this.disabled = false;
this.active = false; this.active = false;
this.meltFrameCount = 20; this.meltFrameCount = 20;
this.meltFrames = []; this.meltFrames = [];
this.setXY = function (o, x, y) { this.setXY = function (o, x, y) {
if (!o) { if (!o) {
return false; return false;
} }
if (storm.usePixelPosition || targetElementIsRelative) { if (storm.usePixelPosition || targetElementIsRelative) {
o.style.left = x - storm.flakeWidth + "px"; o.style.left = x - storm.flakeWidth + "px";
o.style.top = y - storm.flakeHeight + "px"; o.style.top = y - storm.flakeHeight + "px";
@ -172,7 +172,7 @@ function snow(flakesMax) {
} }
} }
}; };
this.events = (function () { this.events = (function () {
var old = !window.addEventListener && window.attachEvent, var old = !window.addEventListener && window.attachEvent,
slice = Array.prototype.slice, slice = Array.prototype.slice,
@ -180,7 +180,7 @@ function snow(flakesMax) {
add: old ? "attachEvent" : "addEventListener", add: old ? "attachEvent" : "addEventListener",
remove: old ? "detachEvent" : "removeEventListener" remove: old ? "detachEvent" : "removeEventListener"
}; };
function getArgs(oArgs) { function getArgs(oArgs) {
var args = slice.call(oArgs), var args = slice.call(oArgs),
len = args.length; len = args.length;
@ -194,7 +194,7 @@ function snow(flakesMax) {
} }
return args; return args;
} }
function apply(args, sType) { function apply(args, sType) {
var element = args.shift(), var element = args.shift(),
method = [evt[sType]]; method = [evt[sType]];
@ -204,32 +204,32 @@ function snow(flakesMax) {
element[method].apply(element, args); element[method].apply(element, args);
} }
} }
function addEvent() { function addEvent() {
apply(getArgs(arguments), "add"); apply(getArgs(arguments), "add");
} }
function removeEvent() { function removeEvent() {
apply(getArgs(arguments), "remove"); apply(getArgs(arguments), "remove");
} }
return { return {
add: addEvent, add: addEvent,
remove: removeEvent remove: removeEvent
}; };
})(); })();
function rnd(n, min) { function rnd(n, min) {
if (isNaN(min)) { if (isNaN(min)) {
min = 0; min = 0;
} }
return Math.random() * n + min; return Math.random() * n + min;
} }
function plusMinus(n) { function plusMinus(n) {
return parseInt(rnd(2), 10) === 1 ? n * -1 : n; return parseInt(rnd(2), 10) === 1 ? n * -1 : n;
} }
this.randomizeWind = function () { this.randomizeWind = function () {
var i; var i;
vRndX = plusMinus(rnd(storm.vMaxX, 0.2)); vRndX = plusMinus(rnd(storm.vMaxX, 0.2));
@ -242,7 +242,7 @@ function snow(flakesMax) {
} }
} }
}; };
this.scrollHandler = function () { this.scrollHandler = function () {
var i; var i;
// "attach" snowflakes to bottom of window if no absolute bottom value was given // "attach" snowflakes to bottom of window if no absolute bottom value was given
@ -265,7 +265,7 @@ function snow(flakesMax) {
} }
} }
}; };
this.resizeHandler = function () { this.resizeHandler = function () {
if (window.innerWidth || window.innerHeight) { if (window.innerWidth || window.innerHeight) {
screenX = window.innerWidth - 16 - storm.flakeRightOffset; screenX = window.innerWidth - 16 - storm.flakeRightOffset;
@ -286,14 +286,14 @@ function snow(flakesMax) {
docHeight = document.body.offsetHeight; docHeight = document.body.offsetHeight;
screenX2 = parseInt(screenX / 2, 10); screenX2 = parseInt(screenX / 2, 10);
}; };
this.resizeHandlerAlt = function () { this.resizeHandlerAlt = function () {
screenX = storm.targetElement.offsetWidth - storm.flakeRightOffset; screenX = storm.targetElement.offsetWidth - storm.flakeRightOffset;
screenY = storm.flakeBottom || storm.targetElement.offsetHeight; screenY = storm.flakeBottom || storm.targetElement.offsetHeight;
screenX2 = parseInt(screenX / 2, 10); screenX2 = parseInt(screenX / 2, 10);
docHeight = document.body.offsetHeight; docHeight = document.body.offsetHeight;
}; };
this.freeze = function () { this.freeze = function () {
// pause animation // pause animation
if (!storm.disabled) { if (!storm.disabled) {
@ -303,7 +303,7 @@ function snow(flakesMax) {
} }
storm.timer = null; storm.timer = null;
}; };
this.resume = function () { this.resume = function () {
if (storm.disabled) { if (storm.disabled) {
storm.disabled = 0; storm.disabled = 0;
@ -312,7 +312,7 @@ function snow(flakesMax) {
} }
storm.timerInit(); storm.timerInit();
}; };
this.toggleSnow = function () { this.toggleSnow = function () {
if (!storm.flakes.length) { if (!storm.flakes.length) {
// first run // first run
@ -328,7 +328,7 @@ function snow(flakesMax) {
} }
} }
}; };
this.stop = function () { this.stop = function () {
var i; var i;
this.freeze(); this.freeze();
@ -347,14 +347,14 @@ function snow(flakesMax) {
} }
} }
}; };
this.show = function () { this.show = function () {
var i; var i;
for (i = 0; i < this.flakes.length; i++) { for (i = 0; i < this.flakes.length; i++) {
this.flakes[i].o.style.display = "block"; this.flakes[i].o.style.display = "block";
} }
}; };
this.SnowFlake = function (type, x, y) { this.SnowFlake = function (type, x, y) {
var s = this; var s = this;
this.type = type; this.type = type;
@ -390,7 +390,7 @@ function snow(flakesMax) {
this.o.style.fontWeight = "normal"; this.o.style.fontWeight = "normal";
this.o.style.zIndex = storm.zIndex; this.o.style.zIndex = storm.zIndex;
docFrag.appendChild(this.o); docFrag.appendChild(this.o);
this.refresh = function () { this.refresh = function () {
if (isNaN(s.x) || isNaN(s.y)) { if (isNaN(s.x) || isNaN(s.y)) {
// safety check // safety check
@ -398,7 +398,7 @@ function snow(flakesMax) {
} }
storm.setXY(s.o, s.x, s.y); storm.setXY(s.o, s.x, s.y);
}; };
this.stick = function () { this.stick = function () {
if ( if (
noFixed || noFixed ||
@ -415,7 +415,7 @@ function snow(flakesMax) {
s.o.style.display = "block"; s.o.style.display = "block";
} }
}; };
this.vCheck = function () { this.vCheck = function () {
if (s.vX >= 0 && s.vX < 0.2) { if (s.vX >= 0 && s.vX < 0.2) {
s.vX = 0.2; s.vX = 0.2;
@ -426,7 +426,7 @@ function snow(flakesMax) {
s.vY = 0.2; s.vY = 0.2;
} }
}; };
this.move = function () { this.move = function () {
var vX = s.vX * windOffset, var vX = s.vX * windOffset,
yDiff; yDiff;
@ -481,25 +481,25 @@ function snow(flakesMax) {
} }
} }
}; };
this.animate = function () { this.animate = function () {
// main animation loop // main animation loop
// move, check status, die etc. // move, check status, die etc.
s.move(); s.move();
}; };
this.setVelocities = function () { this.setVelocities = function () {
s.vX = vRndX + rnd(storm.vMaxX * 0.12, 0.1); s.vX = vRndX + rnd(storm.vMaxX * 0.12, 0.1);
s.vY = vRndY + rnd(storm.vMaxY * 0.12, 0.1); s.vY = vRndY + rnd(storm.vMaxY * 0.12, 0.1);
}; };
this.setOpacity = function (o, opacity) { this.setOpacity = function (o, opacity) {
if (!opacitySupported) { if (!opacitySupported) {
return false; return false;
} }
o.style.opacity = opacity; o.style.opacity = opacity;
}; };
this.melt = function () { this.melt = function () {
if (!storm.useMeltEffect || !s.melting) { if (!storm.useMeltEffect || !s.melting) {
s.recycle(); s.recycle();
@ -519,7 +519,7 @@ function snow(flakesMax) {
} }
} }
}; };
this.recycle = function () { this.recycle = function () {
s.o.style.display = "none"; s.o.style.display = "none";
s.o.style.position = fixedForEverything ? "fixed" : "absolute"; s.o.style.position = fixedForEverything ? "fixed" : "absolute";
@ -541,11 +541,11 @@ function snow(flakesMax) {
s.o.style.display = "block"; s.o.style.display = "block";
s.active = 1; s.active = 1;
}; };
this.recycle(); // set up x/y coords etc. this.recycle(); // set up x/y coords etc.
this.refresh(); this.refresh();
}; };
this.snow = function () { this.snow = function () {
var active = 0, var active = 0,
flake = null, flake = null,
@ -570,7 +570,7 @@ function snow(flakesMax) {
features.getAnimationFrame(storm.snow); features.getAnimationFrame(storm.snow);
} }
}; };
this.mouseMove = function (e) { this.mouseMove = function (e) {
if (!storm.followMouse) { if (!storm.followMouse) {
return true; return true;
@ -583,7 +583,7 @@ function snow(flakesMax) {
windOffset = (x / screenX2) * windMultiplier; windOffset = (x / screenX2) * windMultiplier;
} }
}; };
this.createSnow = function (limit, allowInactive) { this.createSnow = function (limit, allowInactive) {
var i; var i;
for (i = 0; i < limit; i++) { for (i = 0; i < limit; i++) {
@ -596,12 +596,12 @@ function snow(flakesMax) {
} }
storm.targetElement.appendChild(docFrag); storm.targetElement.appendChild(docFrag);
}; };
this.timerInit = function () { this.timerInit = function () {
storm.timer = true; storm.timer = true;
storm.snow(); storm.snow();
}; };
this.init = function () { this.init = function () {
var i; var i;
for (i = 0; i < storm.meltFrameCount; i++) { for (i = 0; i < storm.meltFrameCount; i++) {
@ -628,7 +628,7 @@ function snow(flakesMax) {
storm.animationInterval = Math.max(20, storm.animationInterval); storm.animationInterval = Math.max(20, storm.animationInterval);
storm.timerInit(); storm.timerInit();
}; };
this.start = function (bFromOnLoad) { this.start = function (bFromOnLoad) {
if (!didInit) { if (!didInit) {
didInit = true; didInit = true;
@ -678,7 +678,7 @@ function snow(flakesMax) {
storm.active = true; storm.active = true;
} }
}; };
function doDelayedStart() { function doDelayedStart() {
window.setTimeout(function () { window.setTimeout(function () {
storm.start(true); storm.start(true);
@ -686,7 +686,7 @@ function snow(flakesMax) {
// event cleanup // event cleanup
storm.events.remove(isIE ? document : window, "mousemove", doDelayedStart); storm.events.remove(isIE ? document : window, "mousemove", doDelayedStart);
} }
function doStart() { function doStart() {
if (!storm.excludeMobile || !isMobile) { if (!storm.excludeMobile || !isMobile) {
doDelayedStart(); doDelayedStart();
@ -694,12 +694,12 @@ function snow(flakesMax) {
// event cleanup // event cleanup
storm.events.remove(window, "load", doStart); storm.events.remove(window, "load", doStart);
} }
// hooks for starting the snow // hooks for starting the snow
if (storm.autoStart) { if (storm.autoStart) {
storm.events.add(window, "load", doStart, false); storm.events.add(window, "load", doStart, false);
} }
return this; return this;
} }

View File

@ -86,7 +86,7 @@ function vote(type, id, dir) {
} }
} }
} }
const xhr = createXhrWithFormKey("/vote/" + type.replace('-mobile','') + "/" + id + "/" + votedirection); const xhr = createXhrWithFormKey("/vote/" + type.replace('-mobile','') + "/" + id + "/" + votedirection);
xhr[0].send(xhr[1]); xhr[0].send(xhr[1]);
} }
@ -144,7 +144,7 @@ function buy(mb) {
document.getElementById('giveaward').disabled=false; document.getElementById('giveaward').disabled=false;
let owned = document.getElementById(`${kind}-owned`) let owned = document.getElementById(`${kind}-owned`)
let ownednum = Number(owned.textContent) + 1; let ownednum = Number(owned.textContent) + 1;
owned.textContent = ownednum owned.textContent = ownednum
} }
} }
}; };
@ -166,7 +166,7 @@ function giveaward(t) {
owned.textContent = ownednum owned.textContent = ownednum
if (ownednum == 0) if (ownednum == 0)
document.getElementById('giveaward').disabled=true; document.getElementById('giveaward').disabled=true;
} }
); );
} }

View File

@ -108,7 +108,7 @@ function buildRouletteTable() {
for (let i = 25; i < 37; i++) { for (let i = 25; i < 37; i++) {
const correctNumber = CELL_TO_NUMBER_LOOKUP[i]; const correctNumber = CELL_TO_NUMBER_LOOKUP[i];
const isRed = reds.includes(correctNumber); const isRed = reds.includes(correctNumber);
html += `<div html += `<div
id="STRAIGHT_UP_BET#${correctNumber}" id="STRAIGHT_UP_BET#${correctNumber}"
data-nonce="${nonce}" data-nonce="${nonce}"
@ -238,7 +238,7 @@ function buildRouletteBets(bets) {
data-bs-placement="bottom" data-bs-placement="bottom"
title="" title=""
aria-label="Marseybux" aria-label="Marseybux"
width="32" class="mr-1 ml-1" width="32" class="mr-1 ml-1"
data-bs-original-title="Marseybux"> data-bs-original-title="Marseybux">
`; `;
const { participants, coin, marseybux } = flatBets.reduce((prev, next) => { const { participants, coin, marseybux } = flatBets.reduce((prev, next) => {

View File

@ -98,7 +98,7 @@ function delete_commentModal(t, id) {
document.getElementById("comment-"+id).remove() document.getElementById("comment-"+id).remove()
} }
else else
{ {
document.getElementsByClassName(`comment-${id}-only`)[0].classList.add('deleted'); document.getElementsByClassName(`comment-${id}-only`)[0].classList.add('deleted');
document.getElementById(`delete-${id}`).classList.add('d-none'); document.getElementById(`delete-${id}`).classList.add('d-none');
document.getElementById(`undelete-${id}`).classList.remove('d-none'); document.getElementById(`undelete-${id}`).classList.remove('d-none');
@ -123,7 +123,7 @@ function post_reply(id){
form.append('file', e); form.append('file', e);
} }
catch(e) {} catch(e) {}
const xhr = createXhrWithFormKey("/reply", "POST", form); const xhr = createXhrWithFormKey("/reply", "POST", form);
xhr[0].onload=function(){ xhr[0].onload=function(){
let data let data

View File

@ -63,7 +63,7 @@ function postToast(t, url, data, extraActionsOnSuccess, method="POST") {
showToast(success, message); showToast(success, message);
if (!isShopConfirm) { if (!isShopConfirm) {
t.disabled = false; t.disabled = false;
t.classList.remove("disabled"); t.classList.remove("disabled");
} }
return success; return success;
}; };

View File

@ -4,6 +4,6 @@ let audio = new Audio(`/assets/images/${fart}.webp`);
audio.play(); audio.play();
if (audio.paused) { if (audio.paused) {
document.addEventListener('click', () => { document.addEventListener('click', () => {
if (audio.paused) audio.play(); if (audio.paused) audio.play();
}, {once : true}) }, {once : true})
} }

View File

@ -43,7 +43,7 @@ async function getGifs(form) {
noGIFs.innerHTML = null; noGIFs.innerHTML = null;
loadGIFs.innerHTML = null; loadGIFs.innerHTML = null;
container.innerHTML = ` container.innerHTML = `
<div class="card"> <div class="card">
<div class="gif-cat-overlay"><div>Agree</div></div> <div class="gif-cat-overlay"><div>Agree</div></div>
<img loading="lazy" src="https://media.giphy.com/media/wGhYz3FHaRJgk/200w.webp"> <img loading="lazy" src="https://media.giphy.com/media/wGhYz3FHaRJgk/200w.webp">

View File

@ -65,7 +65,7 @@ function registerServiceWorker(serviceWorkerUrl, applicationServerPublicKey, api
.catch(function() { .catch(function() {
}); });
} else { } else {
} }
return swRegistration; return swRegistration;
} }

View File

@ -75,4 +75,4 @@ self.addEventListener('notificationclick', (e) => {
const hadWindowToFocus = clientsArr.some((windowClient) => windowClient.url === e.notification.data.url ? (windowClient.focus(), true) : false); const hadWindowToFocus = clientsArr.some((windowClient) => windowClient.url === e.notification.data.url ? (windowClient.focus(), true) : false);
if (!hadWindowToFocus) clients.openWindow(e.notification.data.url).then((windowClient) => windowClient ? windowClient.focus() : null); if (!hadWindowToFocus) clients.openWindow(e.notification.data.url).then((windowClient) => windowClient ? windowClient.focus() : null);
})); }));
}); });

View File

@ -13,7 +13,7 @@ function updatebgselection(){
const backgrounds = [ const backgrounds = [
{ {
folder: "glitter", folder: "glitter",
backgrounds: backgrounds:
[ [
"1.webp", "1.webp",
"2.webp", "2.webp",
@ -109,7 +109,7 @@ document.onpaste = function(event) {
alert("You can't upload more than 4 files at one time!") alert("You can't upload more than 4 files at one time!")
return return
} }
if (files.length) if (files.length)
{ {
f=document.getElementById('file-upload'); f=document.getElementById('file-upload');

View File

@ -38,7 +38,7 @@ function unblock_user(t, url) {
}, },
() => { () => {
t.parentElement.parentElement.remove(); t.parentElement.parentElement.remove();
} }
); );
} }

View File

@ -12,12 +12,12 @@ function highlight_unread(localstoragevar) {
catch(e) {} catch(e) {}
} }
} }
} }
} }
highlight_unread("comment-counts") highlight_unread("comment-counts")
if (!location.href.includes("?context")) { if (!location.href.includes("?context")) {
localStorage.setItem("old-comment-counts", localStorage.getItem("comment-counts")) localStorage.setItem("old-comment-counts", localStorage.getItem("comment-counts"))
const comments = JSON.parse(localStorage.getItem("comment-counts")) || {} const comments = JSON.parse(localStorage.getItem("comment-counts")) || {}

View File

@ -82,7 +82,7 @@ class Badge(Base):
text = self.badge.description text = self.badge.description
else: else:
return self.name return self.name
return f'{self.name} - {text}' return f'{self.name} - {text}'
@property @property

View File

@ -285,7 +285,7 @@ class Comment(Base):
body += f''' data-nonce="{{g.nonce}}" data-onclick="poll_vote_no_v()"''' body += f''' data-nonce="{{g.nonce}}" data-onclick="poll_vote_no_v()"'''
body += f'''><label class="custom-control-label" for="comment-{o.id}">{o.body_html}<span class="presult-{self.id}''' body += f'''><label class="custom-control-label" for="comment-{o.id}">{o.body_html}<span class="presult-{self.id}'''
if not self.total_poll_voted(v): body += ' d-none' if not self.total_poll_voted(v): body += ' d-none'
body += f'"> - <a href="/votes/comment/option/{o.id}"><span id="score-comment-{o.id}">{o.upvotes}</span> votes</a></label></div>''' body += f'"> - <a href="/votes/comment/option/{o.id}"><span id="score-comment-{o.id}">{o.upvotes}</span> votes</a></label></div>'''
if not self.ghost and self.author.show_sig(v): if not self.ghost and self.author.show_sig(v):
@ -322,15 +322,15 @@ class Comment(Base):
if self.author.shadowbanned and not (v and v.shadowbanned): return True if self.author.shadowbanned and not (v and v.shadowbanned): return True
if (self.wordle_result) and (not self.body or len(self.body_html) <= 100) and 9 > self.level > 1: return True if (self.wordle_result) and (not self.body or len(self.body_html) <= 100) and 9 > self.level > 1: return True
if v and v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True if v and v.filter_words and self.body and any(x in self.body for x in v.filter_words): return True
return False return False
@property @property
@lazy @lazy
def is_op(self): return self.author_id==self.post.author_id def is_op(self): return self.author_id==self.post.author_id
@lazy @lazy
def filtered_flags(self, v): def filtered_flags(self, v):
return [f for f in self.flags if (v and v.shadowbanned) or not f.user.shadowbanned] return [f for f in self.flags if (v and v.shadowbanned) or not f.user.shadowbanned]
@ -356,7 +356,7 @@ class Comment(Base):
body += "<strong class='ml-2'>Correct!</strong>" body += "<strong class='ml-2'>Correct!</strong>"
elif wordle_status == 'lost': elif wordle_status == 'lost':
body += f"<strong class='ml-2'>Lost. The answer was: {wordle_answer}</strong>" body += f"<strong class='ml-2'>Lost. The answer was: {wordle_answer}</strong>"
body += '</span>' body += '</span>'
return body return body

View File

@ -22,8 +22,8 @@ class Leaderboard:
user_func = None user_func = None
value_func = None value_func = None
def __init__(self, header_name:str, table_header_name:str, html_id:str, table_column_name:str, def __init__(self, header_name:str, table_header_name:str, html_id:str, table_column_name:str,
user_relative_url:Optional[str], query_function:Callable[..., Tuple[Any, Any, Any]], user_relative_url:Optional[str], query_function:Callable[..., Tuple[Any, Any, Any]],
criteria, v:User, value_func:Optional[Callable[[User], Union[int, Column]]], db:scoped_session, users, limit=LEADERBOARD_LIMIT): criteria, v:User, value_func:Optional[Callable[[User], Union[int, Column]]], db:scoped_session, users, limit=LEADERBOARD_LIMIT):
self.header_name = header_name self.header_name = header_name
self.table_header_name = table_header_name self.table_header_name = table_header_name
@ -52,11 +52,11 @@ class Leaderboard:
sq = db.query(User.id, func.rank().over(order_by=order_by.desc()).label("rank")).subquery() sq = db.query(User.id, func.rank().over(order_by=order_by.desc()).label("rank")).subquery()
position = db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] position = db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1]
return (leaderboard, position, None) return (leaderboard, position, None)
@classmethod @classmethod
def count_and_label(cls, criteria): def count_and_label(cls, criteria):
return func.count(criteria).label("count") return func.count(criteria).label("count")
@classmethod @classmethod
def rank_filtered_rank_label_by_desc(cls, criteria): def rank_filtered_rank_label_by_desc(cls, criteria):
return func.rank().over(order_by=func.count(criteria).desc()).label("rank") return func.rank().over(order_by=func.count(criteria).desc()).label("rank")
@ -71,27 +71,27 @@ class Leaderboard:
sq_criteria = User.id == sq.c.author_id sq_criteria = User.id == sq.c.author_id
else: else:
raise ValueError("This leaderboard function only supports Badge.user_id and Marsey.author_id") raise ValueError("This leaderboard function only supports Badge.user_id and Marsey.author_id")
leaderboard = db.query(User, sq.c.count).join(sq, sq_criteria).order_by(sq.c.count.desc()) leaderboard = db.query(User, sq.c.count).join(sq, sq_criteria).order_by(sq.c.count.desc())
position = db.query(User.id, sq.c.rank, sq.c.count).join(sq, sq_criteria).filter(User.id == v.id).one_or_none() position = db.query(User.id, sq.c.rank, sq.c.count).join(sq, sq_criteria).filter(User.id == v.id).one_or_none()
if position: position = (position[1], position[2]) if position: position = (position[1], position[2])
else: position = (leaderboard.count() + 1, 0) else: position = (leaderboard.count() + 1, 0)
leaderboard = leaderboard.limit(limit).all() leaderboard = leaderboard.limit(limit).all()
return (leaderboard, position[0], position[1]) return (leaderboard, position[0], position[1])
@classmethod @classmethod
def get_blockers_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit): def get_blockers_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit):
if lb_criteria != UserBlock.target_id: if lb_criteria != UserBlock.target_id:
raise ValueError("This leaderboard function only supports UserBlock.target_id") raise ValueError("This leaderboard function only supports UserBlock.target_id")
sq = db.query(lb_criteria, cls.count_and_label(lb_criteria)).group_by(lb_criteria).subquery() sq = db.query(lb_criteria, cls.count_and_label(lb_criteria)).group_by(lb_criteria).subquery()
leaderboard = db.query(User, sq.c.count).join(User, User.id == sq.c.target_id).order_by(sq.c.count.desc()) leaderboard = db.query(User, sq.c.count).join(User, User.id == sq.c.target_id).order_by(sq.c.count.desc())
sq = db.query(lb_criteria, cls.count_and_label(lb_criteria), cls.rank_filtered_rank_label_by_desc(lb_criteria)).group_by(lb_criteria).subquery() sq = db.query(lb_criteria, cls.count_and_label(lb_criteria), cls.rank_filtered_rank_label_by_desc(lb_criteria)).group_by(lb_criteria).subquery()
position = db.query(sq.c.rank, sq.c.count).join(User, User.id == sq.c.target_id).filter(sq.c.target_id == v.id).limit(1).one_or_none() position = db.query(sq.c.rank, sq.c.count).join(User, User.id == sq.c.target_id).filter(sq.c.target_id == v.id).limit(1).one_or_none()
if not position: position = (leaderboard.count() + 1, 0) if not position: position = (leaderboard.count() + 1, 0)
leaderboard = leaderboard.limit(limit).all() leaderboard = leaderboard.limit(limit).all()
return (leaderboard, position[0], position[1]) return (leaderboard, position[0], position[1])
@classmethod @classmethod
def get_hat_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit): def get_hat_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit):
leaderboard = db.query(User, func.count(lb_criteria)).join(lb_criteria).group_by(User).order_by(func.count(lb_criteria).desc()) leaderboard = db.query(User, func.count(lb_criteria)).join(lb_criteria).group_by(User).order_by(func.count(lb_criteria).desc())

View File

@ -13,7 +13,7 @@ class SubRelationship(Base):
@declared_attr @declared_attr
def user_id(self): def user_id(self):
return Column(Integer, ForeignKey("users.id"), primary_key=True) return Column(Integer, ForeignKey("users.id"), primary_key=True)
@declared_attr @declared_attr
def sub(self): def sub(self):
return Column(String(20), ForeignKey("subs.name"), primary_key=True) return Column(String(20), ForeignKey("subs.name"), primary_key=True)
@ -28,7 +28,7 @@ class SubRelationship(Base):
def __repr__(self): def __repr__(self):
return f"<{self.__class__.__name__}(user_id={self.user_id}, sub={self.sub})>" return f"<{self.__class__.__name__}(user_id={self.user_id}, sub={self.sub})>"
class SubJoin(SubRelationship): class SubJoin(SubRelationship):
__tablename__ = "sub_joins" __tablename__ = "sub_joins"

View File

@ -145,14 +145,14 @@ class Submission(Base):
@property @property
@lazy @lazy
def is_youtube(self): def is_youtube(self):
return self.domain == "youtube.com" and self.embed_url and self.embed_url.startswith('<lite-youtube') return self.domain == "youtube.com" and self.embed_url and self.embed_url.startswith('<lite-youtube')
@property @property
@lazy @lazy
def thumb_url(self): def thumb_url(self):
if self.over_18: return f"{SITE_FULL}/i/nsfw.webp?v=1" if self.over_18: return f"{SITE_FULL}/i/nsfw.webp?v=1"
elif not self.url: return f"{SITE_FULL}/i/{SITE_NAME}/default_text.webp?v=2" elif not self.url: return f"{SITE_FULL}/i/{SITE_NAME}/default_text.webp?v=2"
elif self.thumburl: elif self.thumburl:
if self.thumburl.startswith('/'): return SITE_FULL + self.thumburl if self.thumburl.startswith('/'): return SITE_FULL + self.thumburl
return self.thumburl return self.thumburl
elif self.is_youtube or self.is_video: return f"{SITE_FULL}/i/default_thumb_video.webp?v=2" elif self.is_youtube or self.is_video: return f"{SITE_FULL}/i/default_thumb_video.webp?v=2"
@ -171,7 +171,7 @@ class Submission(Base):
'title': self.title, 'title': self.title,
'permalink': self.permalink, 'permalink': self.permalink,
} }
if self.deleted_utc: if self.deleted_utc:
return {'is_banned': bool(self.is_banned), return {'is_banned': bool(self.is_banned),
'deleted_utc': True, 'deleted_utc': True,
@ -240,7 +240,7 @@ class Submission(Base):
url = normalize_urls_runtime(url, v) url = normalize_urls_runtime(url, v)
if url.startswith("https://old.reddit.com/r/") and '/comments/' in url and "sort=" not in url: if url.startswith("https://old.reddit.com/r/") and '/comments/' in url and "sort=" not in url:
if "?" in url: url += "&context=9" if "?" in url: url += "&context=9"
else: url += "?context=8" else: url += "?context=8"
if not v or v.controversial: url += "&sort=controversial" if not v or v.controversial: url += "&sort=controversial"
elif url.startswith("https://watchpeopledie.tv/videos/"): elif url.startswith("https://watchpeopledie.tv/videos/"):
@ -249,7 +249,7 @@ class Submission(Base):
"https://videos.watchpeopledie.tv/", 1) "https://videos.watchpeopledie.tv/", 1)
return url return url
@lazy @lazy
def total_bet_voted(self, v): def total_bet_voted(self, v):
if "closed" in self.body.lower(): return True if "closed" in self.body.lower(): return True
@ -297,7 +297,7 @@ class Submission(Base):
if o.exclusive == 3: if o.exclusive == 3:
body += " - <b>WINNER!</b>" body += " - <b>WINNER!</b>"
if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']: if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']:
body += f'''<button class="btn btn-primary distribute" data-areyousure="postToastReload(this,'/distribute/{o.id}')" data-nonce="{{g.nonce}}" data-onclick="areyousure(this)">Declare winner</button>''' body += f'''<button class="btn btn-primary distribute" data-areyousure="postToastReload(this,'/distribute/{o.id}')" data-nonce="{{g.nonce}}" data-onclick="areyousure(this)">Declare winner</button>'''
body += "</div>" body += "</div>"
@ -314,7 +314,7 @@ class Submission(Base):
body += f''' data-nonce="{{g.nonce}}" data-onclick="poll_vote_no_v()"''' body += f''' data-nonce="{{g.nonce}}" data-onclick="poll_vote_no_v()"'''
body += f'''><label class="custom-control-label" for="post-{o.id}">{o.body_html}<span class="presult-{self.id}''' body += f'''><label class="custom-control-label" for="post-{o.id}">{o.body_html}<span class="presult-{self.id}'''
if not self.total_poll_voted(v): body += ' d-none' if not self.total_poll_voted(v): body += ' d-none'
body += f'"> - <a href="/votes/post/option/{o.id}"><span id="score-post-{o.id}">{o.upvotes}</span> votes</a></label></div>''' body += f'"> - <a href="/votes/post/option/{o.id}"><span id="score-post-{o.id}">{o.upvotes}</span> votes</a></label></div>'''

View File

@ -204,7 +204,7 @@ class User(Base):
g.db.query(User).filter(User.id == self.id).update({ User.marseybux: User.marseybux + amount }) g.db.query(User).filter(User.id == self.id).update({ User.marseybux: User.marseybux + amount })
g.db.flush() g.db.flush()
def charge_account(self, currency, amount, **kwargs): def charge_account(self, currency, amount, **kwargs):
in_db = g.db.query(User).filter(User.id == self.id).with_for_update().one() in_db = g.db.query(User).filter(User.id == self.id).with_for_update().one()
@ -214,19 +214,19 @@ class User(Base):
if currency == 'coins': if currency == 'coins':
account_balance = in_db.coins account_balance = in_db.coins
if not should_check_balance or account_balance >= amount: if not should_check_balance or account_balance >= amount:
g.db.query(User).filter(User.id == self.id).update({ User.coins: User.coins - amount }) g.db.query(User).filter(User.id == self.id).update({ User.coins: User.coins - amount })
succeeded = True succeeded = True
elif currency == 'marseybux': elif currency == 'marseybux':
account_balance = in_db.marseybux account_balance = in_db.marseybux
if not should_check_balance or account_balance >= amount: if not should_check_balance or account_balance >= amount:
g.db.query(User).filter(User.id == self.id).update({ User.marseybux: User.marseybux - amount }) g.db.query(User).filter(User.id == self.id).update({ User.marseybux: User.marseybux - amount })
succeeded = True succeeded = True
if succeeded: g.db.flush() if succeeded: g.db.flush()
return succeeded return succeeded
@property @property
@ -417,7 +417,7 @@ class User(Base):
if badge in owned_badges: discount -= discounts[badge] if badge in owned_badges: discount -= discounts[badge]
return discount return discount
@property @property
@lazy @lazy
def can_view_offsitementions(self): def can_view_offsitementions(self):
@ -586,14 +586,14 @@ class User(Base):
Notification.user_id == self.id, Notification.user_id == self.id,
not_(and_(Comment.sentto != None, Comment.sentto == MODMAIL_ID, User.is_muted)), not_(and_(Comment.sentto != None, Comment.sentto == MODMAIL_ID, User.is_muted)),
)) ))
if not self.can_see_shadowbanned: if not self.can_see_shadowbanned:
notifs = notifs.filter( notifs = notifs.filter(
User.shadowbanned == None, User.shadowbanned == None,
Comment.is_banned == False, Comment.is_banned == False,
Comment.deleted_utc == 0, Comment.deleted_utc == 0,
) )
return notifs.count() + self.post_notifications_count + self.modaction_notifications_count + self.reddit_notifications_count return notifs.count() + self.post_notifications_count + self.modaction_notifications_count + self.reddit_notifications_count
@property @property
@ -603,7 +603,7 @@ class User(Base):
- self.message_notifications_count \ - self.message_notifications_count \
- self.post_notifications_count \ - self.post_notifications_count \
- self.modaction_notifications_count \ - self.modaction_notifications_count \
- self.reddit_notifications_count - self.reddit_notifications_count
@property @property
@lazy @lazy
@ -659,7 +659,7 @@ class User(Base):
SubAction.user_id != self.id, SubAction.user_id != self.id,
SubAction.sub.in_(self.moderated_subs), SubAction.sub.in_(self.moderated_subs),
).count() ).count()
return 0 return 0
@ -669,8 +669,8 @@ class User(Base):
if not self.can_view_offsitementions or self.id == AEVANN_ID: return 0 if not self.can_view_offsitementions or self.id == AEVANN_ID: return 0
return g.db.query(Comment).filter( return g.db.query(Comment).filter(
Comment.created_utc > self.last_viewed_reddit_notifs, Comment.created_utc > self.last_viewed_reddit_notifs,
Comment.is_banned == False, Comment.deleted_utc == 0, Comment.is_banned == False, Comment.deleted_utc == 0,
Comment.body_html.like('%<p>New site mention%<a href="https://old.reddit.com/r/%'), Comment.body_html.like('%<p>New site mention%<a href="https://old.reddit.com/r/%'),
Comment.parent_submission == None, Comment.author_id == AUTOJANNY_ID).count() Comment.parent_submission == None, Comment.author_id == AUTOJANNY_ID).count()
@property @property
@ -730,7 +730,7 @@ class User(Base):
def has_follower(self, user): def has_follower(self, user):
if not user or self.id == user.id: return False # users can't follow themselves if not user or self.id == user.id: return False # users can't follow themselves
return g.db.query(Follow).filter_by(target_id=self.id, user_id=user.id).one_or_none() return g.db.query(Follow).filter_by(target_id=self.id, user_id=user.id).one_or_none()
@lazy @lazy
def is_visible_to(self, user) -> bool: def is_visible_to(self, user) -> bool:
if not self.is_private: return True if not self.is_private: return True
@ -752,7 +752,7 @@ class User(Base):
return f"{SITE_FULL}/e/chudsey.webp" return f"{SITE_FULL}/e/chudsey.webp"
if self.rainbow: if self.rainbow:
return f"{SITE_FULL}/e/marseysalutepride.webp" return f"{SITE_FULL}/e/marseysalutepride.webp"
if self.profileurl: if self.profileurl:
if self.profileurl.startswith('/'): return SITE_FULL + self.profileurl if self.profileurl.startswith('/'): return SITE_FULL + self.profileurl
return self.profileurl return self.profileurl
return f"{SITE_FULL}/i/default-profile-pic.webp?v=1008" return f"{SITE_FULL}/i/default-profile-pic.webp?v=1008"
@ -927,7 +927,7 @@ class User(Base):
if self.patron == 6: if self.patron == 6:
return 'Contributed at least $200' return 'Contributed at least $200'
return '' return ''
@classmethod @classmethod
def can_see_content(cls, user:Optional["User"], other:Union[Submission, Comment, Sub]) -> bool: def can_see_content(cls, user:Optional["User"], other:Union[Submission, Comment, Sub]) -> bool:
''' '''

View File

@ -35,7 +35,7 @@ def _archiveorg(url):
except: pass except: pass
def archive_url(url): def archive_url(url):
gevent.spawn(_archiveorg, url) gevent.spawn(_archiveorg, url)
if url.startswith('https://twitter.com/'): if url.startswith('https://twitter.com/'):
url = url.replace('https://twitter.com/', 'https://nitter.lacontrevoie.fr/') url = url.replace('https://twitter.com/', 'https://nitter.lacontrevoie.fr/')
@ -64,7 +64,7 @@ def execute_snappy(post:Submission, v:User):
if SNAPPY_MARSEYS and SNAPPY_QUOTES: if SNAPPY_MARSEYS and SNAPPY_QUOTES:
if IS_FISTMAS() or random.random() > 0.5: if IS_FISTMAS() or random.random() > 0.5:
SNAPPY_CHOICES = SNAPPY_QUOTES SNAPPY_CHOICES = SNAPPY_QUOTES
else: else:
SNAPPY_CHOICES = SNAPPY_MARSEYS SNAPPY_CHOICES = SNAPPY_MARSEYS
elif SNAPPY_MARSEYS: SNAPPY_CHOICES = SNAPPY_MARSEYS elif SNAPPY_MARSEYS: SNAPPY_CHOICES = SNAPPY_MARSEYS
elif SNAPPY_QUOTES: SNAPPY_CHOICES = SNAPPY_QUOTES elif SNAPPY_QUOTES: SNAPPY_CHOICES = SNAPPY_QUOTES
@ -350,7 +350,7 @@ def execute_blackjack_custom(v, target, body, type):
def execute_blackjack(v, target, body, type): def execute_blackjack(v, target, body, type):
if not execute_blackjack_custom(v, target, body, type): if not execute_blackjack_custom(v, target, body, type):
return False return False
if not body: return True if not body: return True
execute = False execute = False
@ -510,8 +510,8 @@ def execute_lawlz_actions(v:User, p:Submission):
g.db.add(ma_2) g.db.add(ma_2)
g.db.add(ma_3) g.db.add(ma_3)
def process_poll_options(target:Union[Submission, Comment], def process_poll_options(target:Union[Submission, Comment],
cls:Union[Type[SubmissionOption], Type[CommentOption]], cls:Union[Type[SubmissionOption], Type[CommentOption]],
options:Iterable[str], exclusive:int, friendly_name:str, options:Iterable[str], exclusive:int, friendly_name:str,
db:scoped_session) -> None: db:scoped_session) -> None:
for option in options: for option in options:

View File

@ -66,7 +66,7 @@ def notif_comment2(p):
search_html = f'%</a> has mentioned you: <a href="/post/{p.id}">%' search_html = f'%</a> has mentioned you: <a href="/post/{p.id}">%'
existing = g.db.query(Comment.id).filter(Comment.author_id == AUTOJANNY_ID, Comment.parent_submission == None, Comment.body_html.like(search_html)).first() existing = g.db.query(Comment.id).filter(Comment.author_id == AUTOJANNY_ID, Comment.parent_submission == None, Comment.body_html.like(search_html)).first()
if existing: return existing[0] if existing: return existing[0]
else: else:
text = f"@{p.author.username} has mentioned you: [{p.title}](/post/{p.id})" text = f"@{p.author.username} has mentioned you: [{p.title}](/post/{p.id})"

View File

@ -85,7 +85,7 @@ CASINO_RELEASE_DAY = 1662825600
AJ_REPLACEMENTS = { AJ_REPLACEMENTS = {
' your ': " you're ", ' your ': " you're ",
' to ': " too ", ' to ': " too ",
' Your ': " You're ", ' Your ': " You're ",
' To ': " Too ", ' To ': " Too ",
@ -986,7 +986,7 @@ forced_hats = {
"earlylife": ("The Merchant", "SHUT IT DOWN, the goys know!"), "earlylife": ("The Merchant", "SHUT IT DOWN, the goys know!"),
"marsify": ("Marsified", "I can't pick my own Marseys, help!"), "marsify": ("Marsified", "I can't pick my own Marseys, help!"),
"is_suspended": ("Behind Bars", "This user is banned and needs to do better!"), "is_suspended": ("Behind Bars", "This user is banned and needs to do better!"),
"agendaposter": (("Egg_irl", "This user is getting in touch with xir identity!"), "agendaposter": (("Egg_irl", "This user is getting in touch with xir identity!"),
("Trans Flag", "Just in case you forgot, trans lives matter."), ("Trans Flag", "Just in case you forgot, trans lives matter."),
("Trans Flag II", "Your egg is cracked; wear it with pride!"), ("Trans Flag II", "Your egg is cracked; wear it with pride!"),
("Pride Flag", "Never forget that this is a primarily gay community. Dude bussy lmao."), ("Pride Flag", "Never forget that this is a primarily gay community. Dude bussy lmao."),

View File

@ -2,78 +2,78 @@ from copy import deepcopy
MODACTION_TYPES = { MODACTION_TYPES = {
'chud': { 'chud': {
"str": 'chudded {self.target_link}', "str": 'chudded {self.target_link}',
"icon": 'fa-snooze', "icon": 'fa-snooze',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'approve_app': { 'approve_app': {
"str": 'approved an application by {self.target_link}', "str": 'approved an application by {self.target_link}',
"icon": 'fa-robot', "icon": 'fa-robot',
"color": 'bg-success' "color": 'bg-success'
}, },
'badge_grant': { 'badge_grant': {
"str": 'granted badge to {self.target_link}', "str": 'granted badge to {self.target_link}',
"icon": 'fa-badge', "icon": 'fa-badge',
"color": 'bg-success' "color": 'bg-success'
}, },
'badge_remove': { 'badge_remove': {
"str": 'removed badge from {self.target_link}', "str": 'removed badge from {self.target_link}',
"icon": 'fa-badge', "icon": 'fa-badge',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'ban_comment': { 'ban_comment': {
"str": 'removed {self.target_link}', "str": 'removed {self.target_link}',
"icon": 'fa-comment', "icon": 'fa-comment',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'ban_domain': { 'ban_domain': {
"str": 'banned a domain', "str": 'banned a domain',
"icon": 'fa-globe', "icon": 'fa-globe',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'ban_post': { 'ban_post': {
"str": 'removed post {self.target_link}', "str": 'removed post {self.target_link}',
"icon": 'fa-feather-alt', "icon": 'fa-feather-alt',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'ban_user': { 'ban_user': {
"str": 'banned user {self.target_link}', "str": 'banned user {self.target_link}',
"icon": 'fa-user-slash', "icon": 'fa-user-slash',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'delete_report': { 'delete_report': {
"str": 'deleted report on {self.target_link}', "str": 'deleted report on {self.target_link}',
"icon": 'fa-flag', "icon": 'fa-flag',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'disable_bots': { 'disable_bots': {
"str": 'disabled bots', "str": 'disabled bots',
"icon": 'fa-robot', "icon": 'fa-robot',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'disable_fart_mode': { 'disable_fart_mode': {
"str": 'disabled fart mode', "str": 'disabled fart mode',
"icon": 'fa-gas-pump-slash', "icon": 'fa-gas-pump-slash',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'disable_read_only_mode': { 'disable_read_only_mode': {
"str": 'disabled read only mode', "str": 'disabled read only mode',
"icon": 'fa-book', "icon": 'fa-book',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'disable_signups': { 'disable_signups': {
"str": 'disabled signups', "str": 'disabled signups',
"icon": 'fa-users', "icon": 'fa-users',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'disable_login_required': { 'disable_login_required': {
"str": 'disabled login required', "str": 'disabled login required',
"icon": 'fa-users', "icon": 'fa-users',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'disable_under_attack': { 'disable_under_attack': {
"str": 'disabled under attack mode', "str": 'disabled under attack mode',
"icon": 'fa-shield', "icon": 'fa-shield',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'disable_under_siege': { 'disable_under_siege': {
@ -82,58 +82,58 @@ MODACTION_TYPES = {
"color": 'bg-muted' "color": 'bg-muted'
}, },
'distinguish_comment': { 'distinguish_comment': {
"str": 'distinguished {self.target_link}', "str": 'distinguished {self.target_link}',
"icon": 'fa-crown', "icon": 'fa-crown',
"color": 'bg-success' "color": 'bg-success'
}, },
'distinguish_post': { 'distinguish_post': {
"str": 'distinguished {self.target_link}', "str": 'distinguished {self.target_link}',
"icon": 'fa-crown', "icon": 'fa-crown',
"color": 'bg-success' "color": 'bg-success'
}, },
'distribute': { 'distribute': {
"str": 'distributed bet winnings to voters on {self.target_link}', "str": 'distributed bet winnings to voters on {self.target_link}',
"icon": 'fa-dollar-sign', "icon": 'fa-dollar-sign',
"color": 'bg-success' "color": 'bg-success'
}, },
'edit_post': { 'edit_post': {
"str": 'edited {self.target_link}', "str": 'edited {self.target_link}',
"icon": 'fa-edit', "icon": 'fa-edit',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'edit_rules': { 'edit_rules': {
"str": 'edited the rules', "str": 'edited the rules',
"icon": 'fa-columns', "icon": 'fa-columns',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'enable_bots': { 'enable_bots': {
"str": 'enabled bots', "str": 'enabled bots',
"icon": 'fa-robot', "icon": 'fa-robot',
"color": 'bg-success' "color": 'bg-success'
}, },
'enable_fart_mode': { 'enable_fart_mode': {
"str": 'enabled fart mode', "str": 'enabled fart mode',
"icon": 'fa-gas-pump', "icon": 'fa-gas-pump',
"color": 'bg-success' "color": 'bg-success'
}, },
'enable_read_only_mode': { 'enable_read_only_mode': {
"str": 'enabled read only mode', "str": 'enabled read only mode',
"icon": 'fa-book', "icon": 'fa-book',
"color": 'bg-success' "color": 'bg-success'
}, },
'enable_signups': { 'enable_signups': {
"str": 'enabled signups', "str": 'enabled signups',
"icon": 'fa-users', "icon": 'fa-users',
"color": 'bg-success' "color": 'bg-success'
}, },
'enable_login_required': { 'enable_login_required': {
"str": 'enabled login required', "str": 'enabled login required',
"icon": 'fa-users', "icon": 'fa-users',
"color": 'bg-success' "color": 'bg-success'
}, },
'enable_under_attack': { 'enable_under_attack': {
"str": 'enabled under attack mode', "str": 'enabled under attack mode',
"icon": 'fa-shield', "icon": 'fa-shield',
"color": 'bg-success' "color": 'bg-success'
}, },
'enable_under_siege': { 'enable_under_siege': {
@ -142,13 +142,13 @@ MODACTION_TYPES = {
"color": 'bg-success', "color": 'bg-success',
}, },
'flair_post': { 'flair_post': {
"str": 'set a flair on {self.target_link}', "str": 'set a flair on {self.target_link}',
"icon": 'fa-tag', "icon": 'fa-tag',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'link_accounts': { 'link_accounts': {
"str": 'linked {self.target_link}', "str": 'linked {self.target_link}',
"icon": 'fa-link', "icon": 'fa-link',
"color": 'bg-success' "color": 'bg-success'
}, },
'delink_accounts': { 'delink_accounts': {
@ -157,8 +157,8 @@ MODACTION_TYPES = {
"color": 'bg-danger' "color": 'bg-danger'
}, },
'make_admin': { 'make_admin': {
"str": 'made {self.target_link} an admin', "str": 'made {self.target_link} an admin',
"icon": 'fa-user-crown', "icon": 'fa-user-crown',
"color": 'bg-success' "color": 'bg-success'
}, },
'mod_mute_user': { 'mod_mute_user': {
@ -172,169 +172,169 @@ MODACTION_TYPES = {
"color": 'bg-success' "color": 'bg-success'
}, },
'monthly': { 'monthly': {
"str": 'distributed monthly marseybux', "str": 'distributed monthly marseybux',
"icon": 'fa-sack-dollar', "icon": 'fa-sack-dollar',
"color": 'bg-success' "color": 'bg-success'
}, },
'move_hole': { 'move_hole': {
"str": 'changed hole of {self.target_link}', "str": 'changed hole of {self.target_link}',
"icon": 'fa-manhole', "icon": 'fa-manhole',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'nuke_user': { 'nuke_user': {
"str": 'removed all content of {self.target_link}', "str": 'removed all content of {self.target_link}',
"icon": 'fa-radiation-alt', "icon": 'fa-radiation-alt',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'pin_comment': { 'pin_comment': {
"str": 'pinned {self.target_link}', "str": 'pinned {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-success' "color": 'bg-success'
}, },
'pin_post': { 'pin_post': {
"str": 'pinned post {self.target_link}', "str": 'pinned post {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-success' "color": 'bg-success'
}, },
'clear_cloudflare_cache': { 'clear_cloudflare_cache': {
"str": 'cleared cloudflare cache', "str": 'cleared cloudflare cache',
"icon": 'fab fa-cloudflare', "icon": 'fab fa-cloudflare',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'reject_app': { 'reject_app': {
"str": 'rejected an application request by {self.target_link}', "str": 'rejected an application request by {self.target_link}',
"icon": 'fa-robot', "icon": 'fa-robot',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'remove_admin': { 'remove_admin': {
"str": 'removed {self.target_link} as admin', "str": 'removed {self.target_link} as admin',
"icon": 'fa-user-crown', "icon": 'fa-user-crown',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'revert': { 'revert': {
"str": 'reverted {self.target_link} mod actions', "str": 'reverted {self.target_link} mod actions',
"icon": 'fa-history', "icon": 'fa-history',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'revoke_app': { 'revoke_app': {
"str": 'revoked an application by {self.target_link}', "str": 'revoked an application by {self.target_link}',
"icon": 'fa-robot', "icon": 'fa-robot',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'set_flair_locked': { 'set_flair_locked': {
"str": "set {self.target_link}'s flair (locked)", "str": "set {self.target_link}'s flair (locked)",
"icon": 'fa-award', "icon": 'fa-award',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'set_flair_notlocked': { 'set_flair_notlocked': {
"str": "set {self.target_link}'s flair (not locked)", "str": "set {self.target_link}'s flair (not locked)",
"icon": 'fa-award', "icon": 'fa-award',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'set_new': { 'set_new': {
"str": 'changed the default sorting of comments on {self.target_link} to `new`', "str": 'changed the default sorting of comments on {self.target_link} to `new`',
"icon": 'fa-sparkles', "icon": 'fa-sparkles',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'set_hot': { 'set_hot': {
"str": 'changed the default sorting of comments on {self.target_link} to `hot`', "str": 'changed the default sorting of comments on {self.target_link} to `hot`',
"icon": 'fa-fire', "icon": 'fa-fire',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'set_nsfw': { 'set_nsfw': {
"str": 'set {self.target_link} as +18', "str": 'set {self.target_link} as +18',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'set_nsfw_comment': { 'set_nsfw_comment': {
"str": 'set {self.target_link} as +18', "str": 'set {self.target_link} as +18',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'shadowban': { 'shadowban': {
"str": 'shadowbanned {self.target_link}', "str": 'shadowbanned {self.target_link}',
"icon": 'fa-eye-slash', "icon": 'fa-eye-slash',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'unchud': { 'unchud': {
"str": 'unchudded {self.target_link}', "str": 'unchudded {self.target_link}',
"icon": 'fa-snooze', "icon": 'fa-snooze',
"color": 'bg-success' "color": 'bg-success'
}, },
'unban_comment': { 'unban_comment': {
"str": 'reinstated {self.target_link}', "str": 'reinstated {self.target_link}',
"icon": 'fa-comment', "icon": 'fa-comment',
"color": 'bg-success' "color": 'bg-success'
}, },
'unban_domain': { 'unban_domain': {
"str": 'unbanned a domain', "str": 'unbanned a domain',
"icon": 'fa-globe', "icon": 'fa-globe',
"color": 'bg-success' "color": 'bg-success'
}, },
'unban_post': { 'unban_post': {
"str": 'reinstated post {self.target_link}', "str": 'reinstated post {self.target_link}',
"icon": 'fa-feather-alt', "icon": 'fa-feather-alt',
"color": 'bg-success' "color": 'bg-success'
}, },
'unban_user': { 'unban_user': {
"str": 'unbanned user {self.target_link}', "str": 'unbanned user {self.target_link}',
"icon": 'fa-user', "icon": 'fa-user',
"color": 'bg-success' "color": 'bg-success'
}, },
'undistinguish_comment': { 'undistinguish_comment': {
"str": 'un-distinguished {self.target_link}', "str": 'un-distinguished {self.target_link}',
"icon": 'fa-crown', "icon": 'fa-crown',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'undistinguish_post': { 'undistinguish_post': {
"str": 'un-distinguished {self.target_link}', "str": 'un-distinguished {self.target_link}',
"icon": 'fa-crown', "icon": 'fa-crown',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'unnuke_user': { 'unnuke_user': {
"str": 'approved all content of {self.target_link}', "str": 'approved all content of {self.target_link}',
"icon": 'fa-radiation-alt', "icon": 'fa-radiation-alt',
"color": 'bg-success' "color": 'bg-success'
}, },
'unpin_comment': { 'unpin_comment': {
"str": 'unpinned {self.target_link}', "str": 'unpinned {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'unpin_post': { 'unpin_post': {
"str": 'unpinned post {self.target_link}', "str": 'unpinned post {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'unset_nsfw': { 'unset_nsfw': {
"str": 'unset {self.target_link} as +18', "str": 'unset {self.target_link} as +18',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-success' "color": 'bg-success'
}, },
'unset_nsfw_comment': { 'unset_nsfw_comment': {
"str": 'unset {self.target_link} as +18', "str": 'unset {self.target_link} as +18',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-success' "color": 'bg-success'
}, },
'unshadowban': { 'unshadowban': {
"str": 'unshadowbanned {self.target_link}', "str": 'unshadowbanned {self.target_link}',
"icon": 'fa-eye', "icon": 'fa-eye',
"color": 'bg-success' "color": 'bg-success'
}, },
'update_hat': { 'update_hat': {
"str": 'updated hat image', "str": 'updated hat image',
"icon": 'fa-hat-cowboy', "icon": 'fa-hat-cowboy',
"color": 'bg-success' "color": 'bg-success'
}, },
'update_marsey': { 'update_marsey': {
"str": 'updated marsey', "str": 'updated marsey',
"icon": 'fa-cat', "icon": 'fa-cat',
"color": 'bg-success' "color": 'bg-success'
}, },
} }
MODACTION_PRIVILEGED_TYPES = {'shadowban', 'unshadowban', MODACTION_PRIVILEGED_TYPES = {'shadowban', 'unshadowban',
'mod_mute_user', 'mod_unmute_user', 'mod_mute_user', 'mod_unmute_user',
'link_accounts', 'delink_accounts'} 'link_accounts', 'delink_accounts'}
MODACTION_TYPES_FILTERED = deepcopy({t:v for t,v in MODACTION_TYPES.items() MODACTION_TYPES_FILTERED = deepcopy({t:v for t,v in MODACTION_TYPES.items()
if not t in MODACTION_PRIVILEGED_TYPES}) if not t in MODACTION_PRIVILEGED_TYPES})

View File

@ -1,52 +1,52 @@
SUBACTION_TYPES = { SUBACTION_TYPES = {
'exile_user': { 'exile_user': {
"str": 'exiled user {self.target_link}', "str": 'exiled user {self.target_link}',
"icon": 'fa-user-slash', "icon": 'fa-user-slash',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'unexile_user': { 'unexile_user': {
"str": 'unexiled user {self.target_link}', "str": 'unexiled user {self.target_link}',
"icon": 'fa-user', "icon": 'fa-user',
"color": 'bg-success' "color": 'bg-success'
}, },
'make_mod': { 'make_mod': {
"str": 'made {self.target_link} a mod', "str": 'made {self.target_link} a mod',
"icon": 'fa-user-crown', "icon": 'fa-user-crown',
"color": 'bg-success' "color": 'bg-success'
}, },
'remove_mod': { 'remove_mod': {
"str": 'removed {self.target_link} as mod', "str": 'removed {self.target_link} as mod',
"icon": 'fa-user-crown', "icon": 'fa-user-crown',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'kick_post': { 'kick_post': {
"str": 'kicked post {self.target_link}', "str": 'kicked post {self.target_link}',
"icon": 'fa-feather-alt', "icon": 'fa-feather-alt',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'move_chudrama': { 'move_chudrama': {
"str": 'moved post {self.target_link} to <a href="/h/chudrama">/h/chudrama</a>', "str": 'moved post {self.target_link} to <a href="/h/chudrama">/h/chudrama</a>',
"icon": 'fa-feather-alt', "icon": 'fa-feather-alt',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'flair_post': { 'flair_post': {
"str": 'set a flair on {self.target_link}', "str": 'set a flair on {self.target_link}',
"icon": 'fa-tag', "icon": 'fa-tag',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'edit_sidebar': { 'edit_sidebar': {
"str": 'edited the sidebar', "str": 'edited the sidebar',
"icon": 'fa-columns', "icon": 'fa-columns',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'edit_css': { 'edit_css': {
"str": 'edited the css', "str": 'edited the css',
"icon": 'fa-css3-alt', "icon": 'fa-css3-alt',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'upload_banner': { 'upload_banner': {
"str": 'uploaded a banner', "str": 'uploaded a banner',
"icon": 'fa-landscape', "icon": 'fa-landscape',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'delete_banner': { 'delete_banner': {
@ -55,63 +55,63 @@ SUBACTION_TYPES = {
"color": 'bg-danger', "color": 'bg-danger',
}, },
'change_sidebar_image': { 'change_sidebar_image': {
"str": 'changed the sidebar image', "str": 'changed the sidebar image',
"icon": 'fa-image', "icon": 'fa-image',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'change_marsey': { 'change_marsey': {
"str": 'changed the hole marsey', "str": 'changed the hole marsey',
"icon": 'fa-cat', "icon": 'fa-cat',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'pin_post': { 'pin_post': {
"str": 'pinned post {self.target_link}', "str": 'pinned post {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-success' "color": 'bg-success'
}, },
'unpin_post': { 'unpin_post': {
"str": 'unpinned post {self.target_link}', "str": 'unpinned post {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'pin_comment': { 'pin_comment': {
"str": 'pinned {self.target_link}', "str": 'pinned {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-success' "color": 'bg-success'
}, },
'unpin_comment': { 'unpin_comment': {
"str": 'unpinned {self.target_link}', "str": 'unpinned {self.target_link}',
"icon": 'fa-thumbtack fa-rotate--45', "icon": 'fa-thumbtack fa-rotate--45',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'enable_stealth': { 'enable_stealth': {
"str": 'enabled stealth mode', "str": 'enabled stealth mode',
"icon": 'fa-user-ninja', "icon": 'fa-user-ninja',
"color": 'bg-primary' "color": 'bg-primary'
}, },
'disable_stealth': { 'disable_stealth': {
"str": 'disabled stealth mode', "str": 'disabled stealth mode',
"icon": 'fa-user-ninja', "icon": 'fa-user-ninja',
"color": 'bg-muted' "color": 'bg-muted'
}, },
'set_nsfw': { 'set_nsfw': {
"str": 'set nsfw on post {self.target_link}', "str": 'set nsfw on post {self.target_link}',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'unset_nsfw': { 'unset_nsfw': {
"str": 'un-set nsfw on post {self.target_link}', "str": 'un-set nsfw on post {self.target_link}',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-success' "color": 'bg-success'
}, },
'set_nsfw_comment': { 'set_nsfw_comment': {
"str": 'set nsfw on a {self.target_link}', "str": 'set nsfw on a {self.target_link}',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-danger' "color": 'bg-danger'
}, },
'unset_nsfw_comment': { 'unset_nsfw_comment': {
"str": 'un-set nsfw on a {self.target_link}', "str": 'un-set nsfw on a {self.target_link}',
"icon": 'fa-eye-evil', "icon": 'fa-eye-evil',
"color": 'bg-success' "color": 'bg-success'
}, },
} }

View File

@ -78,7 +78,7 @@ def get_users(usernames:Iterable[str], graceful=False) -> List[User]:
return users return users
def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]: def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]:
try: try:
id = int(id) id = int(id)
except: except:
if graceful: return None if graceful: return None
@ -97,7 +97,7 @@ def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, inclu
def get_accounts_dict(ids:Union[Iterable[str], Iterable[int]], v:Optional[User]=None, graceful=False, include_shadowbanned=True) -> Optional[dict[int, User]]: def get_accounts_dict(ids:Union[Iterable[str], Iterable[int]], v:Optional[User]=None, graceful=False, include_shadowbanned=True) -> Optional[dict[int, User]]:
if not ids: return {} if not ids: return {}
try: try:
ids = set([int(id) for id in ids]) ids = set([int(id) for id in ids])
except: except:
if graceful: return None if graceful: return None
@ -132,15 +132,15 @@ def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Option
post=post.filter(Submission.id == i post=post.filter(Submission.id == i
).outerjoin( ).outerjoin(
vt, vt,
vt.c.submission_id == Submission.id, vt.c.submission_id == Submission.id,
).outerjoin( ).outerjoin(
blocking, blocking,
blocking.c.target_id == Submission.author_id, blocking.c.target_id == Submission.author_id,
) )
post=post.one_or_none() post=post.one_or_none()
if not post: if not post:
if graceful: return None if graceful: return None
else: abort(404) else: abort(404)
@ -163,7 +163,7 @@ def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False, extra
if v: if v:
vt = g.db.query(Vote.vote_type, Vote.submission_id).filter( vt = g.db.query(Vote.vote_type, Vote.submission_id).filter(
Vote.submission_id.in_(pids), Vote.submission_id.in_(pids),
Vote.user_id==v.id Vote.user_id==v.id
).subquery() ).subquery()
@ -180,11 +180,11 @@ def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False, extra
).outerjoin( ).outerjoin(
vt, vt.c.submission_id==Submission.id vt, vt.c.submission_id==Submission.id
).outerjoin( ).outerjoin(
blocking, blocking,
blocking.c.target_id == Submission.author_id, blocking.c.target_id == Submission.author_id,
).outerjoin( ).outerjoin(
blocked, blocked,
blocked.c.user_id == Submission.author_id, blocked.c.user_id == Submission.author_id,
) )
else: else:
query = g.db.query(Submission).filter(Submission.id.in_(pids)) query = g.db.query(Submission).filter(Submission.id.in_(pids))
@ -245,7 +245,7 @@ def add_block_props(target:Union[Submission, Comment, User], v:Optional[User]):
id = target.id id = target.id
else: else:
raise TypeError("add_block_props only supports non-None submissions, comments, and users") raise TypeError("add_block_props only supports non-None submissions, comments, and users")
if hasattr(target, 'is_blocking') and hasattr(target, 'is_blocked'): if hasattr(target, 'is_blocking') and hasattr(target, 'is_blocked'):
return target return target

View File

@ -57,7 +57,7 @@ def end_lottery_session():
chance_to_win = str(chance_to_win)[:3] chance_to_win = str(chance_to_win)[:3]
if user.id == winner: if user.id == winner:
notification_text = f'You won {active_lottery.prize} coins in the lottershe! ' \ notification_text = f'You won {active_lottery.prize} coins in the lottershe! ' \
+ f'Congratulations!\nYour odds of winning were: {chance_to_win}%' + f'Congratulations!\nYour odds of winning were: {chance_to_win}%'
else: else:
notification_text = f'You did not win the lottershe. Better luck next time!\n' \ notification_text = f'You did not win the lottershe. Better luck next time!\n' \
+ f'Your odds of winning were: {chance_to_win}%\nWinner: @{winning_user.username} (won {active_lottery.prize} coins)' + f'Your odds of winning were: {chance_to_win}%\nWinner: @{winning_user.username} (won {active_lottery.prize} coins)'

View File

@ -16,8 +16,8 @@ from files.classes.notifications import Notification
# Note: while https://api.pushshift.io/meta provides the key # Note: while https://api.pushshift.io/meta provides the key
# server_ratelimit_per_minute, in practice Cloudflare puts stricter, # server_ratelimit_per_minute, in practice Cloudflare puts stricter,
# unofficially documented limits at around 60/minute. We get nowhere near this # unofficially documented limits at around 60/minute. We get nowhere near this
# with current keyword quantities. If this ever changes, consider reading the # with current keyword quantities. If this ever changes, consider reading the
# value from /meta (or just guessing) and doing a random selection of keywords. # value from /meta (or just guessing) and doing a random selection of keywords.
def offsite_mentions_task(cache:Cache): def offsite_mentions_task(cache:Cache):
@ -83,7 +83,7 @@ def get_mentions(cache:Cache, queries:Iterable[str], reddit_notifs_users=False):
'text': text, 'text': text,
}) })
try: try:
if not reddit_notifs_users: if not reddit_notifs_users:
cache.set(const.REDDIT_NOTIFS_CACHE_KEY, after + 1) cache.set(const.REDDIT_NOTIFS_CACHE_KEY, after + 1)
except: except:
print("Failed to set cache value; there may be duplication of reddit notifications", flush=True) print("Failed to set cache value; there may be duplication of reddit notifications", flush=True)

View File

@ -150,7 +150,7 @@ def censor_slurs(body:Optional[str], logged_user):
def replace_re(body:str, regex:re.Pattern, regex_upper:re.Pattern, sub_func, sub_func_upper): def replace_re(body:str, regex:re.Pattern, regex_upper:re.Pattern, sub_func, sub_func_upper):
body = regex_upper.sub(sub_func_upper, body) body = regex_upper.sub(sub_func_upper, body)
return regex.sub(sub_func, body) return regex.sub(sub_func, body)
if not logged_user or logged_user == 'chat' or logged_user.slurreplacer: if not logged_user or logged_user == 'chat' or logged_user.slurreplacer:
body = replace_re(body, slur_regex, slur_regex_upper, sub_matcher_slurs, sub_matcher_slurs_upper) body = replace_re(body, slur_regex, slur_regex_upper, sub_matcher_slurs, sub_matcher_slurs_upper)
if SITE_NAME == 'rDrama': if SITE_NAME == 'rDrama':

View File

@ -10,7 +10,7 @@ from files.helpers.alerts import *
from files.helpers.get import get_account from files.helpers.get import get_account
class RouletteAction(str, Enum): class RouletteAction(str, Enum):
STRAIGHT_UP_BET = "STRAIGHT_UP_BET", STRAIGHT_UP_BET = "STRAIGHT_UP_BET",
LINE_BET = "LINE_BET" LINE_BET = "LINE_BET"
COLUMN_BET = "COLUMN_BET" COLUMN_BET = "COLUMN_BET"
DOZEN_BET = "DOZEN_BET" DOZEN_BET = "DOZEN_BET"

View File

@ -96,7 +96,7 @@ def allowed_attributes(tag, name, value):
if tag == 'table': if tag == 'table':
if name == 'class' and value == 'table': return True if name == 'class' and value == 'table': return True
return False return False
def build_url_re(tlds, protocols): def build_url_re(tlds, protocols):

View File

@ -54,7 +54,7 @@ def casino_slot_pull(gambler, wager_value, currency):
return casino_game.id, casino_game.game_state return casino_game.id, casino_game.game_state
else: else:
return None, "{}", return None, "{}",
def build_symbols(for_payout): def build_symbols(for_payout):
@ -132,7 +132,7 @@ def check_slots_command(c:Comment, v:User, u:User):
currency = 'coins' currency = 'coins'
else: else:
return return
if u.rehab: if u.rehab:
if v.id == u.id: if v.id == u.id:
abort(403, "You are under Rehab award effect!") abort(403, "You are under Rehab award effect!")
@ -146,7 +146,7 @@ def check_slots_command(c:Comment, v:User, u:User):
abort(400, "Invalid wager.") abort(400, "Invalid wager.")
return return
if wager < 100: if wager < 100:
if v.id == u.id: if v.id == u.id:
abort(400, f"Wager must be 100 {currency} or more") abort(400, f"Wager must be 100 {currency} or more")
return return

View File

@ -38,25 +38,25 @@ def chart(kind, site):
day_cutoffs = [today_cutoff - 86400 * 7 * i for i in range(num_of_weeks)][1:] day_cutoffs = [today_cutoff - 86400 * 7 * i for i in range(num_of_weeks)][1:]
day_cutoffs.insert(0, calendar.timegm(now)) day_cutoffs.insert(0, calendar.timegm(now))
daily_times = [time.strftime('%d/%m', time.gmtime(day_cutoffs[i + 1])) daily_times = [time.strftime('%d/%m', time.gmtime(day_cutoffs[i + 1]))
for i in range(len(day_cutoffs) - 1)][::-1] for i in range(len(day_cutoffs) - 1)][::-1]
daily_signups = [g.db.query(User).filter( daily_signups = [g.db.query(User).filter(
User.created_utc < day_cutoffs[i], User.created_utc < day_cutoffs[i],
User.created_utc > day_cutoffs[i + 1]).count() User.created_utc > day_cutoffs[i + 1]).count()
for i in range(len(day_cutoffs) - 1)][::-1] for i in range(len(day_cutoffs) - 1)][::-1]
post_stats = [g.db.query(Submission).filter( post_stats = [g.db.query(Submission).filter(
Submission.created_utc < day_cutoffs[i], Submission.created_utc < day_cutoffs[i],
Submission.created_utc > day_cutoffs[i + 1], Submission.created_utc > day_cutoffs[i + 1],
Submission.is_banned == False).count() Submission.is_banned == False).count()
for i in range(len(day_cutoffs) - 1)][::-1] for i in range(len(day_cutoffs) - 1)][::-1]
comment_stats = [g.db.query(Comment).filter( comment_stats = [g.db.query(Comment).filter(
Comment.created_utc < day_cutoffs[i], Comment.created_utc < day_cutoffs[i],
Comment.created_utc > day_cutoffs[i + 1], Comment.created_utc > day_cutoffs[i + 1],
Comment.is_banned == False, Comment.is_banned == False,
Comment.author_id != AUTOJANNY_ID).count() Comment.author_id != AUTOJANNY_ID).count()
for i in range(len(day_cutoffs) - 1)][::-1] for i in range(len(day_cutoffs) - 1)][::-1]
plt.rcParams['figure.figsize'] = (chart_width, 20) plt.rcParams['figure.figsize'] = (chart_width, 20)

View File

@ -83,7 +83,7 @@ def get_active_twentyone_game_state(gambler):
def charge_gambler(gambler, amount, currency): def charge_gambler(gambler, amount, currency):
charged = gambler.charge_account(currency, amount) charged = gambler.charge_account(currency, amount)
if not charged: if not charged:
raise Exception("Gambler cannot afford charge.") raise Exception("Gambler cannot afford charge.")
@ -244,7 +244,7 @@ def handle_payout(gambler, state, game):
raise Exception("Attempted to payout a game that has not finished.") raise Exception("Attempted to payout a game that has not finished.")
gambler.pay_account(game.currency, payout) gambler.pay_account(game.currency, payout)
if game.currency == 'coins': if game.currency == 'coins':
if status in {BlackjackStatus.BLACKJACK, BlackjackStatus.WON}: if status in {BlackjackStatus.BLACKJACK, BlackjackStatus.WON}:
distribute_wager_badges(gambler, game.wager, won=True) distribute_wager_badges(gambler, game.wager, won=True)
@ -259,7 +259,7 @@ def handle_payout(gambler, state, game):
def remove_exploitable_information(state): def remove_exploitable_information(state):
safe_state = state safe_state = state
if len(safe_state['dealer']) >= 2: if len(safe_state['dealer']) >= 2:
safe_state['dealer'][1] = '?' safe_state['dealer'][1] = '?'

View File

@ -51,7 +51,7 @@ def move_acc(v:User, new_id, old_id):
old_id = int(old_id) old_id = int(old_id)
new_id = int(new_id) new_id = int(new_id)
olduser = g.db.get(User, old_id) olduser = g.db.get(User, old_id)
newuser = g.db.get(User, new_id) newuser = g.db.get(User, new_id)
@ -307,7 +307,7 @@ def distribute(v:User, option_id):
losing_voters.extend([x.user_id for x in o.votes]) losing_voters.extend([x.user_id for x in o.votes])
for uid in losing_voters: for uid in losing_voters:
add_notif(cid, uid) add_notif(cid, uid)
ma = ModAction( ma = ModAction(
kind="distribute", kind="distribute",
user_id=v.id, user_id=v.id,
@ -455,7 +455,7 @@ def admin_home(v):
if v.admin_level >= PERMS['SITE_SETTINGS_UNDER_ATTACK']: if v.admin_level >= PERMS['SITE_SETTINGS_UNDER_ATTACK']:
under_attack = (get_security_level() or 'high') == 'under_attack' under_attack = (get_security_level() or 'high') == 'under_attack'
return render_template("admin/admin_home.html", v=v, return render_template("admin/admin_home.html", v=v,
under_attack=under_attack) under_attack=under_attack)
@app.post("/admin/site_settings/<setting>") @app.post("/admin/site_settings/<setting>")
@ -575,7 +575,7 @@ def badge_grant_post(v):
if v.id != user.id: if v.id != user.id:
text = f"@{v.username} (a site admin) has given you the following profile badge:\n\n![]({new_badge.path})\n\n**{new_badge.name}**\n\n{new_badge.badge.description}" text = f"@{v.username} (a site admin) has given you the following profile badge:\n\n![]({new_badge.path})\n\n**{new_badge.name}**\n\n{new_badge.badge.description}"
send_repeatable_notification(user.id, text) send_repeatable_notification(user.id, text)
ma = ModAction( ma = ModAction(
kind="badge_grant", kind="badge_grant",
user_id=v.id, user_id=v.id,
@ -851,7 +851,7 @@ def admin_removed(v):
def admin_removed_comments(v): def admin_removed_comments(v):
try: page = int(request.values.get("page", 1)) try: page = int(request.values.get("page", 1))
except: page = 1 except: page = 1
ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all() ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
ids=[x[0] for x in ids] ids=[x[0] for x in ids]
next_exists = len(ids) > PAGE_SIZE next_exists = len(ids) > PAGE_SIZE
@ -926,7 +926,7 @@ def shadowban(user_id, v):
_note=f'reason: "{reason}"' _note=f'reason: "{reason}"'
) )
g.db.add(ma) g.db.add(ma)
cache.delete_memoized(frontlist) cache.delete_memoized(frontlist)
return {"message": f"@{user.username} has been shadowbanned!"} return {"message": f"@{user.username} has been shadowbanned!"}
@ -951,7 +951,7 @@ def unshadowban(user_id, v):
target_user_id=user.id, target_user_id=user.id,
) )
g.db.add(ma) g.db.add(ma)
cache.delete_memoized(frontlist) cache.delete_memoized(frontlist)
return {"message": f"@{user.username} has been unshadowbanned!"} return {"message": f"@{user.username} has been unshadowbanned!"}
@ -982,7 +982,7 @@ def admin_title_change(user_id, v):
if user.flairchanged: kind = "set_flair_locked" if user.flairchanged: kind = "set_flair_locked"
else: kind = "set_flair_notlocked" else: kind = "set_flair_notlocked"
ma=ModAction( ma=ModAction(
kind=kind, kind=kind,
user_id=v.id, user_id=v.id,
@ -1379,7 +1379,7 @@ def unsticky_post(post_id, v):
if post.stickied: if post.stickied:
if FEATURES['AWARDS'] and post.stickied.endswith(PIN_AWARD_TEXT): abort(403, "Can't unpin award pins!") if FEATURES['AWARDS'] and post.stickied.endswith(PIN_AWARD_TEXT): abort(403, "Can't unpin award pins!")
if post.author_id == LAWLZ_ID and post.stickied_utc and SITE_NAME == 'rDrama': abort(403, "Can't unpin lawlzposts!") if post.author_id == LAWLZ_ID and post.stickied_utc and SITE_NAME == 'rDrama': abort(403, "Can't unpin lawlzposts!")
post.stickied = None post.stickied = None
post.stickied_utc = None post.stickied_utc = None
g.db.add(post) g.db.add(post)
@ -1424,13 +1424,13 @@ def sticky_comment(cid, v):
g.db.add(c) g.db.add(c)
return {"message": "Comment pinned!"} return {"message": "Comment pinned!"}
@app.post("/unsticky_comment/<int:cid>") @app.post("/unsticky_comment/<int:cid>")
@admin_level_required(PERMS['POST_COMMENT_MODERATION']) @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def unsticky_comment(cid, v): def unsticky_comment(cid, v):
comment = get_comment(cid, v=v) comment = get_comment(cid, v=v)
if comment.stickied: if comment.stickied:
if FEATURES['AWARDS'] and comment.stickied.endswith(PIN_AWARD_TEXT): abort(403, "Can't unpin award pins!") if FEATURES['AWARDS'] and comment.stickied.endswith(PIN_AWARD_TEXT): abort(403, "Can't unpin award pins!")
@ -1481,7 +1481,7 @@ def remove_comment(c_id, v):
@admin_level_required(PERMS['POST_COMMENT_MODERATION']) @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
def approve_comment(c_id, v): def approve_comment(c_id, v):
comment = get_comment(c_id) comment = get_comment(c_id)
if comment.author.id == v.id and comment.author.agendaposter and AGENDAPOSTER_PHRASE not in comment.body.lower() and not (comment.parent_submission and comment.post.sub == 'chudrama'): if comment.author.id == v.id and comment.author.agendaposter and AGENDAPOSTER_PHRASE not in comment.body.lower() and not (comment.parent_submission and comment.post.sub == 'chudrama'):
abort(400, "You can't bypass the chud award!") abort(400, "You can't bypass the chud award!")
@ -1572,7 +1572,7 @@ def ban_domain(v):
def unban_domain(v:User, domain): def unban_domain(v:User, domain):
existing = g.db.get(BannedDomain, domain) existing = g.db.get(BannedDomain, domain)
if not existing: abort(400, 'Domain is not banned!') if not existing: abort(400, 'Domain is not banned!')
g.db.delete(existing) g.db.delete(existing)
ma = ModAction( ma = ModAction(
kind="unban_domain", kind="unban_domain",
@ -1595,7 +1595,7 @@ def admin_nuke_user(v):
for post in g.db.query(Submission).filter_by(author_id=user.id).all(): for post in g.db.query(Submission).filter_by(author_id=user.id).all():
if post.is_banned: if post.is_banned:
continue continue
post.is_banned = True post.is_banned = True
post.ban_reason = v.username post.ban_reason = v.username
g.db.add(post) g.db.add(post)
@ -1628,7 +1628,7 @@ def admin_nunuke_user(v):
for post in g.db.query(Submission).filter_by(author_id=user.id).all(): for post in g.db.query(Submission).filter_by(author_id=user.id).all():
if not post.is_banned: if not post.is_banned:
continue continue
post.is_banned = False post.is_banned = False
post.ban_reason = None post.ban_reason = None
post.is_approved = v.id post.is_approved = v.id

View File

@ -63,7 +63,7 @@ def after_request(response:Response):
if response.status_code < 400: if response.status_code < 400:
_set_cloudflare_cookie(response) _set_cloudflare_cookie(response)
_commit_and_close_db() _commit_and_close_db()
return response return response
@ -82,7 +82,7 @@ def _set_cloudflare_cookie(response:Response) -> None:
if not logged_in and request.cookies.get("lo"): if not logged_in and request.cookies.get("lo"):
response.delete_cookie("lo", domain=app.config["COOKIE_DOMAIN"], samesite="Lax") response.delete_cookie("lo", domain=app.config["COOKIE_DOMAIN"], samesite="Lax")
elif logged_in and not request.cookies.get("lo"): elif logged_in and not request.cookies.get("lo"):
response.set_cookie("lo", CLOUDFLARE_COOKIE_VALUE if logged_in else '', response.set_cookie("lo", CLOUDFLARE_COOKIE_VALUE if logged_in else '',
max_age=SESSION_LIFETIME, samesite="Lax", max_age=SESSION_LIFETIME, samesite="Lax",
domain=app.config["COOKIE_DOMAIN"]) domain=app.config["COOKIE_DOMAIN"])

View File

@ -371,7 +371,7 @@ def update_marsey(v):
return error("Image uploads are not allowed through TOR.") return error("Image uploads are not allowed through TOR.")
if not file.content_type.startswith('image/'): if not file.content_type.startswith('image/'):
return error("You need to submit an image!") return error("You need to submit an image!")
for x in IMAGE_FORMATS: for x in IMAGE_FORMATS:
if path.isfile(f'/asset_submissions/marseys/original/{name}.{x}'): if path.isfile(f'/asset_submissions/marseys/original/{name}.{x}'):
os.remove(f'/asset_submissions/marseys/original/{name}.{x}') os.remove(f'/asset_submissions/marseys/original/{name}.{x}')
@ -387,7 +387,7 @@ def update_marsey(v):
copyfile(new_path, filename) copyfile(new_path, filename)
process_image(filename, v, resize=200, trim=True) process_image(filename, v, resize=200, trim=True)
purge_files_in_cache([f"https://{SITE}/e/{name}.webp", f"https://{SITE}/assets/images/emojis/{name}.webp", f"https://{SITE}/asset_submissions/marseys/original/{name}.{format}"]) purge_files_in_cache([f"https://{SITE}/e/{name}.webp", f"https://{SITE}/assets/images/emojis/{name}.webp", f"https://{SITE}/asset_submissions/marseys/original/{name}.{format}"])
if tags and existing.tags != tags and tags != "none": if tags and existing.tags != tags and tags != "none":
existing.tags = tags existing.tags = tags
g.db.add(existing) g.db.add(existing)

View File

@ -103,7 +103,7 @@ def buy(v:User, award):
v.lootboxes_bought += 1 v.lootboxes_bought += 1
lootbox_msg = "You open your lootbox and receive: " + ', '.join(lootbox_items) lootbox_msg = "You open your lootbox and receive: " + ', '.join(lootbox_items)
send_repeatable_notification(v.id, lootbox_msg) send_repeatable_notification(v.id, lootbox_msg)
if v.lootboxes_bought == 10: if v.lootboxes_bought == 10:
badge_grant(badge_id=76, user=v) badge_grant(badge_id=76, user=v)
elif v.lootboxes_bought == 50: elif v.lootboxes_bought == 50:
@ -131,16 +131,16 @@ def buy(v:User, award):
def award_thing(v, thing_type, id): def award_thing(v, thing_type, id):
kind = request.values.get("kind", "").strip() kind = request.values.get("kind", "").strip()
if thing_type == 'post': if thing_type == 'post':
thing = get_post(id) thing = get_post(id)
else: else:
thing = get_comment(id) thing = get_comment(id)
if not thing.parent_submission and not thing.wall_user_id: abort(404) # don't let users award messages if not thing.parent_submission and not thing.wall_user_id: abort(404) # don't let users award messages
if v.shadowbanned: abort(500) if v.shadowbanned: abort(500)
author = thing.author author = thing.author
if author.shadowbanned: abort(404) if author.shadowbanned: abort(404)
AWARDS = deepcopy(AWARDS_ENABLED) AWARDS = deepcopy(AWARDS_ENABLED)
if v.house: if v.house:
AWARDS[v.house] = HOUSE_AWARDS[v.house] AWARDS[v.house] = HOUSE_AWARDS[v.house]
@ -288,7 +288,7 @@ def award_thing(v, thing_type, id):
if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400 if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400
else: author.agendaposter = int(time.time()) + 86400 else: author.agendaposter = int(time.time()) + 86400
badge_grant(user=author, badge_id=28) badge_grant(user=author, badge_id=28)
elif kind == "flairlock": elif kind == "flairlock":
new_name = note[:100].replace("𒐪","").replace("","").strip() new_name = note[:100].replace("𒐪","").replace("","").strip()
@ -375,10 +375,10 @@ def award_thing(v, thing_type, id):
elif "Vampire" in kind and kind == v.house: elif "Vampire" in kind and kind == v.house:
if author.bite: author.bite += 172800 if author.bite: author.bite += 172800
else: author.bite = int(time.time()) + 172800 else: author.bite = int(time.time()) + 172800
if not author.old_house: if not author.old_house:
author.old_house = author.house author.old_house = author.house
if 'Vampire' not in author.house: if 'Vampire' not in author.house:
author.house = 'Vampire' author.house = 'Vampire'

View File

@ -54,7 +54,7 @@ def casino_game_page(v:User, game):
@limiter.limit("100/minute;2000/hour;12000/day") @limiter.limit("100/minute;2000/hour;12000/day")
@auth_required @auth_required
def casino_game_feed(v:User, game): def casino_game_feed(v:User, game):
if v.rehab: if v.rehab:
abort(403, "You are under Rehab award effect!") abort(403, "You are under Rehab award effect!")
elif game not in CASINO_GAME_KINDS: elif game not in CASINO_GAME_KINDS:
abort(404) abort(404)

View File

@ -83,7 +83,7 @@ def speak(data, v):
"text_censored": censor_slurs(text_html, 'chat'), "text_censored": censor_slurs(text_html, 'chat'),
"time": int(time.time()), "time": int(time.time()),
} }
if v.shadowbanned or not execute_blackjack(v, None, text, "chat"): if v.shadowbanned or not execute_blackjack(v, None, text, "chat"):
emit('speak', data) emit('speak', data)
elif recipient: elif recipient:

View File

@ -43,7 +43,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
g.db.commit() g.db.commit()
post = comment.post post = comment.post
if post.over_18 and not (v and v.over_18) and not session.get('over_18', 0) >= int(time.time()): if post.over_18 and not (v and v.over_18) and not session.get('over_18', 0) >= int(time.time()):
if v and v.client: abort(403, "This content is not suitable for some users and situations.") if v and v.client: abort(403, "This content is not suitable for some users and situations.")
else: return render_template("errors/nsfw.html", v=v), 403 else: return render_template("errors/nsfw.html", v=v), 403
@ -70,9 +70,9 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
execute_shadowban_viewers_and_voters(v, post) execute_shadowban_viewers_and_voters(v, post)
execute_shadowban_viewers_and_voters(v, comment) execute_shadowban_viewers_and_voters(v, comment)
if v and v.client: return top_comment.json(db=g.db) if v and v.client: return top_comment.json(db=g.db)
else: else:
if post.is_banned and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)): template = "submission_banned.html" if post.is_banned and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)): template = "submission_banned.html"
else: template = "submission.html" else: template = "submission.html"
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr) return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
@ -107,7 +107,7 @@ def comment(v:User):
post_target = get_post(parent.parent_submission, v=v, graceful=True) or get_account(parent.wall_user_id, v=v, include_blocks=True, include_shadowbanned=False) post_target = get_post(parent.parent_submission, v=v, graceful=True) or get_account(parent.wall_user_id, v=v, include_blocks=True, include_shadowbanned=False)
parent_comment_id = parent.id parent_comment_id = parent.id
if parent.author_id == v.id: rts = True if parent.author_id == v.id: rts = True
if not v.can_post_in_ghost_threads and isinstance(post_target, Submission) and post_target.ghost: if not v.can_post_in_ghost_threads and isinstance(post_target, Submission) and post_target.ghost:
abort(403, f"You need {TRUESCORE_GHOST_MINIMUM} truescore to post in ghost threads") abort(403, f"You need {TRUESCORE_GHOST_MINIMUM} truescore to post in ghost threads")
ghost = parent.ghost ghost = parent.ghost
else: abort(404) else: abort(404)
@ -200,7 +200,7 @@ def comment(v:User):
abort(415) abort(415)
body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT] body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT]
if v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES'] and posting_to_submission and post_target.id == SNAPPY_THREAD and level == 1: if v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES'] and posting_to_submission and post_target.id == SNAPPY_THREAD and level == 1:
with open(f"snappy_{SITE_NAME}.txt", "a", encoding="utf-8") as f: with open(f"snappy_{SITE_NAME}.txt", "a", encoding="utf-8") as f:
f.write('\n{[para]}\n' + body) f.write('\n{[para]}\n' + body)
@ -297,7 +297,7 @@ def comment(v:User):
for x in subscribers: for x in subscribers:
notify_users.add(x[0]) notify_users.add(x[0])
if parent_user.id != v.id: if parent_user.id != v.id:
notify_users.add(parent_user.id) notify_users.add(parent_user.id)
@ -422,9 +422,9 @@ def edit_comment(cid, v):
if int(time.time()) - c.created_utc > 60 * 3: c.edited_utc = int(time.time()) if int(time.time()) - c.created_utc > 60 * 3: c.edited_utc = int(time.time())
g.db.add(c) g.db.add(c)
notify_users = NOTIFY_USERS(body, v) notify_users = NOTIFY_USERS(body, v)
for x in notify_users-bots: for x in notify_users-bots:
notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=x).one_or_none() notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=x).one_or_none()
if not notif: if not notif:
@ -481,12 +481,12 @@ def undelete_comment(cid, v):
@feature_required('PINS') @feature_required('PINS')
@auth_required @auth_required
def pin_comment(cid, v): def pin_comment(cid, v):
comment = get_comment(cid, v=v) comment = get_comment(cid, v=v)
if not comment.stickied: if not comment.stickied:
if v.id != comment.post.author_id: abort(403) if v.id != comment.post.author_id: abort(403)
if comment.post.ghost: comment.stickied = "(OP)" if comment.post.ghost: comment.stickied = "(OP)"
else: comment.stickied = v.username + " (OP)" else: comment.stickied = v.username + " (OP)"
@ -498,18 +498,18 @@ def pin_comment(cid, v):
send_repeatable_notification(comment.author_id, message) send_repeatable_notification(comment.author_id, message)
return {"message": "Comment pinned!"} return {"message": "Comment pinned!"}
@app.post("/unpin_comment/<int:cid>") @app.post("/unpin_comment/<int:cid>")
@auth_required @auth_required
def unpin_comment(cid, v): def unpin_comment(cid, v):
comment = get_comment(cid, v=v) comment = get_comment(cid, v=v)
if comment.stickied: if comment.stickied:
if v.id != comment.post.author_id: abort(403) if v.id != comment.post.author_id: abort(403)
if not comment.stickied.endswith(" (OP)"): if not comment.stickied.endswith(" (OP)"):
abort(403, "You can only unpin comments you have pinned!") abort(403, "You can only unpin comments you have pinned!")
comment.stickied = None comment.stickied = None
@ -602,7 +602,7 @@ def handle_wordle_action(cid, v):
comment.wordle_result = f'{guesses}_{status}_{answer}' comment.wordle_result = f'{guesses}_{status}_{answer}'
g.db.add(comment) g.db.add(comment)
return {"response" : comment.wordle_html(v)} return {"response" : comment.wordle_html(v)}
@ -613,7 +613,7 @@ def toggle_comment_nsfw(cid, v):
if comment.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (comment.post.sub and v.mods(comment.post.sub)): if comment.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (comment.post.sub and v.mods(comment.post.sub)):
abort(403) abort(403)
if comment.over_18 and v.is_suspended_permanently: if comment.over_18 and v.is_suspended_permanently:
abort(403) abort(403)

View File

@ -22,7 +22,7 @@ def feeds_user(sort='hot', t='all'):
t=t, t=t,
v=None, v=None,
) )
posts = get_posts(ids) posts = get_posts(ids)
doc, tag, text = Doc().tagtext() doc, tag, text = Doc().tagtext()
@ -54,7 +54,7 @@ def feeds_user(sort='hot', t='all'):
with tag("published"): with tag("published"):
text(datetime.datetime.utcfromtimestamp(post.created_utc).isoformat()+"Z") text(datetime.datetime.utcfromtimestamp(post.created_utc).isoformat()+"Z")
with tag("author"): with tag("author"):
with tag("name"): with tag("name"):
text(post.author_name) text(post.author_name)

View File

@ -35,7 +35,7 @@ def front_all(v, sub=None, subdomain=None):
sub = get_sub_by_name(sub, graceful=True) sub = get_sub_by_name(sub, graceful=True)
if sub and not User.can_see(v, sub): if sub and not User.can_see(v, sub):
abort(403) abort(403)
if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404) if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404)
try: page = max(int(request.values.get("page", 1)), 1) try: page = max(int(request.values.get("page", 1)), 1)
@ -52,7 +52,7 @@ def front_all(v, sub=None, subdomain=None):
sort=request.values.get("sort", defaultsorting) sort=request.values.get("sort", defaultsorting)
t=request.values.get('t', defaulttime) t=request.values.get('t', defaulttime)
try: gt=int(request.values.get("after", 0)) try: gt=int(request.values.get("after", 0))
except: gt=0 except: gt=0
@ -79,7 +79,7 @@ def front_all(v, sub=None, subdomain=None):
) )
posts = get_posts(ids, v=v, eager=True) posts = get_posts(ids, v=v, eager=True)
if v: if v:
if v.hidevotedon: posts = [x for x in posts if not hasattr(x, 'voted') or not x.voted] if v.hidevotedon: posts = [x for x in posts if not hasattr(x, 'voted') or not x.voted]
award_timers(v) award_timers(v)
@ -91,7 +91,7 @@ def front_all(v, sub=None, subdomain=None):
@cache.memoize(timeout=86400) @cache.memoize(timeout=86400)
def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='', gt=0, lt=0, sub=None, site=None, pins=True, holes=True): def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='', gt=0, lt=0, sub=None, site=None, pins=True, holes=True):
posts = g.db.query(Submission) posts = g.db.query(Submission)
if v and v.hidevotedon: if v and v.hidevotedon:
posts = posts.outerjoin(Vote, posts = posts.outerjoin(Vote,
and_(Vote.submission_id == Submission.id, Vote.user_id == v.id) and_(Vote.submission_id == Submission.id, Vote.user_id == v.id)
@ -148,7 +148,7 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
pins = g.db.query(Submission).filter(Submission.sub == sub.name, Submission.hole_pinned != None) pins = g.db.query(Submission).filter(Submission.sub == sub.name, Submission.hole_pinned != None)
else: else:
pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False) pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False)
if v: if v:
pins = pins.filter(or_(Submission.sub == None, Submission.sub.notin_(v.all_blocks))) pins = pins.filter(or_(Submission.sub == None, Submission.sub.notin_(v.all_blocks)))
for pin in pins: for pin in pins:
@ -184,7 +184,7 @@ def random_post(v:User):
@auth_required @auth_required
def random_user(v:User): def random_user(v:User):
u = g.db.query(User.username).filter(User.song != None, User.shadowbanned == None).order_by(func.random()).first() u = g.db.query(User.username).filter(User.song != None, User.shadowbanned == None).order_by(func.random()).first()
if u: u = u[0] if u: u = u[0]
else: abort(404, "No users have set a profile anthem so far!") else: abort(404, "No users have set a profile anthem so far!")

View File

@ -63,14 +63,14 @@ def calc_users():
ua = str(user_agents.parse(g.agent)) ua = str(user_agents.parse(g.agent))
if 'spider' not in ua.lower() and 'bot' not in ua.lower(): if 'spider' not in ua.lower() and 'bot' not in ua.lower():
loggedout[session["session_id"]] = (timestamp, ua) loggedout[session["session_id"]] = (timestamp, ua)
loggedin = {k: v for k, v in loggedin.items() if (timestamp - v) < LOGGEDIN_ACTIVE_TIME} loggedin = {k: v for k, v in loggedin.items() if (timestamp - v) < LOGGEDIN_ACTIVE_TIME}
loggedout = {k: v for k, v in loggedout.items() if (timestamp - v[0]) < LOGGEDIN_ACTIVE_TIME} loggedout = {k: v for k, v in loggedout.items() if (timestamp - v[0]) < LOGGEDIN_ACTIVE_TIME}
cache.set(LOGGED_IN_CACHE_KEY, loggedin) cache.set(LOGGED_IN_CACHE_KEY, loggedin)
cache.set(LOGGED_OUT_CACHE_KEY, loggedout) cache.set(LOGGED_OUT_CACHE_KEY, loggedout)
loggedin_counter = len(loggedin) loggedin_counter = len(loggedin)
loggedout_counter = len(loggedout) loggedout_counter = len(loggedout)
return {'loggedin_counter':loggedin_counter, return {'loggedin_counter':loggedin_counter,
'loggedout_counter':loggedout_counter, 'loggedout_counter':loggedout_counter,
'loggedin_chat':loggedin_chat} 'loggedin_chat':loggedin_chat}
@ -82,7 +82,7 @@ def inject_constants():
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL,
"AUTOJANNY_ID":AUTOJANNY_ID, "MODMAIL_ID":MODMAIL_ID, "VAPID_PUBLIC_KEY":VAPID_PUBLIC_KEY, "AUTOJANNY_ID":AUTOJANNY_ID, "MODMAIL_ID":MODMAIL_ID, "VAPID_PUBLIC_KEY":VAPID_PUBLIC_KEY,
"listdir":listdir, "os_path":path, "AEVANN_ID":AEVANN_ID, "listdir":listdir, "os_path":path, "AEVANN_ID":AEVANN_ID,
"PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR, "PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR,
"COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES, "COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES,
"HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED, "HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED,
"GUMROAD_LINK":GUMROAD_LINK, "DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION, "GUMROAD_LINK":GUMROAD_LINK, "DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION,
@ -95,9 +95,9 @@ def inject_constants():
"site_settings":get_settings(), "EMAIL":EMAIL, "max": max, "min": min, "user_can_see":User.can_see, "site_settings":get_settings(), "EMAIL":EMAIL, "max": max, "min": min, "user_can_see":User.can_see,
"TELEGRAM_ID":TELEGRAM_ID, "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN, "TELEGRAM_ID":TELEGRAM_ID, "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN,
"TRUESCORE_DONATE_MINIMUM":TRUESCORE_DONATE_MINIMUM, "TRUESCORE_DONATE_MINIMUM":TRUESCORE_DONATE_MINIMUM,
"DONATE_LINK":DONATE_LINK, "DONATE_SERVICE":DONATE_SERVICE, "BAN_EVASION_DOMAIN":BAN_EVASION_DOMAIN, "DONATE_LINK":DONATE_LINK, "DONATE_SERVICE":DONATE_SERVICE, "BAN_EVASION_DOMAIN":BAN_EVASION_DOMAIN,
"HOUSE_JOIN_COST":HOUSE_JOIN_COST, "HOUSE_SWITCH_COST":HOUSE_SWITCH_COST, "IMAGE_FORMATS":','.join(IMAGE_FORMATS), "HOUSE_JOIN_COST":HOUSE_JOIN_COST, "HOUSE_SWITCH_COST":HOUSE_SWITCH_COST, "IMAGE_FORMATS":','.join(IMAGE_FORMATS),
"PAGE_SIZES":PAGE_SIZES, "THEMES":THEMES, "COMMENT_SORTS":COMMENT_SORTS, "SORTS":SORTS, "PAGE_SIZES":PAGE_SIZES, "THEMES":THEMES, "COMMENT_SORTS":COMMENT_SORTS, "SORTS":SORTS,
"TIME_FILTERS":TIME_FILTERS, "HOUSES":HOUSES, "TIERS_ID_TO_NAME":TIERS_ID_TO_NAME, "TIME_FILTERS":TIME_FILTERS, "HOUSES":HOUSES, "TIERS_ID_TO_NAME":TIERS_ID_TO_NAME,
"DEFAULT_CONFIG_VALUE":DEFAULT_CONFIG_VALUE, "IS_LOCALHOST":IS_LOCALHOST, "BACKGROUND_CATEGORIES":BACKGROUND_CATEGORIES, "PAGE_SIZE":PAGE_SIZE, "TAGLINES":TAGLINES, "IS_FISTMAS":IS_FISTMAS, "get_alt_graph":get_alt_graph, "current_registered_users":current_registered_users "DEFAULT_CONFIG_VALUE":DEFAULT_CONFIG_VALUE, "IS_LOCALHOST":IS_LOCALHOST, "BACKGROUND_CATEGORIES":BACKGROUND_CATEGORIES, "PAGE_SIZE":PAGE_SIZE, "TAGLINES":TAGLINES, "IS_FISTMAS":IS_FISTMAS, "get_alt_graph":get_alt_graph, "current_registered_users":current_registered_users
} }

View File

@ -346,7 +346,7 @@ def sign_up_post(v:Optional[User]):
check_for_alts(new_user) check_for_alts(new_user)
send_notification(new_user.id, WELCOME_MSG) send_notification(new_user.id, WELCOME_MSG)
if SIGNUP_FOLLOW_ID: if SIGNUP_FOLLOW_ID:
signup_autofollow = get_account(SIGNUP_FOLLOW_ID) signup_autofollow = get_account(SIGNUP_FOLLOW_ID)
new_follow = Follow(user_id=new_user.id, target_id=signup_autofollow.id) new_follow = Follow(user_id=new_user.id, target_id=signup_autofollow.id)
@ -502,7 +502,7 @@ def request_2fa_disable():
token=generate_hash(f"{user.id}+{user.username}+disable2fa+{valid}+{user.mfa_secret}+{user.login_nonce}") token=generate_hash(f"{user.id}+{user.username}+disable2fa+{valid}+{user.mfa_secret}+{user.login_nonce}")
action_url=f"{SITE_FULL}/reset_2fa?id={user.id}&t={valid}&token={token}" action_url=f"{SITE_FULL}/reset_2fa?id={user.id}&t={valid}&token={token}"
send_mail(to_address=user.email, send_mail(to_address=user.email,
subject="2FA Removal Request", subject="2FA Removal Request",
html=render_template("email/2fa_remove.html", html=render_template("email/2fa_remove.html",

View File

@ -329,7 +329,7 @@ def notifications(v:User):
total.extend(c.replies2) total.extend(c.replies2)
if c not in listing: listing.append(c) if c not in listing: listing.append(c)
total.extend(listing) total.extend(listing)
total_cids = [x.id for x in total] total_cids = [x.id for x in total]

View File

@ -97,7 +97,7 @@ def delete_oauth_app(v, aid):
abort(404) abort(404)
app = g.db.get(OauthApp, aid) app = g.db.get(OauthApp, aid)
if not app: abort(404) if not app: abort(404)
if app.author_id != v.id: abort(403) if app.author_id != v.id: abort(403)
for auth in g.db.query(ClientAuth).filter_by(oauth_client=app.id).all(): for auth in g.db.query(ClientAuth).filter_by(oauth_client=app.id).all():

View File

@ -22,7 +22,7 @@ def vote_option(option_id, v):
if option.exclusive == 2: if option.exclusive == 2:
if option.post.total_bet_voted(v): if option.post.total_bet_voted(v):
abort(403, "You can't bet on a closed poll!") abort(403, "You can't bet on a closed poll!")
if not v.charge_account('coins', POLL_BET_COINS): if not v.charge_account('coins', POLL_BET_COINS):
abort(400, f"You don't have {POLL_BET_COINS} coins!") abort(400, f"You don't have {POLL_BET_COINS} coins!")
g.db.add(v) g.db.add(v)
autojanny = get_account(AUTOJANNY_ID) autojanny = get_account(AUTOJANNY_ID)

View File

@ -45,7 +45,7 @@ def publish(pid, v):
post.private = False post.private = False
post.created_utc = int(time.time()) post.created_utc = int(time.time())
g.db.add(post) g.db.add(post)
if not post.ghost: if not post.ghost:
notify_users = NOTIFY_USERS(f'{post.title} {post.body}', v) notify_users = NOTIFY_USERS(f'{post.title} {post.body}', v)
@ -189,7 +189,7 @@ def view_more(v, pid, sort, offset):
except: abort(400) except: abort(400)
try: ids = set(int(x) for x in request.values.get("ids").split(',')) try: ids = set(int(x) for x in request.values.get("ids").split(','))
except: abort(400) except: abort(400)
if v: if v:
# shadowban check is done in sort_objects # shadowban check is done in sort_objects
# output is needed: see comments.py # output is needed: see comments.py
@ -209,7 +209,7 @@ def view_more(v, pid, sort, offset):
comments = sort_objects(sort, comments, Comment, comments = sort_objects(sort, comments, Comment,
include_shadowbanned=False) include_shadowbanned=False)
comments = comments.offset(offset).all() comments = comments.offset(offset).all()
comments2 = [] comments2 = []
@ -226,7 +226,7 @@ def view_more(v, pid, sort, offset):
ids.add(comment.id) ids.add(comment.id)
count += g.db.query(Comment).filter_by(parent_submission=post.id, parent_comment_id=comment.id).count() + 1 count += g.db.query(Comment).filter_by(parent_submission=post.id, parent_comment_id=comment.id).count() + 1
if count > 20: break if count > 20: break
if len(comments) == len(comments2): offset = 0 if len(comments) == len(comments2): offset = 0
else: offset += 1 else: offset += 1
comments = comments2 comments = comments2
@ -255,7 +255,7 @@ def more_comments(v, cid):
if comments: p = comments[0].post if comments: p = comments[0].post
else: p = None else: p = None
return render_template("comments.html", v=v, comments=comments, p=p, render_replies=True) return render_template("comments.html", v=v, comments=comments, p=p, render_replies=True)
@app.post("/edit_post/<int:pid>") @app.post("/edit_post/<int:pid>")
@ -320,7 +320,7 @@ def edit_post(pid, v):
for text in [p.body, p.title, p.url]: for text in [p.body, p.title, p.url]:
if not execute_blackjack(v, p, text, 'submission'): break if not execute_blackjack(v, p, text, 'submission'): break
if len(body_html) > POST_BODY_HTML_LENGTH_LIMIT: if len(body_html) > POST_BODY_HTML_LENGTH_LIMIT:
abort(400, f"Submission body_html too long!") abort(400, f"Submission body_html too long!")
p.body_html = body_html p.body_html = body_html
@ -367,13 +367,13 @@ def thumbnail_thread(pid:int, vid:int):
return f"{post_url}/{fragment_url}" return f"{post_url}/{fragment_url}"
post = db.get(Submission, pid) post = db.get(Submission, pid)
if not post or not post.url: if not post or not post.url:
time.sleep(5) time.sleep(5)
post = db.get(Submission, pid) post = db.get(Submission, pid)
if not post or not post.url: return if not post or not post.url: return
fetch_url = post.url fetch_url = post.url
if fetch_url.startswith('/') and '\\' not in fetch_url: if fetch_url.startswith('/') and '\\' not in fetch_url:
@ -404,12 +404,12 @@ def thumbnail_thread(pid:int, vid:int):
] ]
for tag_name in meta_tags: for tag_name in meta_tags:
tag = soup.find( tag = soup.find(
'meta', 'meta',
attrs={ attrs={
"name": tag_name, "name": tag_name,
"content": True "content": True
} }
) )
@ -510,7 +510,7 @@ def is_repost():
params=parsed_url.params, params=parsed_url.params,
query=urlencode(filtered, doseq=True), query=urlencode(filtered, doseq=True),
fragment=parsed_url.fragment) fragment=parsed_url.fragment)
url = urlunparse(new_url) url = urlunparse(new_url)
url = url.rstrip('/') url = url.rstrip('/')
@ -539,7 +539,7 @@ def submit_post(v:User, sub=None):
def error(error): def error(error):
if g.is_api_or_xhr: abort(400, error) if g.is_api_or_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
@ -555,7 +555,7 @@ def submit_post(v:User, sub=None):
title_html = filter_emojis_only(title, graceful=True, count_marseys=True, torture=torture) title_html = filter_emojis_only(title, graceful=True, count_marseys=True, torture=torture)
if v.marseyawarded and not marseyaward_title_regex.fullmatch(title_html): if v.marseyawarded and not marseyaward_title_regex.fullmatch(title_html):
return error("You can only type marseys!") return error("You can only type marseys!")
if len(title_html) > POST_TITLE_HTML_LENGTH_LIMIT: if len(title_html) > POST_TITLE_HTML_LENGTH_LIMIT:
return error("Rendered title is too big!") return error("Rendered title is too big!")
if sub == 'changelog' and not v.admin_level >= PERMS['POST_TO_CHANGELOG']: if sub == 'changelog' and not v.admin_level >= PERMS['POST_TO_CHANGELOG']:
@ -610,7 +610,7 @@ def submit_post(v:User, sub=None):
params=parsed_url.params, params=parsed_url.params,
query=urlencode(filtered, doseq=True), query=urlencode(filtered, doseq=True),
fragment=parsed_url.fragment) fragment=parsed_url.fragment)
url = urlunparse(new_url) url = urlunparse(new_url)
url = url.rstrip('/') url = url.rstrip('/')
@ -660,7 +660,7 @@ def submit_post(v:User, sub=None):
if not url and not body and not request.files.get("file") and not request.files.get("file-url"): if not url and not body and not request.files.get("file") and not request.files.get("file-url"):
return error("Please enter a url or some text.") return error("Please enter a url or some text.")
if not IS_LOCALHOST: if not IS_LOCALHOST:
dup = g.db.query(Submission).filter( dup = g.db.query(Submission).filter(
Submission.author_id == v.id, Submission.author_id == v.id,
Submission.deleted_utc == 0, Submission.deleted_utc == 0,
@ -738,7 +738,7 @@ def submit_post(v:User, sub=None):
submission_id=post.id submission_id=post.id
) )
g.db.add(vote) g.db.add(vote)
if request.files.get('file-url') and not g.is_tor: if request.files.get('file-url') and not g.is_tor:
file = request.files['file-url'] file = request.files['file-url']
@ -761,7 +761,7 @@ def submit_post(v:User, sub=None):
post.url = process_audio(file, v) post.url = process_audio(file, v)
else: else:
abort(415) abort(415)
if not post.thumburl and post.url: if not post.thumburl and post.url:
gevent.spawn(thumbnail_thread, post.id, v.id) gevent.spawn(thumbnail_thread, post.id, v.id)
@ -889,7 +889,7 @@ def mark_post_nsfw(pid, v):
if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)): if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)):
abort(403) abort(403)
if post.over_18 and v.is_suspended_permanently: if post.over_18 and v.is_suspended_permanently:
abort(403) abort(403)
@ -923,7 +923,7 @@ def unmark_post_nsfw(pid, v):
if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)): if post.author_id != v.id and not v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and not (post.sub and v.mods(post.sub)):
abort(403) abort(403)
if post.over_18 and v.is_suspended_permanently: if post.over_18 and v.is_suspended_permanently:
abort(403) abort(403)
@ -1056,7 +1056,7 @@ def get_post_title(v):
try: try:
x = gevent.with_timeout(POST_TITLE_TIMEOUT, requests.get, url, headers=titleheaders, timeout=POST_TITLE_TIMEOUT, proxies=proxies) x = gevent.with_timeout(POST_TITLE_TIMEOUT, requests.get, url, headers=titleheaders, timeout=POST_TITLE_TIMEOUT, proxies=proxies)
except: abort(400) except: abort(400)
content_type = x.headers.get("Content-Type") content_type = x.headers.get("Content-Type")
if not content_type or "text/html" not in content_type: abort(400) if not content_type or "text/html" not in content_type: abort(400)

View File

@ -19,5 +19,5 @@ def push_subscribe(v):
subscription_json=subscription_json, subscription_json=subscription_json,
) )
g.db.add(subscription) g.db.add(subscription)
return '' return ''

View File

@ -58,7 +58,7 @@ def flag_post(pid, v):
moved = move_post(post, v, reason) moved = move_post(post, v, reason)
if moved: return {"message": moved} if moved: return {"message": moved}
existing = g.db.query(Flag.post_id).filter_by(user_id=v.id, post_id=post.id).one_or_none() existing = g.db.query(Flag.post_id).filter_by(user_id=v.id, post_id=post.id).one_or_none()
if existing: abort(409, "You already reported this post!") if existing: abort(409, "You already reported this post!")
flag = Flag(post_id=post.id, user_id=v.id, reason=reason) flag = Flag(post_id=post.id, user_id=v.id, reason=reason)
@ -74,7 +74,7 @@ def flag_post(pid, v):
def flag_comment(cid, v): def flag_comment(cid, v):
comment = get_comment(cid) comment = get_comment(cid)
existing = g.db.query(CommentFlag.comment_id).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() existing = g.db.query(CommentFlag.comment_id).filter_by(user_id=v.id, comment_id=comment.id).one_or_none()
if existing: abort(409, "You already reported this comment!") if existing: abort(409, "You already reported this comment!")
@ -125,7 +125,7 @@ def remove_report_comment(v, cid, uid):
uid = int(uid) uid = int(uid)
except: abort(404) except: abort(404)
report = g.db.query(CommentFlag).filter_by(comment_id=cid, user_id=uid).one_or_none() report = g.db.query(CommentFlag).filter_by(comment_id=cid, user_id=uid).one_or_none()
if report: if report:
g.db.delete(report) g.db.delete(report)
@ -143,7 +143,7 @@ def move_post(post:Submission, v:User, reason:str) -> Union[bool, str]:
sub_from = post.sub sub_from = post.sub
sub_to = get_sub_by_name(reason, graceful=True) sub_to = get_sub_by_name(reason, graceful=True)
sub_to = sub_to.name if sub_to else None sub_to = sub_to.name if sub_to else None
can_move_post = v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (post.sub and v.mods(sub_from)) can_move_post = v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (post.sub and v.mods(sub_from))
if sub_from != 'chudrama': # posts can only be moved out of /h/chudrama by admins if sub_from != 'chudrama': # posts can only be moved out of /h/chudrama by admins
can_move_post = can_move_post or post.author_id == v.id can_move_post = can_move_post or post.author_id == v.id
@ -158,7 +158,7 @@ def move_post(post:Submission, v:User, reason:str) -> Union[bool, str]:
abort(403, f"You need to be a member of House {sub_to.capitalize()} to post in /h/{sub_to}") abort(403, f"You need to be a member of House {sub_to.capitalize()} to post in /h/{sub_to}")
else: else:
abort(403, f"@{post.author.username} needs to be a member of House {sub_to.capitalize()} for their post to be moved to /h/{sub_to}") abort(403, f"@{post.author.username} needs to be a member of House {sub_to.capitalize()} for their post to be moved to /h/{sub_to}")
post.sub = sub_to post.sub = sub_to
post.hole_pinned = None post.hole_pinned = None
g.db.add(post) g.db.add(post)

View File

@ -41,7 +41,7 @@ def get_alt_graph_ids(uid:int) -> List[int]:
).select_from(Alt, alt_graph_cte).filter( ).select_from(Alt, alt_graph_cte).filter(
or_(alt_graph_cte.c.user_id == Alt.user1, alt_graph_cte.c.user_id == Alt.user2) or_(alt_graph_cte.c.user_id == Alt.user1, alt_graph_cte.c.user_id == Alt.user2)
) )
alt_graph_cte = alt_graph_cte.union(alt_graph_cte_inner) alt_graph_cte = alt_graph_cte.union(alt_graph_cte_inner)
return set([x[0] for x in g.db.query(User.id).filter(User.id == alt_graph_cte.c.user_id, User.id != uid).all()]) return set([x[0] for x in g.db.query(User.id).filter(User.id == alt_graph_cte.c.user_id, User.id != uid).all()])
@ -86,7 +86,7 @@ def check_for_alts(current:User, include_current_session=True):
if a.user1 != current_id: add_alt(a.user1, current_id) if a.user1 != current_id: add_alt(a.user1, current_id)
if a.user2 != past_id: add_alt(a.user2, past_id) if a.user2 != past_id: add_alt(a.user2, past_id)
if a.user2 != current_id: add_alt(a.user2, current_id) if a.user2 != current_id: add_alt(a.user2, current_id)
past_accs.add(current_id) past_accs.add(current_id)
if include_current_session: if include_current_session:
session["history"] = list(past_accs) session["history"] = list(past_accs)
@ -110,7 +110,7 @@ def execute_shadowban_viewers_and_voters(v:Optional[User], target:Union[Submissi
max_upvotes = min(ti, 13) max_upvotes = min(ti, 13)
rand = randint(0, max_upvotes) rand = randint(0, max_upvotes)
if target.upvotes >= rand: return if target.upvotes >= rand: return
amount = randint(0, 3) amount = randint(0, 3)
if amount != 1: return if amount != 1: return

View File

@ -59,13 +59,13 @@ def searchposts(v:User):
posts = g.db.query(Submission.id) \ posts = g.db.query(Submission.id) \
.join(Submission.author) \ .join(Submission.author) \
.filter(Submission.author_id.notin_(v.userblocks)) .filter(Submission.author_id.notin_(v.userblocks))
if v.admin_level < PERMS['POST_COMMENT_MODERATION']: if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
posts = posts.filter( posts = posts.filter(
Submission.deleted_utc == 0, Submission.deleted_utc == 0,
Submission.is_banned == False, Submission.is_banned == False,
Submission.private == False) Submission.private == False)
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'], v=v, include_shadowbanned=False) author = get_user(criteria['author'], v=v, include_shadowbanned=False)
@ -95,7 +95,7 @@ def searchposts(v:User):
words = [or_(Submission.title.ilike('%'+x+'%'), Submission.body.ilike('%'+x+'%')) \ words = [or_(Submission.title.ilike('%'+x+'%'), Submission.body.ilike('%'+x+'%')) \
for x in criteria['q']] for x in criteria['q']]
posts = posts.filter(*words) posts = posts.filter(*words)
if 'over18' in criteria: posts = posts.filter(Submission.over_18==True) if 'over18' in criteria: posts = posts.filter(Submission.over_18==True)
if 'domain' in criteria: if 'domain' in criteria:
@ -187,7 +187,7 @@ def searchcomments(v:User):
Comment.author_id.notin_(v.userblocks), Comment.author_id.notin_(v.userblocks),
) )
if 'post' in criteria: if 'post' in criteria:
try: post = int(criteria['post']) try: post = int(criteria['post'])
except: abort(404) except: abort(404)
@ -282,21 +282,21 @@ def searchusers(v:User):
t = request.values.get('t', 'all').lower() t = request.values.get('t', 'all').lower()
term=query.lstrip('@') term=query.lstrip('@')
term = term.replace('\\','').replace('_','\_').replace('%','') term = term.replace('\\','').replace('_','\_').replace('%','')
users=g.db.query(User).filter( users=g.db.query(User).filter(
or_( or_(
User.username.ilike(f'%{term}%'), User.username.ilike(f'%{term}%'),
User.original_username.ilike(f'%{term}%') User.original_username.ilike(f'%{term}%')
) )
) )
if v.admin_level < PERMS['USER_SHADOWBAN']: if v.admin_level < PERMS['USER_SHADOWBAN']:
users = users.filter(User.shadowbanned == None) users = users.filter(User.shadowbanned == None)
users=users.order_by(User.username.ilike(term).desc(), User.stored_subscriber_count.desc()) users=users.order_by(User.username.ilike(term).desc(), User.stored_subscriber_count.desc())
total=users.count() total=users.count()
users = users.offset(PAGE_SIZE * (page-1)).limit(PAGE_SIZE+1).all() users = users.offset(PAGE_SIZE * (page-1)).limit(PAGE_SIZE+1).all()
next_exists=(len(users)>PAGE_SIZE) next_exists=(len(users)>PAGE_SIZE)
users=users[:PAGE_SIZE] users=users[:PAGE_SIZE]

View File

@ -111,7 +111,7 @@ def settings_personal_post(v):
updated = False updated = False
# begin common selectors # # begin common selectors #
def update_flag(column_name:str, request_name:str): def update_flag(column_name:str, request_name:str):
if not request.values.get(request_name, ''): return False if not request.values.get(request_name, ''): return False
request_flag = request.values.get(request_name, '') == 'true' request_flag = request.values.get(request_name, '') == 'true'
@ -119,7 +119,7 @@ def settings_personal_post(v):
setattr(v, column_name, request_flag) setattr(v, column_name, request_flag)
return True return True
return False return False
def update_potentially_permanent_flag(column_name:str, request_name:str, friendly_name:str, badge_id:Optional[int]): def update_potentially_permanent_flag(column_name:str, request_name:str, friendly_name:str, badge_id:Optional[int]):
if not request.values.get(request_name): return False if not request.values.get(request_name): return False
current_value = getattr(v, column_name) current_value = getattr(v, column_name)
@ -161,14 +161,14 @@ def settings_personal_post(v):
updated = True updated = True
v.poor = request.values.get("poor", v.poor) == 'true' v.poor = request.values.get("poor", v.poor) == 'true'
session['poor'] = v.poor session['poor'] = v.poor
slur_filter_updated = updated or update_potentially_permanent_flag("slurreplacer", "slurreplacer", "slur replacer", 192) slur_filter_updated = updated or update_potentially_permanent_flag("slurreplacer", "slurreplacer", "slur replacer", 192)
if isinstance(slur_filter_updated, bool): if isinstance(slur_filter_updated, bool):
updated = slur_filter_updated updated = slur_filter_updated
else: else:
g.db.add(v) g.db.add(v)
return slur_filter_updated return slur_filter_updated
profanity_filter_updated = updated or update_potentially_permanent_flag("profanityreplacer", "profanityreplacer", "profanity replacer", 190) profanity_filter_updated = updated or update_potentially_permanent_flag("profanityreplacer", "profanityreplacer", "profanity replacer", 190)
if isinstance(profanity_filter_updated, bool): if isinstance(profanity_filter_updated, bool):
updated = profanity_filter_updated updated = profanity_filter_updated
@ -191,7 +191,7 @@ def settings_personal_post(v):
updated = True updated = True
v.spider = int(request.values.get("spider") == 'true') v.spider = int(request.values.get("spider") == 'true')
if v.spider: badge_grant(user=v, badge_id=179) if v.spider: badge_grant(user=v, badge_id=179)
else: else:
badge = v.has_badge(179) badge = v.has_badge(179)
if badge: g.db.delete(badge) if badge: g.db.delete(badge)
@ -317,7 +317,7 @@ def settings_personal_post(v):
updated = True updated = True
cache.delete_memoized(frontlist) cache.delete_memoized(frontlist)
else: abort(400) else: abort(400)
updated = updated or set_selector_option("defaultsortingcomments", "defaultsortingcomments", COMMENT_SORTS, "comment sort") updated = updated or set_selector_option("defaultsortingcomments", "defaultsortingcomments", COMMENT_SORTS, "comment sort")
updated = updated or set_selector_option("defaultsorting", "defaultsorting", SORTS, "post sort") updated = updated or set_selector_option("defaultsorting", "defaultsorting", SORTS, "post sort")
updated = updated or set_selector_option("defaulttime", "defaulttime", TIME_FILTERS, "time filter") updated = updated or set_selector_option("defaulttime", "defaulttime", TIME_FILTERS, "time filter")
@ -337,7 +337,7 @@ def settings_personal_post(v):
if v.house: if v.house:
if v.house.replace(' Founder', '') == house: abort(409, f"You're already in House {house}") if v.house.replace(' Founder', '') == house: abort(409, f"You're already in House {house}")
cost = HOUSE_SWITCH_COST cost = HOUSE_SWITCH_COST
else: else:
cost = HOUSE_JOIN_COST cost = HOUSE_JOIN_COST
success = v.charge_account('coins', cost) success = v.charge_account('coins', cost)
@ -345,7 +345,7 @@ def settings_personal_post(v):
success = v.charge_account('marseybux', cost) success = v.charge_account('marseybux', cost)
if not success: abort(403) if not success: abort(403)
if house == "None": house = '' if house == "None": house = ''
v.house = house v.house = house
updated = True updated = True
@ -389,7 +389,7 @@ def set_color(v:User, attr:str, color:Optional[str]):
@auth_required @auth_required
def namecolor(v): def namecolor(v):
return set_color(v, "namecolor", request.values.get("namecolor")) return set_color(v, "namecolor", request.values.get("namecolor"))
@app.post("/settings/themecolor") @app.post("/settings/themecolor")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER) @limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@limiter.limit(DEFAULT_RATELIMIT_SLOWER, key_func=lambda:f'{request.host}-{session.get("lo_user")}') @limiter.limit(DEFAULT_RATELIMIT_SLOWER, key_func=lambda:f'{request.host}-{session.get("lo_user")}')
@ -430,7 +430,7 @@ def gumroad(v):
g.db.add(v) g.db.add(v)
badge_grant(badge_id=20+tier, user=v) badge_grant(badge_id=20+tier, user=v)
return {"message": f"{patron} rewards claimed!"} return {"message": f"{patron} rewards claimed!"}
@ -640,7 +640,7 @@ def settings_security(v:User):
def settings_block_user(v): 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: abort(404, "This user doesn't exist.") if not user: abort(404, "This user doesn't exist.")
if user.unblockable: if user.unblockable:
if not v.shadowbanned: if not v.shadowbanned:
send_notification(user.id, f"@{v.username} has tried to block you and failed because of your unblockable status!") send_notification(user.id, f"@{v.username} has tried to block you and failed because of your unblockable status!")
@ -778,12 +778,12 @@ def settings_song_change(v):
if not yt_id_regex.fullmatch(id): if not yt_id_regex.fullmatch(id):
return render_template("settings/personal.html", v=v, error="Not a YouTube link"), 400 return render_template("settings/personal.html", v=v, error="Not a YouTube link"), 400
if path.isfile(f'/songs/{id}.mp3'): if path.isfile(f'/songs/{id}.mp3'):
v.song = id v.song = id
g.db.add(v) g.db.add(v)
return render_template("settings/personal.html", v=v, msg="Profile Anthem successfully updated!") return render_template("settings/personal.html", v=v, msg="Profile Anthem successfully updated!")
req = requests.get(f"https://www.googleapis.com/youtube/v3/videos?id={id}&key={YOUTUBE_KEY}&part=contentDetails", timeout=5).json() req = requests.get(f"https://www.googleapis.com/youtube/v3/videos?id={id}&key={YOUTUBE_KEY}&part=contentDetails", timeout=5).json()
duration = req['items'][0]['contentDetails']['duration'] duration = req['items'][0]['contentDetails']['duration']
if duration == 'P0D': if duration == 'P0D':
@ -794,7 +794,7 @@ def settings_song_change(v):
if "M" in duration: if "M" in duration:
duration = int(duration.split("PT")[1].split("M")[0]) duration = int(duration.split("PT")[1].split("M")[0])
if duration > 15: if duration > 15:
return render_template("settings/personal.html", v=v, error="Duration of the video must not exceed 15 minutes."), 400 return render_template("settings/personal.html", v=v, error="Duration of the video must not exceed 15 minutes."), 400
@ -835,7 +835,7 @@ def settings_song_change(v):
@auth_required @auth_required
def settings_title_change(v): def settings_title_change(v):
if v.flairchanged: abort(403) if v.flairchanged: abort(403)
customtitleplain = sanitize_settings_text(request.values.get("title"), 100) customtitleplain = sanitize_settings_text(request.values.get("title"), 100)
if len(customtitleplain) > 100: if len(customtitleplain) > 100:

View File

@ -142,7 +142,7 @@ def log(v:User):
actions = [] actions = []
else: else:
actions = g.db.query(ModAction) actions = g.db.query(ModAction)
if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']): if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
actions = actions.filter(ModAction.kind.notin_(MODACTION_PRIVILEGED_TYPES)) actions = actions.filter(ModAction.kind.notin_(MODACTION_PRIVILEGED_TYPES))
if admin_id: if admin_id:
@ -156,7 +156,7 @@ def log(v:User):
if kind: actions = actions.filter_by(kind=kind) if kind: actions = actions.filter_by(kind=kind)
actions = actions.order_by(ModAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all() actions = actions.order_by(ModAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all()
next_exists=len(actions) > PAGE_SIZE next_exists=len(actions) > PAGE_SIZE
actions=actions[:PAGE_SIZE] actions=actions[:PAGE_SIZE]
admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.username).all()] admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.username).all()]
@ -228,7 +228,7 @@ def submit_contact(v):
execute_blackjack(v, new_comment, new_comment.body_html, 'modmail') execute_blackjack(v, new_comment, new_comment.body_html, 'modmail')
execute_under_siege(v, new_comment, new_comment.body_html, 'modmail') execute_under_siege(v, new_comment, new_comment.body_html, 'modmail')
new_comment.top_comment_id = new_comment.id new_comment.top_comment_id = new_comment.id
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != AEVANN_ID) admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != AEVANN_ID)
for admin in admins.all(): for admin in admins.all():
@ -254,7 +254,7 @@ def badge_list(site):
counts = {} counts = {}
for c in counts_raw: for c in counts_raw:
counts[c[0]] = (c[1], float(c[1]) * 100 / max(users, 1)) counts[c[0]] = (c[1], float(c[1]) * 100 / max(users, 1))
return badges, counts return badges, counts
@app.get("/badges") @app.get("/badges")

View File

@ -37,7 +37,7 @@ def exile_post(v:User, pid):
_note=f'for <a href="{p.permalink}">{p.title_html}</a>' _note=f'for <a href="{p.permalink}">{p.title_html}</a>'
) )
g.db.add(ma) g.db.add(ma)
return {"message": f"@{u.username} has been exiled from /h/{sub} successfully!"} return {"message": f"@{u.username} has been exiled from /h/{sub} successfully!"}
@app.post("/exile/comment/<int:cid>") @app.post("/exile/comment/<int:cid>")
@ -92,11 +92,11 @@ def unexile(v:User, sub, uid):
target_user_id=u.id target_user_id=u.id
) )
g.db.add(ma) g.db.add(ma)
if g.is_api_or_xhr: if g.is_api_or_xhr:
return {"message": f"@{u.username} has been unexiled from /h/{sub} successfully!"} return {"message": f"@{u.username} has been unexiled from /h/{sub} successfully!"}
return redirect(f'/h/{sub}/exilees') return redirect(f'/h/{sub}/exilees')
@app.post("/h/<sub>/block") @app.post("/h/<sub>/block")
@ -205,7 +205,7 @@ def sub_blockers(v:User, sub):
.filter_by(sub=sub.name) \ .filter_by(sub=sub.name) \
.order_by(nullslast(SubBlock.created_utc.desc()), User.username).all() .order_by(nullslast(SubBlock.created_utc.desc()), User.username).all()
return render_template("sub/blockers.html", return render_template("sub/blockers.html",
v=v, sub=sub, users=users, verb="blocking") v=v, sub=sub, users=users, verb="blocking")
@ -219,7 +219,7 @@ def sub_followers(v:User, sub):
.filter_by(sub=sub.name) \ .filter_by(sub=sub.name) \
.order_by(nullslast(SubSubscription.created_utc.desc()), User.username).all() .order_by(nullslast(SubSubscription.created_utc.desc()), User.username).all()
return render_template("sub/blockers.html", return render_template("sub/blockers.html",
v=v, sub=sub, users=users, verb="following") v=v, sub=sub, users=users, verb="following")
@ -265,7 +265,7 @@ def add_mod(v:User, sub):
@is_not_permabanned @is_not_permabanned
def remove_mod(v:User, sub): def remove_mod(v:User, sub):
sub = get_sub_by_name(sub).name sub = get_sub_by_name(sub).name
if not v.mods(sub): abort(403) if not v.mods(sub): abort(403)
if v.shadowbanned: abort(500) if v.shadowbanned: abort(500)
@ -510,7 +510,7 @@ def delete_sub_banner(v:User, sub:str, index:int):
@limiter.limit("1/10 second;30/day") @limiter.limit("1/10 second;30/day")
@limiter.limit("1/10 second;30/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}') @limiter.limit("1/10 second;30/day", key_func=lambda:f'{request.host}-{session.get("lo_user")}')
@is_not_permabanned @is_not_permabanned
def delete_all_sub_banners(v:User, sub:str): def delete_all_sub_banners(v:User, sub:str):
sub = get_sub_by_name(sub) sub = get_sub_by_name(sub)
if not v.mods(sub.name): abort(403) if not v.mods(sub.name): abort(403)
if v.shadowbanned: return redirect(f'/h/{sub}/settings') if v.shadowbanned: return redirect(f'/h/{sub}/settings')
@ -542,7 +542,7 @@ def sub_sidebar(v:User, sub):
sub = get_sub_by_name(sub) sub = get_sub_by_name(sub)
if not v.mods(sub.name): abort(403) if not v.mods(sub.name): abort(403)
if v.shadowbanned: return redirect(f'/h/{sub}/settings') if v.shadowbanned: return redirect(f'/h/{sub}/settings')
file = request.files["sidebar"] file = request.files["sidebar"]
name = f'/images/{time.time()}'.replace('.','') + '.webp' name = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(name) file.save(name)
@ -573,7 +573,7 @@ def sub_marsey(v:User, sub):
sub = get_sub_by_name(sub) sub = get_sub_by_name(sub)
if not v.mods(sub.name): abort(403) if not v.mods(sub.name): abort(403)
if v.shadowbanned: return redirect(f'/h/{sub}/settings') if v.shadowbanned: return redirect(f'/h/{sub}/settings')
file = request.files["marsey"] file = request.files["marsey"]
name = f'/images/{time.time()}'.replace('.','') + '.webp' name = f'/images/{time.time()}'.replace('.','') + '.webp'
file.save(name) file.save(name)
@ -692,12 +692,12 @@ def sub_stealth(v:User, sub):
@feature_required('PINS') @feature_required('PINS')
@is_not_permabanned @is_not_permabanned
def mod_pin(cid, v): def mod_pin(cid, v):
comment = get_comment(cid, v=v) comment = get_comment(cid, v=v)
if not comment.stickied: if not comment.stickied:
if not (comment.post.sub and v.mods(comment.post.sub)): abort(403) if not (comment.post.sub and v.mods(comment.post.sub)): abort(403)
comment.stickied = v.username + " (Mod)" comment.stickied = v.username + " (Mod)"
g.db.add(comment) g.db.add(comment)
@ -719,9 +719,9 @@ def mod_pin(cid, v):
@app.post("/unmod_pin/<int:cid>") @app.post("/unmod_pin/<int:cid>")
@is_not_permabanned @is_not_permabanned
def mod_unpin(cid, v): def mod_unpin(cid, v):
comment = get_comment(cid, v=v) comment = get_comment(cid, v=v)
if comment.stickied: if comment.stickied:
if not (comment.post.sub and v.mods(comment.post.sub)): abort(403) if not (comment.post.sub and v.mods(comment.post.sub)): abort(403)
@ -776,7 +776,7 @@ def hole_log(v:User, sub):
if kind: actions = actions.filter_by(kind=kind) if kind: actions = actions.filter_by(kind=kind)
actions = actions.order_by(SubAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all() actions = actions.order_by(SubAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all()
next_exists=len(actions)>25 next_exists=len(actions)>25
actions=actions[:25] actions=actions[:25]
mods = [x[0] for x in g.db.query(Mod.user_id).filter_by(sub=sub.name).all()] mods = [x[0] for x in g.db.query(Mod.user_id).filter_by(sub=sub.name).all()]

View File

@ -96,7 +96,7 @@ def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, sta
listing = [p.id for p in listing] listing = [p.id for p in listing]
next_exists = len(listing) > PAGE_SIZE next_exists = len(listing) > PAGE_SIZE
listing = listing[:PAGE_SIZE] listing = listing[:PAGE_SIZE]
if cls == Submission: if cls == Submission:
listing = get_posts(listing, v=v, eager=True) listing = get_posts(listing, v=v, eager=True)
elif cls == Comment: elif cls == Comment:
@ -238,7 +238,7 @@ def all_upvoters_downvoters(v:User, username:str, vote_dir:int, is_who_simps_hat
users = g.db.query(User).filter(User.id.in_(votes.keys())) users = g.db.query(User).filter(User.id.in_(votes.keys()))
if not v.can_see_shadowbanned: if not v.can_see_shadowbanned:
users = users.filter(User.shadowbanned == None) users = users.filter(User.shadowbanned == None)
users2 = [(user, votes[user.id]) for user in users.all()] users2 = [(user, votes[user.id]) for user in users.all()]
users = sorted(users2, key=lambda x: x[1], reverse=True) users = sorted(users2, key=lambda x: x[1], reverse=True)
@ -255,7 +255,7 @@ def all_upvoters_downvoters(v:User, username:str, vote_dir:int, is_who_simps_hat
try: page = int(request.values.get("page", 1)) try: page = int(request.values.get("page", 1))
except: page = 1 except: page = 1
users = users[PAGE_SIZE * (page-1):] users = users[PAGE_SIZE * (page-1):]
next_exists = (len(users) > PAGE_SIZE) next_exists = (len(users) > PAGE_SIZE)
users = users[:PAGE_SIZE] users = users[:PAGE_SIZE]
@ -340,7 +340,7 @@ def transfer_currency(v:User, username:str, currency_name:Literal['coins', 'mars
send_repeatable_notification(receiver.id, notif_text) send_repeatable_notification(receiver.id, notif_text)
g.db.add(v) g.db.add(v)
return {"message": f"{amount - tax} {currency_name} have been transferred to @{receiver.username}"} return {"message": f"{amount - tax} {currency_name} have been transferred to @{receiver.username}"}
@app.post("/@<username>/transfer_coins") @app.post("/@<username>/transfer_coins")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER) @limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@limiter.limit(DEFAULT_RATELIMIT_SLOWER, key_func=lambda:f'{request.host}-{session.get("lo_user")}') @limiter.limit(DEFAULT_RATELIMIT_SLOWER, key_func=lambda:f'{request.host}-{session.get("lo_user")}')
@ -445,7 +445,7 @@ def subscribe(v, post_id):
new_sub = Subscription(user_id=v.id, submission_id=post_id) new_sub = Subscription(user_id=v.id, submission_id=post_id)
g.db.add(new_sub) g.db.add(new_sub)
return {"message": "Subscribed to post successfully!"} return {"message": "Subscribed to post successfully!"}
@app.post("/unsubscribe/<int:post_id>") @app.post("/unsubscribe/<int:post_id>")
@limiter.limit(DEFAULT_RATELIMIT_SLOWER) @limiter.limit(DEFAULT_RATELIMIT_SLOWER)
@limiter.limit(DEFAULT_RATELIMIT_SLOWER, key_func=lambda:f'{request.host}-{session.get("lo_user")}') @limiter.limit(DEFAULT_RATELIMIT_SLOWER, key_func=lambda:f'{request.host}-{session.get("lo_user")}')
@ -629,7 +629,7 @@ def is_available(name:str):
if len(name)<3 or len(name)>25: if len(name)<3 or len(name)>25:
return {name:False} return {name:False}
name2 = name.replace('\\', '').replace('_','\_').replace('%','') name2 = name.replace('\\', '').replace('_','\_').replace('%','')
x = g.db.query(User).filter( x = g.db.query(User).filter(
@ -648,7 +648,7 @@ def is_available(name:str):
def user_id(id): def user_id(id):
user = get_account(id) user = get_account(id)
return redirect(user.url) return redirect(user.url)
@app.get("/u/<username>") @app.get("/u/<username>")
@auth_required @auth_required
def redditor_moment_redirect(v:User, username:str): def redditor_moment_redirect(v:User, username:str):
@ -785,10 +785,10 @@ def u_username_wall(v:Optional[User], username:str):
next_exists = (len(comments) > PAGE_SIZE) next_exists = (len(comments) > PAGE_SIZE)
comments = comments[:PAGE_SIZE] comments = comments[:PAGE_SIZE]
if (v and v.client) or request.path.endswith(".json"): if (v and v.client) or request.path.endswith(".json"):
return {"data": [c.json(g.db) for c in comments]} return {"data": [c.json(g.db) for c in comments]}
return render_template("userpage/wall.html", u=u, v=v, listing=comments, page=page, next_exists=next_exists, is_following=is_following, standalone=True, render_replies=True, wall=True) return render_template("userpage/wall.html", u=u, v=v, listing=comments, page=page, next_exists=next_exists, is_following=is_following, standalone=True, render_replies=True, wall=True)
@ -837,12 +837,12 @@ def u_username_wall_comment(v:User, username:str, cid):
c = c.parent_comment c = c.parent_comment
context -= 1 context -= 1
top_comment = c top_comment = c
if v: if v:
# this is required because otherwise the vote and block # this is required because otherwise the vote and block
# props won't save properly unless you put them in a list # props won't save properly unless you put them in a list
output = get_comments_v_properties(v, False, None, Comment.top_comment_id == c.top_comment_id)[1] output = get_comments_v_properties(v, False, None, Comment.top_comment_id == c.top_comment_id)[1]
if v and v.client: return top_comment.json(db=g.db) if v and v.client: return top_comment.json(db=g.db)
return render_template("userpage/wall.html", u=u, v=v, listing=[top_comment], page=1, is_following=is_following, standalone=True, render_replies=True, wall=True, comment_info=comment_info) return render_template("userpage/wall.html", u=u, v=v, listing=[top_comment], page=1, is_following=is_following, standalone=True, render_replies=True, wall=True, comment_info=comment_info)
@ -899,7 +899,7 @@ def u_username(v:Optional[User], username:str):
if u.unban_utc: if u.unban_utc:
if (v and v.client) or request.path.endswith(".json"): if (v and v.client) or request.path.endswith(".json"):
return {"data": [x.json(g.db) for x in listing]} return {"data": [x.json(g.db) for x in listing]}
return render_template("userpage/submissions.html", return render_template("userpage/submissions.html",
unban=u.unban_string, unban=u.unban_string,
u=u, u=u,
@ -913,7 +913,7 @@ def u_username(v:Optional[User], username:str):
if (v and v.client) or request.path.endswith(".json"): if (v and v.client) or request.path.endswith(".json"):
return {"data": [x.json(g.db) for x in listing]} return {"data": [x.json(g.db) for x in listing]}
return render_template("userpage/submissions.html", return render_template("userpage/submissions.html",
u=u, u=u,
v=v, v=v,
@ -955,7 +955,7 @@ def u_username_comments(username, v=None):
try: page = max(int(request.values.get("page", "1")), 1) try: page = max(int(request.values.get("page", "1")), 1)
except: page = 1 except: page = 1
sort=request.values.get("sort","new") sort=request.values.get("sort","new")
t=request.values.get("t","all") t=request.values.get("t","all")
@ -990,7 +990,7 @@ def u_username_comments(username, v=None):
if (v and v.client) or request.path.endswith(".json"): if (v and v.client) or request.path.endswith(".json"):
return {"data": [c.json(g.db) for c in listing]} return {"data": [c.json(g.db) for c in listing]}
return render_template("userpage/comments.html", u=u, v=v, listing=listing, page=page, sort=sort, t=t,next_exists=next_exists, is_following=is_following, standalone=True) return render_template("userpage/comments.html", u=u, v=v, listing=listing, page=page, sort=sort, t=t,next_exists=next_exists, is_following=is_following, standalone=True)
@ -1064,7 +1064,7 @@ def unfollow_user(username, v):
if follow: if follow:
g.db.delete(follow) g.db.delete(follow)
g.db.flush() g.db.flush()
target.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=target.id).count() target.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=target.id).count()
g.db.add(target) g.db.add(target)
@ -1087,7 +1087,7 @@ def remove_follow(username, v):
if not follow: return {"message": f"@{target.username} has been removed as a follower!"} if not follow: return {"message": f"@{target.username} has been removed as a follower!"}
g.db.delete(follow) g.db.delete(follow)
g.db.flush() g.db.flush()
v.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=v.id).count() v.stored_subscriber_count = g.db.query(Follow).filter_by(target_id=v.id).count()
g.db.add(v) g.db.add(v)
@ -1129,7 +1129,7 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone
ids = ids[:PAGE_SIZE] ids = ids[:PAGE_SIZE]
extra = None extra = None
if not v.admin_level >= PERMS['POST_COMMENT_MODERATION']: if not v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
extra = lambda q:q.filter(cls.is_banned == False, cls.deleted_utc == 0) extra = lambda q:q.filter(cls.is_banned == False, cls.deleted_utc == 0)
if cls is Submission: if cls is Submission:
@ -1138,7 +1138,7 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone
listing = get_comments(ids, v=v, extra=extra) listing = get_comments(ids, v=v, extra=extra)
else: else:
raise TypeError("Only supports Submissions and Comments. This is probably the result of a bug with *this* function") raise TypeError("Only supports Submissions and Comments. This is probably the result of a bug with *this* function")
if v.client: return {"data": [x.json(g.db) for x in listing]} if v.client: return {"data": [x.json(g.db) for x in listing]}
return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone) return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone)
@ -1183,7 +1183,7 @@ def fp(v:User, fp):
if existing: continue if existing: continue
add_alt(user1=v.id, user2=u.id) add_alt(user1=v.id, user2=u.id)
print(v.username + ' + ' + u.username, flush=True) print(v.username + ' + ' + u.username, flush=True)
check_for_alts(v) check_for_alts(v)
g.db.add(v) g.db.add(v)
return '', 204 return '', 204
@ -1282,13 +1282,13 @@ def settings_kofi(v:User):
abort(400, f"You must have a verified email to verify {patron} status and claim your rewards!") abort(400, f"You must have a verified email to verify {patron} status and claim your rewards!")
transactions = g.db.query(Transaction).filter_by(email=v.email, claimed=None).all() transactions = g.db.query(Transaction).filter_by(email=v.email, claimed=None).all()
if not transactions: if not transactions:
abort(400, f"{patron} rewards already claimed") abort(400, f"{patron} rewards already claimed")
highest_tier = 0 highest_tier = 0
marseybux = 0 marseybux = 0
for transaction in transactions: for transaction in transactions:
tier = kofi_tiers[transaction.amount] tier = kofi_tiers[transaction.amount]
marseybux += marseybux_li[tier] marseybux += marseybux_li[tier]

View File

@ -87,7 +87,7 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
else: else:
abort(400) abort(400)
existing = existing.one_or_none() existing = existing.one_or_none()
if IS_FISTMAS(): if IS_FISTMAS():
coin_mult = 2 coin_mult = 2
coin_value = coin_delta * coin_mult coin_value = coin_delta * coin_mult
@ -125,7 +125,7 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
real=real, real=real,
coins=coin_value coins=coin_value
) )
elif vote_cls == CommentVote: elif vote_cls == CommentVote:
vote = CommentVote(user_id=v.id, vote = CommentVote(user_id=v.id,
vote_type=new, vote_type=new,
comment_id=target_id, comment_id=target_id,

View File

@ -18,7 +18,7 @@ def get_logged_in_user():
token = request.headers.get("Authorization","").strip() token = request.headers.get("Authorization","").strip()
if token: if token:
client = g.db.query(ClientAuth).filter(ClientAuth.access_token == token).one_or_none() client = g.db.query(ClientAuth).filter(ClientAuth.access_token == token).one_or_none()
if client: if client:
v = client.user v = client.user
v.client = client v.client = client
else: else:
@ -65,7 +65,7 @@ def get_logged_in_user():
if f'@{v.username}, ' not in f.read(): if f'@{v.username}, ' not in f.read():
t = time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time())) t = time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time()))
log_file(f'@{v.username}, {v.truescore}, {ip}, {t}\n', 'eg.log') log_file(f'@{v.username}, {v.truescore}, {ip}, {t}\n', 'eg.log')
g.is_api_or_xhr = bool((v and v.client) or request.headers.get("xhr")) g.is_api_or_xhr = bool((v and v.client) or request.headers.get("xhr"))
return v return v

View File

@ -29,7 +29,7 @@
{% if not app.client_id%} {% if not app.client_id%}
<button type="button" class="btn btn-primary ml-auto mr-2" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/approve/{{app.id}}')">Approve</button> <button type="button" class="btn btn-primary ml-auto mr-2" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/approve/{{app.id}}')">Approve</button>
<button type="button" class="btn btn-secondary mr-0" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/reject/{{app.id}}')">Reject</button> <button type="button" class="btn btn-secondary mr-0" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/reject/{{app.id}}')">Reject</button>
{% else %} {% else %}

View File

@ -35,7 +35,7 @@
{% if not app.client_id %} {% if not app.client_id %}
<button type="button" class="btn btn-primary ml-auto mr-2" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/approve/{{app.id}}')">Approve</button> <button type="button" class="btn btn-primary ml-auto mr-2" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/approve/{{app.id}}')">Approve</button>
<button type="button" class="btn btn-secondary mr-0" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/reject/{{app.id}}')">Reject</button> <button type="button" class="btn btn-secondary mr-0" data-nonce="{{g.nonce}}" data-onclick="postToastReload(this,'/admin/app/reject/{{app.id}}')">Reject</button>
{% else %} {% else %}

View File

@ -33,7 +33,7 @@
<div class="custom-control"> <div class="custom-control">
<input autocomplete="off" class="custom-control-input" type="radio" id="{{badge.id}}" name="badge_id" value="{{badge.id}}" required> <input autocomplete="off" class="custom-control-input" type="radio" id="{{badge.id}}" name="badge_id" value="{{badge.id}}" required>
<label class="custom-control-label" for="{{badge.id}}"></label> <label class="custom-control-label" for="{{badge.id}}"></label>
</div> </div>
</td> </td>
<td> <td>
<label for="badge-{{badge.id}}"> <label for="badge-{{badge.id}}">

View File

@ -6,12 +6,12 @@
{% include "comments.html" %} {% include "comments.html" %}
{% endwith %} {% endwith %}
{% if not listing %} {% if not listing %}
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
<div class="text-center py-6"> <div class="text-center py-6">
<h4 class="p-2">There are no comments here (yet).</h4> <h4 class="p-2">There are no comments here (yet).</h4>
</div> </div>
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -6,12 +6,12 @@
{% include "comments.html" %} {% include "comments.html" %}
{% endwith %} {% endwith %}
{% if not listing %} {% if not listing %}
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
<div class="text-center py-6"> <div class="text-center py-6">
<h4 class="p-2">There are no comments here (yet).</h4> <h4 class="p-2">There are no comments here (yet).</h4>
</div> </div>
</div> </div>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -1,5 +1,5 @@
{% extends "default.html" %} {% extends "default.html" %}
{% block pagetitle %}{{game.capitalize()}}{% endblock %} {% block pagetitle %}{{game.capitalize()}}{% endblock %}
{% block content %} {% block content %}
<link rel="stylesheet" href="{{('css/casino/game_screen.css') | asset}}"> <link rel="stylesheet" href="{{('css/casino/game_screen.css') | asset}}">
<script defer src="{{'js/casino/game_screen.js' | asset}}"></script> <script defer src="{{'js/casino/game_screen.js' | asset}}"></script>

View File

@ -35,8 +35,8 @@
{% if c.is_banned %}removed by @{{c.ban_reason}} (Admin){% elif c.deleted_utc %}Deleted by author{% elif c.is_blocking %}You are blocking @{{c.author_name}}{% endif %} {% if c.is_banned %}removed by @{{c.ban_reason}} (Admin){% elif c.deleted_utc %}Deleted by author{% elif c.is_blocking %}You are blocking @{{c.author_name}}{% endif %}
</div> </div>
</div> </div>
{% if render_replies %} {% if render_replies %}
<div id="replies-of-{{c.fullname}}"> <div id="replies-of-{{c.fullname}}">
{% if level<9 or request.path.startswith('/notifications') %} {% if level<9 or request.path.startswith('/notifications') %}
{% for reply in replies %} {% for reply in replies %}
@ -197,7 +197,7 @@
{% elif c.created_utc %} {% elif c.created_utc %}
<span id="timestamp-{{c.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{c.created_utc}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" class="time-stamp">&nbsp;{{c.age_string}}</span> <span id="timestamp-{{c.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{c.created_utc}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" class="time-stamp">&nbsp;{{c.age_string}}</span>
{% endif %} {% endif %}
{% if c.edited_utc %} {% if c.edited_utc %}
<span class="time-edited" id="time-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{c.edited_utc}}')"><span>&#183;</span> <span class="font-italic">Edited {{c.edited_string}}</span></span> <span class="time-edited" id="time-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-onmouseover="timestamp(this, '{{c.edited_utc}}')"><span>&#183;</span> <span class="font-italic">Edited {{c.edited_string}}</span></span>
{% endif %} {% endif %}
@ -251,26 +251,26 @@
{% if c.parent_submission or c.wall_user_id %} {% if c.parent_submission or c.wall_user_id %}
{% if v and v.id==c.author_id %} {% if v and v.id==c.author_id %}
<div id="comment-edit-{{c.id}}" class="d-none comment-write collapsed child"> <div id="comment-edit-{{c.id}}" class="d-none comment-write collapsed child">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}10000{% endif %}" data-preview="preview-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('comment-edit-body-{{c.id}}','charcount-edit-{{c.id}}')" id="comment-edit-body-{{c.id}}" data-id="{{c.id}}" name="body" form="comment-edit-form-{{c.id}}" class="comment-box form-control rounded" placeholder="Add your comment..." rows="3">{{c.body}}</textarea> <textarea autocomplete="off" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}10000{% endif %}" data-preview="preview-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('comment-edit-body-{{c.id}}','charcount-edit-{{c.id}}')" id="comment-edit-body-{{c.id}}" data-id="{{c.id}}" name="body" form="comment-edit-form-{{c.id}}" class="comment-box form-control rounded" placeholder="Add your comment..." rows="3">{{c.body}}</textarea>
<div class="text-small font-weight-bold mt-1" id="charcount-edit-{{c.id}}" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div> <div class="text-small font-weight-bold mt-1" id="charcount-edit-{{c.id}}" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
<div class="comment-format"> <div class="comment-format">
<small class="btn btn-secondary format m-0" data-nonce="{{g.nonce}}" data-onclick="getGifs('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF"><span class="font-weight-bolder text-uppercase">GIF</span></small> <small class="btn btn-secondary format m-0" data-nonce="{{g.nonce}}" data-onclick="getGifs('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF"><span class="font-weight-bolder text-uppercase">GIF</span></small>
&nbsp; &nbsp;
<small class="btn btn-secondary format m-0" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></small> <small class="btn btn-secondary format m-0" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('comment-edit-body-{{c.id}}')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></small>
&nbsp; &nbsp;
<label class="btn btn-secondary format m-0" for="file-edit-reply-{{c.id}}"> <label class="btn btn-secondary format m-0" for="file-edit-reply-{{c.id}}">
<div id="filename-edit-reply-{{c.id}}"><i class="fas fa-file"></i></div> <div id="filename-edit-reply-{{c.id}}"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-edit-reply-{{c.id}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-edit-reply-{{c.id}}','file-edit-reply-{{c.id}}')" hidden> <input autocomplete="off" id="file-edit-reply-{{c.id}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-edit-reply-{{c.id}}','file-edit-reply-{{c.id}}')" hidden>
</label> </label>
</div> </div>
<button type="button" id="edit-btn-{{c.id}}" form="comment-edit-form-{{c.id}}" class="btn btn-primary ml-2 fl-r commentmob" data-nonce="{{g.nonce}}" data-onclick="comment_edit('{{c.id}}');remove_dialog()">Save Edit</button> <button type="button" id="edit-btn-{{c.id}}" form="comment-edit-form-{{c.id}}" class="btn btn-primary ml-2 fl-r commentmob" data-nonce="{{g.nonce}}" data-onclick="comment_edit('{{c.id}}');remove_dialog()">Save Edit</button>
<button type="button" id="cancel-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="toggleEdit('{{c.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto fl-r commentmob">Cancel</button> <button type="button" id="cancel-edit-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="toggleEdit('{{c.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto fl-r commentmob">Cancel</button>
<div id="preview-edit-{{c.id}}" class="preview mb-3 mt-5"></div> <div id="preview-edit-{{c.id}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div> <div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div>
</div> </div>
@ -290,45 +290,45 @@
{% if v and not c.deleted_utc %} {% if v and not c.deleted_utc %}
<button type="button" class="list-inline-item mr-3 btn nobackground" data-nonce="{{g.nonce}}" data-onclick="toggleReplyBox('reply-to-{{c.fullname}}')"><i class="fas fa-reply" style="margin-top:0.35rem"></i></button> <button type="button" class="list-inline-item mr-3 btn nobackground" data-nonce="{{g.nonce}}" data-onclick="toggleReplyBox('reply-to-{{c.fullname}}')"><i class="fas fa-reply" style="margin-top:0.35rem"></i></button>
{% endif %} {% endif %}
<li class="list-inline-item"> <li class="list-inline-item">
<button type="button" data-bs-toggle="modal" data-bs-target="#actionsModal-{{c.id}}"> <button type="button" data-bs-toggle="modal" data-bs-target="#actionsModal-{{c.id}}">
<i class="fas fa-ellipsis-h"></i> <i class="fas fa-ellipsis-h"></i>
</button> </button>
</li> </li>
{% if v and (request.path.startswith('/@') and not wall) and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %} {% if v and (request.path.startswith('/@') and not wall) and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
<li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none"> <li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none">
{% if voted==1 %} {% if voted==1 %}
<span class="mr-2 arrow-up comment-{{c.id}}-up active"></span> <span class="mr-2 arrow-up comment-{{c.id}}-up active"></span>
{% endif %} {% endif %}
<span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}style="cursor: default">{{score}}</span> <span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}style="cursor: default">{{score}}</span>
{% if voted==-1 %} {% if voted==-1 %}
<span class="ml-2 my-0 arrow-down comment-{{c.id}}-down active"></span> <span class="ml-2 my-0 arrow-down comment-{{c.id}}-down active"></span>
{% endif %} {% endif %}
</li> </li>
{% elif v %} {% elif v %}
<li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none"> <li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none">
<span tabindex="0" role="button" data-nonce="{{g.nonce}}" data-onclick="vote('comment-mobile', '{{c.id}}', '1')" class="comment-mobile-{{c.id}}-up mx-0 pr-1 arrow-up upvote-button comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"> <span tabindex="0" role="button" data-nonce="{{g.nonce}}" data-onclick="vote('comment-mobile', '{{c.id}}', '1')" class="comment-mobile-{{c.id}}-up mx-0 pr-1 arrow-up upvote-button comment-{{c.id}}-up {% if voted==1 %}active{% endif %}">
</span> </span>
<span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}style="cursor: default">{{score}}</span> <span class="comment-mobile-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}style="cursor: default">{{score}}</span>
<span {% if DISABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" data-nonce="{{g.nonce}}" data-onclick="vote('comment-mobile', '{{c.id}}', '-1')" class="comment-mobile-{{c.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"> <span {% if DISABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" role="button" data-nonce="{{g.nonce}}" data-onclick="vote('comment-mobile', '{{c.id}}', '-1')" class="comment-mobile-{{c.id}}-down mx-0 pl-1 my-0 arrow-down downvote-button comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}">
</span> </span>
</li> </li>
{% else %} {% else %}
<li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none"> <li id="voting-{{c.id}}-mobile" class="voting list-inline-item d-md-none">
<span tabindex="0" class="arrow-{{c.id}}-mobile-up mx-0 pr-1 arrow-mobile-up" data-href="/login?redirect={{request.full_path | urlencode}}"> <span tabindex="0" class="arrow-{{c.id}}-mobile-up mx-0 pr-1 arrow-mobile-up" data-href="/login?redirect={{request.full_path | urlencode}}">
<i class="fas fa-arrow-alt-up mx-0"></i> <i class="fas fa-arrow-alt-up mx-0"></i>
</span> </span>
<span class="comment-mobile-score-{{c.id}} score{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}style="cursor: default">{{score}}</span> <span class="comment-mobile-score-{{c.id}} score{% if c.controversial %} controversial{% endif %}"{% if not c.is_banned %} data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}"{% endif %}style="cursor: default">{{score}}</span>
<span tabindex="0" class="arrow-{{c.id}}-mobile-down arrow-mobile-down mx-0 pl-1 my-0" data-href="/login?redirect={{request.full_path | urlencode}}"> <span tabindex="0" class="arrow-{{c.id}}-mobile-down arrow-mobile-down mx-0 pl-1 my-0" data-href="/login?redirect={{request.full_path | urlencode}}">
<i class="fas fa-arrow-alt-down mx-0"></i> <i class="fas fa-arrow-alt-down mx-0"></i>
</span> </span>
@ -344,35 +344,35 @@
<button type="button" class="btn caction py-0 m-0 px-3 nobackground arrow-up mx-0 comment-{{c.id}}-up active"></button> <button type="button" class="btn caction py-0 m-0 px-3 nobackground arrow-up mx-0 comment-{{c.id}}-up active"></button>
{% endif %} {% endif %}
{% elif v %} {% elif v %}
<button type="button" tabindex="0" data-nonce="{{g.nonce}}" data-onclick="vote('comment', '{{c.id}}', '1')" class="comment-{{c.id}}-up btn caction py-0 m-0 px-3 nobackground arrow-up upvote-button mx-0 comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"></button> <button type="button" tabindex="0" data-nonce="{{g.nonce}}" data-onclick="vote('comment', '{{c.id}}', '1')" class="comment-{{c.id}}-up btn caction py-0 m-0 px-3 nobackground arrow-up upvote-button mx-0 comment-{{c.id}}-up {% if voted==1 %}active{% endif %}"></button>
{% else %} {% else %}
<button type="button" tabindex="0" class="comment-{{c.id}}-up btn caction nobackground py-0 m-0 px-3 arrow-up" data-href="/login?redirect={{request.full_path | urlencode}}"></button> <button type="button" tabindex="0" class="comment-{{c.id}}-up btn caction nobackground py-0 m-0 px-3 arrow-up" data-href="/login?redirect={{request.full_path | urlencode}}"></button>
{% endif %} {% endif %}
<span class="btn caction nobackground p-0 m-0" style="cursor: default"> <span class="btn caction nobackground p-0 m-0" style="cursor: default">
<span data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}" class="comment-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}">{{score}}</span> <span data-bs-toggle="tooltip" data-bs-placement="top" title="+{{ups}} | -{{downs}}" class="comment-score-{{c.id}} score comment-score-{{c.id}} {% if voted==1 %}score-up{% elif voted==-1%}score-down{% endif %}{% if c.controversial %} controversial{% endif %}">{{score}}</span>
</span> </span>
{% if v and (request.path.startswith('/@') and not wall) and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %} {% if v and (request.path.startswith('/@') and not wall) and v.admin_level < PERMS['VIEW_VOTE_BUTTONS_ON_USER_PAGE'] %}
{% if voted==-1 %} {% if voted==-1 %}
<li class=" arrow-down py-0 m-0 px-3 comment-{{c.id}}-down active"></li> <li class=" arrow-down py-0 m-0 px-3 comment-{{c.id}}-down active"></li>
{% endif %} {% endif %}
{% elif v %} {% elif v %}
<button type="button" {% if DISABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" data-nonce="{{g.nonce}}" data-onclick="vote('comment', '{{c.id}}', '-1')" class="comment-{{c.id}}-down btn caction py-0 m-0 px-3 nobackground arrow-down downvote-button comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"></button> <button type="button" {% if DISABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" data-nonce="{{g.nonce}}" data-onclick="vote('comment', '{{c.id}}', '-1')" class="comment-{{c.id}}-down btn caction py-0 m-0 px-3 nobackground arrow-down downvote-button comment-{{c.id}}-down {% if voted==-1 %}active{% endif %}"></button>
{% else %} {% else %}
<button type="button" {% if DISABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" class="comment-{{c.id}}-down btn caction py-0 m-0 px-3 nobackground arrow-down" data-href="/login?redirect={{request.full_path | urlencode}}"></button> <button type="button" {% if DISABLE_DOWNVOTES %}style="display:None!important"{% endif %} tabindex="0" class="comment-{{c.id}}-down btn caction py-0 m-0 px-3 nobackground arrow-down" data-href="/login?redirect={{request.full_path | urlencode}}"></button>
{% endif %} {% endif %}
{% if not c.ghost or (v and v.id == AEVANN_ID) %} {% if not c.ghost or (v and v.id == AEVANN_ID) %}
<a href="/votes/{{c.fullname}}" class="btn caction nobackground px-1 text-muted"><i class="fas fa-arrows-v"></i>Votes</a> <a href="/votes/{{c.fullname}}" class="btn caction nobackground px-1 text-muted"><i class="fas fa-arrows-v"></i>Votes</a>
{% endif %} {% endif %}
<a class="btn caction nobackground px-1 text-muted" href="{{c.permalink}}"><i class="fas fa-book-open"></i>Context</a> <a class="btn caction nobackground px-1 text-muted" href="{{c.permalink}}"><i class="fas fa-book-open"></i>Context</a>
<button type="button" class="btn caction py-0 nobackground px-1 text-muted copy-link" data-clipboard-text="{% if SITE == 'rdrama.net' %}https://{{BAN_EVASION_DOMAIN}}{{c.shortlink}}{% else %}{{c.permalink}}{% endif %}"><i class="fas fa-copy"></i>Copy link</button> <button type="button" class="btn caction py-0 nobackground px-1 text-muted copy-link" data-clipboard-text="{% if SITE == 'rdrama.net' %}https://{{BAN_EVASION_DOMAIN}}{{c.shortlink}}{% else %}{{c.permalink}}{% endif %}"><i class="fas fa-copy"></i>Copy link</button>
@ -387,16 +387,16 @@
{% if FEATURES['AWARDS'] -%} {% if FEATURES['AWARDS'] -%}
<button type="button" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="modal" data-bs-target="#awardModal" data-url="/award/comment/{{c.id}}" data-nonce="{{g.nonce}}"><i class="fas fa-gift"></i>Give Award</button> <button type="button" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="modal" data-bs-target="#awardModal" data-url="/award/comment/{{c.id}}" data-nonce="{{g.nonce}}"><i class="fas fa-gift"></i>Give Award</button>
{%- endif %} {%- endif %}
<button type="button" id="unsave-{{c.id}}" class="btn caction py-0 nobackground px-1 {% if c.id in v.saved_comment_idlist %}d-md-inline-block{% endif %} text-muted d-none" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unsave_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}','d-md-inline-block')"><i class="fas fa-save"></i>Unsave</button> <button type="button" id="unsave-{{c.id}}" class="btn caction py-0 nobackground px-1 {% if c.id in v.saved_comment_idlist %}d-md-inline-block{% endif %} text-muted d-none" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unsave_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}','d-md-inline-block')"><i class="fas fa-save"></i>Unsave</button>
<button type="button" id="save-{{c.id}}" class="btn caction py-0 nobackground px-1 {% if c.id not in v.saved_comment_idlist %}d-md-inline-block{% endif %} text-muted d-none" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/save_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}','d-md-inline-block')"><i class="fas fa-save"></i>Save</button> <button type="button" id="save-{{c.id}}" class="btn caction py-0 nobackground px-1 {% if c.id not in v.saved_comment_idlist %}d-md-inline-block{% endif %} text-muted d-none" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/save_comment/{{c.id}}','save-{{c.id}}','unsave-{{c.id}}','d-md-inline-block')"><i class="fas fa-save"></i>Save</button>
{% endif %} {% endif %}
{% if c.parent_submission or c.wall_user_id %} {% if c.parent_submission or c.wall_user_id %}
{% if v and c.author_id == v.id %} {% if v and c.author_id == v.id %}
<button type="button" class="btn caction py-0 nobackground px-1 text-muted" data-nonce="{{g.nonce}}" data-onclick="toggleEdit('{{c.id}}')"><i class="fas fa-edit fa-fw"></i>Edit</button> <button type="button" class="btn caction py-0 nobackground px-1 text-muted" data-nonce="{{g.nonce}}" data-onclick="toggleEdit('{{c.id}}')"><i class="fas fa-edit fa-fw"></i>Edit</button>
<button type="button" id="undelete-{{c.id}}" class="btn caction py-0 nobackground px-1 text-muted {% if not c.deleted_utc %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/undelete/comment/{{c.id}}','delete-{{c.id}}','undelete-{{c.id}}','d-none')" data-toggleelement="comment-{{c.id}}-only" data-toggleattr="deleted"><i class="fas fa-trash-alt fa-fw"></i>Undelete</button> <button type="button" id="undelete-{{c.id}}" class="btn caction py-0 nobackground px-1 text-muted {% if not c.deleted_utc %}d-none{% endif %}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/undelete/comment/{{c.id}}','delete-{{c.id}}','undelete-{{c.id}}','d-none')" data-toggleelement="comment-{{c.id}}-only" data-toggleattr="deleted"><i class="fas fa-trash-alt fa-fw"></i>Undelete</button>
<button type="button" id="delete-{{c.id}}" class="btn caction py-0 nobackground px-1 text-muted {% if c.deleted_utc %}d-none{% endif %}" data-bs-toggle="modal" data-bs-target="#deleteCommentModal" data-nonce="{{g.nonce}}" data-onclick="delete_commentModal(this, '{{c.id}}')"><i class="fas fa-trash-alt fa-fw"></i>Delete</button> <button type="button" id="delete-{{c.id}}" class="btn caction py-0 nobackground px-1 text-muted {% if c.deleted_utc %}d-none{% endif %}" data-bs-toggle="modal" data-bs-target="#deleteCommentModal" data-nonce="{{g.nonce}}" data-onclick="delete_commentModal(this, '{{c.id}}')"><i class="fas fa-trash-alt fa-fw"></i>Delete</button>
@ -437,7 +437,7 @@
{% if url != "" %} {% if url != "" %}
<button type="button" id="unpin-{{c.id}}" class="dropdown-item list-inline-item {% if c.stickied %}d-md-block{% endif %} text-muted d-none text-info" data-bs-dismiss="modal" data-bs-target="#actionsModal-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/un{{url}}/{{c.id}}','pin-{{c.id}}','unpin-{{c.id}}','d-md-block')"><i class="fas fa-thumbtack fa-rotate--45 text-info fa-fw"></i>Unpin</button> <button type="button" id="unpin-{{c.id}}" class="dropdown-item list-inline-item {% if c.stickied %}d-md-block{% endif %} text-muted d-none text-info" data-bs-dismiss="modal" data-bs-target="#actionsModal-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/un{{url}}/{{c.id}}','pin-{{c.id}}','unpin-{{c.id}}','d-md-block')"><i class="fas fa-thumbtack fa-rotate--45 text-info fa-fw"></i>Unpin</button>
<button type="button" id="pin-{{c.id}}" class="dropdown-item list-inline-item {% if not c.stickied %}d-md-block{% endif %} text-muted d-none text-info" data-bs-dismiss="modal" data-bs-target="#actionsModal-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/{{url}}/{{c.id}}','pin-{{c.id}}','unpin-{{c.id}}','d-md-block')"><i class="fas fa-thumbtack fa-rotate--45 text-info fa-fw"></i>Pin</button> <button type="button" id="pin-{{c.id}}" class="dropdown-item list-inline-item {% if not c.stickied %}d-md-block{% endif %} text-muted d-none text-info" data-bs-dismiss="modal" data-bs-target="#actionsModal-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/{{url}}/{{c.id}}','pin-{{c.id}}','unpin-{{c.id}}','d-md-block')"><i class="fas fa-thumbtack fa-rotate--45 text-info fa-fw"></i>Pin</button>
{% endif %} {% endif %}
{% endif %} {% endif %}
@ -480,7 +480,7 @@
</div> </div>
{% if v and v.id != c.author_id and c.body %} {% if v and v.id != c.author_id and c.body %}
<div autocomplete="off" class="markdown d-none card border my-2 p-3 comment-box form-control rounded" id="markdown-{{c.id}}" readonly>{{c.body.strip()}}</div> <div autocomplete="off" class="markdown d-none card border my-2 p-3 comment-box form-control rounded" id="markdown-{{c.id}}" readonly>{{c.body.strip()}}</div>
{% endif %} {% endif %}
{{macros.comment_reply_box(c.fullname, "reply-to-" + c.fullname, "d-none", "collapsed child", 'reply-to-' + c.fullname, true)}} {{macros.comment_reply_box(c.fullname, "reply-to-" + c.fullname, "d-none", "collapsed child", 'reply-to-' + c.fullname, true)}}
@ -489,7 +489,7 @@
<button type="button" class="copy-link ml-3" data-clipboard-text="{{c.log_link}}"><i class="far fa-copy text-muted"></i></button> <button type="button" class="copy-link ml-3" data-clipboard-text="{{c.log_link}}"><i class="far fa-copy text-muted"></i></button>
{% endif %} {% endif %}
{% if render_replies %} {% if render_replies %}
<div id="replies-of-{{c.fullname}}"> <div id="replies-of-{{c.fullname}}">
{% if request.path.startswith('/notifications/') and replies|length > 8 %} {% if request.path.startswith('/notifications/') and replies|length > 8 %}
{% for reply in replies %} {% for reply in replies %}
@ -506,7 +506,7 @@
</div> </div>
{% if request.path.startswith('/notifications') and c.level == 1 and c.sentto and not c.parent_submission and c.author_id != AUTOJANNY_ID %} {% if request.path.startswith('/notifications') and c.level == 1 and c.sentto and not c.parent_submission and c.author_id != AUTOJANNY_ID %}
{% if (v and v.admin_level >= PERMS['USER_BAN']) and (c.sentto == MODMAIL_ID) %} {% if (v and v.admin_level >= PERMS['USER_BAN']) and (c.sentto == MODMAIL_ID) %}
<button type="button" class="btn btn-danger mr-3 {% if c.author.is_muted %}d-none{% endif %}" id="mute-user-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/mute_user/{{c.author.id}}','mute-user-{{c.id}}','unmute-user-{{c.id}}','d-none')">Mute</button> <button type="button" class="btn btn-danger mr-3 {% if c.author.is_muted %}d-none{% endif %}" id="mute-user-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/mute_user/{{c.author.id}}','mute-user-{{c.id}}','unmute-user-{{c.id}}','d-none')">Mute</button>
<button type="button" class="btn btn-primary mr-3 {% if not c.author.is_muted %}d-none{% endif %}" id="unmute-user-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unmute_user/{{c.author.id}}','mute-user-{{c.id}}','unmute-user-{{c.id}}','d-none')">Unmute</button> <button type="button" class="btn btn-primary mr-3 {% if not c.author.is_muted %}d-none{% endif %}" id="unmute-user-{{c.id}}" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unmute_user/{{c.author.id}}','mute-user-{{c.id}}','unmute-user-{{c.id}}','d-none')">Unmute</button>
{% endif %} {% endif %}
@ -517,9 +517,9 @@
<div id="reply-message-{{c.fullname}}" class="d-none"> <div id="reply-message-{{c.fullname}}" class="d-none">
<div id="comment-form-space-{{c.id}}" class="comment-write collapsed child"> <div id="comment-form-space-{{c.id}}" class="comment-write collapsed child">
<div class="input-group"> <div class="input-group">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<textarea required autocomplete="off" minlength="1" maxlength="10000" name="body" form="reply-to-c_{{c.id}}" data-id="{{c.id}}" class="comment-box form-control rounded" id="reply-form-body-{{c.id}}" rows="3" data-preview="message-reply-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea> <textarea required autocomplete="off" minlength="1" maxlength="10000" name="body" form="reply-to-c_{{c.id}}" data-id="{{c.id}}" class="comment-box form-control rounded" id="reply-form-body-{{c.id}}" rows="3" data-preview="message-reply-{{c.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea>
<div class="comment-format" id="comment-format-bar-{{c.id}}"> <div class="comment-format" id="comment-format-bar-{{c.id}}">
<button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary m-0 mt-3 mr-1" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button> <button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary m-0 mt-3 mr-1" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
{% if c.sentto == MODMAIL_ID %} {% if c.sentto == MODMAIL_ID %}
@ -530,7 +530,7 @@
{% endif %} {% endif %}
</div> </div>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="remove_dialog()" class="btn btn-link text-muted ml-auto" data-toggleelement="reply-message-{{c.fullname}}" data-toggleattr="d-none">Cancel</button> <button type="button" data-nonce="{{g.nonce}}" data-onclick="remove_dialog()" class="btn btn-link text-muted ml-auto" data-toggleelement="reply-message-{{c.fullname}}" data-toggleattr="d-none">Cancel</button>
<button type="button" id="save-reply-to-{{c.id}}" class="btn btn-primary ml-2" data-nonce="{{g.nonce}}" data-onclick="post_reply('{{c.id}}');remove_dialog()">Reply</button> <button type="button" id="save-reply-to-{{c.id}}" class="btn btn-primary ml-2" data-nonce="{{g.nonce}}" data-onclick="post_reply('{{c.id}}');remove_dialog()">Reply</button>
</div> </div>
<div id="message-reply-{{c.id}}" class="preview mt-2"></div> <div id="message-reply-{{c.id}}" class="preview mt-2"></div>
@ -576,7 +576,7 @@
{% if c.author_id == v.id %} {% if c.author_id == v.id %}
<button type="button" data-bs-dismiss="modal" data-nonce="{{g.nonce}}" data-onclick="toggleEdit('{{c.id}}')" class="list-group-item"><i class="fas fa-edit mr-2"></i>Edit</button> <button type="button" data-bs-dismiss="modal" data-nonce="{{g.nonce}}" data-onclick="toggleEdit('{{c.id}}')" class="list-group-item"><i class="fas fa-edit mr-2"></i>Edit</button>
<button type="button" id="undelete2-{{c.id}}" class="{% if not c.deleted_utc %}d-none{% endif %} list-group-item text-success" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/undelete/comment/{{c.id}}', 'delete2-{{c.id}}', 'undelete2-{{c.id}}','d-none')" data-toggleelement="comment-{{c.id}}-only" data-toggleattr="deleted" data-bs-dismiss="modal"><i class="far fa-trash-alt text-success mr-2"></i>Undelete</button> <button type="button" id="undelete2-{{c.id}}" class="{% if not c.deleted_utc %}d-none{% endif %} list-group-item text-success" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/undelete/comment/{{c.id}}', 'delete2-{{c.id}}', 'undelete2-{{c.id}}','d-none')" data-toggleelement="comment-{{c.id}}-only" data-toggleattr="deleted" data-bs-dismiss="modal"><i class="far fa-trash-alt text-success mr-2"></i>Undelete</button>
<button type="button" id="delete2-{{c.id}}" class="{% if c.deleted_utc %}d-none{% endif %} list-group-item text-danger" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#deleteCommentModal" data-nonce="{{g.nonce}}" data-onclick="delete_commentModal(this, '{{c.id}}')"><i class="far fa-trash-alt text-danger mr-2"></i>Delete</button> <button type="button" id="delete2-{{c.id}}" class="{% if c.deleted_utc %}d-none{% endif %} list-group-item text-danger" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#deleteCommentModal" data-nonce="{{g.nonce}}" data-onclick="delete_commentModal(this, '{{c.id}}')"><i class="far fa-trash-alt text-danger mr-2"></i>Delete</button>
@ -711,7 +711,7 @@
<p class="d-mob-none">Your comment will be deleted everywhere on {{SITE_NAME}}.</p> <p class="d-mob-none">Your comment will be deleted everywhere on {{SITE_NAME}}.</p>
<p class="text-muted d-md-none">Your comment will be deleted everywhere on {{SITE_NAME}}.</p> <p class="text-muted d-md-none">Your comment will be deleted everywhere on {{SITE_NAME}}.</p>
<button type="button" id="deleteCommentButton" class="btn btn-danger btn-block mt-5" data-bs-dismiss="modal">Delete comment</button> <button type="button" id="deleteCommentButton" class="btn btn-danger btn-block mt-5" data-bs-dismiss="modal">Delete comment</button>
<button type="button" class="btn btn-secondary btn-block" data-bs-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary btn-block" data-bs-dismiss="modal">Cancel</button>

View File

@ -38,7 +38,7 @@
opacity: 0; opacity: 0;
overflow: hidden; overflow: hidden;
} }
body, body,
td, td,
th { th {
@ -80,7 +80,7 @@
p.sub { p.sub {
font-size: 13px; font-size: 13px;
} }
.align-right { .align-right {
text-align: right; text-align: right;
} }
@ -90,7 +90,7 @@
.align-center { .align-center {
text-align: center; text-align: center;
} }
.button { .button {
background-color: #FF66AC; background-color: #FF66AC;
border-top: 10px solid #FF66AC; border-top: 10px solid #FF66AC;
@ -124,7 +124,7 @@
text-align: center !important; text-align: center !important;
} }
} }
.attributes { .attributes {
margin: 0 0 21px; margin: 0 0 21px;
} }
@ -136,7 +136,7 @@
.attributes_item { .attributes_item {
padding: 0; padding: 0;
} }
.related { .related {
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -164,7 +164,7 @@
text-align: center; text-align: center;
padding: 25px 0 10px; padding: 25px 0 10px;
} }
.discount { .discount {
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -182,7 +182,7 @@
text-align: center; text-align: center;
font-size: 15px; font-size: 15px;
} }
.social { .social {
width: auto; width: auto;
} }
@ -195,7 +195,7 @@
margin: 0 8px 10px 8px; margin: 0 8px 10px 8px;
padding: 0; padding: 0;
} }
.purchase { .purchase {
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -267,7 +267,7 @@
-premailer-cellpadding: 0; -premailer-cellpadding: 0;
-premailer-cellspacing: 0; -premailer-cellspacing: 0;
} }
.email-masthead { .email-masthead {
display: none; display: none;
} }
@ -280,7 +280,7 @@
color: #121213; color: #121213;
text-decoration: none; text-decoration: none;
} }
.email-body { .email-body {
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -328,7 +328,7 @@
.content-cell { .content-cell {
padding: 35px; padding: 35px;
} }
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {
.email-body_inner, .email-body_inner,
.email-footer { .email-footer {

View File

@ -135,7 +135,7 @@ Text 2
Poll — Pick Multiple<br> Poll — Pick Multiple<br>
<span style="font-style: italic; font-weight: normal;"> <span style="font-style: italic; font-weight: normal;">
* Polls always appear at end of post. * Polls always appear at end of post.
</span> </span>
</td> </td>
<td>$$bussy$$<br>$$gussy$$</td> <td>$$bussy$$<br>$$gussy$$</td>
<td> <td>

View File

@ -46,7 +46,7 @@
<th>Owners</th> <th>Owners</th>
<th>Price</th> <th>Price</th>
<th>Actions</th> <th>Actions</th>
<th>Added on</th> <th>Added on</th>
</tr> </tr>
</thead> </thead>
@ -79,7 +79,7 @@
<div id="if-owned-{{hat.id}}" {% if hat.id not in owned_hat_ids %}class="d-none"{% endif %}> <div id="if-owned-{{hat.id}}" {% if hat.id not in owned_hat_ids %}class="d-none"{% endif %}>
<button type="button" id="unequip-{{hat.id}}" class="unequip {% if hat.id not in v.equipped_hat_ids %}d-none{% endif %} btn btn-success" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this, '/unequip_hat/{{hat.id}}', 'equip-{{hat.id}}', 'unequip-{{hat.id}}', 'd-none')"><span class="m-auto">Unequip</span></button> <button type="button" id="unequip-{{hat.id}}" class="unequip {% if hat.id not in v.equipped_hat_ids %}d-none{% endif %} btn btn-success" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this, '/unequip_hat/{{hat.id}}', 'equip-{{hat.id}}', 'unequip-{{hat.id}}', 'd-none')"><span class="m-auto">Unequip</span></button>
<button type="button" id="equip-{{hat.id}}" class="equip {% if hat.id in v.equipped_hat_ids %}d-none{% endif %} btn btn-success" data-nonce="{{g.nonce}}" data-onclick="equip_hat(this, '{{hat.id}}', '{{hat.name}}')"><span class="m-auto">Equip</span></button> <button type="button" id="equip-{{hat.id}}" class="equip {% if hat.id in v.equipped_hat_ids %}d-none{% endif %} btn btn-success" data-nonce="{{g.nonce}}" data-onclick="equip_hat(this, '{{hat.id}}', '{{hat.name}}')"><span class="m-auto">Equip</span></button>
</div> </div>
</td> </td>
@ -89,5 +89,5 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% endblock %} {% endblock %}

View File

@ -63,7 +63,7 @@
{% endif %} {% endif %}
<img id="header--icon" alt="header icon" {% if sub %}src="{{sub.marsey_url}}"{% else %}src="{{icon_url}}"{% endif %}> <img id="header--icon" alt="header icon" {% if sub %}src="{{sub.marsey_url}}"{% else %}src="{{icon_url}}"{% endif %}>
</a> </a>
{% if sub %} {% if sub %}
<a id="sub-name" href="/h/{{sub}}" class="font-weight-bold ml-2 flex-grow-1 mt-1" {% if sub.name|length >= 17 %}style="font-size:max(10px,1.2vw)"{% else %}style="font-size:max(14px,1.2vw)"{% endif %}>{% if not HOLE_STYLE_FLAIR %}/h/{% endif %}{{sub}}</a> <a id="sub-name" href="/h/{{sub}}" class="font-weight-bold ml-2 flex-grow-1 mt-1" {% if sub.name|length >= 17 %}style="font-size:max(10px,1.2vw)"{% else %}style="font-size:max(14px,1.2vw)"{% endif %}>{% if not HOLE_STYLE_FLAIR %}/h/{% endif %}{{sub}}</a>
{% elif has_logo %} {% elif has_logo %}
@ -77,7 +77,7 @@
</a> </a>
</div> </div>
{% endif %} {% endif %}
{% if not request.path.startswith('/search/') %} {% if not request.path.startswith('/search/') %}
<div class="flex-grow-1 d-fl d-mob-none {% if not v %}pad{% endif %}"> <div class="flex-grow-1 d-fl d-mob-none {% if not v %}pad{% endif %}">
<form class="form-inline search flex-nowrap mx-0 mx-lg-auto mb-0" {% if err %}style="margin-right:40rem!important"{% endif %} action="{% if request.path.startswith('/search') %}{{request.path}}{% else %}/search/posts/{% endif %}" method="get"> <form class="form-inline search flex-nowrap mx-0 mx-lg-auto mb-0" {% if err %}style="margin-right:40rem!important"{% endif %} action="{% if request.path.startswith('/search') %}{{request.path}}{% else %}/search/posts/{% endif %}" method="get">
@ -102,7 +102,7 @@
<a class="mobile-nav-icon d-md-none" href="/notifications" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Notifications"><i class="fas fa-bell align-middle text-gray-500 black"></i></a> <a class="mobile-nav-icon d-md-none" href="/notifications" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Notifications"><i class="fas fa-bell align-middle text-gray-500 black"></i></a>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if not err %} {% if not err %}
{% if v and v.admin_level >= PERMS['ADMIN_HOME_VISIBLE'] %} {% if v and v.admin_level >= PERMS['ADMIN_HOME_VISIBLE'] %}
<a class="mobile-nav-icon d-md-none" href="/admin"><i class="fas fa-crown align-middle text-gray-500 black"></i></a> <a class="mobile-nav-icon d-md-none" href="/admin"><i class="fas fa-crown align-middle text-gray-500 black"></i></a>
@ -154,7 +154,7 @@
{% if FEATURES['CHAT'] and v.admin_level >= PERMS['CHAT'] -%} {% if FEATURES['CHAT'] and v.admin_level >= PERMS['CHAT'] -%}
<li class="nav-item d-none d-lg-flex align-items-center justify-content-center text-center mx-1"> <li class="nav-item d-none d-lg-flex align-items-center justify-content-center text-center mx-1">
<a class="nav-link position-relative" href="/chat"> <a class="nav-link position-relative" href="/chat">
<i class="fas fa-messages" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Chat"></i> <i class="fas fa-messages" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Chat"></i>
<b class="text-lg" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Users in chat right now"> <b class="text-lg" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Users in chat right now">
{{loggedin_chat}} {{loggedin_chat}}
</b> </b>
@ -165,7 +165,7 @@
<li class="nav-item d-flex align-items-center justify-content-center text-center mx-1"> <li class="nav-item d-flex align-items-center justify-content-center text-center mx-1">
<a class="nav-link" href="/random_user" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Random User"><i class="fas fa-music"></i></a> <a class="nav-link" href="/random_user" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Random User"><i class="fas fa-music"></i></a>
</li> </li>
<li class="nav-item d-none d-lg-flex align-items-center justify-content-center text-center mx-1"> <li class="nav-item d-none d-lg-flex align-items-center justify-content-center text-center mx-1">
<a class="nav-link" href="/comments" data-bs-toggle="tooltip" data-bs-placement="bottom" title="All Comments"><i class="fas fa-comment-dots"></i></a> <a class="nav-link" href="/comments" data-bs-toggle="tooltip" data-bs-placement="bottom" title="All Comments"><i class="fas fa-comment-dots"></i></a>
</li> </li>
@ -287,7 +287,7 @@
<li class="nav-item"> <li class="nav-item">
<button type="button" class="nav-link copy-link" data-clipboard-text="{{SITE_FULL}}/signup?ref={{v.username}}"><i class="fas fa-user-friends fa-fw mr-3"></i>Invite friends</button> <button type="button" class="nav-link copy-link" data-clipboard-text="{{SITE_FULL}}/signup?ref={{v.username}}"><i class="fas fa-user-friends fa-fw mr-3"></i>Invite friends</button>
</li> </li>
<a class="nav-item nav-link" href="https://rdrama.net/h/changelog"><i class="fas fa-clipboard fa-fw mr-3"></i>Changelog</a> <a class="nav-item nav-link" href="https://rdrama.net/h/changelog"><i class="fas fa-clipboard fa-fw mr-3"></i>Changelog</a>
<a class="nav-item nav-link" rel="nofollow noopener" href="https://fsdfsd.net/rDrama/rDrama"><i class="fab fa-git-alt fa-fw mr-3"></i>Source code</a> <a class="nav-item nav-link" rel="nofollow noopener" href="https://fsdfsd.net/rDrama/rDrama"><i class="fab fa-git-alt fa-fw mr-3"></i>Source code</a>
@ -301,7 +301,7 @@
{% if SITE_NAME == 'rDrama' %} {% if SITE_NAME == 'rDrama' %}
<a class="nav-item nav-link" href="/archives"><i class="fas fa-book fa-fw mr-3"></i>Archives</a> <a class="nav-item nav-link" href="/archives"><i class="fas fa-book fa-fw mr-3"></i>Archives</a>
{% endif %} {% endif %}
<a class="nav-item nav-link" href="/contact"><i class="fas fa-file-signature fa-fw mr-3"></i>Contact us</a> <a class="nav-item nav-link" href="/contact"><i class="fas fa-file-signature fa-fw mr-3"></i>Contact us</a>
<li class="nav-item border-top border-bottom mt-2 pt-2"> <li class="nav-item border-top border-bottom mt-2 pt-2">

View File

@ -1,33 +1,33 @@
{%- {%-
set JOURNOID_BANNERS = [ set JOURNOID_BANNERS = [
( (
"Official site of /r/SubredditDrama 🍿", "Official site of /r/SubredditDrama 🍿",
"https://reddit.com/r/subredditdrama", "https://reddit.com/r/subredditdrama",
"" ""
), ),
( (
"As seen on The Independent 📰✨💞", "As seen on The Independent 📰✨💞",
"https://www.independent.co.uk/news/world/americas/us-politics/reddit-conservatives-post-trans-child-fake-b2060803.html", "https://www.independent.co.uk/news/world/americas/us-politics/reddit-conservatives-post-trans-child-fake-b2060803.html",
"https://rdrama.net//post/61530" "https://rdrama.net//post/61530"
), ),
( (
"As fact-checked by Reuters 📰✨💞", "As fact-checked by Reuters 📰✨💞",
"https://www.reuters.com/article/factcheck-socialmedia-gender/fact-check-post-about-parent-forcefully-medicating-transgender-child-is-fabricated-idUSL2N2WC1OK", "https://www.reuters.com/article/factcheck-socialmedia-gender/fact-check-post-about-parent-forcefully-medicating-transgender-child-is-fabricated-idUSL2N2WC1OK",
"https://rdrama.net//post/60443" "https://rdrama.net//post/60443"
), ),
( (
"As analyzed by Mashable 📰✨💞", "As analyzed by Mashable 📰✨💞",
"https://mashable.com/article/libs-of-tiktok-furries-school-troll-fake", "https://mashable.com/article/libs-of-tiktok-furries-school-troll-fake",
"https://rdrama.net//post/63155" "https://rdrama.net//post/63155"
), ),
( (
"As seen on Business Insider's retraction 📰✨💞", "As seen on Business Insider's retraction 📰✨💞",
"https://businessinsider.com/reddit-shuts-down-forum-for-texas-abortion-bounty-hunters-2021-9", "https://businessinsider.com/reddit-shuts-down-forum-for-texas-abortion-bounty-hunters-2021-9",
"https://rdrama.net//post/19236" "https://rdrama.net//post/19236"
), ),
( (
"As discussed on The Glenn Beck Program 📻✨💞", "As discussed on The Glenn Beck Program 📻✨💞",
"https://www.audacy.com/podcasts/the-glenn-beck-program-45436/elon-musk-vs-the-world-guests-rob-collins-riaz-patel-42722-1386209895", "https://www.audacy.com/podcasts/the-glenn-beck-program-45436/elon-musk-vs-the-world-guests-rob-collins-riaz-patel-42722-1386209895",
"https://rdrama.net//post/64305" "https://rdrama.net//post/64305"
), ),
( (

View File

@ -28,7 +28,7 @@
<div class="row" style="overflow: visible;padding-top:5px;"> <div class="row" style="overflow: visible;padding-top:5px;">
<div class="col"> <div class="col">
<div class="d-flex justify-content-between align-items-center"> <div class="d-flex justify-content-between align-items-center">
{% block navbar %} {% block navbar %}
<div class="d-flex align-items-center mb-3 ml-auto"> <div class="d-flex align-items-center mb-3 ml-auto">
<div class="dropdown dropdown-actions"> <div class="dropdown dropdown-actions">
@ -44,7 +44,7 @@
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
<div class="dropdown dropdown-actions ml-3"> <div class="dropdown dropdown-actions ml-3">
<button type="button" class="btn btn-secondary dropdown-toggle" id="dropdownMenuButton2" data-bs-toggle="dropdown"> <button type="button" class="btn btn-secondary dropdown-toggle" id="dropdownMenuButton2" data-bs-toggle="dropdown">
{% if type %}<i class="fas {{types[type]['icon']}} mr-2"></i>{{type}}{% else %}<i class="fas fa-broom mr-2"></i>All{% endif %} {% if type %}<i class="fas {{types[type]['icon']}} mr-2"></i>{{type}}{% else %}<i class="fas fa-broom mr-2"></i>All{% endif %}

View File

@ -17,7 +17,7 @@
Already have an account? <a href="/login{{'?redirect='+redirect if redirect else ''}}" class="font-weight-bold toggle-login">Log in</a> Already have an account? <a href="/login{{'?redirect='+redirect if redirect else ''}}" class="font-weight-bold toggle-login">Log in</a>
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %} {% block scripts %}
<div class="toast clipboard" id="toast-success" role="alert" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000"> <div class="toast clipboard" id="toast-success" role="alert" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body text-center"> <div class="toast-body text-center">
<i class="fas fa-check-circle text-success mr-2"></i>Link copied to clipboard <i class="fas fa-check-circle text-success mr-2"></i>Link copied to clipboard

View File

@ -1,7 +1,7 @@
{% extends "default.html" %} {% extends "default.html" %}
{% block pagetitle %}Directory{% endblock %} {% block pagetitle %}Directory{% endblock %}
{% block pagetype %}directory{% endblock %} {% block pagetype %}directory{% endblock %}
{# Title (~25char max), Description (~80char max), {# Title (~25char max), Description (~80char max),
Icon (fa-foo-bar), Color (#ff0000), URL (/post/12345/) #} Icon (fa-foo-bar), Color (#ff0000), URL (/post/12345/) #}
{%- set MEGATHREAD_INDEX = [] -%} {%- set MEGATHREAD_INDEX = [] -%}

View File

@ -41,5 +41,5 @@
<div class="toast-body bg-danger text-center text-white"> <div class="toast-body bg-danger text-center text-white">
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text2">Error, please try again later.</span> <i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text2">Error, please try again later.</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -18,7 +18,7 @@
<p class="d-mob-none">Your post will be deleted everywhere on {{SITE_NAME}}.</p> <p class="d-mob-none">Your post will be deleted everywhere on {{SITE_NAME}}.</p>
<p class="text-muted d-md-none">Your post will be deleted everywhere on {{SITE_NAME}}.</p> <p class="text-muted d-md-none">Your post will be deleted everywhere on {{SITE_NAME}}.</p>
<button type="button" id="deletePostButton" class="btn btn-danger btn-block mt-5" data-bs-dismiss="modal">Delete post</button> <button type="button" id="deletePostButton" class="btn btn-danger btn-block mt-5" data-bs-dismiss="modal">Delete post</button>
<button type="button" class="btn btn-secondary btn-block" data-bs-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary btn-block" data-bs-dismiss="modal">Cancel</button>

View File

@ -81,7 +81,7 @@
<div> <div>
{% if ma.sub %} {% if ma.sub %}
<a href="/h/{{ma.sub}}">/h/{{ma.sub}}</a> <a href="/h/{{ma.sub}}">/h/{{ma.sub}}</a>
- -
{% endif %} {% endif %}
<a href="{{ma.user.url}}" class="font-weight-bold text-black" target="_self">@{{ma.user.username}}</a> <a href="{{ma.user.url}}" class="font-weight-bold text-black" target="_self">@{{ma.user.username}}</a>
<span>{{ma.string | safe}}</span> <span>{{ma.string | safe}}</span>
@ -106,7 +106,7 @@
<i class="fas fa-check-circle text-success mr-2"></i>Link copied to clipboard <i class="fas fa-check-circle text-success mr-2"></i>Link copied to clipboard
</div> </div>
</div> </div>
<script defer src="{{'js/vendor/clipboard.js' | asset}}"></script> <script defer src="{{'js/vendor/clipboard.js' | asset}}"></script>
{% else %} {% else %}
{% with comments=notifications %} {% with comments=notifications %}

View File

@ -22,7 +22,7 @@
<button type="button" id="save-{{p.id}}" class="{% if p.id in v.saved_idlist %}d-none{% endif %} list-inline-item" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/save_post/{{p.id}}','save-{{p.id}}','unsave-{{p.id}}','d-none')"><i class="fas fa-save"></i>Save</button> <button type="button" id="save-{{p.id}}" class="{% if p.id in v.saved_idlist %}d-none{% endif %} list-inline-item" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/save_post/{{p.id}}','save-{{p.id}}','unsave-{{p.id}}','d-none')"><i class="fas fa-save"></i>Save</button>
<button type="button" id="unsave-{{p.id}}" class="{% if not p.id in v.saved_idlist %}d-none{% endif %} list-inline-item" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unsave_post/{{p.id}}','save-{{p.id}}','unsave-{{p.id}}','d-none')"><i class="fas fa-save"></i>Unsave</button> <button type="button" id="unsave-{{p.id}}" class="{% if not p.id in v.saved_idlist %}d-none{% endif %} list-inline-item" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this,'/unsave_post/{{p.id}}','save-{{p.id}}','unsave-{{p.id}}','d-none')"><i class="fas fa-save"></i>Unsave</button>
<button type="button" class="list-inline-item" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#reportPostModal" data-nonce="{{g.nonce}}" data-onclick="report_postModal('{{p.id}}')"><i class="fas fa-flag"></i>Report</button> <button type="button" class="list-inline-item" data-bs-toggle="modal" data-bs-dismiss="modal" data-bs-target="#reportPostModal" data-nonce="{{g.nonce}}" data-onclick="report_postModal('{{p.id}}')"><i class="fas fa-flag"></i>Report</button>
{% endif %} {% endif %}
@ -42,7 +42,7 @@
<ul class="dropdown-menu"> <ul class="dropdown-menu">
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.oauth_app %} {% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.oauth_app %}
<a class="dropdown-item list-inline-item text-info" href="{{p.oauth_app.permalink}}/posts"><i class="fas fa-code"></i>API App</a> <a class="dropdown-item list-inline-item text-info" href="{{p.oauth_app.permalink}}/posts"><i class="fas fa-code"></i>API App</a>
{% endif %} {% endif %}
{% if v.can_edit(p) %} {% if v.can_edit(p) %}
<button type="button" class="dropdown-item {% if p.new %} d-none{% endif %} list-inline-item text-info" id="{{p.id}}-sort-new" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this, '/post/{{p.id}}/new', '{{p.id}}-sort-new', '{{p.id}}-unsort-new', 'd-none', null, 'PUT')"><i class="fas fa-sparkles text-center text-primary mr-2"></i>Set Default Sort New</button> <button type="button" class="dropdown-item {% if p.new %} d-none{% endif %} list-inline-item text-info" id="{{p.id}}-sort-new" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this, '/post/{{p.id}}/new', '{{p.id}}-sort-new', '{{p.id}}-unsort-new', 'd-none', null, 'PUT')"><i class="fas fa-sparkles text-center text-primary mr-2"></i>Set Default Sort New</button>
<button type="button" class="dropdown-item {% if not p.new %} d-none{% endif %} list-inline-item text-info" id="{{p.id}}-unsort-new" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this, '/post/{{p.id}}/new', '{{p.id}}-unsort-new', '{{p.id}}-sort-new', 'd-none', null, 'DELETE')"><i class="fas fa-fire text-center text-primary mr-2"></i>Set Default Sort Hot</button> <button type="button" class="dropdown-item {% if not p.new %} d-none{% endif %} list-inline-item text-info" id="{{p.id}}-unsort-new" data-nonce="{{g.nonce}}" data-onclick="postToastSwitch(this, '/post/{{p.id}}/new', '{{p.id}}-unsort-new', '{{p.id}}-sort-new', 'd-none', null, 'DELETE')"><i class="fas fa-fire text-center text-primary mr-2"></i>Set Default Sort Hot</button>

View File

@ -66,7 +66,7 @@
{% if request.path.startswith('/search/posts') %} {% if request.path.startswith('/search/posts') %}
<div> <div>
<div style="display: inline-block; width: 150px; text-align: center;">Post Title Only:</div> <div style="display: inline-block; width: 150px; text-align: center;">Post Title Only:</div>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="addParam()" class="searchparam mb-1">title:true</button> <button type="button" data-nonce="{{g.nonce}}" data-onclick="addParam()" class="searchparam mb-1">title:true</button>
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -6,10 +6,10 @@
</div> </div>
{% if error %} {% if error %}
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
{{macros.ghost_box(error, '', 1)}} {{macros.ghost_box(error, '', 1)}}
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -91,7 +91,7 @@
<option value="{{entry}}"{{' selected' if v.defaulttime==entry}}>{{entry}}</option> <option value="{{entry}}"{{' selected' if v.defaulttime==entry}}>{{entry}}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -17,12 +17,12 @@
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<label for="edit-{{app.id}}-name" class="mb-0 w-lg-25">App Name</label> <label for="edit-{{app.id}}-name" class="mb-0 w-lg-25">App Name</label>
<input autocomplete="off" id="edit-{{app.id}}-name" class="form-control" type="text" name="name" value="{{app.app_name}}"> <input autocomplete="off" id="edit-{{app.id}}-name" class="form-control" type="text" name="name" value="{{app.app_name}}">
{% if app.client_id %} {% if app.client_id %}
<label for="edit-{{app.id}}-client-id" class="mb-0 w-lg-25">Client ID</label> <label for="edit-{{app.id}}-client-id" class="mb-0 w-lg-25">Client ID</label>
<input autocomplete="off" id="edit-{{app.id}}-client-id" class="form-control copy-link" type="text" name="name" value="{{app.client_id}}" data-clipboard-text="{{app.client_id}}" readonly="readonly"> <input autocomplete="off" id="edit-{{app.id}}-client-id" class="form-control copy-link" type="text" name="name" value="{{app.client_id}}" data-clipboard-text="{{app.client_id}}" readonly="readonly">
{% endif %} {% endif %}
<label for="edit-{{app.id}}-redirect" class="mb-0 w-lg-25">Redirect URI</label> <label for="edit-{{app.id}}-redirect" class="mb-0 w-lg-25">Redirect URI</label>
<input autocomplete="off" id="edit-{{app.id}}-redirect" class="form-control" type="text" name="redirect_uri" value="{{app.redirect_uri}}"> <input autocomplete="off" id="edit-{{app.id}}-redirect" class="form-control" type="text" name="redirect_uri" value="{{app.redirect_uri}}">
<label for="edit-{{app.id}}-desc" class="mb-0 w-lg-25">Description</label> <label for="edit-{{app.id}}-desc" class="mb-0 w-lg-25">Description</label>

View File

@ -73,9 +73,9 @@
{% macro text_area_section(id, form_action, form_name, section_title, contents, below_text, placeholder_text, show_extras, show_file_upload, maxlength, show_if) %} {% macro text_area_section(id, form_action, form_name, section_title, contents, below_text, placeholder_text, show_extras, show_file_upload, maxlength, show_if) %}
{% if show_if -%} {% if show_if -%}
<div class="body d-lg-flex border-bottom"> <div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">{{section_title}}</label> <label class="text-black w-lg-25">{{section_title}}</label>
<div class="w-lg-100"> <div class="w-lg-100">
<form id="{{id}}-form" action="{{form_action}}" method="post" enctype="multipart/form-data"> <form id="{{id}}-form" action="{{form_action}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" id="{{id}}-text" class="form-control rounded" placeholder="{{placeholder_text}}" rows="3" name="{{form_name}}" form="{{id}}-form" maxlength="{{maxlength}}">{% if contents %}{{contents}}{% endif %}</textarea> <textarea autocomplete="off" id="{{id}}-text" class="form-control rounded" placeholder="{{placeholder_text}}" rows="3" name="{{form_name}}" form="{{id}}-form" maxlength="{{maxlength}}">{% if contents %}{{contents}}{% endif %}</textarea>

View File

@ -47,7 +47,7 @@
<div class="body w-lg-100"> <div class="body w-lg-100">
<p>Change the background for the website.</p> <p>Change the background for the website.</p>
<div class="input-group mb2"> <div class="input-group mb2">
<select autocomplete="off" id='backgroundSelector' class="form-control" form="profile-settings" name="background" data-nonce="{{g.nonce}}" data-onchange="updatebgselection();"> <select autocomplete="off" id='backgroundSelector' class="form-control" form="profile-settings" name="background" data-nonce="{{g.nonce}}" data-onchange="updatebgselection();">
{% for entry in BACKGROUND_CATEGORIES %} {% for entry in BACKGROUND_CATEGORIES %}
<option value="{{entry}}" {% if v.background and v.background.startswith(entry) %}selected{% endif %}> <option value="{{entry}}" {% if v.background and v.background.startswith(entry) %}selected{% endif %}>
{{entry}} {{entry}}
@ -55,10 +55,10 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<form class="d-flex mt-3 mb-2" id="upload-custom-background" action="/settings/custom_background" method="post" enctype="multipart/form-data"> <form class="d-flex mt-3 mb-2" id="upload-custom-background" action="/settings/custom_background" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<label class="btn btn-primary" for="upload-custom-background-file"> <label class="btn btn-primary" for="upload-custom-background-file">
<i class="fas fa-image mr-1"></i> <i class="fas fa-image mr-1"></i>
{% if v.background and v.background.startswith('/images/') %} {% if v.background and v.background.startswith('/images/') %}
{{v.background}} {{v.background}}
{% else %} {% else %}

View File

@ -51,7 +51,7 @@
{% if FEATURES['MARSEYBUX'] %} {% if FEATURES['MARSEYBUX'] %}
<span class="text-small text-muted pl-1">Must be same email as the one you used to donate <span class="text-small text-muted pl-1">Must be same email as the one you used to donate
{% if v.truescore >= TRUESCORE_DONATE_MINIMUM %} {% if v.truescore >= TRUESCORE_DONATE_MINIMUM %}
on on
{% if KOFI_TOKEN %} {% if KOFI_TOKEN %}
<a rel="nofollow noopener" class="text-primary" href="{{KOFI_LINK}}">Kofi</a> <a rel="nofollow noopener" class="text-primary" href="{{KOFI_LINK}}">Kofi</a>
{% else %} {% else %}
@ -61,14 +61,14 @@
</span> </span>
{% endif %} {% endif %}
</div> </div>
</form> </form>
</div> </div>
</section> </section>
<section id="site-settings-password-section" class="settings-section-section"> <section id="site-settings-password-section" class="settings-section-section">
<h5>Password</h5> <h5>Password</h5>
<div class="settings-section rounded"> <div class="settings-section rounded">
<form action="/settings/security" method="post"> <form action="/settings/security" method="post">
<div class="body"> <div class="body">
<div class="d-lg-flex"> <div class="d-lg-flex">
<label for="old_password" class="mb-0 w-lg-25">Old Password</label> <label for="old_password" class="mb-0 w-lg-25">Old Password</label>
<input autocomplete="off" class="form-control mb-2 w-lg-100" id="old_password" type="password" name="old_password" required> <input autocomplete="off" class="form-control mb-2 w-lg-100" id="old_password" type="password" name="old_password" required>

View File

@ -78,5 +78,5 @@
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -22,7 +22,7 @@
<button type="submit" class="btn btn-primary ml-auto" id="create_button" {% if cost > v.coins %}disabled{% endif %}>Create {{HOLE_NAME|capitalize}}</button> <button type="submit" class="btn btn-primary ml-auto" id="create_button" {% if cost > v.coins %}disabled{% endif %}>Create {{HOLE_NAME|capitalize}}</button>
</div> </div>
<p class="mt-2 mr-1" style="float: right"><b>Cost</b>: {{cost}} coins</p> <p class="mt-2 mr-1" style="float: right"><b>Cost</b>: {{cost}} coins</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -130,7 +130,7 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
<div id="post-text" class="{% if p.author.agendaposter and p.sub != 'chudrama' %}agendaposter{% endif %} {% if p.author.rainbow %}rainbow-text{% endif %}"> <div id="post-text" class="{% if p.author.agendaposter and p.sub != 'chudrama' %}agendaposter{% endif %} {% if p.author.rainbow %}rainbow-text{% endif %}">
{% if p.is_image %} {% if p.is_image %}
<div class="row no-gutters mb-4"> <div class="row no-gutters mb-4">
@ -175,23 +175,23 @@
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<input type="hidden" name="current_page" value="{{request.path}}"> <input type="hidden" name="current_page" value="{{request.path}}">
<textarea id="post-edit-title" autocomplete="off" max-length="500" name="title" class="comment-box form-control rounded" required placeholder="title">{{p.title}}</textarea> <textarea id="post-edit-title" autocomplete="off" max-length="500" name="title" class="comment-box form-control rounded" required placeholder="title">{{p.title}}</textarea>
<textarea autocomplete="off" name="body" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}20000{% endif %}" data-preview="post-edit-{{p.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('post-edit-box-{{p.id}}','charcount-post-edit')" id="post-edit-box-{{p.id}}" form="post-edit-form-{{p.id}}" class="comment-box form-control rounded" placeholder="Add text to your post..." rows="10" data-id="{{p.id}}">{{p.body}}</textarea> <textarea autocomplete="off" name="body" {% if v.longpost %}minlength="280"{% endif %} maxlength="{% if v.bird %}140{% else %}20000{% endif %}" data-preview="post-edit-{{p.id}}" data-nonce="{{g.nonce}}" data-oninput="markdown(this);charLimit('post-edit-box-{{p.id}}','charcount-post-edit')" id="post-edit-box-{{p.id}}" form="post-edit-form-{{p.id}}" class="comment-box form-control rounded" placeholder="Add text to your post..." rows="10" data-id="{{p.id}}">{{p.body}}</textarea>
<div class="text-small font-weight-bold mt-1" id="charcount-post-edit" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div> <div class="text-small font-weight-bold mt-1" id="charcount-post-edit" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></div>
<div class="comment-format"> <div class="comment-format">
<button type="button" class="format btn btn-secondary"><span class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('post-edit-box-{{p.id}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></button> <button type="button" class="format btn btn-secondary"><span class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('post-edit-box-{{p.id}}')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></button>
<button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-edit-box-{{p.id}}')" class="format btn btn-secondary" role="button" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button> <button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-edit-box-{{p.id}}')" class="format btn btn-secondary" role="button" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<label class="format btn btn-secondary m-0 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-edit-{{p.id}}"> <label class="format btn btn-secondary m-0 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-edit-{{p.id}}">
<div id="filename-show-edit-{{p.id}}"><i class="fas fa-file"></i></div> <div id="filename-show-edit-{{p.id}}"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload-edit-{{p.id}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-edit-{{p.id}}','file-upload-edit-{{p.id}}')" hidden> <input autocomplete="off" id="file-upload-edit-{{p.id}}" accept="image/*, video/*, audio/*" type="file" multiple="multiple" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-edit-{{p.id}}','file-upload-edit-{{p.id}}')" hidden>
</label> </label>
<small class="format d-none"><i class="fas fa-link"></i></small> <small class="format d-none"><i class="fas fa-link"></i></small>
</div> </div>
<button type="submit" form="post-edit-form-{{p.id}}" class="btn btn-primary ml-2 fl-r" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()">Save Edit</button> <button type="submit" form="post-edit-form-{{p.id}}" class="btn btn-primary ml-2 fl-r" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()">Save Edit</button>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="togglePostEdit('{{p.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto fl-r">Cancel</button> <button type="button" data-nonce="{{g.nonce}}" data-onclick="togglePostEdit('{{p.id}}');remove_dialog()" class="btn btn-link text-muted ml-auto fl-r">Cancel</button>
</form> </form>
<div id="post-edit-{{p.id}}" class="preview mb-3 mt-5"></div> <div id="post-edit-{{p.id}}" class="preview mb-3 mt-5"></div>
<div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div> <div class="form-text text-small p-0 m-0"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div>
@ -301,7 +301,7 @@
</div> </div>
{% if v and v.id != p.author_id and p.body and not v_forbid_deleted %} {% if v and v.id != p.author_id and p.body and not v_forbid_deleted %}
<div autocomplete="off" class="markdown d-none card border my-2 p-3 comment-box form-control rounded" id="markdown-{{p.id}}" readonly>{{p.body.strip()}}</div> <div autocomplete="off" class="markdown d-none card border my-2 p-3 comment-box form-control rounded" id="markdown-{{p.id}}" readonly>{{p.body.strip()}}</div>
{% endif %} {% endif %}
<div class="row border-md-0 comment-section pb-3"> <div class="row border-md-0 comment-section pb-3">
@ -342,7 +342,7 @@
{% include "comments.html" %} {% include "comments.html" %}
{% endwith %} {% endwith %}
</div> </div>
{% if offset %} {% if offset %}
<script defer src="{{'js/view_more.js' | asset}}"></script> <script defer src="{{'js/view_more.js' | asset}}"></script>
{% endif %} {% endif %}

View File

@ -31,7 +31,7 @@
</div> </div>
<div id="voting" class="d-md-block my-auto mr-3 text-center"> <div id="voting" class="d-md-block my-auto mr-3 text-center">
<div class="post-{{p.id}}-up arrow-up mx-auto"> <div class="post-{{p.id}}-up arrow-up mx-auto">
</div> </div>
@ -44,7 +44,7 @@
</div> </div>
{% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.body_html %} {% if v and v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.body_html %}
<div class="post-body mt-4 mb-2"> <div class="post-body mt-4 mb-2">
{{p.body_html | safe}} {{p.body_html | safe}}
</div> </div>
{% endif %} {% endif %}

View File

@ -144,7 +144,7 @@
{% endif %} {% endif %}
</li> </li>
{% if p.realbody(v, listing=True) %} {% if p.realbody(v, listing=True) %}
<button type="button" class="list-inline-item ml-2" data-nonce="{{g.nonce}}" data-onclick="expandText('{{p.id}}')"><i class="fas fa-expand-alt mx-0 text-expand-icon-{{p.id}}"></i></button> <button type="button" class="list-inline-item ml-2" data-nonce="{{g.nonce}}" data-onclick="expandText('{{p.id}}')"><i class="fas fa-expand-alt mx-0 text-expand-icon-{{p.id}}"></i></button>
{% endif %} {% endif %}
@ -250,8 +250,8 @@
{% else %} {% else %}
{% if u %} {% if u %}
{% if v and v.id == u.id %} {% if v and v.id == u.id %}
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
<div class="text-center px-3 my-3"> <div class="text-center px-3 my-3">
<span class="fa-stack fa-2x text-muted mb-4"> <span class="fa-stack fa-2x text-muted mb-4">
<i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i> <i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i>
@ -260,12 +260,12 @@
<h5>You haven't {% if "/saved/" in request.path %}saved{% elif "/subscribed/" in request.path %}subscribed to{% else %}made{% endif %} a post yet</h5> <h5>You haven't {% if "/saved/" in request.path %}saved{% elif "/subscribed/" in request.path %}subscribed to{% else %}made{% endif %} a post yet</h5>
<p class="text-muted mb-md-5">Your {% if "/saved/" in request.path %}saved posts{% elif "/subscribed/" in request.path %}subscribed posts{% else %}posting history{% endif %} will show here.</p> <p class="text-muted mb-md-5">Your {% if "/saved/" in request.path %}saved posts{% elif "/subscribed/" in request.path %}subscribed posts{% else %}posting history{% endif %} will show here.</p>
{% if "/saved/" not in request.path and "/subscribed/" not in request.path %}<a href="/submit" class="btn btn-primary">Create a post</a>{% endif %} {% if "/saved/" not in request.path and "/subscribed/" not in request.path %}<a href="/submit" class="btn btn-primary">Create a post</a>{% endif %}
</div> </div>
</div> </div>
</div> </div>
{% else %} {% else %}
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
<div class="text-center px-3 my-3"> <div class="text-center px-3 my-3">
<span class="fa-stack fa-2x text-muted mb-4"> <span class="fa-stack fa-2x text-muted mb-4">
<i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i> <i class="fas fa-square text-gray-500 opacity-25 fa-stack-2x"></i>
@ -273,16 +273,16 @@
</span> </span>
<h5>@{{u.username}} hasn't made a post yet</h5> <h5>@{{u.username}} hasn't made a post yet</h5>
<p class="text-muted mb-1">Their posting history will show here.</p> <p class="text-muted mb-1">Their posting history will show here.</p>
</div> </div>
</div> </div>
</div> </div>
{% endif %} {% endif %}
{% elif request.path != '/notifications/posts' %} {% elif request.path != '/notifications/posts' %}
<div class="row no-gutters"> <div class="row no-gutters">
<div class="col"> <div class="col">
{{macros.ghost_box(error if request.path.startswith('/search') else '', '', 1)}} {{macros.ghost_box(error if request.path.startswith('/search') else '', '', 1)}}
</div> </div>
</div> </div>
{% endif %} {% endif %}

View File

@ -31,7 +31,7 @@
</div> </div>
<label class='mt-4' for="title">Post Title</label> <label class='mt-4' for="title">Post Title</label>
<input autocomplete="off" class="form-control allow-emojis" id="post-title" type="text" name="title" placeholder="Required" value="{{title}}" minlength="1" maxlength="500" required data-nonce="{{g.nonce}}" data-oninput="checkForRequired();savetext()"> <input autocomplete="off" class="form-control allow-emojis" id="post-title" type="text" name="title" placeholder="Required" value="{{title}}" minlength="1" maxlength="500" required data-nonce="{{g.nonce}}" data-oninput="checkForRequired();savetext()">
<button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-title')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-2" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button> <button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-title')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn-2" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<div id="urlblock"> <div id="urlblock">
<label for="URL" class="mt-3">URL</label> <label for="URL" class="mt-3">URL</label>
<input autocomplete="off" class="form-control" id="post-url" name="url" type="url" placeholder="Optional if you have text." value="{{request.values.get('url','')}}" required data-nonce="{{g.nonce}}" data-oninput="checkForRequired();hide_image();savetext();checkRepost();autoSuggestTitle()"> <input autocomplete="off" class="form-control" id="post-url" name="url" type="url" placeholder="Optional if you have text." value="{{request.values.get('url','')}}" required data-nonce="{{g.nonce}}" data-oninput="checkForRequired();hide_image();savetext();checkRepost();autoSuggestTitle()">
@ -59,11 +59,11 @@
</div> </div>
<small class="btn btn-secondary format d-inline-block m-0"><span class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('post-text')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></small> <small class="btn btn-secondary format d-inline-block m-0"><span class="font-weight-bolder text-uppercase" data-nonce="{{g.nonce}}" data-onclick="getGifs('post-text')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></small>
&nbsp; &nbsp;
<button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-text')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button> <button role="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('post-text')" class="btn btn-secondary format d-inline-block m-0" id="emoji-reply-btn" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
<label class="format btn btn-secondary m-0 ml-2 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-submit"> <label class="format btn btn-secondary m-0 ml-2 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-submit">
<div id="filename-show-submit"><i class="fas fa-file"></i></div> <div id="filename-show-submit"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload-submit" multiple="multiple" accept="image/*, video/*, audio/*" type="file" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-submit','file-upload-submit');checkForRequired()" hidden> <input autocomplete="off" id="file-upload-submit" multiple="multiple" accept="image/*, video/*, audio/*" type="file" name="file" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-show-submit','file-upload-submit');checkForRequired()" hidden>
</label> </label>
<div id="preview" class="preview my-3"></div> <div id="preview" class="preview my-3"></div>
<div class="form-text text-small my-1"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div> <div class="form-text text-small my-1"><a href="/formatting" {% if v and v.newtab %}data-target="t" target="_blank"{% endif %}>Formatting help</a></div>
<div class="custom-control custom-checkbox"> <div class="custom-control custom-checkbox">

View File

@ -41,7 +41,7 @@
<input id="submit-hat" disabled type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" class="btn btn-primary ml-auto" value="Submit Hat"> <input id="submit-hat" disabled type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" class="btn btn-primary ml-auto" value="Submit Hat">
</div> </div>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
@ -60,7 +60,7 @@
<div class="d-lg-flex"> <div class="d-lg-flex">
<div class="body w-lg-100"> <div class="body w-lg-100">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<div><label class="mt-3">Image</label></div> <div><label class="mt-3">Image</label></div>
<img loading="lazy" src="/asset_submissions/hats/{{hat.name}}.webp?s={{range(1, 10000000)|random}}" style="max-width:50%;border:5px white solid"> <img loading="lazy" src="/asset_submissions/hats/{{hat.name}}.webp?s={{range(1, 10000000)|random}}" style="max-width:50%;border:5px white solid">
@ -78,7 +78,7 @@
<label class="mt-3" for="{{hat.name}}-name">Name</label> <label class="mt-3" for="{{hat.name}}-name">Name</label>
<input autocomplete="off" type="text" id="{{hat.name}}-name" class="form-control" name="name" maxlength="30" value="{{hat.name}}" pattern='hat[a-zA-Z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{hat.name}}-name" class="form-control" name="name" maxlength="30" value="{{hat.name}}" pattern='hat[a-zA-Z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}>
> >
<label class="mt-3" for="{{hat.name}}-description">Description</label> <label class="mt-3" for="{{hat.name}}-description">Description</label>
<input autocomplete="off" type="text" id="{{hat.name}}-description" class="form-control" name="description" maxlength="300" value="{{hat.description}}" pattern='[^<>&\n\t]{1,300}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{hat.name}}-description" class="form-control" name="description" maxlength="300" value="{{hat.description}}" pattern='[^<>&\n\t]{1,300}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_HATS'] %}readonly{% endif %}>

View File

@ -36,7 +36,7 @@
<input id="submit-marsey" disabled type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" class="btn btn-primary ml-auto" value="Submit Marsey"> <input id="submit-marsey" disabled type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this)" class="btn btn-primary ml-auto" value="Submit Marsey">
</div> </div>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
@ -55,10 +55,10 @@
<div class="d-lg-flex"> <div class="d-lg-flex">
<div class="body w-lg-100"> <div class="body w-lg-100">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<div><label class="mt-3">Image</label></div> <div><label class="mt-3">Image</label></div>
<img loading="lazy" src="/asset_submissions/marseys/{{marsey.name}}.webp?s={{range(1, 10000000)|random}}" style="max-width:50%;border:5px white solid"> <img loading="lazy" src="/asset_submissions/marseys/{{marsey.name}}.webp?s={{range(1, 10000000)|random}}" style="max-width:50%;border:5px white solid">
<div><label class="mt-3" for="{{marsey.name}}-submitter">Submitter</label></div> <div><label class="mt-3" for="{{marsey.name}}-submitter">Submitter</label></div>
<input autocomplete="off" type="text" id="{{marsey.name}}-submitter" class="form-control" maxlength="30" value="{{marsey.submitter}}" readonly> <input autocomplete="off" type="text" id="{{marsey.name}}-submitter" class="form-control" maxlength="30" value="{{marsey.submitter}}" readonly>
@ -67,7 +67,7 @@
<label class="mt-3" for="{{marsey.name}}-name">Name</label> <label class="mt-3" for="{{marsey.name}}-name">Name</label>
<input autocomplete="off" type="text" id="{{marsey.name}}-name" class="form-control" name="name" maxlength="30" value="{{marsey.name}}" pattern='marsey[a-z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{marsey.name}}-name" class="form-control" name="name" maxlength="30" value="{{marsey.name}}" pattern='marsey[a-z0-9]{1,24}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}readonly{% endif %}>
<label class="mt-3" for="{{marsey.name}}-tags">Tags</label> <label class="mt-3" for="{{marsey.name}}-tags">Tags</label>
<input autocomplete="off" type="text" id="{{marsey.name}}-tags" class="form-control" name="tags" maxlength="200" value="{{marsey.tags}}" pattern='[a-z0-9: ]{1,200}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}readonly{% endif %}> <input autocomplete="off" type="text" id="{{marsey.name}}-tags" class="form-control" name="tags" maxlength="200" value="{{marsey.tags}}" pattern='[a-z0-9: ]{1,200}' placeholder="Required" required {% if v.admin_level < PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'] %}readonly{% endif %}>
</div> </div>

Some files were not shown because too many files have changed in this diff Show More