Merge branch 'frost' into new-user-filtering
This commit is contained in:
commit
0002f66f36
82 changed files with 1036 additions and 1528 deletions
|
@ -58,6 +58,7 @@ app.config['MAIL_USERNAME'] = environ.get("MAIL_USERNAME", "").strip()
|
|||
app.config['MAIL_PASSWORD'] = environ.get("MAIL_PASSWORD", "").strip()
|
||||
app.config['DESCRIPTION'] = environ.get("DESCRIPTION", "DESCRIPTION GOES HERE").strip()
|
||||
app.config['SETTINGS'] = {}
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = app.config['DATABASE_URL']
|
||||
|
||||
r=redis.Redis(host=environ.get("REDIS_URL", "redis://localhost"), decode_responses=True, ssl_cert_reqs=None)
|
||||
|
||||
|
|
|
@ -4625,9 +4625,7 @@ img[pat][src^="/pp/"], img[pat][src$="/pic"] {
|
|||
color: #f27d0c !important;
|
||||
font-weight: 800;
|
||||
}
|
||||
.agendaposter {
|
||||
text-transform: uppercase !important;
|
||||
}
|
||||
|
||||
code {
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
|
BIN
files/assets/images/emojis/feather.webp
Normal file
BIN
files/assets/images/emojis/feather.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
|
@ -1,158 +0,0 @@
|
|||
const fav = document.getElementById('EMOJIS_favorite')
|
||||
const search_bar = document.getElementById('emoji_search')
|
||||
const search_container = document.getElementById('emoji-tab-search')
|
||||
let emojis = 1
|
||||
|
||||
|
||||
function loadEmojis(form) {
|
||||
if (emojis == 1)
|
||||
{
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", '/marsey_list');
|
||||
xhr.setRequestHeader('xhr', 'xhr');
|
||||
var f = new FormData();
|
||||
xhr.onload = function() {
|
||||
emojis = {
|
||||
'marsey': JSON.parse(xhr.response),
|
||||
|
||||
'marseyalphabet': ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','exclamationpoint','space','period','questionmark'],
|
||||
|
||||
'platy': ['platytrans','platyfuckyou','plarsy','platyabused','platyblizzard','platyboxer','platydevil','platyfear','platygirlmagic','platygolong','platyhaes','platyking','platylove','platyneet','platyold','platypatience','platypopcorn','platyrich','platysarcasm','platysilly','platysleeping','platythink','platytired','platytuxedomask','platyblush','platybruh','platycaveman','platycheer','platydown','platyeyes','platyheart','platylol','platymicdrop','platynooo','platysalute','platyseethe','platythumbsup','platywave'],
|
||||
|
||||
'tay': ['taylove','tayaaa','tayadmire','taycat','taycelebrate','taychefkiss','taychristmas','tayclap','taycold','taycrown','tayflex','tayflirt','taygrimacing','tayhappy','tayheart','tayhmm','tayhuh','tayhyperdab','tayjammin','taylaugh','taymindblown','tayno','taynod','taypeace','taypray','tayrun','tayscrunch','tayshake','tayshrug','taysilly','tayslide','taysmart','taystop','taytantrum','taytea','taythink','tayvibin','taywhat','taywine','taywine2','taywink','tayyes'],
|
||||
|
||||
'classic': ['flowers','scootlgbt','idhitit','2thumbsup','aliendj','ambulance','angry','angrywhip','argue','aroused','ashamed','badass','banana','band','banghead','batman','bigeyes','bite','blind','blowkiss','blush','bong','bounce','bow','breakheart','bs','cartwheel','cat','celebrate','chainsaw','cheers','clap','cold','confused','crazyeyes','cry','cthulhu','cute','laughing','daydream','ddr','deadpool','devilsmile','diddle','die','distress','disturbing','dizzy','domo','doughboy','drink','drool','dudeweedlmao','edward','electro','elephant','embarrassed','emo','emo2','evil','evilclown','evilgrin','facepalm','fap','flamethrower','flipbird','flirt','frown','gasp','glomp','go','gooby','grr','gtfo','guitar','haha','handshake','happydance','headbang','heart','heartbeat','hearts','highfive','hmm','hmph','holdhands','horny','hug','hugging','hugs','hump','humpbed','hysterical','ily','inlove','jason','jawdrop','jedi','jester','kaboom','kick','kiss','kitty','laughchair','lick','link','lol','lolbeat','loving','makeout','medal','megaman','megamanguitar','meow','metime','mooning','mummy','na','nauseous','nervous','ninja','nod','nono','omg','onfire','ooo','orly','tongueout','paddle','panda','pandabutt','paranoid','party','pat','peek','pikachu','pimp','plzdie','poke','popcorn','pout','probe','puke','punch','quote','raccoon','roar','rofl','roflmao','rolleyes','sad','sadeyes','sadhug','samurai','sarcasm','scoot','scream','shmoopy','shrug','skull','slap','slapfight','sleepy','smackfish','smackhead','smh','smile','smoke','sonic','spank','sparta','sperm','spiderman','stab','star','stare','stfu','suicide','surprisehug','suspicious','sweat','swordfight','taco','talk2hand','tantrum','teehee','thinking','threesome','throw','throwaway','tickle','typing','uhuh','vampbat','viking','violin','vulgar','wah','wat','whip','whipping','wink','witch','wizard','woah','worm','woo','work','worship','wow','xd','yay','zzz'],
|
||||
|
||||
'rage': ['trolldespair','clueless','troll','bitchplease','spit','challengeaccepted','contentiouscereal','cryingatcuteness','derp','derpcornsyrup','derpcrying','derpcute','derpdumb','derpeuphoria','derpinahd','derpinapokerface','derpinasnickering','derpprocessing','derprealization','derpsnickering','derptalking','derpthinking','derpthumbsup','derpunimpressed','derpwhy','donotwant','epicfacefeatures','fancywithwine','fffffffuuuuuuuuuuuu','flipthetable','foreveralone','foreveralonehappy','hewillnever','idontknow','interuptedreading','iseewhatyoudidthere','killherkillher','ledesire','leexcited','legenius','lelolidk','lemiddlefinger','lemindblown','leokay','lepanicrunning','lepokerface','lepokerface2','lerageface','leseriousface','likeaboss','lolface','longwhiskers','manymiddlefingers','megusta','motherfucker','motherofgod','mysides','ohgodwhy','pervertedspiderman','picard','ragestrangle','rukiddingme','tfwyougettrolled','trollolol','truestorybro','xallthey','yuno'],
|
||||
|
||||
'wojak': ['purerage','naziseethe','holdupjak','ethottalking','chadwomanasian','chadwomanblack','chadwomanlatinx','chadwomannordic','trumpjaktalking','rdramajanny','soyreddit','doomerboy','npcsupport','npcoppse','grugthink','soyconsoomer','soyjaktalking','soyquack','tradboy','sciencejak','soyjakanimeglasses','soymad','boomerportrait','soycry','punchjak','seethejak','chadyes','chadno','abusivewife','ancap','bardfinn','bloomer','boomer','boomermonster','brainletbush','brainletcaved','brainletchair','brainletchest','brainletmaga','brainletpit','chad','chadarab','chadasian','chadblack','chadjesus','chadjew','chadjihadi','chadlatino','chadlibleft','chadnordic','chadsikh','chadusa','coomer','doomer','doomerfront','doomergirl','ethot','fatbrain','fatpriest','femboy','gogetter','grug','monke','nazijak','npc','npcfront','npcmaga','psychojak','ragejak','ragemask','ramonajak','soyjackwow','soyjak','soyjakfront','soyjakhipster','soyjakmaga','soyjakyell','tomboy','zoomer','zoomersoy'],
|
||||
|
||||
'flags': ['russia','niger','lgbt','animesexual','blacknation','blm','blueline','dreamgender','fatpride','incelpride','israel','kazakhstan','landlordlove','scalperpride','superstraight','trans','translord','transracial','usa'],
|
||||
|
||||
'wolf': ['wombiezolf','wolfdramanomicon','wolfamogus','wolfmarine','wolfromulusremus','wolfrope','wolftinfoil','wolfmarseymask','wolfputin','wolfdrama','wolfcumjar','wolflgbt','wolfmarseyhead','wolfnoir','wolfsherifssmoking','wolftrans','wolfvaporwave','wolfangry','wolfbrains','wolfcry','wolfdead','wolfdevilish','wolffacepalm','wolfhappy','wolfidea','wolfkoala','wolflaugh','wolflove','wolfmeditate','wolfphone','wolfrainbow','wolfroses','wolfsad','wolfsfear','wolfsleep','wolftear','wolfthink','wolfthumbsup','wolfupsidedown','wolfvictory','wolfwave','wolfwink'],
|
||||
|
||||
'misc': ['chadyescapy','chadnocapy','capygitcommit','capysneedboat','chadbasedcapy','chadcopecapy','chaddilatecapy','chaddonekingcapy','chaddonequeencapy','chadfixedkingcapy','chadfixedqueencapy','chadokcapy','chadseethecapy','chadsneedcapy','chadthankskingcapy','chadthanksqueencapy','sherpat','xdoubt','gigachadjesus','yotsubafish','yotsubalol','sigmatalking','zoroarkconfused','zoroarkhappy','zoroarkpout','zoroarksleepy','casanovanova','deuxwaifu','flairlessmong','hardislife','redditgigachad','rfybear','etika','sneed','retardedchildren','bruh','autism','doot','kylieface','queenyes','wholesomeseal','gigachadglow','gigachadorthodox','gigachad','gigachad2','gigachad3']
|
||||
}
|
||||
|
||||
cringetopia = document.getElementById('EMOJIS_cringetopia')
|
||||
if (cringetopia)
|
||||
emojis['cringetopia'] = ['19dollarfortnitecard','ahawow','ahayeah','alex','amogus','amogusbubble','amongpoop','amusing','anarchy','angelblob','angry','angryman','awaakesoyjack','backseatmodding','based','bassproshop','berkfail','berkstache','bert','bestmovieever','binface','blackpill','blingbob','blingbobhd','bluepill','booba','boof','boohoo','brainlet','britishmoment','brownnose','bruh','bruhsmoke','brunocheers','brunopog','bussin','byelol','canigetmod','car','cereal','cerkies','chad','chaddiscordmoderator','chadstare','cheeks','cheers','cheesed','cheeseu','chungus','chunky','clueless','cocka','cokeza','comeagain','coom','cope','coping','cryaboutit','cryingcool','cryrage','cum','cummies','cutelittledude','da','dab','dababy','datrolly','davyree','dayum','death','delight','disbelief','disgostang','disgust','donotdisturb','doritoberk','downisrael','downvote','downwert','drbob','drumtime','erotic','evilblob','face','facepalm','factsandlogic','fake','fatcryrage','fear','fedora','fistbumpl','fistbumpr','fjalsunna','floppacheers','floppagun','fluoride','flushspin','funwa','furrymurder','gas','getajob','gigachad','gigajammin','godiwishthatwereme','gogetter','goingcrazy','goinginsane','gold','gone','goofy','goonpog','goteem','grabhand','grind','gun','hahawyd','hatred','heart','heh','hehehe','hesapeonyouknow','hesepsteinyouknow','hesgayyouknow','hesretardedyouknow','hesrightyouknow','hitormiss','holy','hopeless','horny','hot','hulk','hunky','iloveyou','insanity','ipgrabber','irantroll','isawthat','itendsnow','itsover','itsoverseal','jewbob','joebiden','josh','kanyerant','keith','kill','kissin','laughing','lean','leftgun','lessgooooooooooo','lessgoooooooooooo','letsfuckinggooooooooooo','lick','light','like','littledrummerboy','lmao','logo','logoff','lolrage','love','madman','malding','maldinggif','manpain','march','me_lon','menendez','mewhen','mf','mhm','mhmdoubt','mlady','murder','nefarious','nefariousacts','newport','newport~1','nibburger_king','nigerianreaction','nooo','noooo','noose','noperms','normalize','ohwow','okboomer','orange','pain','pardon','payne','peepotalk','pepecringe','pepecringe2','pepeherrington','peperagecry','pepoboner','pepoojamm','phillip','pitchfork','pleading','please','pouroneout40','praiseallah','prayge','psycho','quagmirelet','ratio','real','really','redditnation','redpill','redwojack','regice','ricardosmile','ripbozo','sad','sadcat','sadge','sadtroll','salute','scare','schizothread','secretside','sheesh','shh','shocked','shotty','sigma','sigmamale','sigmasnap','simpjack','siren','skill_issue','slime','slow','smoketime','sniff','society','society2','soy','spit','spit2','splendid','squidwardno','stare','stare1','stfu','stoppedwert','stopwert','susamogus','suscoin','susge','susiety','tacobell','tempest','thanosd','thanoslol','thistbh','thonk','tiktokcoin','tiresome','tm06','troll','trollcrazy','trollcrazyfurry','trollcrazypoint','trollcrazyrussia','trollcrazyukraine','trolldisappointed','trollface','trollinsane','trollsus','truetrue','turbobrainlet','tuvvokmoment','twetwe','unblockme','updonda','upiran','upvote','upwert','vengeance','virgin','wa','waaaah','wallstreet','wertegg','wertpinion','what','whatdeath','whensus','wholesome','wolfcode','womanmoment','woohoo','wtff','xplode','yeeeees','yeet','yes','yeshoney','yet','you','zombie_phillip']
|
||||
|
||||
loadEmojis(form);
|
||||
}
|
||||
xhr.send(f);
|
||||
}
|
||||
else {
|
||||
fav.setAttribute('data-form-destination', form)
|
||||
|
||||
const commentBox = document.getElementById(form)
|
||||
commentBox.setAttribute('data-curr-pos', commentBox.selectionStart);
|
||||
|
||||
if (fav.innerHTML == "")
|
||||
{
|
||||
let str = ""
|
||||
const favorite_emojis = JSON.parse(localStorage.getItem("favorite_emojis"))
|
||||
if (favorite_emojis)
|
||||
{
|
||||
const sortable = Object.fromEntries(
|
||||
Object.entries(favorite_emojis).sort(([,a],[,b]) => b-a)
|
||||
);
|
||||
|
||||
for (const emoji of Object.keys(sortable).slice(0, 25))
|
||||
str += `<button class="btn m-1 px-0 emoji2" onclick="getEmoji('${emoji}')" data-bs-toggle="tooltip" title=":${emoji}:" delay:="0"><img loading="lazy" width=50 src="/e/${emoji}.webp" alt="${emoji}-emoji"></button>`
|
||||
|
||||
fav.innerHTML = str
|
||||
}
|
||||
}
|
||||
if (search_bar.value == "") {
|
||||
search_container.innerHTML = ""
|
||||
document.getElementById("tab-content").classList.remove("d-none");
|
||||
if (document.getElementById("EMOJIS_marsey").innerHTML == "")
|
||||
{
|
||||
for (const [k, v] of Object.entries(emojis)) {
|
||||
let container = document.getElementById(`EMOJIS_${k}`)
|
||||
let str = ''
|
||||
if (k == 'marsey')
|
||||
{
|
||||
for (const e of v) {
|
||||
let k = e.toLowerCase().split(" : ")[0];
|
||||
str += `<button class="btn m-1 px-0 emoji2" onclick="getEmoji('${k}')" style="background: None!important; width:60px; overflow: hidden; border: none" data-bs-toggle="tooltip" title=":${k}:" delay:="0"><img loading="lazy" width=50 src="/e/${k}.webp" alt="${k}-emoji"></button>`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const e of v) {
|
||||
str += `<button class="btn m-1 px-0 emoji2" onclick="getEmoji('${e}')" style="background: None!important; width:60px; overflow: hidden; border: none" data-bs-toggle="tooltip" title=":${e}:" delay:="0"><img loading="lazy" width=50 src="/e/${e}.webp" alt="${e}-emoji"></button>`;
|
||||
}
|
||||
}
|
||||
|
||||
container.innerHTML = str
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
let str = ''
|
||||
for (const [key, value] of Object.entries(emojis)) {
|
||||
if (key == "marsey")
|
||||
{
|
||||
for (const e of value) {
|
||||
let arr = e.toLowerCase().split(" : ");
|
||||
let k = arr[0];
|
||||
let v = arr[1];
|
||||
if (str.includes(`'${k}'`)) continue;
|
||||
if (k.match(search_bar.value.toLowerCase()) || search_bar.value.toLowerCase().match(k) || v.match(search_bar.value.toLowerCase())) {
|
||||
str += `<button class="btn m-1 px-0 emoji2" onclick="getEmoji('${k}')" data-bs-toggle="tooltip" title=":${k}:" delay:="0"><img loading="lazy" width=50 src="/e/${k}.webp" alt="${k}-emoji"></button>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key != "marseyalphabet")
|
||||
{
|
||||
for (const e of value) {
|
||||
if (e.match(search_bar.value.toLowerCase()) || search_bar.value.toLowerCase().match(e)) {
|
||||
str += `<button class="btn m-1 px-0 emoji2" onclick="getEmoji('${e}')" style="background: None!important; width:60px; overflow: hidden; border: none" data-bs-toggle="tooltip" title=":${e}:" delay:="0"><img loading="lazy" width=50 src="/e/${e}.webp" alt="${e}-emoji"></button>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.getElementById("tab-content").classList.add("d-none");
|
||||
search_container.innerHTML = str
|
||||
}
|
||||
search_bar.oninput = function () {
|
||||
loadEmojis(form);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function getEmoji(searchTerm) {
|
||||
const form = fav.getAttribute('data-form-destination')
|
||||
const commentBox = document.getElementById(form)
|
||||
const old = commentBox.value;
|
||||
const curPos = parseInt(commentBox.getAttribute('data-curr-pos'));
|
||||
|
||||
const firstHalf = old.slice(0, curPos)
|
||||
const lastHalf = old.slice(curPos)
|
||||
|
||||
let emoji = ':' + searchTerm + ':'
|
||||
const previousChar = firstHalf.slice(-1)
|
||||
if (firstHalf.length > 0 && previousChar !== " " && previousChar !== "\n") {
|
||||
emoji = " " + emoji
|
||||
}
|
||||
if (lastHalf.length > 0 && lastHalf[0] !== " ") {
|
||||
emoji = emoji + " "
|
||||
}
|
||||
|
||||
commentBox.value = firstHalf + emoji + lastHalf;
|
||||
|
||||
const newPos = curPos + emoji.length
|
||||
|
||||
commentBox.setAttribute('data-curr-pos', newPos.toString());
|
||||
|
||||
commentBox.dispatchEvent(new Event('input'));
|
||||
|
||||
const favorite_emojis = JSON.parse(localStorage.getItem("favorite_emojis")) || {}
|
||||
if (favorite_emojis[searchTerm]) favorite_emojis[searchTerm] += 1
|
||||
else favorite_emojis[searchTerm] = 1
|
||||
localStorage.setItem("favorite_emojis", JSON.stringify(favorite_emojis))
|
||||
}
|
221
files/assets/js/marked.custom.js
Normal file
221
files/assets/js/marked.custom.js
Normal file
|
@ -0,0 +1,221 @@
|
|||
function appendToken(parentElement, childToken) {
|
||||
var childElement = tokenToHTMLElement(childToken);
|
||||
if (typeof childElement === 'string') {
|
||||
parentElement.textContent += childElement;
|
||||
} else if (childElement !== null) {
|
||||
parentElement.appendChild(childElement)
|
||||
}
|
||||
}
|
||||
|
||||
function appentTextOrElement(parentElement, textOrElement) {
|
||||
if (typeof textOrElement === 'string') {
|
||||
parentElement.textContent += textOrElement;
|
||||
} else {
|
||||
parentElement.appendChild(textOrElement);
|
||||
}
|
||||
}
|
||||
|
||||
function motteSpecialMarkdown(text) {
|
||||
if (typeof text !== 'string') {
|
||||
return '';
|
||||
}
|
||||
|
||||
var spoilerMatch = text.match(/^(.*?)\|\|(.*?)\|\|(.*)$/);
|
||||
|
||||
if (spoilerMatch) {
|
||||
var left = spoilerMatch[1];
|
||||
var mid = spoilerMatch[2];
|
||||
var right = spoilerMatch[3];
|
||||
var parentSpan = document.createElement('span');
|
||||
var leftSpan = document.createElement('span');
|
||||
var spoilerSpan = document.createElement('span');
|
||||
var rightSpan = document.createElement('span');
|
||||
spoilerSpan.textContent = mid;
|
||||
spoilerSpan.classList.add('spoiler');
|
||||
appentTextOrElement(leftSpan, motteSpecialMarkdown(left));
|
||||
appentTextOrElement(rightSpan, motteSpecialMarkdown(right));
|
||||
parentSpan.appendChild(leftSpan);
|
||||
parentSpan.appendChild(spoilerSpan);
|
||||
parentSpan.appendChild(rightSpan);
|
||||
return parentSpan;
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
function tokenToHTMLElement(token) {
|
||||
var element = null;
|
||||
|
||||
if (token.type === 'space') {
|
||||
element = document.createElement('span');
|
||||
element.textContent = ' ';
|
||||
return element;
|
||||
} else if (typeof token.type === 'undefined' || token.type === 'text') {
|
||||
element = document.createElement('span');
|
||||
appentTextOrElement(element, motteSpecialMarkdown(token.text));
|
||||
return element;
|
||||
} else if (token.type === 'hr') {
|
||||
return document.createElement('hr');
|
||||
} else if (token.type === 'br') {
|
||||
return document.createElement('br');
|
||||
} else if (token.type === 'heading') {
|
||||
element = document.createElement('h' + Math.floor(Math.max(1, Math.min(6, token.depth))));
|
||||
} else if (token.type === 'code') {
|
||||
element = document.createElement('pre');
|
||||
element.setAttribute('data-lang', token.lang);
|
||||
} else if (token.type === 'list_item') {
|
||||
element = document.createElement('li');
|
||||
} else if (token.type === 'blockquote') {
|
||||
element = document.createElement('blockquote');
|
||||
} else if (token.type === 'list') {
|
||||
if (token.ordered) {
|
||||
element = document.createElement('ol');
|
||||
} else {
|
||||
element = document.createElement('ul');
|
||||
}
|
||||
} else if (token.type === 'table') {
|
||||
var table, thead, tbody, tr, th, td;
|
||||
table = document.createElement('table');
|
||||
table.classList.add('table');
|
||||
thead = document.createElement('thead');
|
||||
tbody = document.createElement('thead');
|
||||
tr = document.createElement('tr');
|
||||
for (var x = 0; x < token.header.length; x++) {
|
||||
th = document.createElement('th');
|
||||
appendToken(th, token.header[x]);
|
||||
tr.appendChild(th);
|
||||
}
|
||||
thead.appendChild(tr);
|
||||
table.appendChild(thead);
|
||||
for (var y = 0; y < token.rows.length; y++) {
|
||||
row = token.rows[y];
|
||||
tr = document.createElement('tr');
|
||||
for (var x = 0; x < row.length; x++) {
|
||||
td = document.createElement('td');
|
||||
appendToken(td, row[x]);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
tbody.appendChild(tr);
|
||||
}
|
||||
table.appendChild(tbody);
|
||||
return table;
|
||||
} else if (token.type === 'paragraph') {
|
||||
element = document.createElement('p');
|
||||
} else if (token.type === 'div') {
|
||||
element = document.createElement('div');
|
||||
} else if (token.type === 'em') {
|
||||
element = document.createElement('i');
|
||||
} else if (token.type === 'strong') {
|
||||
element = document.createElement('b');
|
||||
} else if (token.type === 'del') {
|
||||
element = document.createElement('del');
|
||||
} else if (token.type === 'codespan') {
|
||||
element = document.createElement('code');
|
||||
element.textContent = token.text;
|
||||
return element;
|
||||
} else if (token.type === 'escape') {
|
||||
} else if (token.type === 'link') {
|
||||
element = document.createElement('a');
|
||||
element.setAttribute('href', token.href);
|
||||
element.textContent = token.text;
|
||||
return element;
|
||||
} else if (token.type === 'image') {
|
||||
element = document.createElement('img');
|
||||
element.setAttribute('src', token.href);
|
||||
element.setAttribute('alt', token.text);
|
||||
return element;
|
||||
} else {
|
||||
console.log(token);
|
||||
element = document.createElement('div');
|
||||
}
|
||||
|
||||
var children = (token.tokens || token.items || []);
|
||||
if (element !== null && children.length > 0) {
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var childElement = tokenToHTMLElement(children[i]);
|
||||
if (childElement.outerHTML.match(/"spoiler"/g)) {
|
||||
console.log(element, token, childElement, children[i]);
|
||||
}
|
||||
appendToken(element, children[i]);
|
||||
}
|
||||
} else if (element.children.length === 0 && element.textContent === '') {
|
||||
element.textContent += token.text;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function safeMarkdown(input) {
|
||||
var seenTokens = [];
|
||||
var outputToken = {"type": "div", "raw": input, "text": "", "tokens": []};
|
||||
function seeRecursive(token) {
|
||||
seenTokens.push(token);
|
||||
var children = (
|
||||
token.tokens
|
||||
|| token.items
|
||||
|| (token.header||[]).concat(token.rows||[])
|
||||
|| []
|
||||
);
|
||||
if (token.header) {
|
||||
children = children.concat(token.header);
|
||||
}
|
||||
for (var y = 0; y < (token.rows||[]).length; y++) {
|
||||
children = children.concat(token.rows[y]);
|
||||
}
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
seeRecursive(children[i]);
|
||||
}
|
||||
}
|
||||
marked.use({
|
||||
walkTokens: function(token) {
|
||||
if (!seenTokens.includes(token)) {
|
||||
outputToken.tokens.push(token);
|
||||
seeRecursive(token);
|
||||
}
|
||||
},
|
||||
});
|
||||
marked(input);
|
||||
marked.use({
|
||||
walkTokens: false,
|
||||
tokenizer: false,
|
||||
});
|
||||
|
||||
[ 'escape', 'del', ];
|
||||
|
||||
return tokenToHTMLElement(outputToken);
|
||||
}
|
||||
|
||||
setTimeout(() => markdown('post-text','preview'), 200);
|
||||
|
||||
function markdown(first, second) {
|
||||
var input = document.getElementById(first).value;
|
||||
|
||||
var dest = document.getElementById(second);
|
||||
for (var i = 0; i < dest.children.length; i++) {
|
||||
dest.removeChild(dest.children[i]);
|
||||
}
|
||||
document.getElementById(second).appendChild(safeMarkdown(input));
|
||||
}
|
||||
|
||||
function charLimit(form, text) {
|
||||
|
||||
var input = document.getElementById(form);
|
||||
|
||||
var text = document.getElementById(text);
|
||||
|
||||
var length = input.value.length;
|
||||
|
||||
var maxLength = input.getAttribute("maxlength");
|
||||
|
||||
if (length >= maxLength) {
|
||||
text.style.color = "#E53E3E";
|
||||
}
|
||||
else if (length >= maxLength * .72){
|
||||
text.style.color = "#FFC107";
|
||||
}
|
||||
else {
|
||||
text.style.color = "#A0AEC0";
|
||||
}
|
||||
|
||||
text.innerText = length + ' / ' + maxLength;
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -1,22 +1,95 @@
|
|||
from .alts import *
|
||||
from .badges import *
|
||||
from .clients import *
|
||||
from .comment import *
|
||||
from .domains import *
|
||||
from .flags import *
|
||||
from .user import *
|
||||
from .userblock import *
|
||||
from .usernotes import *
|
||||
from .submission import *
|
||||
from .votes import *
|
||||
from .domains import *
|
||||
from .subscriptions import *
|
||||
from files.__main__ import app
|
||||
from .mod_logs import *
|
||||
from .award import *
|
||||
from .marsey import *
|
||||
from .sub_block import *
|
||||
from .saves import *
|
||||
from .views import *
|
||||
from .notifications import *
|
||||
from .follows import *
|
||||
################################################################
|
||||
# WARNING! THIS FILE IS EVIL. #
|
||||
################################################################
|
||||
# Previously, this file had a series of #
|
||||
# from .alts import * #
|
||||
# from .award import * #
|
||||
# from .badges import * #
|
||||
# and so on in that fashion. That means that anywhere that #
|
||||
# from files.classes import * #
|
||||
# (and there were a lot of places like that) got anything #
|
||||
# was imported for any model imported. So if you, for example, #
|
||||
# removed #
|
||||
# from secrets import token_hex #
|
||||
# from files/classes/user.py, the registration page would #
|
||||
# break because files/routes/login.py did #
|
||||
# from files.classes import * #
|
||||
# in order to get the token_hex function rather than #
|
||||
# importing it with something like #
|
||||
# from secrets import token_hex #
|
||||
# #
|
||||
# Anyway, not fixing that right now, but in order to #
|
||||
# what needed to be imported here such that #
|
||||
# from files.classes import * #
|
||||
# still imported the same stuff as before I ran the following: #
|
||||
# $ find files/classes -type f -name '*.py' \ #
|
||||
# -exec grep import '{}' ';' \ #
|
||||
# | grep 'import' \ #
|
||||
# | grep -v 'from [.]\|__init__\|from files.classes' \ #
|
||||
# | sed 's/^[^:]*://g' \ #
|
||||
# | sort \ #
|
||||
# | uniq #
|
||||
# and then reordered the list such that import * did not stomp #
|
||||
# over stuff that had been explicitly imported. #
|
||||
################################################################
|
||||
|
||||
# First the import * from places which don't go circular
|
||||
from sqlalchemy import *
|
||||
from flask import *
|
||||
|
||||
# Then everything except what's in files.*
|
||||
import pyotp
|
||||
import random
|
||||
import re
|
||||
import time
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
from flask import g
|
||||
from flask import render_template
|
||||
from json import loads
|
||||
from math import floor
|
||||
from os import environ
|
||||
from os import environ, remove, path
|
||||
from random import randint
|
||||
from secrets import token_hex
|
||||
from sqlalchemy.orm import deferred, aliased
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.orm import relationship, deferred
|
||||
from urllib.parse import urlencode, urlparse, parse_qs
|
||||
from urllib.parse import urlparse
|
||||
|
||||
# It is now safe to define the models
|
||||
from .alts import Alt
|
||||
from .award import AwardRelationship
|
||||
from .badges import BadgeDef, Badge
|
||||
from .clients import OauthApp, ClientAuth
|
||||
from .comment import Comment
|
||||
from .domains import BannedDomain
|
||||
from .exiles import Exile
|
||||
from .flags import Flag, CommentFlag
|
||||
from .follows import Follow
|
||||
from .marsey import Marsey
|
||||
from .mod import Mod
|
||||
from .mod_logs import ModAction
|
||||
from .notifications import Notification
|
||||
from .saves import SaveRelationship, CommentSaveRelationship
|
||||
from .sub import Sub
|
||||
from .sub_block import SubBlock
|
||||
from .submission import Submission
|
||||
from .subscriptions import Subscription
|
||||
from .user import User
|
||||
from .userblock import UserBlock
|
||||
from .usernotes import UserTag, UserNote
|
||||
from .views import ViewerRelationship
|
||||
from .votes import Vote, CommentVote
|
||||
|
||||
# Then the import * from files.*
|
||||
from files.helpers.const import *
|
||||
from files.helpers.images import *
|
||||
from files.helpers.lazy import *
|
||||
from files.helpers.security import *
|
||||
|
||||
# Then the specific stuff we don't want stomped on
|
||||
from files.helpers.discord import remove_user
|
||||
from files.helpers.lazy import lazy
|
||||
from files.__main__ import Base, app, cache
|
||||
|
|
|
@ -7,7 +7,9 @@ class Alt(Base):
|
|||
|
||||
user1 = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
user2 = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
is_manual = Column(Boolean, default=False)
|
||||
is_manual = Column(Boolean, nullable=False, default=False)
|
||||
|
||||
Index('alts_user2_idx', user2)
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
|
|
|
@ -8,17 +8,24 @@ from files.helpers.const import *
|
|||
class AwardRelationship(Base):
|
||||
|
||||
__tablename__ = "award_relationships"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('user_id', 'submission_id', 'comment_id', name='award_constraint'),
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
submission_id = Column(Integer, ForeignKey("submissions.id"))
|
||||
comment_id = Column(Integer, ForeignKey("comments.id"))
|
||||
kind = Column(String)
|
||||
kind = Column(String, nullable=False)
|
||||
|
||||
user = relationship("User", primaryjoin="AwardRelationship.user_id==User.id", viewonly=True)
|
||||
post = relationship("Submission", primaryjoin="AwardRelationship.submission_id==Submission.id", viewonly=True)
|
||||
comment = relationship("Comment", primaryjoin="AwardRelationship.comment_id==Comment.id", viewonly=True)
|
||||
|
||||
Index('award_user_idx', user_id)
|
||||
Index('award_post_idx', submission_id)
|
||||
Index('award_comment_idx', comment_id)
|
||||
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
|
|
@ -9,15 +9,17 @@ from json import loads
|
|||
|
||||
class BadgeDef(Base):
|
||||
__tablename__ = "badge_defs"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('name', name='badge_def_name_unique'),
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(String)
|
||||
name = Column(String, nullable=False)
|
||||
description = Column(String)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<BadgeDef(id={self.id})>"
|
||||
|
||||
|
||||
class Badge(Base):
|
||||
|
||||
__tablename__ = "badges"
|
||||
|
@ -27,6 +29,8 @@ class Badge(Base):
|
|||
description = Column(String)
|
||||
url = Column(String)
|
||||
|
||||
Index('badges_badge_id_idx', badge_id)
|
||||
|
||||
user = relationship("User", viewonly=True)
|
||||
badge = relationship("BadgeDef", primaryjoin="foreign(Badge.badge_id) == remote(BadgeDef.id)", viewonly=True)
|
||||
|
||||
|
@ -36,11 +40,7 @@ class Badge(Base):
|
|||
@property
|
||||
@lazy
|
||||
def text(self):
|
||||
if self.name == "Chud":
|
||||
ti = self.user.agendaposter
|
||||
if ti: text = self.badge.description + " until " + datetime.utcfromtimestamp(ti).strftime('%Y-%m-%d %H:%M:%S')
|
||||
else: text = self.badge.description + " permanently"
|
||||
elif self.badge_id in {94,95,96,97,98,109}:
|
||||
if self.badge_id in {94,95,96,97,98,109}:
|
||||
if self.badge_id == 94: ti = self.user.progressivestack
|
||||
elif self.badge_id == 95: ti = self.user.bird
|
||||
elif self.badge_id == 96: ti = self.user.flairchanged
|
||||
|
|
|
@ -11,13 +11,16 @@ import time
|
|||
class OauthApp(Base):
|
||||
|
||||
__tablename__ = "oauth_apps"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('client_id', name='unique_id'),
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
client_id = Column(String)
|
||||
app_name = Column(String)
|
||||
redirect_uri = Column(String)
|
||||
description = Column(String)
|
||||
author_id = Column(Integer, ForeignKey("users.id"))
|
||||
app_name = Column(String(length=50), nullable=False)
|
||||
redirect_uri = Column(String(length=50), nullable=False)
|
||||
description = Column(String(length=256), nullable=False)
|
||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
|
||||
author = relationship("User", viewonly=True)
|
||||
|
||||
|
@ -65,10 +68,13 @@ class OauthApp(Base):
|
|||
class ClientAuth(Base):
|
||||
|
||||
__tablename__ = "client_auths"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('access_token', name='unique_access'),
|
||||
)
|
||||
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
oauth_client = Column(Integer, ForeignKey("oauth_apps.id"), primary_key=True)
|
||||
access_token = Column(String)
|
||||
access_token = Column(String, nullable=False)
|
||||
|
||||
user = relationship("User", viewonly=True)
|
||||
application = relationship("OauthApp", viewonly=True)
|
||||
|
|
|
@ -19,28 +19,28 @@ class Comment(Base):
|
|||
__tablename__ = "comments"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
author_id = Column(Integer, ForeignKey("users.id"))
|
||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
parent_submission = Column(Integer, ForeignKey("submissions.id"))
|
||||
created_utc = Column(Integer)
|
||||
edited_utc = Column(Integer, default=0)
|
||||
is_banned = Column(Boolean, default=False)
|
||||
ghost = Column(Boolean, default=False)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
edited_utc = Column(Integer, default=0, nullable=False)
|
||||
is_banned = Column(Boolean, default=False, nullable=False)
|
||||
ghost = Column(Boolean, default=False, nullable=False)
|
||||
bannedfor = Column(Boolean)
|
||||
distinguish_level = Column(Integer, default=0)
|
||||
deleted_utc = Column(Integer, default=0)
|
||||
distinguish_level = Column(Integer, default=0, nullable=False)
|
||||
deleted_utc = Column(Integer, default=0, nullable=False)
|
||||
is_approved = Column(Integer, ForeignKey("users.id"))
|
||||
level = Column(Integer, default=1)
|
||||
level = Column(Integer, default=1, nullable=False)
|
||||
parent_comment_id = Column(Integer, ForeignKey("comments.id"))
|
||||
top_comment_id = Column(Integer)
|
||||
over_18 = Column(Boolean, default=False)
|
||||
is_bot = Column(Boolean, default=False)
|
||||
over_18 = Column(Boolean, default=False, nullable=False)
|
||||
is_bot = Column(Boolean, default=False, nullable=False)
|
||||
is_pinned = Column(String)
|
||||
is_pinned_utc = Column(Integer)
|
||||
sentto = Column(Integer, ForeignKey("users.id"))
|
||||
app_id = Column(Integer, ForeignKey("oauth_apps.id"))
|
||||
upvotes = Column(Integer, default=1)
|
||||
downvotes = Column(Integer, default=0)
|
||||
realupvotes = Column(Integer, default=1)
|
||||
upvotes = Column(Integer, default=1, nullable=False)
|
||||
downvotes = Column(Integer, default=0, nullable=False)
|
||||
realupvotes = Column(Integer, default=1, nullable=False)
|
||||
body = Column(String)
|
||||
body_html = Column(String)
|
||||
ban_reason = Column(String)
|
||||
|
@ -49,6 +49,12 @@ class Comment(Base):
|
|||
wordle_result = Column(String)
|
||||
treasure_amount = Column(String)
|
||||
|
||||
Index('comment_parent_index', parent_comment_id)
|
||||
Index('comment_post_id_index', parent_submission)
|
||||
Index('comments_user_index', author_id)
|
||||
Index('fki_comment_approver_fkey', is_approved)
|
||||
Index('fki_comment_sentto_fkey', sentto)
|
||||
|
||||
oauth_app = relationship("OauthApp", viewonly=True)
|
||||
post = relationship("Submission", viewonly=True)
|
||||
author = relationship("User", primaryjoin="User.id==Comment.author_id")
|
||||
|
@ -351,7 +357,6 @@ class Comment(Base):
|
|||
body = self.body_html or ""
|
||||
|
||||
if body:
|
||||
body = censor_slurs(body, v)
|
||||
|
||||
if v:
|
||||
body = body.replace("old.reddit.com", v.reddit)
|
||||
|
@ -417,7 +422,7 @@ class Comment(Base):
|
|||
|
||||
if not body: return ""
|
||||
|
||||
return censor_slurs(body, v)
|
||||
return body
|
||||
|
||||
def print(self):
|
||||
print(f'post: {self.id}, comment: {self.author_id}', flush=True)
|
||||
|
|
|
@ -5,4 +5,10 @@ class BannedDomain(Base):
|
|||
|
||||
__tablename__ = "banneddomains"
|
||||
domain = Column(String, primary_key=True)
|
||||
reason = Column(String)
|
||||
reason = Column(String, nullable=False)
|
||||
Index(
|
||||
'domains_domain_trgm_idx',
|
||||
domain,
|
||||
postgresql_using='gin',
|
||||
postgresql_ops={'description':'gin_trgm_ops'}
|
||||
)
|
||||
|
|
|
@ -7,7 +7,10 @@ class Exile(Base):
|
|||
__tablename__ = "exiles"
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
sub = Column(String, ForeignKey("subs.name"), primary_key=True)
|
||||
exiler_id = Column(Integer, ForeignKey("users.id"))
|
||||
exiler_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
|
||||
Index('fki_exile_exiler_fkey', exiler_id)
|
||||
Index('fki_exile_sub_fkey', sub)
|
||||
|
||||
exiler = relationship("User", primaryjoin="User.id==Exile.exiler_id", viewonly=True)
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@ class Flag(Base):
|
|||
post_id = Column(Integer, ForeignKey("submissions.id"))
|
||||
user_id = Column(Integer, ForeignKey("users.id"))
|
||||
reason = Column(String)
|
||||
created_utc = Column(Integer)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('flag_user_idx', user_id)
|
||||
|
||||
user = relationship("User", primaryjoin = "Flag.user_id == User.id", uselist = False, viewonly=True)
|
||||
|
||||
|
@ -36,7 +38,7 @@ class Flag(Base):
|
|||
|
||||
@lazy
|
||||
def realreason(self, v):
|
||||
return censor_slurs(self.reason, v)
|
||||
return self.reason
|
||||
|
||||
|
||||
class CommentFlag(Base):
|
||||
|
@ -46,7 +48,9 @@ class CommentFlag(Base):
|
|||
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
reason = Column(String)
|
||||
created_utc = Column(Integer)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('cflag_user_idx', user_id)
|
||||
|
||||
user = relationship("User", primaryjoin = "CommentFlag.user_id == User.id", uselist = False, viewonly=True)
|
||||
|
||||
|
@ -69,4 +73,4 @@ class CommentFlag(Base):
|
|||
|
||||
@lazy
|
||||
def realreason(self, v):
|
||||
return censor_slurs(self.reason, v)
|
||||
return self.reason
|
||||
|
|
|
@ -7,7 +7,9 @@ class Follow(Base):
|
|||
__tablename__ = "follows"
|
||||
target_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
created_utc = Column(Integer)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('follow_user_id_index', user_id)
|
||||
|
||||
user = relationship("User", uselist=False, primaryjoin="User.id==Follow.user_id", viewonly=True)
|
||||
target = relationship("User", primaryjoin="User.id==Follow.target_id", viewonly=True)
|
||||
|
|
|
@ -5,9 +5,13 @@ class Marsey(Base):
|
|||
__tablename__ = "marseys"
|
||||
|
||||
name = Column(String, primary_key=True)
|
||||
author_id = Column(Integer, ForeignKey("users.id"))
|
||||
tags = Column(String)
|
||||
count = Column(Integer, default=0)
|
||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
tags = Column(String(length=200), nullable=False)
|
||||
count = Column(Integer, default=0, nullable=False)
|
||||
|
||||
Index('marseys_idx2', author_id)
|
||||
Index('marseys_idx3', count.desc())
|
||||
Index('marseys_idx', name)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<Marsey(name={self.name})>"
|
||||
|
|
|
@ -9,7 +9,9 @@ class Mod(Base):
|
|||
__tablename__ = "mods"
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
sub = Column(String, ForeignKey("subs.name"), primary_key=True)
|
||||
created_utc = Column(Integer)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('fki_mod_sub_fkey', sub)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
|
||||
|
|
|
@ -16,7 +16,13 @@ class ModAction(Base):
|
|||
target_submission_id = Column(Integer, ForeignKey("submissions.id"))
|
||||
target_comment_id = Column(Integer, ForeignKey("comments.id"))
|
||||
_note=Column(String)
|
||||
created_utc = Column(Integer)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('fki_modactions_user_fkey', target_user_id)
|
||||
Index('modaction_action_idx', kind)
|
||||
Index('modaction_cid_idx', target_comment_id)
|
||||
Index('modaction_id_idx', id.desc())
|
||||
Index('modaction_pid_idx', target_submission_id)
|
||||
|
||||
user = relationship("User", primaryjoin="User.id==ModAction.user_id", viewonly=True)
|
||||
target_user = relationship("User", primaryjoin="User.id==ModAction.target_user_id", viewonly=True)
|
||||
|
@ -110,11 +116,6 @@ class ModAction(Base):
|
|||
return f"/log/{self.id}"
|
||||
|
||||
ACTIONTYPES = {
|
||||
'agendaposter': {
|
||||
"str": 'set chud theme on {self.target_link}',
|
||||
"icon": 'fa-snooze',
|
||||
"color": 'bg-danger'
|
||||
},
|
||||
'approve_app': {
|
||||
"str": 'approved an application by {self.target_link}',
|
||||
"icon": 'fa-robot',
|
||||
|
@ -350,11 +351,6 @@ ACTIONTYPES = {
|
|||
"icon": 'fa-eye-slash',
|
||||
"color": 'bg-danger'
|
||||
},
|
||||
'unagendaposter': {
|
||||
"str": 'removed chud theme from {self.target_link}',
|
||||
"icon": 'fa-snooze',
|
||||
"color": 'bg-success'
|
||||
},
|
||||
'unban_comment': {
|
||||
"str": 'reinstated {self.target_link}',
|
||||
"icon": 'fa-comment',
|
||||
|
|
|
@ -9,8 +9,12 @@ class Notification(Base):
|
|||
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True)
|
||||
read = Column(Boolean, default=False)
|
||||
created_utc = Column(Integer)
|
||||
read = Column(Boolean, default=False, nullable=False)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('notification_read_idx', read)
|
||||
Index('notifications_comment_idx', comment_id)
|
||||
Index('notifs_user_read_idx', user_id, read)
|
||||
|
||||
comment = relationship("Comment", viewonly=True)
|
||||
user = relationship("User", viewonly=True)
|
||||
|
|
|
@ -10,6 +10,8 @@ class SaveRelationship(Base):
|
|||
user_id=Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
submission_id=Column(Integer, ForeignKey("submissions.id"), primary_key=True)
|
||||
|
||||
Index('fki_save_relationship_submission_fkey', submission_id)
|
||||
|
||||
|
||||
|
||||
class CommentSaveRelationship(Base):
|
||||
|
@ -18,3 +20,5 @@ class CommentSaveRelationship(Base):
|
|||
|
||||
user_id=Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
comment_id=Column(Integer, ForeignKey("comments.id"), primary_key=True)
|
||||
|
||||
Index('fki_comment_save_relationship_comment_fkey', comment_id)
|
||||
|
|
|
@ -20,6 +20,8 @@ class Sub(Base):
|
|||
bannerurl = Column(String)
|
||||
css = Column(String)
|
||||
|
||||
Index('subs_idx', name)
|
||||
|
||||
blocks = relationship("SubBlock", lazy="dynamic", primaryjoin="SubBlock.sub==Sub.name", viewonly=True)
|
||||
|
||||
|
||||
|
|
|
@ -8,5 +8,7 @@ class SubBlock(Base):
|
|||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
sub = Column(String, ForeignKey("subs.name"), primary_key=True)
|
||||
|
||||
Index('fki_sub_blocks_sub_fkey', sub)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<SubBlock(user_id={self.user_id}, sub={self.sub})>"
|
||||
|
|
|
@ -19,32 +19,32 @@ class Submission(Base):
|
|||
__tablename__ = "submissions"
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
author_id = Column(Integer, ForeignKey("users.id"))
|
||||
edited_utc = Column(Integer, default=0)
|
||||
created_utc = Column(Integer)
|
||||
author_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||
edited_utc = Column(Integer, default=0, nullable=False)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
thumburl = Column(String)
|
||||
is_banned = Column(Boolean, default=False)
|
||||
is_banned = Column(Boolean, default=False, nullable=False)
|
||||
bannedfor = Column(Boolean)
|
||||
ghost = Column(Boolean, default=False)
|
||||
views = Column(Integer, default=0)
|
||||
deleted_utc = Column(Integer, default=0)
|
||||
distinguish_level = Column(Integer, default=0)
|
||||
ghost = Column(Boolean, default=False, nullable=False)
|
||||
views = Column(Integer, default=0, nullable=False)
|
||||
deleted_utc = Column(Integer, default=0, nullable=False)
|
||||
distinguish_level = Column(Integer, default=0, nullable=False)
|
||||
stickied = Column(String)
|
||||
stickied_utc = Column(Integer)
|
||||
sub = Column(String, ForeignKey("subs.name"))
|
||||
is_pinned = Column(Boolean, default=False)
|
||||
private = Column(Boolean, default=False)
|
||||
club = Column(Boolean, default=False)
|
||||
comment_count = Column(Integer, default=0)
|
||||
is_pinned = Column(Boolean, default=False, nullable=False)
|
||||
private = Column(Boolean, default=False, nullable=False)
|
||||
club = Column(Boolean, default=False, nullable=False)
|
||||
comment_count = Column(Integer, default=0, nullable=False)
|
||||
is_approved = Column(Integer, ForeignKey("users.id"))
|
||||
over_18 = Column(Boolean, default=False)
|
||||
is_bot = Column(Boolean, default=False)
|
||||
upvotes = Column(Integer, default=1)
|
||||
downvotes = Column(Integer, default=0)
|
||||
over_18 = Column(Boolean, default=False, nullable=False)
|
||||
is_bot = Column(Boolean, default=False, nullable=False)
|
||||
upvotes = Column(Integer, default=1, nullable=False)
|
||||
downvotes = Column(Integer, default=0, nullable=False)
|
||||
realupvotes = Column(Integer, default=1)
|
||||
app_id=Column(Integer, ForeignKey("oauth_apps.id"))
|
||||
title = Column(String)
|
||||
title_html = Column(String)
|
||||
title = Column(String, nullable=False)
|
||||
title_html = Column(String, nullable=False)
|
||||
url = Column(String)
|
||||
body = Column(String)
|
||||
body_html = Column(String)
|
||||
|
@ -53,6 +53,18 @@ class Submission(Base):
|
|||
embed_url = Column(String)
|
||||
filter_state = Column(String)
|
||||
|
||||
Index('fki_submissions_approver_fkey', is_approved)
|
||||
Index('post_app_id_idx', app_id)
|
||||
Index('subimssion_binary_group_idx', is_banned, deleted_utc, over_18)
|
||||
Index('submission_isbanned_idx', is_banned)
|
||||
Index('submission_isdeleted_idx', deleted_utc)
|
||||
Index('submission_new_sort_idx', is_banned, deleted_utc, created_utc.desc(), over_18)
|
||||
Index('submission_pinned_idx', is_pinned)
|
||||
Index('submissions_author_index', author_id)
|
||||
Index('submissions_created_utc_asc_idx', created_utc.nullsfirst())
|
||||
Index('submissions_created_utc_desc_idx', created_utc.desc())
|
||||
Index('submissions_over18_index', over_18)
|
||||
|
||||
author = relationship("User", primaryjoin="Submission.author_id==User.id")
|
||||
oauth_app = relationship("OauthApp", viewonly=True)
|
||||
approved_by = relationship("User", uselist=False, primaryjoin="Submission.is_approved==User.id", viewonly=True)
|
||||
|
@ -370,8 +382,6 @@ class Submission(Base):
|
|||
|
||||
body = self.body_html or ""
|
||||
|
||||
body = censor_slurs(body, v)
|
||||
|
||||
if v:
|
||||
body = body.replace("old.reddit.com", v.reddit)
|
||||
|
||||
|
@ -436,8 +446,6 @@ class Submission(Base):
|
|||
|
||||
if not body: return ""
|
||||
|
||||
body = censor_slurs(body, v)
|
||||
|
||||
if v:
|
||||
body = body.replace("old.reddit.com", v.reddit)
|
||||
|
||||
|
@ -457,8 +465,6 @@ class Submission(Base):
|
|||
elif self.title_html: title = self.title_html
|
||||
else: title = self.title
|
||||
|
||||
title = censor_slurs(title, v)
|
||||
|
||||
return title
|
||||
|
||||
@lazy
|
||||
|
@ -468,8 +474,6 @@ class Submission(Base):
|
|||
else: return f'{CC} MEMBERS ONLY'
|
||||
else: title = self.title
|
||||
|
||||
title = censor_slurs(title, v)
|
||||
|
||||
return title
|
||||
|
||||
@property
|
||||
|
|
|
@ -7,6 +7,8 @@ class Subscription(Base):
|
|||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
submission_id = Column(Integer, ForeignKey("submissions.id"), primary_key=True)
|
||||
|
||||
Index('subscription_user_index', user_id)
|
||||
|
||||
user = relationship("User", uselist=False, viewonly=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
@ -29,61 +29,68 @@ cardview = bool(int(environ.get("CARD_VIEW", 1)))
|
|||
|
||||
class User(Base):
|
||||
__tablename__ = "users"
|
||||
__table_args__ = (
|
||||
UniqueConstraint('bannerurl', name='one_banner'),
|
||||
UniqueConstraint('discord_id', name='one_discord_account'),
|
||||
UniqueConstraint('id', name='uid_unique'),
|
||||
UniqueConstraint('original_username', name='users_original_username_key'),
|
||||
UniqueConstraint('username', name='users_username_key'),
|
||||
)
|
||||
id = Column(Integer, primary_key=True)
|
||||
username = Column(String)
|
||||
namecolor = Column(String, default=DEFAULT_COLOR)
|
||||
username = Column(String(length=255), nullable=False)
|
||||
namecolor = Column(String(length=6), default=DEFAULT_COLOR, nullable=False)
|
||||
background = Column(String)
|
||||
customtitle = Column(String)
|
||||
customtitleplain = deferred(Column(String))
|
||||
titlecolor = Column(String, default=DEFAULT_COLOR)
|
||||
theme = Column(String, default=defaulttheme)
|
||||
themecolor = Column(String, default=DEFAULT_COLOR)
|
||||
cardview = Column(Boolean, default=cardview)
|
||||
titlecolor = Column(String(length=6), default=DEFAULT_COLOR, nullable=False)
|
||||
theme = Column(String, default=defaulttheme, nullable=False)
|
||||
themecolor = Column(String, default=DEFAULT_COLOR, nullable=False)
|
||||
cardview = Column(Boolean, default=cardview, nullable=False)
|
||||
song = Column(String)
|
||||
highres = Column(String)
|
||||
profileurl = Column(String)
|
||||
bannerurl = Column(String)
|
||||
house = Column(String)
|
||||
patron = Column(Integer, default=0)
|
||||
patron_utc = Column(Integer, default=0)
|
||||
patron = Column(Integer, default=0, nullable=False)
|
||||
patron_utc = Column(Integer, default=0, nullable=False)
|
||||
verified = Column(String)
|
||||
verifiedcolor = Column(String)
|
||||
marseyawarded = Column(Integer)
|
||||
rehab = Column(Integer)
|
||||
longpost = Column(Integer)
|
||||
winnings = Column(Integer, default=0)
|
||||
winnings = Column(Integer, default=0, nullable=False)
|
||||
unblockable = Column(Boolean)
|
||||
bird = Column(Integer)
|
||||
email = deferred(Column(String))
|
||||
css = deferred(Column(String))
|
||||
profilecss = deferred(Column(String))
|
||||
passhash = deferred(Column(String))
|
||||
post_count = Column(Integer, default=0)
|
||||
comment_count = Column(Integer, default=0)
|
||||
received_award_count = Column(Integer, default=0)
|
||||
created_utc = Column(Integer)
|
||||
admin_level = Column(Integer, default=0)
|
||||
coins_spent = Column(Integer, default=0)
|
||||
lootboxes_bought = Column(Integer, default=0)
|
||||
agendaposter = Column(Integer, default=0)
|
||||
changelogsub = Column(Boolean, default=False)
|
||||
is_activated = Column(Boolean, default=False)
|
||||
passhash = deferred(Column(String, nullable=False))
|
||||
post_count = Column(Integer, default=0, nullable=False)
|
||||
comment_count = Column(Integer, default=0, nullable=False)
|
||||
received_award_count = Column(Integer, default=0, nullable=False)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
admin_level = Column(Integer, default=0, nullable=False)
|
||||
coins_spent = Column(Integer, default=0, nullable=False)
|
||||
lootboxes_bought = Column(Integer, default=0, nullable=False)
|
||||
agendaposter = Column(Integer, default=0, nullable=False)
|
||||
changelogsub = Column(Boolean, default=False, nullable=False)
|
||||
is_activated = Column(Boolean, default=False, nullable=False)
|
||||
shadowbanned = Column(String)
|
||||
over_18 = Column(Boolean, default=False)
|
||||
hidevotedon = Column(Boolean, default=False)
|
||||
highlightcomments = Column(Boolean, default=True)
|
||||
slurreplacer = Column(Boolean, default=True)
|
||||
over_18 = Column(Boolean, default=False, nullable=False)
|
||||
hidevotedon = Column(Boolean, default=False, nullable=False)
|
||||
highlightcomments = Column(Boolean, default=True, nullable=False)
|
||||
slurreplacer = Column(Boolean, default=True, nullable=False)
|
||||
flairchanged = Column(Integer)
|
||||
newtab = Column(Boolean, default=False)
|
||||
newtabexternal = Column(Boolean, default=True)
|
||||
reddit = Column(String, default='old.reddit.com')
|
||||
newtab = Column(Boolean, default=False, nullable=False)
|
||||
newtabexternal = Column(Boolean, default=True, nullable=False)
|
||||
reddit = Column(String, default='old.reddit.com', nullable=False)
|
||||
nitter = Column(Boolean)
|
||||
mute = Column(Boolean)
|
||||
unmutable = Column(Boolean)
|
||||
eye = Column(Boolean)
|
||||
alt = Column(Boolean)
|
||||
frontsize = Column(Integer, default=25)
|
||||
controversial = Column(Boolean, default=False)
|
||||
frontsize = Column(Integer, default=25, nullable=False)
|
||||
controversial = Column(Boolean, default=False, nullable=False)
|
||||
bio = deferred(Column(String))
|
||||
bio_html = Column(String)
|
||||
sig = deferred(Column(String))
|
||||
|
@ -97,28 +104,49 @@ class User(Base):
|
|||
friends_html = deferred(Column(String))
|
||||
enemies = deferred(Column(String))
|
||||
enemies_html = deferred(Column(String))
|
||||
is_banned = Column(Integer, default=0)
|
||||
unban_utc = Column(Integer, default=0)
|
||||
is_banned = Column(Integer, default=0, nullable=False)
|
||||
unban_utc = Column(Integer, default=0, nullable=False)
|
||||
ban_reason = deferred(Column(String))
|
||||
club_allowed = Column(Boolean)
|
||||
login_nonce = Column(Integer, default=0)
|
||||
login_nonce = Column(Integer, default=0, nullable=False)
|
||||
reserved = deferred(Column(String))
|
||||
coins = Column(Integer, default=0)
|
||||
truecoins = Column(Integer, default=0)
|
||||
procoins = Column(Integer, default=0)
|
||||
coins = Column(Integer, default=0, nullable=False)
|
||||
truecoins = Column(Integer, default=0, nullable=False)
|
||||
procoins = Column(Integer, default=0, nullable=False)
|
||||
mfa_secret = deferred(Column(String))
|
||||
is_private = Column(Boolean, default=False)
|
||||
stored_subscriber_count = Column(Integer, default=0)
|
||||
defaultsortingcomments = Column(String, default="new")
|
||||
defaultsorting = Column(String, default="new")
|
||||
defaulttime = Column(String, default=defaulttimefilter)
|
||||
is_nofollow = Column(Boolean, default=False)
|
||||
is_private = Column(Boolean, default=False, nullable=False)
|
||||
stored_subscriber_count = Column(Integer, default=0, nullable=False)
|
||||
defaultsortingcomments = Column(String, default="new", nullable=False)
|
||||
defaultsorting = Column(String, default="new", nullable=False)
|
||||
defaulttime = Column(String, default=defaulttimefilter, nullable=False)
|
||||
is_nofollow = Column(Boolean, default=False, nullable=False)
|
||||
custom_filter_list = Column(String)
|
||||
discord_id = Column(String)
|
||||
ban_evade = Column(Integer, default=0)
|
||||
ban_evade = Column(Integer, default=0, nullable=False)
|
||||
original_username = deferred(Column(String))
|
||||
referred_by = Column(Integer, ForeignKey("users.id"))
|
||||
subs_created = Column(Integer, default=0)
|
||||
subs_created = Column(Integer, default=0, nullable=False)
|
||||
|
||||
Index(
|
||||
'users_original_username_trgm_idx',
|
||||
original_username,
|
||||
postgresql_using='gin',
|
||||
postgresql_ops={'description':'gin_trgm_ops'}
|
||||
)
|
||||
Index(
|
||||
'users_username_trgm_idx',
|
||||
username,
|
||||
postgresql_using='gin',
|
||||
postgresql_ops={'description':'gin_trgm_ops'}
|
||||
)
|
||||
|
||||
Index('discord_id_idx', discord_id)
|
||||
Index('fki_user_referrer_fkey', referred_by)
|
||||
Index('user_banned_idx', is_banned)
|
||||
Index('user_private_idx', is_private)
|
||||
Index('users_created_utc_index', created_utc)
|
||||
Index('users_subs_idx', stored_subscriber_count)
|
||||
Index('users_unbanutc_idx', unban_utc.desc())
|
||||
|
||||
badges = relationship("Badge", viewonly=True)
|
||||
subscriptions = relationship("Subscription", viewonly=True)
|
||||
|
@ -495,8 +523,7 @@ class User(Base):
|
|||
@property
|
||||
@lazy
|
||||
def profile_url(self):
|
||||
if self.agendaposter: return f"{SITE_FULL}/assets/images/astolfo.webp?v=1"
|
||||
if self.profileurl:
|
||||
if self.profileurl:
|
||||
if self.profileurl.startswith('/'): return SITE_FULL + self.profileurl
|
||||
return self.profileurl
|
||||
return f"{SITE_FULL}/assets/images/default-profile-pic.webp?v=1008"
|
||||
|
|
|
@ -8,6 +8,8 @@ class UserBlock(Base):
|
|||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
target_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
|
||||
Index('block_target_idx', target_id)
|
||||
|
||||
user = relationship("User", primaryjoin="User.id==UserBlock.user_id", viewonly=True)
|
||||
target = relationship("User", primaryjoin="User.id==UserBlock.target_id", viewonly=True)
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@ class ViewerRelationship(Base):
|
|||
|
||||
user_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
|
||||
viewer_id = Column(Integer, ForeignKey('users.id'), primary_key=True)
|
||||
last_view_utc = Column(Integer)
|
||||
last_view_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('fki_view_viewer_fkey', viewer_id)
|
||||
|
||||
viewer = relationship("User", primaryjoin="ViewerRelationship.viewer_id == User.id", viewonly=True)
|
||||
|
||||
|
|
|
@ -11,10 +11,13 @@ class Vote(Base):
|
|||
|
||||
submission_id = Column(Integer, ForeignKey("submissions.id"), primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
vote_type = Column(Integer)
|
||||
vote_type = Column(Integer, nullable=False)
|
||||
app_id = Column(Integer, ForeignKey("oauth_apps.id"))
|
||||
real = Column(Boolean, default=True)
|
||||
created_utc = Column(Integer)
|
||||
real = Column(Boolean, default=True, nullable=False)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('votes_type_index', vote_type)
|
||||
Index('vote_user_index', user_id)
|
||||
|
||||
user = relationship("User", lazy="subquery", viewonly=True)
|
||||
post = relationship("Submission", lazy="subquery", viewonly=True)
|
||||
|
@ -52,10 +55,13 @@ class CommentVote(Base):
|
|||
|
||||
comment_id = Column(Integer, ForeignKey("comments.id"), primary_key=True)
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
vote_type = Column(Integer)
|
||||
vote_type = Column(Integer, nullable=False)
|
||||
app_id = Column(Integer, ForeignKey("oauth_apps.id"))
|
||||
real = Column(Boolean, default=True)
|
||||
created_utc = Column(Integer)
|
||||
real = Column(Boolean, default=True, nullable=False)
|
||||
created_utc = Column(Integer, nullable=False)
|
||||
|
||||
Index('cvote_user_index', user_id)
|
||||
Index('commentvotes_comments_type_index', vote_type)
|
||||
|
||||
user = relationship("User", lazy="subquery")
|
||||
comment = relationship("Comment", lazy="subquery", viewonly=True)
|
||||
|
|
7
files/cli.py
Normal file
7
files/cli.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from flask_migrate import Migrate
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from .__main__ import app
|
||||
import files.classes
|
||||
|
||||
db = SQLAlchemy(app)
|
||||
migrate = Migrate(app, db)
|
|
@ -28,76 +28,11 @@ AJ_REPLACEMENTS = {
|
|||
}
|
||||
|
||||
SLURS = {
|
||||
"retarded": "r-slurred",
|
||||
"retard": "r-slur",
|
||||
"gayfag": "gaystrag",
|
||||
"poorfag": "poorstrag",
|
||||
"richfag": "richstrag",
|
||||
"newfag": "newstrag",
|
||||
"oldfag": "oldstrag",
|
||||
"faggotry": "cute twinkry",
|
||||
"faggot": "cute twink",
|
||||
"pedophile": "libertarian",
|
||||
"kill yourself": "keep yourself safe",
|
||||
"n1gger": "BIPOC",
|
||||
"nlgger": "BIPOC",
|
||||
"nigger": "BIPOC",
|
||||
"steve akins": "penny verity oaken",
|
||||
"trannie": "🚂🚃🚃",
|
||||
"tranny": "🚂🚃🚃",
|
||||
"troon": "🚂🚃🚃",
|
||||
"nonewnormal": "HorseDewormerAddicts",
|
||||
"kikery": "https://sciencedirect.com/science/article/abs/pii/S016028960600033X",
|
||||
"kike": "https://sciencedirect.com/science/article/abs/pii/S016028960600033X",
|
||||
"latinos": "latinx",
|
||||
"latino": "latinx",
|
||||
"latinas": "latinx",
|
||||
"latina": "latinx",
|
||||
"hispanics": "latinx",
|
||||
"hispanic": "latinx",
|
||||
"uss liberty incident": "tragic accident aboard the USS Liberty",
|
||||
"lavon affair": "Lavon Misunderstanding",
|
||||
"shylock": "Israeli friend",
|
||||
"mohammad": "Prophet Mohammad (PBUH)",
|
||||
"muhammad": "Prophet Mohammad (PBUH)",
|
||||
"i hate marsey": "i love marsey",
|
||||
"dancing israelis": "i love Israel",
|
||||
"sodomite": "total dreamboat",
|
||||
"pajeet": "sexy Indian dude",
|
||||
"landlord": "landchad",
|
||||
"tenant": "renthog",
|
||||
"renter": "rentoid",
|
||||
"autistic": "neurodivergent",
|
||||
"holohoax": "i tried to claim the Holocaust didn't happen because I am a pencil-dicked imbecile and the word filter caught me lol",
|
||||
"groomercord": "discord (actually a pretty cool service)",
|
||||
"pedocord": "discord (actually a pretty cool service)",
|
||||
"i hate carp": "i love Carp",
|
||||
"manlet": "little king",
|
||||
"gamer": "g*mer",
|
||||
"journalist": "journ*list",
|
||||
"journalism": "journ*lism",
|
||||
"wuhan flu": "SARS-CoV-2 syndemic",
|
||||
"china flu": "SARS-CoV-2 syndemic",
|
||||
"china virus": "SARS-CoV-2 syndemic",
|
||||
"kung flu": "SARS-CoV-2 syndemic",
|
||||
"elon musk": "rocket daddy",
|
||||
"fake and gay": "fake and straight",
|
||||
|
||||
" rapist ": " male feminist ",
|
||||
" pedo ": " libertarian ",
|
||||
" kys ": " keep yourself safe ",
|
||||
" fag ": " cute twink ",
|
||||
}
|
||||
|
||||
single_words = "|".join([slur.lower() for slur in SLURS.keys()])
|
||||
|
||||
|
||||
LONGPOST_REPLIES = ('Wow, you must be a JP fan.', 'This is one of the worst posts I have EVER seen. Delete it.', "No, don't reply like this, please do another wall of unhinged rant please.", '# 😴😴😴', "Ma'am we've been over this before. You need to stop.", "I've known more coherent downies.", "Your pulitzer's in the mail", "That's great and all, but I asked for my burger without cheese.", 'That degree finally paying off', "That's nice sweaty. Why don't you have a seat in the time out corner with Pizzashill until you calm down, then you can have your Capri Sun.", "All them words won't bring your pa back.", "You had a chance to not be completely worthless, but it looks like you threw it away. At least you're consistent.", 'Some people are able to display their intelligence by going on at length on a subject and never actually saying anything. This ability is most common in trades such as politics, public relations, and law. You have impressed me by being able to best them all, while still coming off as an absolute idiot.', "You can type 10,000 characters and you decided that these were the one's that you wanted.", 'Have you owned the libs yet?', "I don't know what you said, because I've seen another human naked.", 'Impressive. Normally people with such severe developmental disabilities struggle to write much more than a sentence or two. He really has exceded our expectations for the writing portion. Sadly the coherency of his writing, along with his abilities in the social skills and reading portions, are far behind his peers with similar disabilities.', "This is a really long way of saying you don't fuck.", "Sorry ma'am, looks like his delusions have gotten worse. We'll have to admit him.", ':#marseywoah:', 'If only you could put that energy into your relationships', 'Posts like this is why I do Heroine.', 'still unemployed then?', 'K', 'look im gunna have 2 ask u 2 keep ur giant dumps in the toilet not in my replys 😷😷😷', "Mommy is soooo proud of you, sweaty. Let's put this sperg out up on the fridge with all your other failures.", "Good job bobby, here's a star", "That was a mistake. You're about to find out the hard way why.", f'You sat down and wrote all this shit. You could have done so many other things with your life. What happened to your life that made you decide writing novels of bullshit on {SITE} was the best option?', "I don't have enough spoons to read this shit", "All those words won't bring daddy back.", 'OUT!', "Damn, you're really mad over this, but thanks for the effort you put into typing that all out! Sadly I won't read it all.", "Jesse what the fuck are you talking about??", "▼you're fucking bananas if you think I'm reading all that, take my downvote and shut up idiot", "Are you feeling okay bud?")
|
||||
|
||||
AGENDAPOSTER_PHRASE = 'trans lives matter'
|
||||
|
||||
AGENDAPOSTER_MSG = """Hi @{username},\n\nYour {type} has been automatically removed because you forgot to include `{AGENDAPOSTER_PHRASE}`.\n\nDon't worry, we're here to help! We won't let you post or comment anything that doesn't express your love and acceptance towards the trans community. Feel free to resubmit your {type} with `{AGENDAPOSTER_PHRASE}` included. \n\n*This is an automated message; if you need help, you can message us [here](/contact).*"""
|
||||
|
||||
NOTIFICATIONS_ID = 1
|
||||
AUTOJANNY_ID = 2
|
||||
SNAPPY_ID = 3
|
||||
|
@ -369,14 +304,6 @@ AWARDS = {
|
|||
"color": "text-blue",
|
||||
"price": 1500
|
||||
},
|
||||
"agendaposter": {
|
||||
"kind": "agendaposter",
|
||||
"title": "Chud",
|
||||
"description": "Forces the chud theme on the recipient for 24 hours.",
|
||||
"icon": "fas fa-snooze",
|
||||
"color": "text-purple",
|
||||
"price": 2500
|
||||
},
|
||||
"deflector": {
|
||||
"kind": "deflector",
|
||||
"title": "Deflector",
|
||||
|
@ -591,38 +518,18 @@ emoji_regex3 = re.compile(f"(?<!\"):([!@{valid_username_chars}]{{1,31}}?):", fla
|
|||
|
||||
snappy_url_regex = re.compile('<a href=\"(https?:\/\/[a-z]{1,20}\.[\w:~,()\-.#&\/=?@%;+]{5,250})\" rel=\"nofollow noopener noreferrer\" target=\"_blank\">([\w:~,()\-.#&\/=?@%;+]{5,250})<\/a>', flags=re.A)
|
||||
|
||||
email_regex = re.compile('([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,100})+', flags=re.A)
|
||||
# Technically this allows stuff that is not a valid email address, but realistically
|
||||
# we care "does this email go to the correct person" rather than "is this email
|
||||
# address syntactically valid", so if we care we should be sending a confirmation
|
||||
# link, and otherwise should be pretty liberal in what we accept here.
|
||||
email_regex = re.compile('[^@]+@[^@]+\.[^@]+', flags=re.A)
|
||||
|
||||
utm_regex = re.compile('utm_[a-z]+=[a-z0-9_]+&', flags=re.A)
|
||||
utm_regex2 = re.compile('[?&]utm_[a-z]+=[a-z0-9_]+', flags=re.A)
|
||||
|
||||
slur_regex = re.compile(f"({single_words})(?![^<]*>)", flags=re.I|re.A)
|
||||
slur_regex_upper = re.compile(f"({single_words.upper()})(?![^<]*>)", flags=re.A)
|
||||
torture_regex = re.compile('(^|\s)(i|me) ', flags=re.I|re.A)
|
||||
torture_regex2 = re.compile("(^|\s)i'm ", flags=re.I|re.A)
|
||||
|
||||
def sub_matcher(match):
|
||||
return SLURS[match.group(0).lower()]
|
||||
|
||||
def sub_matcher_upper(match):
|
||||
return SLURS[match.group(0).lower()].upper()
|
||||
|
||||
def censor_slurs(body, logged_user):
|
||||
if not logged_user or logged_user == 'chat' or logged_user.slurreplacer:
|
||||
body = slur_regex_upper.sub(sub_matcher_upper, body)
|
||||
body = slur_regex.sub(sub_matcher, body)
|
||||
return body
|
||||
|
||||
def torture_ap(body, username):
|
||||
for k, l in AJ_REPLACEMENTS.items():
|
||||
body = body.replace(k, l)
|
||||
body = torture_regex.sub(rf'\1@{username} ', body)
|
||||
body = torture_regex2.sub(rf'\1@{username} is ', body)
|
||||
return body
|
||||
|
||||
YOUTUBE_KEY = environ.get("YOUTUBE_KEY", "").strip()
|
||||
|
||||
ADMIGGERS = (37696,37697,37749,37833,37838)
|
||||
ADMINISTRATORS = (37696, 37697, 37749, 37833, 37838)
|
||||
|
||||
proxies = {"http":"http://127.0.0.1:18080","https":"http://127.0.0.1:18080"}
|
||||
|
||||
|
|
|
@ -49,4 +49,4 @@ def timestamp(timestamp):
|
|||
|
||||
@app.context_processor
|
||||
def inject_constants():
|
||||
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, "AUTOJANNY_ID":AUTOJANNY_ID, "NOTIFICATIONS_ID":NOTIFICATIONS_ID, "PUSHER_ID":PUSHER_ID, "CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "MOOSE_ID":MOOSE_ID, "AEVANN_ID":AEVANN_ID, "PIZZASHILL_ID":PIZZASHILL_ID, "config":app.config.get, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "ADMIGGERS":ADMIGGERS}
|
||||
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL, "AUTOJANNY_ID":AUTOJANNY_ID, "NOTIFICATIONS_ID":NOTIFICATIONS_ID, "PUSHER_ID":PUSHER_ID, "CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "MOOSE_ID":MOOSE_ID, "AEVANN_ID":AEVANN_ID, "PIZZASHILL_ID":PIZZASHILL_ID, "config":app.config.get, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "ADMIGGERS":ADMINISTRATORS}
|
||||
|
|
|
@ -191,26 +191,26 @@ def sanitize(sanitized, alert=False, comment=False, edit=False):
|
|||
|
||||
marseys_used = set()
|
||||
|
||||
emojis = list(emoji_regex.finditer(sanitized))
|
||||
if len(emojis) > 20: edit = True
|
||||
# emojis = list(emoji_regex.finditer(sanitized))
|
||||
# if len(emojis) > 20: edit = True
|
||||
|
||||
captured = []
|
||||
for i in emojis:
|
||||
if i.group(0) in captured: continue
|
||||
captured.append(i.group(0))
|
||||
# captured = []
|
||||
# for i in emojis:
|
||||
# if i.group(0) in captured: continue
|
||||
# captured.append(i.group(0))
|
||||
|
||||
old = i.group(0)
|
||||
if 'marseylong1' in old or 'marseylong2' in old or 'marseyllama1' in old or 'marseyllama2' in old: new = old.lower().replace(">", " class='mb-0'>")
|
||||
else: new = old.lower()
|
||||
# old = i.group(0)
|
||||
# if 'marseylong1' in old or 'marseylong2' in old or 'marseyllama1' in old or 'marseyllama2' in old: new = old.lower().replace(">", " class='mb-0'>")
|
||||
# else: new = old.lower()
|
||||
|
||||
new = render_emoji(new, emoji_regex2, edit, marseys_used, True)
|
||||
# new = render_emoji(new, emoji_regex2, edit, marseys_used, True)
|
||||
|
||||
sanitized = sanitized.replace(old, new)
|
||||
# sanitized = sanitized.replace(old, new)
|
||||
|
||||
emojis = list(emoji_regex2.finditer(sanitized))
|
||||
if len(emojis) > 20: edit = True
|
||||
# emojis = list(emoji_regex2.finditer(sanitized))
|
||||
# if len(emojis) > 20: edit = True
|
||||
|
||||
sanitized = render_emoji(sanitized, emoji_regex2, edit, marseys_used)
|
||||
# sanitized = render_emoji(sanitized, emoji_regex2, edit, marseys_used)
|
||||
|
||||
for rd in ["://reddit.com", "://new.reddit.com", "://www.reddit.com", "://redd.it", "://libredd.it", "://teddit.net"]:
|
||||
sanitized = sanitized.replace(rd, "://old.reddit.com")
|
||||
|
@ -315,7 +315,7 @@ def filter_emojis_only(title, edit=False, graceful=False):
|
|||
|
||||
title = title.replace('','').replace('','').replace("\ufeff", "").replace("𒐪","").replace("\n", "").replace("\r", "").replace("\t", "").replace("&", "&").replace('<','<').replace('>','>').replace('"', '"').replace("'", "'").strip()
|
||||
|
||||
title = render_emoji(title, emoji_regex3, edit)
|
||||
# title = render_emoji(title, emoji_regex3, edit)
|
||||
|
||||
title = strikethrough_regex.sub(r'<del>\1</del>', title)
|
||||
|
||||
|
|
|
@ -950,77 +950,6 @@ def admin_removed_comments(v):
|
|||
)
|
||||
|
||||
|
||||
@app.post("/agendaposter/<user_id>")
|
||||
@admin_level_required(2)
|
||||
def agendaposter(user_id, v):
|
||||
user = g.db.query(User).filter_by(id=user_id).one_or_none()
|
||||
|
||||
days = request.values.get("days") or 30
|
||||
expiry = float(days)
|
||||
expiry = int(time.time() + expiry*60*60*24)
|
||||
|
||||
user.agendaposter = expiry
|
||||
g.db.add(user)
|
||||
|
||||
for alt in user.alts:
|
||||
if alt.admin_level: return {"error": "User is an admin!"}
|
||||
alt.agendaposter = expiry
|
||||
g.db.add(alt)
|
||||
|
||||
note = f"for {days} days"
|
||||
|
||||
ma = ModAction(
|
||||
kind="agendaposter",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id,
|
||||
note = note
|
||||
)
|
||||
g.db.add(ma)
|
||||
|
||||
if not user.has_badge(28):
|
||||
badge = Badge(user_id=user.id, badge_id=28)
|
||||
g.db.add(badge)
|
||||
g.db.flush()
|
||||
send_notification(user.id, f"@AutoJanny has given you the following profile badge:\n\n\n\n{badge.name}")
|
||||
|
||||
|
||||
send_repeatable_notification(user.id, f"@{v.username} has marked you as a chud ({note}).")
|
||||
|
||||
g.db.commit()
|
||||
|
||||
return redirect(user.url)
|
||||
|
||||
|
||||
|
||||
@app.post("/unagendaposter/<user_id>")
|
||||
@admin_level_required(2)
|
||||
def unagendaposter(user_id, v):
|
||||
user = g.db.query(User).filter_by(id=user_id).one_or_none()
|
||||
|
||||
user.agendaposter = 0
|
||||
g.db.add(user)
|
||||
|
||||
for alt in user.alts:
|
||||
alt.agendaposter = 0
|
||||
g.db.add(alt)
|
||||
|
||||
ma = ModAction(
|
||||
kind="unagendaposter",
|
||||
user_id=v.id,
|
||||
target_user_id=user.id
|
||||
)
|
||||
|
||||
g.db.add(ma)
|
||||
|
||||
badge = user.has_badge(28)
|
||||
if badge: g.db.delete(badge)
|
||||
|
||||
send_repeatable_notification(user.id, f"@{v.username} has unmarked you as a chud.")
|
||||
|
||||
g.db.commit()
|
||||
return {"message": "Chud theme disabled!"}
|
||||
|
||||
|
||||
@app.post("/shadowban/<user_id>")
|
||||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||
@admin_level_required(2)
|
||||
|
@ -1538,9 +1467,6 @@ def api_unban_comment(c_id, v):
|
|||
comment = g.db.query(Comment).filter_by(id=c_id).one_or_none()
|
||||
if not comment: abort(404)
|
||||
|
||||
if comment.author.agendaposter and AGENDAPOSTER_PHRASE not in comment.body.lower():
|
||||
return {"error": "You can't bypass the chud award!"}
|
||||
|
||||
if comment.is_banned:
|
||||
ma=ModAction(
|
||||
kind="unban_comment",
|
||||
|
|
|
@ -213,18 +213,6 @@ def award_post(pid, v):
|
|||
cache.delete_memoized(frontlist)
|
||||
else: post.stickied_utc = t
|
||||
g.db.add(post)
|
||||
elif kind == "agendaposter" and not (author.agendaposter and author.agendaposter == 0):
|
||||
if author.marseyawarded:
|
||||
return {"error": "This user is the under the effect of a conflicting award: Marsey award."}, 404
|
||||
|
||||
if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400
|
||||
else: author.agendaposter = int(time.time()) + 86400
|
||||
|
||||
if not author.has_badge(28):
|
||||
badge = Badge(user_id=author.id, badge_id=28)
|
||||
g.db.add(badge)
|
||||
g.db.flush()
|
||||
send_notification(author.id, f"@AutoJanny has given you the following profile badge:\n\n\n\n{badge.name}")
|
||||
elif kind == "flairlock":
|
||||
new_name = note[:100].replace("𒐪","")
|
||||
if not new_name and author.flairchanged:
|
||||
|
@ -451,18 +439,6 @@ def award_comment(cid, v):
|
|||
c.is_pinned_utc = None
|
||||
else: c.is_pinned_utc = t
|
||||
g.db.add(c)
|
||||
elif kind == "agendaposter" and not (author.agendaposter and author.agendaposter == 0):
|
||||
if author.marseyawarded:
|
||||
return {"error": "This user is the under the effect of a conflicting award: Marsey award."}, 404
|
||||
|
||||
if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400
|
||||
else: author.agendaposter = int(time.time()) + 86400
|
||||
|
||||
if not author.has_badge(28):
|
||||
badge = Badge(user_id=author.id, badge_id=28)
|
||||
g.db.add(badge)
|
||||
g.db.flush()
|
||||
send_notification(author.id, f"@AutoJanny has given you the following profile badge:\n\n\n\n{badge.name}")
|
||||
elif kind == "flairlock":
|
||||
new_name = note[:100].replace("𒐪","")
|
||||
if not new_name and author.flairchanged:
|
||||
|
|
|
@ -55,7 +55,7 @@ def speak(data, v):
|
|||
"namecolor": v.namecolor,
|
||||
"text": text,
|
||||
"text_html": text_html,
|
||||
"text_censored": censor_slurs(text_html, 'chat'),
|
||||
"text_censored": text,
|
||||
"time": int(time.time())
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ from files.helpers.blackjack import *
|
|||
from files.helpers.treasure import *
|
||||
from files.classes import *
|
||||
from files.routes.front import comment_idlist
|
||||
from files.routes.static import marsey_list
|
||||
from pusher_push_notifications import PushNotifications
|
||||
from flask import *
|
||||
from files.__main__ import app, limiter
|
||||
|
@ -189,7 +188,7 @@ def api_comment(v):
|
|||
with open(f"snappy_{SITE_NAME}.txt", "a", encoding="utf-8") as f:
|
||||
f.write('\n{[para]}\n' + body)
|
||||
|
||||
if parent_post.id not in ADMIGGERS:
|
||||
if parent_post.id not in ADMINISTRATORS:
|
||||
if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
|
||||
return {"error":"You have to type more than 280 characters!"}, 403
|
||||
elif v.bird and len(body) > 140:
|
||||
|
@ -243,59 +242,6 @@ def api_comment(v):
|
|||
requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data={'files': [f"https://{request.host}/assets/images/badges/{badge.id}.webp"]}, timeout=5)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}, 400
|
||||
elif v.admin_level > 2 and parent_post.id == 37838:
|
||||
try:
|
||||
marsey = loads(body.lower())
|
||||
|
||||
name = marsey["name"]
|
||||
if not marsey_regex.fullmatch(name): return {"error": "Invalid name!"}, 400
|
||||
existing = g.db.query(Marsey.name).filter_by(name=name).one_or_none()
|
||||
if existing: return {"error": "A marsey with this name already exists!"}, 403
|
||||
|
||||
tags = marsey["tags"]
|
||||
if not tags_regex.fullmatch(tags): return {"error": "Invalid tags!"}, 400
|
||||
|
||||
if "author" in marsey: user = get_user(marsey["author"])
|
||||
elif "author_id" in marsey: user = get_account(marsey["author_id"])
|
||||
else: abort(400)
|
||||
|
||||
filename = f'files/assets/images/emojis/{name}.webp'
|
||||
copyfile(oldname, filename)
|
||||
process_image(filename, 200)
|
||||
|
||||
marsey = Marsey(name=name, author_id=user.id, tags=tags, count=0)
|
||||
g.db.add(marsey)
|
||||
g.db.flush()
|
||||
|
||||
all_by_author = g.db.query(Marsey.author_id).filter_by(author_id=user.id).count()
|
||||
|
||||
if all_by_author >= 10 and not user.has_badge(16):
|
||||
new_badge = Badge(badge_id=16, user_id=user.id)
|
||||
|
||||
g.db.add(new_badge)
|
||||
g.db.flush()
|
||||
|
||||
if v.id != user.id:
|
||||
text = f"@AutoJanny has given you the following profile badge:\n\n\n\n{new_badge.name}"
|
||||
send_notification(user.id, text)
|
||||
|
||||
elif all_by_author < 10 and not user.has_badge(17):
|
||||
new_badge = Badge(badge_id=17, user_id=user.id)
|
||||
|
||||
g.db.add(new_badge)
|
||||
g.db.flush()
|
||||
|
||||
if v.id != user.id:
|
||||
text = f"@AutoJanny has given you the following profile badge:\n\n\n\n{new_badge.name}"
|
||||
send_notification(user.id, text)
|
||||
|
||||
|
||||
|
||||
requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data={'files': [f"https://{request.host}/e/{name}.webp"]}, timeout=5)
|
||||
cache.delete_memoized(marsey_list)
|
||||
|
||||
except Exception as e:
|
||||
return {"error": str(e)}, 400
|
||||
body += f"\n\n"
|
||||
elif file.content_type.startswith('video/'):
|
||||
file.save("video.mp4")
|
||||
|
@ -311,13 +257,9 @@ def api_comment(v):
|
|||
body += f"\n\n{url}"
|
||||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
if v.agendaposter and not v.marseyawarded and parent_post.id not in ADMIGGERS:
|
||||
body = torture_ap(body, v.username)
|
||||
|
||||
body_html = sanitize(body, comment=True)
|
||||
|
||||
|
||||
if parent_post.id not in ADMIGGERS and '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower():
|
||||
if parent_post.id not in ADMINISTRATORS and '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower():
|
||||
existing = g.db.query(Comment.id).filter(Comment.author_id == v.id,
|
||||
Comment.deleted_utc == 0,
|
||||
Comment.parent_comment_id == parent_comment_id,
|
||||
|
@ -331,7 +273,7 @@ def api_comment(v):
|
|||
|
||||
is_bot = bool(request.headers.get("Authorization"))
|
||||
|
||||
if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and parent_post.id not in ADMIGGERS and not is_bot and not v.marseyawarded and AGENDAPOSTER_PHRASE not in body.lower() and len(body) > 10:
|
||||
if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and parent_post.id not in ADMINISTRATORS and not is_bot and not v.marseyawarded and len(body) > 10:
|
||||
now = int(time.time())
|
||||
cutoff = now - 60 * 60 * 24
|
||||
|
||||
|
@ -419,39 +361,7 @@ def api_comment(v):
|
|||
|
||||
g.db.add(c_choice)
|
||||
|
||||
if parent_post.id not in ADMIGGERS:
|
||||
if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower():
|
||||
|
||||
c.is_banned = True
|
||||
c.ban_reason = "AutoJanny"
|
||||
|
||||
g.db.add(c)
|
||||
|
||||
|
||||
body = AGENDAPOSTER_MSG.format(username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE)
|
||||
|
||||
body_jannied_html = sanitize(body)
|
||||
|
||||
|
||||
|
||||
c_jannied = Comment(author_id=NOTIFICATIONS_ID,
|
||||
parent_submission=parent_submission,
|
||||
distinguish_level=6,
|
||||
parent_comment_id=c.id,
|
||||
level=level+1,
|
||||
is_bot=True,
|
||||
body_html=body_jannied_html,
|
||||
top_comment_id=c.top_comment_id,
|
||||
ghost=parent_post.ghost
|
||||
)
|
||||
|
||||
g.db.add(c_jannied)
|
||||
g.db.flush()
|
||||
|
||||
n = Notification(comment_id=c_jannied.id, user_id=v.id)
|
||||
g.db.add(n)
|
||||
|
||||
|
||||
if parent_post.id not in ADMINISTRATORS:
|
||||
if not v.shadowbanned:
|
||||
notify_users = NOTIFY_USERS(body, v)
|
||||
|
||||
|
@ -500,7 +410,7 @@ def api_comment(v):
|
|||
|
||||
check_for_blackjack_commands(body, v, c)
|
||||
|
||||
if not c.slots_result and not c.blackjack_result and v.marseyawarded and parent_post.id not in ADMIGGERS and marseyaward_body_regex.search(body_html):
|
||||
if not c.slots_result and not c.blackjack_result and v.marseyawarded and parent_post.id not in ADMINISTRATORS and marseyaward_body_regex.search(body_html):
|
||||
return {"error":"You can only type marseys!"}, 403
|
||||
|
||||
check_for_treasure(body, c)
|
||||
|
@ -540,9 +450,6 @@ def edit_comment(cid, v):
|
|||
elif v.bird and len(body) > 140:
|
||||
return {"error":"You have to type less than 140 characters!"}, 403
|
||||
|
||||
if v.agendaposter and not v.marseyawarded:
|
||||
body = torture_ap(body, v.username)
|
||||
|
||||
if not c.options:
|
||||
for i in poll_regex.finditer(body):
|
||||
body = body.replace(i.group(0), "")
|
||||
|
@ -571,7 +478,7 @@ def edit_comment(cid, v):
|
|||
|
||||
body_html = sanitize(body, edit=True)
|
||||
|
||||
if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower() and AGENDAPOSTER_PHRASE not in body.lower():
|
||||
if '!slots' not in body.lower() and '!blackjack' not in body.lower() and '!wordle' not in body.lower():
|
||||
now = int(time.time())
|
||||
cutoff = now - 60 * 60 * 24
|
||||
|
||||
|
@ -645,39 +552,6 @@ def edit_comment(cid, v):
|
|||
notif = Notification(comment_id=c.id, user_id=CARP_ID)
|
||||
g.db.add(notif)
|
||||
|
||||
if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and not c.is_banned:
|
||||
|
||||
c.is_banned = True
|
||||
c.ban_reason = "AutoJanny"
|
||||
|
||||
g.db.add(c)
|
||||
|
||||
|
||||
body = AGENDAPOSTER_MSG.format(username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE)
|
||||
|
||||
body_jannied_html = sanitize(body)
|
||||
|
||||
|
||||
|
||||
c_jannied = Comment(author_id=NOTIFICATIONS_ID,
|
||||
parent_submission=c.parent_submission,
|
||||
distinguish_level=6,
|
||||
parent_comment_id=c.id,
|
||||
level=c.level+1,
|
||||
is_bot=True,
|
||||
body_html=body_jannied_html,
|
||||
top_comment_id=c.top_comment_id,
|
||||
ghost=c.ghost
|
||||
)
|
||||
|
||||
g.db.add(c_jannied)
|
||||
g.db.flush()
|
||||
|
||||
n = Notification(comment_id=c_jannied.id, user_id=v.id)
|
||||
g.db.add(n)
|
||||
|
||||
|
||||
|
||||
if int(time.time()) - c.created_utc > 60 * 3: c.edited_utc = int(time.time())
|
||||
|
||||
g.db.add(c)
|
||||
|
|
|
@ -227,14 +227,6 @@ def front_all(v, sub=None, subdomain=None):
|
|||
g.db.add(v)
|
||||
g.db.commit()
|
||||
|
||||
if v.agendaposter and v.agendaposter < time.time():
|
||||
v.agendaposter = 0
|
||||
send_repeatable_notification(v.id, "Your chud theme has expired!")
|
||||
g.db.add(v)
|
||||
badge = v.has_badge(28)
|
||||
if badge: g.db.delete(badge)
|
||||
g.db.commit()
|
||||
|
||||
if v.flairchanged and v.flairchanged < time.time():
|
||||
v.flairchanged = None
|
||||
send_repeatable_notification(v.id, "Your flair lock has expired. You can now change your flair!")
|
||||
|
|
|
@ -321,7 +321,7 @@ def sign_up_post(v):
|
|||
session["history"] = []
|
||||
else: admin_level=0
|
||||
|
||||
profileurl = '/e/' + random.choice(marseys_const) + '.webp'
|
||||
profileurl = '/e/feather.webp'
|
||||
|
||||
new_user = User(
|
||||
username=username,
|
||||
|
@ -332,7 +332,7 @@ def sign_up_post(v):
|
|||
referred_by=ref_id or None,
|
||||
ban_evade = int(any((x.is_banned or x.shadowbanned) and not x.unban_utc for x in g.db.query(User).filter(User.id.in_(session.get("history", []))).all() if x)),
|
||||
profileurl=profileurl
|
||||
)
|
||||
)
|
||||
|
||||
g.db.add(new_user)
|
||||
g.db.flush()
|
||||
|
|
|
@ -434,7 +434,6 @@ def edit_post(pid, v):
|
|||
return {"error":"You have to type less than 140 characters!"}, 403
|
||||
|
||||
if title != p.title:
|
||||
if v.id == p.author_id and v.agendaposter and not v.marseyawarded: title = torture_ap(title, v.username)
|
||||
|
||||
title_html = filter_emojis_only(title, edit=True)
|
||||
|
||||
|
@ -467,8 +466,6 @@ def edit_post(pid, v):
|
|||
else: return {"error": "Image/Video files only"}, 400
|
||||
|
||||
if body != p.body:
|
||||
if v.id == p.author_id and v.agendaposter and not v.marseyawarded: body = torture_ap(body, v.username)
|
||||
|
||||
if not p.options:
|
||||
for i in poll_regex.finditer(body):
|
||||
body = body.replace(i.group(0), "")
|
||||
|
@ -498,7 +495,6 @@ def edit_post(pid, v):
|
|||
if v.id == p.author_id and v.marseyawarded and marseyaward_body_regex.search(body_html):
|
||||
return {"error":"You can only type marseys!"}, 403
|
||||
|
||||
|
||||
p.body = body
|
||||
|
||||
if blackjack and any(i in f'{p.body} {p.title} {p.url}'.lower() for i in blackjack.split()):
|
||||
|
@ -510,37 +506,6 @@ def edit_post(pid, v):
|
|||
|
||||
p.body_html = body_html
|
||||
|
||||
if v.id == p.author_id and v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in f'{p.body}{p.title}'.lower() and not p.is_banned:
|
||||
|
||||
p.is_banned = True
|
||||
p.ban_reason = "AutoJanny"
|
||||
|
||||
g.db.add(p)
|
||||
|
||||
body = AGENDAPOSTER_MSG.format(username=v.username, type='post', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE)
|
||||
|
||||
body_jannied_html = sanitize(body)
|
||||
|
||||
c_jannied = Comment(author_id=NOTIFICATIONS_ID,
|
||||
parent_submission=p.id,
|
||||
level=1,
|
||||
over_18=False,
|
||||
is_bot=True,
|
||||
app_id=None,
|
||||
is_pinned='AutoJanny',
|
||||
distinguish_level=6,
|
||||
body_html=body_jannied_html,
|
||||
ghost=p.ghost
|
||||
)
|
||||
|
||||
g.db.add(c_jannied)
|
||||
g.db.flush()
|
||||
|
||||
c_jannied.top_comment_id = c_jannied.id
|
||||
|
||||
n = Notification(comment_id=c_jannied.id, user_id=v.id)
|
||||
g.db.add(n)
|
||||
|
||||
if not p.private and not p.ghost:
|
||||
notify_users = NOTIFY_USERS(f'{p.title} {p.body}', v)
|
||||
if notify_users:
|
||||
|
@ -789,21 +754,10 @@ def submit_post(v, sub=None):
|
|||
|
||||
if v.is_suspended: return error("You can't perform this action while banned.")
|
||||
|
||||
if v.agendaposter and not v.marseyawarded: title = torture_ap(title, v.username)
|
||||
|
||||
title_html = filter_emojis_only(title, graceful=True)
|
||||
|
||||
if v.marseyawarded and not marseyaward_title_regex.fullmatch(title_html):
|
||||
return error("You can only type marseys!")
|
||||
|
||||
if len(title_html) > 1500: return error("Rendered title is too big!")
|
||||
|
||||
if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
|
||||
return error("You have to type more than 280 characters!")
|
||||
elif v.bird and len(body) > 140:
|
||||
return error("You have to type less than 140 characters!")
|
||||
|
||||
|
||||
embed = None
|
||||
|
||||
if url:
|
||||
|
@ -889,7 +843,6 @@ def submit_post(v, sub=None):
|
|||
if not title:
|
||||
return error("Please enter a better title.")
|
||||
|
||||
|
||||
elif len(title) > 500:
|
||||
return error("There's a 500 character limit for titles.")
|
||||
|
||||
|
@ -969,8 +922,6 @@ def submit_post(v, sub=None):
|
|||
choices.append(i.group(1))
|
||||
body = body.replace(i.group(0), "")
|
||||
|
||||
if v.agendaposter and not v.marseyawarded: body = torture_ap(body, v.username)
|
||||
|
||||
if request.files.get("file2") and request.headers.get("cf-ipcountry") != "T1":
|
||||
files = request.files.getlist('file2')[:4]
|
||||
for file in files:
|
||||
|
@ -995,9 +946,6 @@ def submit_post(v, sub=None):
|
|||
|
||||
body_html = sanitize(body)
|
||||
|
||||
if v.marseyawarded and marseyaward_body_regex.search(body_html):
|
||||
return error("You can only type marseys!")
|
||||
|
||||
if len(body_html) > 40000: return error("Submission body_html too long! (max 40k characters)")
|
||||
|
||||
club = bool(request.values.get("club",""))
|
||||
|
@ -1006,11 +954,6 @@ def submit_post(v, sub=None):
|
|||
|
||||
is_bot = bool(request.headers.get("Authorization"))
|
||||
|
||||
if request.values.get("ghost") and v.coins >= 100:
|
||||
v.coins -= 100
|
||||
ghost = True
|
||||
else: ghost = False
|
||||
|
||||
post = Submission(
|
||||
private=bool(request.values.get("private","")),
|
||||
club=club,
|
||||
|
@ -1025,7 +968,7 @@ def submit_post(v, sub=None):
|
|||
title=title[:500],
|
||||
title_html=title_html,
|
||||
sub=sub,
|
||||
ghost=ghost,
|
||||
ghost=False,
|
||||
filter_state='filtered' if v.admin_level == 0 else 'normal'
|
||||
)
|
||||
|
||||
|
@ -1105,9 +1048,6 @@ def submit_post(v, sub=None):
|
|||
if not post.thumburl and post.url:
|
||||
gevent.spawn(thumbnail_thread, post.id)
|
||||
|
||||
|
||||
|
||||
|
||||
if not post.private and not post.ghost:
|
||||
|
||||
notify_users = NOTIFY_USERS(f'{title} {body}', v)
|
||||
|
@ -1127,40 +1067,6 @@ def submit_post(v, sub=None):
|
|||
if post.club and not user.paid_dues: continue
|
||||
add_notif(cid, user.id)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in f'{post.body}{post.title}'.lower():
|
||||
post.is_banned = True
|
||||
post.ban_reason = "AutoJanny"
|
||||
|
||||
body = AGENDAPOSTER_MSG.format(username=v.username, type='post', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE)
|
||||
|
||||
body_jannied_html = sanitize(body)
|
||||
|
||||
|
||||
|
||||
c_jannied = Comment(author_id=NOTIFICATIONS_ID,
|
||||
parent_submission=post.id,
|
||||
level=1,
|
||||
over_18=False,
|
||||
is_bot=True,
|
||||
app_id=None,
|
||||
is_pinned='AutoJanny',
|
||||
distinguish_level=6,
|
||||
body_html=body_jannied_html,
|
||||
)
|
||||
|
||||
g.db.add(c_jannied)
|
||||
g.db.flush()
|
||||
|
||||
c_jannied.top_comment_id = c_jannied.id
|
||||
|
||||
n = Notification(comment_id=c_jannied.id, user_id=v.id)
|
||||
g.db.add(n)
|
||||
|
||||
|
||||
v.post_count = g.db.query(Submission.id).filter_by(author_id=v.id, is_banned=False, deleted_utc=0).count()
|
||||
g.db.add(v)
|
||||
|
||||
|
|
|
@ -611,8 +611,6 @@ def settings_css_get(v):
|
|||
@limiter.limit("1/second;30/minute;200/hour;1000/day")
|
||||
@auth_required
|
||||
def settings_css(v):
|
||||
if v.agendaposter: return {"error": "Agendapostered users can't edit css!"}
|
||||
|
||||
css = request.values.get("css").strip().replace('\\', '').strip()[:4000]
|
||||
v.css = css
|
||||
g.db.add(v)
|
||||
|
|
|
@ -252,12 +252,6 @@ def grassed(v):
|
|||
|
||||
return render_template("grassed.html", v=v, users=users)
|
||||
|
||||
@app.get("/agendaposters")
|
||||
@auth_required
|
||||
def agendaposters(v):
|
||||
users = [x for x in g.db.query(User).filter(User.agendaposter > 0).order_by(User.username).all()]
|
||||
return render_template("agendaposters.html", v=v, users=users)
|
||||
|
||||
|
||||
@app.get("/@<username>/upvoters")
|
||||
@auth_required
|
||||
|
@ -581,8 +575,6 @@ def message2(v, username):
|
|||
|
||||
if not message: return {"error": "Message is empty!"}
|
||||
|
||||
if 'linkedin.com' in message: return {"error": "This domain 'linkedin.com' is banned."}, 403
|
||||
|
||||
body_html = sanitize(message)
|
||||
|
||||
existing = g.db.query(Comment.id).filter(Comment.author_id == v.id,
|
||||
|
@ -639,8 +631,6 @@ def messagereply(v):
|
|||
|
||||
if not message and not request.files.get("file"): return {"error": "Message is empty!"}
|
||||
|
||||
if 'linkedin.com' in message: return {"error": "this domain 'linkedin.com' is banned"}
|
||||
|
||||
id = int(request.values.get("parent_id"))
|
||||
parent = get_comment(id, v=v)
|
||||
user_id = parent.author.id
|
||||
|
|
|
@ -94,7 +94,9 @@ def api_vote_post(post_id, new, v):
|
|||
post.author.truecoins += coin_delta
|
||||
g.db.add(post.author)
|
||||
|
||||
if new == 1 and (v.agendaposter or v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url.startswith('/e/') and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False
|
||||
DEFAULT_IMAGE = '/assets/images/default-profile-pic.webp'
|
||||
|
||||
if new == 1 and (v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url == DEFAULT_IMAGE and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False
|
||||
else: real = True
|
||||
|
||||
vote = Vote(user_id=v.id,
|
||||
|
@ -162,7 +164,9 @@ def api_vote_comment(comment_id, new, v):
|
|||
comment.author.truecoins += coin_delta
|
||||
g.db.add(comment.author)
|
||||
|
||||
if new == 1 and (v.agendaposter or v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url.startswith('/e/') and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False
|
||||
DEFAULT_IMAGE = '/assets/images/default-profile-pic.webp'
|
||||
|
||||
if new == 1 and (v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url == DEFAULT_IMAGE and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False
|
||||
else: real = True
|
||||
|
||||
vote = CommentVote(user_id=v.id,
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
<li><a href="/admin/users">Users Feed</a></li>
|
||||
<li><a href="/admin/shadowbanned">Shadowbanned Users</a></li>
|
||||
<li><a href="/banned">Permabanned Users</a></li>
|
||||
<li><a href="/agendaposters">Users with Chud Theme</a></li>
|
||||
<li><a href="/grassed">Currently Grassed Users</a></li>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -17,25 +17,7 @@
|
|||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=250">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
cursor:url('/assets/images/dildo.webp?v=1008'), auto;
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::before {
|
||||
content: "((("
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::after {
|
||||
content: ")))"
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary {
|
||||
font-size: 0 !important
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary i {
|
||||
font-size: 11px !important
|
||||
}
|
||||
</style>
|
||||
{% elif v.css %}
|
||||
{% if v.css %}
|
||||
<link rel="stylesheet" href="/@{{v.username}}/css">
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
|
|
@ -170,7 +170,6 @@
|
|||
<span id="typing-indicator"></span>
|
||||
<span id="loading-indicator" class="d-none"></span>
|
||||
</div>
|
||||
<i class="btn btn-secondary mr-2 fas fa-smile-beam" style="padding-top:0.65rem" onclick="loadEmojis('input-text')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-placement="bottom" title="Add Emoji"></i>
|
||||
<textarea id="input-text" minlength="1" maxlength="1000" type="text" class="form-control" placeholder="Message" autocomplete="off" autofocus rows="1"></textarea>
|
||||
<button id="chatsend" onclick="send()" class="btn btn-primary ml-3" type="submit">Send</button>
|
||||
</div>
|
||||
|
@ -190,9 +189,6 @@
|
|||
|
||||
<script src="/chat.js?v=16"></script>
|
||||
|
||||
{% include "emoji_modal.html" %}
|
||||
{% include "expanded_image_modal.html" %}
|
||||
|
||||
<script src="/assets/js/lozad.js?v=242"></script>
|
||||
<script src="/assets/js/lite-youtube.js?v=240"></script>
|
||||
|
||||
|
|
|
@ -287,7 +287,7 @@
|
|||
</style>
|
||||
{% endif %}
|
||||
|
||||
<div id="comment-text-{{c.id}}" class="comment-text mb-0 {% if c.author.agendaposter %}agendaposter{% endif %}">
|
||||
<div id="comment-text-{{c.id}}" class="comment-text mb-0">
|
||||
{{c.realbody(v) | safe}}
|
||||
</div>
|
||||
{% if c.parent_submission %}
|
||||
|
@ -310,8 +310,6 @@
|
|||
|
||||
<small class="btn btn-secondary format m-0" aria-hidden="true" onclick="commentForm('comment-edit-body-{{c.id}}');getGif()" 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" aria-hidden="true" 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>
|
||||
|
||||
|
||||
<label class="btn btn-secondary format m-0" for="file-edit-reply-{{c.id}}">
|
||||
<div id="filename-edit-reply-{{c.id}}"><i class="far fa-image"></i></div>
|
||||
|
@ -557,11 +555,7 @@
|
|||
<label class="btn btn-secondary format m-0" for="gif-reply-btn-{{c.fullname}}" onclick="commentForm('reply-form-body-{{c.fullname}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">
|
||||
<span id="gif-reply-btn-{{c.fullname}}" class="font-weight-bolder text-uppercase">GIF</span>
|
||||
</label>
|
||||
|
||||
<label class="btn btn-secondary format m-0" for="gif-reply-btn-{{c.fullname}}" onclick="loadEmojis('reply-form-body-{{c.fullname}}')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji">
|
||||
<i id="emoji-reply-btn-{{c.fullname}}" class="fas fa-smile-beam"></i>
|
||||
</label>
|
||||
|
||||
|
||||
<label class="btn btn-secondary format m-0" for="file-upload-reply-{{c.fullname}}">
|
||||
<div id="filename-show-reply-{{c.fullname}}"><i class="far fa-image"></i></div>
|
||||
<input autocomplete="off" id="file-upload-reply-{{c.fullname}}" type="file" multiple="multiple" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show-reply-{{c.fullname}}','file-upload-reply-{{c.fullname}}')" hidden>
|
||||
|
@ -598,9 +592,6 @@
|
|||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<textarea required autocomplete="off" minlength="1" maxlength="10000" name="body" form="reply-to-t3_{{c.id}}" data-id="{{c.id}}" class="comment-box form-control rounded" id="reply-form-body-{{c.id}}" aria-label="With textarea" rows="3" oninput="markdown('reply-form-body-{{c.id}}', 'message-reply-{{c.id}}')"></textarea>
|
||||
<div class="comment-format" id="comment-format-bar-{{c.id}}">
|
||||
<label class="btn btn-secondary m-0 mt-3 mr-1" onclick="loadEmojis('reply-form-body-{{c.id}}')" aria-hidden="true" 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>
|
||||
</label>
|
||||
|
||||
{% if c.sentto == 2 %}
|
||||
<label class="btn btn-secondary m-0 mt-3" for="file-upload">
|
||||
|
@ -773,7 +764,6 @@
|
|||
{% if not ajax %}
|
||||
{% if v %}
|
||||
{% include "gif_modal.html" %}
|
||||
{% include "emoji_modal.html" %}
|
||||
{% if v.admin_level > 1 %}
|
||||
{% include "ban_modal.html" %}
|
||||
{% endif %}
|
||||
|
@ -844,7 +834,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% if v %}
|
||||
<script src="/assets/js/marked.js?v=251"></script>
|
||||
<script src="/assets/js/vendor/marked.js?v=251"></script>
|
||||
<script src="/assets/js/marked.custom.js?v=251"></script>
|
||||
<script src="/assets/js/comments_v.js?v=266"></script>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -31,9 +31,6 @@
|
|||
<label for="input-message" class="mt-3">Your message</label>
|
||||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<textarea autocomplete="off" maxlength="10000" id="input-message" form="contactform" name="message" class="form-control" required></textarea>
|
||||
<label class="btn btn-secondary format m-0 mt-3" onclick="loadEmojis('input-message')" aria-hidden="true" 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>
|
||||
</label>
|
||||
<label class="btn btn-secondary m-0 mt-3" for="file-upload">
|
||||
<div id="filename"><i class="far fa-image"></i></div>
|
||||
<input autocomplete="off" id="file-upload" type="file" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename','file-upload')" hidden>
|
||||
|
@ -52,7 +49,4 @@
|
|||
|
||||
|
||||
</pre>
|
||||
|
||||
{% include "emoji_modal.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -10,25 +10,7 @@
|
|||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=250">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
cursor:url('/assets/images/dildo.webp?v=1008'), auto;
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::before {
|
||||
content: "((("
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::after {
|
||||
content: ")))"
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary {
|
||||
font-size: 0 !important
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary i {
|
||||
font-size: 11px !important
|
||||
}
|
||||
</style>
|
||||
{% elif v.css %}
|
||||
{% if v.css %}
|
||||
<link rel="stylesheet" href="/@{{v.username}}/css">
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<div id="form" class="d-none"></div>
|
||||
<div class="modal fade" id="emojiModal" tabindex="-1" role="dialog" aria-labelledby="emojiModalTitle" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-dialog-centered p-2 py-5 emoji-modal" role="document">
|
||||
<div class="modal-content" id="emojiTabs">
|
||||
<div class="modal-header">
|
||||
<div>
|
||||
<ul class="nav nav-pills py-2">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active emojitab" data-bs-toggle="tab" href="#emoji-tab-favorite">Favorite</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-marsey">Marsey</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-marseyalphabet">Marsey Alphabet</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-platy">Platy</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-wolf">Zombie Wolf</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-tay">Tay</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-classic">Classic</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-rage">Rage</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-wojak">Wojak</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-flags">Flags</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link emojitab" data-bs-toggle="tab" href="#emoji-tab-misc">Misc</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<i class="fal fa-times text-muted"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="px-3"><input autocomplete="off" class="form-control px-2" type="text" id="emoji_search" placeholder="Search.."></div>
|
||||
|
||||
<div style="overflow-y: scroll;">
|
||||
<div class="modal-body p-0" id="emoji-modal-body">
|
||||
<div id="emoji-tab-search"></div>
|
||||
<div id="no-emojis-found"></div>
|
||||
<div id="tab-content" class="tab-content">
|
||||
<div class="tab-pane fade show active" id="emoji-tab-favorite">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_favorite"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-marsey">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_marsey"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-marseyalphabet">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_marseyalphabet"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-platy">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_platy"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-wolf">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_wolf"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-tay">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_tay"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-classic">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_classic"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-rage">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_rage"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-wojak">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_wojak"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-flags">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_flags"></div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="emoji-tab-misc">
|
||||
<div class="d-flex flex-wrap py-3 pl-2" id="EMOJIS_misc"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/assets/js/emoji_modal.js?v=271"></script>
|
|
@ -9,11 +9,11 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseybrainlet:" loading="lazy" src="/e/marseybrainlet.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">400 Bad Request</h1>
|
||||
<p class="text-muted mb-5">That request was bad and you should feel bad.</p>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>400</h1>
|
||||
<h5>Bad Request</h5>
|
||||
<p class="text-muted mb-5">That request was bad and you should feel bad</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,12 +9,9 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
|
||||
<img alt=":#marseydead:" loading="lazy" src="/e/marseydead.webp">
|
||||
<pre></pre>
|
||||
|
||||
<h1 class="h5">401 Not Authorized</h1>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>401</h1>
|
||||
<h5>Not Authorized</h5>
|
||||
<p class="text-muted mb-5">You need an account for this. Please make one!</p>
|
||||
<div><a href="/signup" class="btn btn-primary mb-2">Create an account</a></div>
|
||||
<div><a href="/login" class="text-muted text-small">Or sign in</a></div>
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseytroll:" loading="lazy" src="/e/marseytroll.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">403 Forbidden</h1>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>403</h1>
|
||||
<h5>Forbidden</h5>
|
||||
<p class="text-muted mb-5">{{description}}</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
</div>
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseyconfused" loading="lazy" src="/e/marseyconfused.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">404 Page Not Found</h1>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>404</h1>
|
||||
<h5>Page Not Found</h5>
|
||||
<p class="text-muted mb-5">That page doesn't exist. If you got here from a link on the website, please report this issue. Thanks!</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
</div>
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseyretard:" loading="lazy" src="/e/marseyretard.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">405 Method Not Allowed</h1>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>405</h1>
|
||||
<h5>Method Not Allowed</h5>
|
||||
<p class="text-muted mb-5">Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
</div>
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseyretard:" loading="lazy" src="/e/marseyretard.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">Max file size is 8 MB.</h1>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>413</h1>
|
||||
<h5>Payload Too Large</h5>
|
||||
<p class="text-muted mb-5">Max file size is 8 MB</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseyrentfree:" loading="lazy" src="/e/marseyrentfree.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">429 Too Many Requests</h1>
|
||||
<div class="text-center px-3 my-8">
|
||||
<h1>429</h1>
|
||||
<h5>Too Many Requests</h5>
|
||||
<p class="text-muted mb-5">Are you hammering the site? Stop that, yo.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,12 +10,10 @@
|
|||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseydead:" loading="lazy" src="/e/marseydead.webp">
|
||||
<pre></pre>
|
||||
<h1 class="h5">500 Internal Server Error</h1>
|
||||
<p class="text-muted mb-5">Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!<3</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to the frontpage</a></div>
|
||||
|
||||
<h1>500</h1>
|
||||
<h5>Internal Server Error</h5>
|
||||
<p class="text-muted mb-5">Something went wrong and it's probably my fault. If you can do it reliably, or it's causing problems for you, please report it!</p>
|
||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,11 +10,10 @@
|
|||
<div class="row justify-content-center">
|
||||
<div class="col col-md-5">
|
||||
<div class="text-center px-3 mt-5">
|
||||
<img alt=":#marseytwerking:" loading="lazy" src="/e/marseytwerking.webp">
|
||||
<h1 class="h5">Are you over 18?</h1>
|
||||
<h1>NSFW</h1>
|
||||
<h5>Are you over 18?</h5>
|
||||
<p class="mb-5">This post is rated +18 (Adult-Only). You must be 18 or older to continue. Are you sure you want to proceed?</p>
|
||||
<div class="btn-toolbar justify-content-center mb-4">
|
||||
|
||||
<form action="/allow_nsfw" method="post">
|
||||
<input type="hidden" name="redir" value="{{request.path}}">
|
||||
<input type="submit" class="btn btn-danger mr-2" value="Yes, I am +18">
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
{% block pagetype %}error-401{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseymerchant:" loading="lazy" class="mb-2" src="/e/marseymerchant.webp">
|
||||
<h1 class="h5">401 Not Authorized</h1>
|
||||
<p class="text-muted">This page is only available to patrons:</p>
|
||||
<a rel="nofollow noopener noreferrer" href="{{config('GUMROAD_LINK')}}">{{config('GUMROAD_LINK')}}</a>
|
||||
</div>
|
||||
<h1>401</h1>
|
||||
<h5>Not Authorized</h5>
|
||||
<p class="text-muted">This page is only available to patrons:</p>
|
||||
<a rel="nofollow noopener noreferrer" href="{{config('GUMROAD_LINK')}}">{{config('GUMROAD_LINK')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -81,37 +81,6 @@ Text 2
|
|||
<td>https://files.catbox.moe/v4om92.mp4</td>
|
||||
<td><video controls preload="none" class="vid"><source referrerpolicy="no-referrer" src="https://files.catbox.moe/v4om92.mp4" type="video/mp4"></video></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Emojis</td>
|
||||
<td>:marseylove:</td>
|
||||
<td><img loading="lazy" data-bs-toggle="tooltip" class="emoji" alt=":marseylove:" title=":marseylove:" height="30" src="/e/marseylove.webp"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mirrored Emojis</td>
|
||||
<td>:!marseylove:</td>
|
||||
<td><img loading="lazy" data-bs-toggle="tooltip" class="emoji mirrored" alt=":!marseylove:" title=":!marseylove:" height="30" src="/e/marseylove.webp"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Large Emojis</td>
|
||||
<td>:#marseylove:</td>
|
||||
<td><img loading="lazy" data-bs-toggle="tooltip" b alt=":marseylove:" title=":marseylove:" src="/e/marseylove.webp"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Large Mirrored Emojis</td>
|
||||
<td>:#!marseylove:</td>
|
||||
<td><img loading="lazy" data-bs-toggle="tooltip" b alt=":!marseylove:" title=":!marseylove:" src="/e/marseylove.webp"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Random Marsey</td>
|
||||
<td>:marseyrandom:</td>
|
||||
<td>???</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Random Fortune</td>
|
||||
<td>#fortune</td>
|
||||
<td>???</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Poll Options (can select multiple options)</td>
|
||||
<td>$$bussy$$ $$gussy$$</td>
|
||||
|
|
|
@ -8,25 +8,7 @@
|
|||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=250">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
cursor:url('/assets/images/dildo.webp?v=1008'), auto;
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::before {
|
||||
content: "((("
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::after {
|
||||
content: ")))"
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary {
|
||||
font-size: 0 !important
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary i {
|
||||
font-size: 11px !important
|
||||
}
|
||||
</style>
|
||||
{% elif v.css %}
|
||||
{% if v.css %}
|
||||
<link rel="stylesheet" href="/@{{v.username}}/css">
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
@ -58,10 +40,10 @@
|
|||
<div class="dropdown dropdown-actions">
|
||||
|
||||
<button class="btn btn-secondary dropdown-toggle" role="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{% if admin %}<img src="/@{{admin}}/pic" alt="avatar" width=20 height=20 class="rounded-circle mr-2">{{admin}}{% else %}<img src="/e/marseyjanny.webp" alt="avatar" width=20 height=20 class="rounded-circle mr-2">All{% endif %}
|
||||
{% if admin %}<img src="/@{{admin}}/pic" alt="avatar" width=20 height=20 class="rounded-circle mr-2">{{admin}}{% else %}<img src="/assets/images/default-profile-pic.webp" alt="avatar" width=20 height=20 class="rounded-circle mr-2">All{% endif %}
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 31px, 0px);">
|
||||
<a class="dropdown-item" href="/log{% if type %}?kind={{type}}{% endif %}"><img src="/e/marseyjanny.webp" alt="avatar" width=20 height=20 class="rounded-circle mr-2">All</a>
|
||||
<a class="dropdown-item" href="/log{% if type %}?kind={{type}}{% endif %}"><img src="/assets/images/default-profile-pic.webp" alt="avatar" width=20 height=20 class="rounded-circle mr-2">All</a>
|
||||
{% for a in admins %}
|
||||
<a class="dropdown-item" href="?admin={{a}}{% if type %}&kind={{type}}{% endif %}"><img loading="lazy" src="/@{{a}}/pic" alt="avatar" width=20 height=20 class="rounded-circle mr-2">{{a}}</a>
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
{% extends "default.html" %}
|
||||
{% block content %}
|
||||
<pre>
|
||||
|
||||
|
||||
</pre>
|
||||
<div class="overflow-x-auto"><table class="table table-striped mb-5">
|
||||
<thead class="bg-primary text-white">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Name</th>
|
||||
<th>Marsey</th>
|
||||
<th><a href="?sort=usage">Usage</a></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="followers-table">
|
||||
{% for marsey in marseys %}
|
||||
<tr>
|
||||
<td>{{loop.index}}</td>
|
||||
<td>{{marsey.name}}</td>
|
||||
<td><img class="marsey" loading="lazy" data-bs-toggle="tooltip" alt=":{{marsey.name}}:" title=":{{marsey.name}}:" src="/e/{{marsey.name}}.webp"></td>
|
||||
<td>{{marsey.count}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -36,25 +36,7 @@
|
|||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=250">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=56">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
cursor:url('/assets/images/dildo.webp?v=1008'), auto;
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::before {
|
||||
content: "((("
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::after {
|
||||
content: ")))"
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary {
|
||||
font-size: 0 !important
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary i {
|
||||
font-size: 11px !important
|
||||
}
|
||||
</style>
|
||||
{% elif v.css and not request.path.startswith('/settings/css') %}
|
||||
{% if v.css and not request.path.startswith('/settings/css') %}
|
||||
<link rel="stylesheet" href="/@{{v.username}}/css">
|
||||
{% endif %}
|
||||
</head>
|
||||
|
|
|
@ -362,8 +362,6 @@
|
|||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<input maxlength=100 {% if v.flairchanged %}disabled{% endif %} autocomplete="off" id="customtitlebody" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if v.flairchanged %}Your flair has been locked until {{ti}}{% elif v.customtitleplain %}{{v.customtitleplain}}{% endif %}">
|
||||
<div class="d-flex mt-2">
|
||||
<a class="format" role="button"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('customtitlebody')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
|
||||
|
||||
<small>Limit of 100 characters</small>
|
||||
<input {% if v.flairchanged %}disabled{% endif %} autocomplete="off" class="btn btn-primary ml-auto" id="titleSave" type="submit" value="Change Flair">
|
||||
</div>
|
||||
|
@ -476,8 +474,6 @@
|
|||
|
||||
<pre style="padding-top:0.7rem;line-height:1" class="btn btn-secondary format d-inline-block m-0 font-weight-bolder text-uppercase" onclick="commentForm('bio-text');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</pre>
|
||||
|
||||
<pre style="padding-top:0.7rem" class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('bio-text')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></pre>
|
||||
|
||||
<label class="btn btn-secondary format d-inline-block m-0">
|
||||
<div id="filename-show"><i class="far fa-image"></i></div>
|
||||
<input autocomplete="off" id="file-upload" type="file" name="file" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} accept="image/*, video/*" onchange="changename('filename-show','file-upload')" hidden>
|
||||
|
@ -554,8 +550,6 @@
|
|||
<pre style="padding-top:0.7rem" class="btn btn-secondary format d-inline-block m-0 fas fa-quote-right" aria-hidden="true" onclick="makeQuote('sig-text')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"></pre>
|
||||
|
||||
<pre style="padding-top:0.7rem;line-height:1" class="btn btn-secondary format d-inline-block m-0 font-weight-bolder text-uppercase" onclick="commentForm('sig-text');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</pre>
|
||||
|
||||
<pre style="padding-top:0.7rem" class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('sig-text')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></pre>
|
||||
</div>
|
||||
<pre></pre>
|
||||
<div class="d-flex">
|
||||
|
@ -620,7 +614,6 @@
|
|||
|
||||
<script src="/assets/js/settings_profile.js?v=251"></script>
|
||||
|
||||
{% include "emoji_modal.html" %}
|
||||
{% include "gif_modal.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -30,292 +30,6 @@
|
|||
</script>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if p.award_count("crab") %}
|
||||
<script>
|
||||
let audio = new Audio('/assets/crab.mp3');
|
||||
audio.loop=true;
|
||||
|
||||
audio.play();
|
||||
window.addEventListener('click', () => {
|
||||
if (audio.paused) audio.play();
|
||||
}, {once : true});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if fart and not (v and v.has_badge(128)) %}
|
||||
<script>
|
||||
fart = Math.floor(Math.random() * 4) + 1
|
||||
let audio = new Audio(`/assets/images/${fart}.webp`);
|
||||
|
||||
audio.play();
|
||||
if (audio.paused) {
|
||||
window.addEventListener('click', () => {
|
||||
if (audio.paused) audio.play();
|
||||
}, {once : true})
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if g.inferior_browser %}
|
||||
{% if p.award_count("wholesome") %}
|
||||
<style>
|
||||
.sealimg {
|
||||
width: 100px;
|
||||
height: 89.5px;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.sealimg {
|
||||
width: 30px;
|
||||
height: 27px;
|
||||
}
|
||||
}
|
||||
|
||||
.seal {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
@keyframes moveX {
|
||||
from { left: 0; } to { left: 98%; }
|
||||
}
|
||||
|
||||
@keyframes moveY {
|
||||
from { top: 0; } to { top: 98%; }
|
||||
}
|
||||
|
||||
.seal1 {
|
||||
animation: moveX 4s linear 0s infinite alternate, moveY 6.8s linear 0s infinite alternate !important;
|
||||
animation-delay:0s;
|
||||
}
|
||||
</style>
|
||||
<div class="seal seal1" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</div>
|
||||
|
||||
{% if p.award_count("wholesome") > 1 %}
|
||||
<style>
|
||||
.seal2 {
|
||||
animation: moveX 5s linear 0s infinite alternate, moveY 8s linear 0s infinite alternate !important;
|
||||
animation-delay:1s;
|
||||
}
|
||||
</style>
|
||||
<div class="seal seal2" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("wholesome") > 2 %}
|
||||
<style>
|
||||
.seal3 {
|
||||
animation: moveX 4s linear 0s infinite alternate, moveY 5s linear 0s infinite alternate !important;
|
||||
animation-delay:2s;
|
||||
}
|
||||
</style>
|
||||
<div class="seal seal3" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("wholesome") > 3 %}
|
||||
<style>
|
||||
.seal4 {
|
||||
animation: moveX 5s linear 0s infinite alternate, moveY 6.8s linear 0s infinite alternate !important;
|
||||
animation-delay:3s;
|
||||
}
|
||||
</style>
|
||||
<div class="seal seal4" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if p.award_count("wholesome") %}
|
||||
<style>
|
||||
.seal {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
.sealimg {
|
||||
width: 100px;
|
||||
height: 89.5px;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.sealimg {
|
||||
width: 30px;
|
||||
height: 27px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="seal" height="100%" width="100%">
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="up" height="100%" width="100%">
|
||||
<marquee direction="right" scrollamount=10 behavior="alternate" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</marquee>
|
||||
</marquee>
|
||||
</div>
|
||||
|
||||
{% if p.award_count("wholesome") > 1 %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="down" height="100%">
|
||||
<marquee direction="right" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("wholesome") > 2 %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="up" height="100%">
|
||||
<marquee direction="left" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("wholesome") > 3 %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="down" height="100%">
|
||||
<marquee direction="left" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="/e/marseywholesome.webp">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% if p.award_count("train") or p.award_count("scooter") %}
|
||||
<style>
|
||||
.train {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
}
|
||||
.train1 {
|
||||
top: 10%
|
||||
}
|
||||
.train2 {
|
||||
top: 35%
|
||||
}
|
||||
.train3 {
|
||||
top: 60%
|
||||
}
|
||||
.train4 {
|
||||
top: 85%
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("train") %}
|
||||
<style>
|
||||
.trainimg {
|
||||
width: 100px;
|
||||
height: 51px;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.trainimg {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<marquee class="train train1" direction="left" scrollamount=10 width="100%">
|
||||
<img alt=":#marseytrain:" class="trainimg mirrored" src="/e/marseytrain.webp">
|
||||
</marquee>
|
||||
|
||||
{% if p.award_count("train") > 1 %}
|
||||
<marquee class="train train2" direction="right" scrollamount=10 width="100%">
|
||||
<img alt=":#marseytrain:" class="trainimg" src="/e/marseytrain.webp">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("train") > 2 %}
|
||||
<marquee class="train train3" direction="left" scrollamount=10 width="100%">
|
||||
<img alt=":#marseytrain:" class="trainimg mirrored" src="/e/marseytrain.webp">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("train") > 3 %}
|
||||
<marquee class="train train4" direction="right" scrollamount=10 width="100%">
|
||||
<img alt=":#marseytrain:" class="trainimg" src="/e/marseytrain.webp">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if p.award_count("scooter") %}
|
||||
<style>
|
||||
.scooterimg {
|
||||
width: 100px;
|
||||
height: 135px;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.scooterimg {
|
||||
width: 40px;
|
||||
height: 54px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<marquee class="train train3" direction="right" scrollamount=10 width="100%">
|
||||
<img alt=":#marseyscooter:" class="scooterimg" src="/e/marseyscooter.webp">
|
||||
</marquee>
|
||||
|
||||
{% if p.award_count("scooter") > 1 %}
|
||||
<marquee class="train train4" direction="left" scrollamount=10 width="100%">
|
||||
<img alt=":#marseyscooter:" class="scooterimg mirrored" src="/e/marseyscooter.webp">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("scooter") > 2 %}
|
||||
<marquee class="train train1" direction="right" scrollamount=10 width="100%">
|
||||
<img alt=":#marseyscooter:" class="scooterimg" src="/e/marseyscooter.webp">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("scooter") > 3 %}
|
||||
<marquee class="train train2" direction="left" scrollamount=10 width="100%">
|
||||
<img alt=":#marseyscooter:" class="scooterimg mirrored" src="/e/marseyscooter.webp">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
{% if p.award_count("tilt") %}
|
||||
<style>
|
||||
@keyframes post-tilt {
|
||||
0% {transform: rotate(0deg);}
|
||||
25% {transform: rotate({{p.award_count("tilt")}}deg);}
|
||||
75% {transform: rotate(-{{p.award_count("tilt")}}deg);}
|
||||
100% {transform: rotate(0deg);}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
@keyframes post-tilt {
|
||||
0% {transform: rotate(0deg);}
|
||||
25% {transform: rotate({{p.award_count("tilt")/4}}deg);}
|
||||
75% {transform: rotate(-{{p.award_count("tilt")/4}}deg);}
|
||||
100% {transform: rotate(0deg);}
|
||||
}
|
||||
}
|
||||
#post-root {
|
||||
animation-name: post-tilt !important;
|
||||
animation-duration: 60s !important;
|
||||
animation-iteration-count: infinite !important;
|
||||
animation-direction: alternate !important;
|
||||
animation-timing-function: linear !important;
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta property="og:type" content="article">
|
||||
|
||||
|
@ -495,13 +209,13 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
{% if p.realurl(v) %}
|
||||
<h1 id="post-title" class="card-title post-title text-left mb-md-3 {% if p.author.agendaposter %}agendaposter{% endif %}"><a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}">
|
||||
<h1 id="post-title" class="card-title post-title text-left mb-md-3"><a {% if not v or v.newtabexternal %}target="_blank"{% endif %} rel="nofollow noopener noreferrer" href="{{p.realurl(v)}}">
|
||||
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
|
||||
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
|
||||
{{p.realtitle(v) | safe}}
|
||||
</a></h1>
|
||||
{% else %}
|
||||
<h1 id="post-title" class="card-title post-title text-left mb-md-3 {% if p.author.agendaposter %}agendaposter{% endif %}">
|
||||
<h1 id="post-title" class="card-title post-title text-left mb-md-3">
|
||||
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
|
||||
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
|
||||
{{p.realtitle(v) | safe}}
|
||||
|
@ -535,7 +249,7 @@
|
|||
{% endif %}
|
||||
|
||||
|
||||
<div id="post-text" {% if p.author.agendaposter %}class="agendaposter"{% endif %}>
|
||||
<div id="post-text">
|
||||
{% if p.is_image %}
|
||||
<div class="row no-gutters">
|
||||
<div class="col">
|
||||
|
@ -580,8 +294,6 @@
|
|||
<a class="format btn btn-secondary" role="button"><i class="fas fa-italic" aria-hidden="true" onclick="makeItalics('post-edit-box-{{p.id}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Italicize"></i></a>
|
||||
<a class="format btn btn-secondary" role="button"><i class="fas fa-quote-right" aria-hidden="true" onclick="makeQuote('post-edit-box-{{p.id}}')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"></i></a>
|
||||
<a class="format btn btn-secondary" role="button"><span class="font-weight-bolder text-uppercase" onclick="commentForm('post-edit-box-{{p.id}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></a>
|
||||
<a class="format btn btn-secondary" role="button"><i class="fas fa-smile-beam" onclick="loadEmojis('post-edit-box-{{p.id}}')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
|
||||
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-edit-{{p.id}}">
|
||||
<div id="filename-show-edit-{{p.id}}"><i class="far fa-image"></i></div>
|
||||
<input autocomplete="off" id="file-upload-edit-{{p.id}}" type="file" multiple="multiple" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show-edit-{{p.id}}','file-upload-edit-{{p.id}}')" hidden>
|
||||
|
@ -777,10 +489,6 @@
|
|||
<label class="btn btn-secondary format d-inline-block m-0" for="gif-reply-btn-{{p.fullname}}">
|
||||
<span id="gif-reply-btn-{{p.fullname}}" class="font-weight-bolder text-uppercase" onclick="commentForm('reply-form-body-{{p.fullname}}');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span>
|
||||
</label>
|
||||
|
||||
<label class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn-{{p.fullname}}">
|
||||
<div id="emoji-reply-btn-{{p.fullname}}" onclick="loadEmojis('reply-form-body-{{p.fullname}}')" aria-hidden="true" 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></div>
|
||||
</label>
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-reply-{{p.fullname}}">
|
||||
<div id="filename-show-reply-{{p.fullname}}"><i class="far fa-image"></i></div>
|
||||
<input autocomplete="off" id="file-upload-reply-{{p.fullname}}" type="file" multiple="multiple" name="file" accept="image/*, video/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show-reply-{{p.fullname}}','file-upload-reply-{{p.fullname}}')" hidden>
|
||||
|
|
|
@ -114,9 +114,7 @@
|
|||
<div class="card-header bg-transparent border-0 d-flex flex-row flex-nowrap pl-2 pl-md-0 p-0 mr-md-2">
|
||||
|
||||
<div style="z-index: 3;">
|
||||
{% if p.club and not (v and (v.paid_dues or v.id == p.author_id)) %}
|
||||
<img alt="post thumnail" loading="lazy" src="/e/marseyglow.webp" class="post-img">
|
||||
{% elif not p.url %}
|
||||
{% if not p.url %}
|
||||
<a {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}">
|
||||
<img alt="post thumnail" loading="lazy" src="{{p.thumb_url}}" class="post-img">
|
||||
</a>
|
||||
|
@ -207,7 +205,7 @@
|
|||
</div>
|
||||
|
||||
<h5 class="card-title post-title text-left w-lg-95 mb-0 pb-0 pb-md-1">
|
||||
<a id="{{p.id}}-title" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}" class="{% if voted and v.id == AEVANN_ID %}visited{% endif %} stretched-link {% if p.author.agendaposter %}agendaposter{% endif %}">
|
||||
<a id="{{p.id}}-title" {% if v and v.newtab and not g.webview %}target="_blank"{% endif %} href="{{p.permalink}}" class="{% if voted and v.id == AEVANN_ID %}visited{% endif %} stretched-link">
|
||||
{% if p.club %}<span class="patron font-weight-bolder mr-1" style="background-color:red; font-size:12px; line-height:2;">{{CC}}</span>{% endif %}
|
||||
{% if p.flair %}<span class="patron font-weight-bolder mr-1" style="background-color:var(--primary); font-size:12px; line-height:2;">{{p.flair | safe}}</span>{% endif %}
|
||||
{{p.realtitle(v) | safe}}
|
||||
|
@ -345,7 +343,7 @@
|
|||
|
||||
{% if not p.club or v and (v.paid_dues or v.id == p.author_id) %}
|
||||
{% if p.realbody(v) %}
|
||||
<div class="d-none card rounded border pt-3 pb-2 my-2 {% if p.author.agendaposter %}agendaposter{% endif %}" id="post-text-{{p.id}}">
|
||||
<div class="d-none card rounded border pt-3 pb-2 my-2" id="post-text-{{p.id}}">
|
||||
{{p.realbody(v) | safe}}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -24,25 +24,7 @@
|
|||
<style>:root{--primary:#{{v.themecolor}}}</style>
|
||||
<link rel="stylesheet" href="/assets/css/main.css?v=250">
|
||||
<link rel="stylesheet" href="/assets/css/{{v.theme}}.css?v=49">
|
||||
{% if v.agendaposter %}
|
||||
<style>
|
||||
html {
|
||||
cursor:url('/assets/images/dildo.webp?v=1008'), auto;
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::before {
|
||||
content: "((("
|
||||
}
|
||||
.nav-item .text-small.font-weight-bold::after {
|
||||
content: ")))"
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary {
|
||||
font-size: 0 !important
|
||||
}
|
||||
.nav-item .text-small-extra.text-primary i {
|
||||
font-size: 11px !important
|
||||
}
|
||||
</style>
|
||||
{% elif v.css %}
|
||||
{% if v.css %}
|
||||
<link rel="stylesheet" href="/@{{v.username}}/css">
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
@ -79,10 +61,6 @@
|
|||
|
||||
<input autocomplete="off" class="form-control" id="post-title" aria-describedby="titleHelpRegister" type="text" name="title" placeholder="Required" value="{{title}}" minlength="1" maxlength="500" required oninput="checkForRequired();savetext()">
|
||||
|
||||
<label class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn-2">
|
||||
<div id="emoji-reply-btn-2" onclick="loadEmojis('post-title')" aria-hidden="true" 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></div>
|
||||
</label>
|
||||
|
||||
<div id="urlblock">
|
||||
<label for="URL" class="mt-3">URL</label>
|
||||
<input autocomplete="off" class="form-control" id="post-url" aria-describedby="URLHelp" name="url" type="url" placeholder="Optional if you have text." value="{{request.values.get('url','')}}" required oninput="checkForRequired();hide_image();savetext();checkRepost(this);autoSuggestTitle()">
|
||||
|
@ -129,9 +107,6 @@
|
|||
|
||||
<small class="btn btn-secondary format d-inline-block m-0"><span class="font-weight-bolder text-uppercase" aria-hidden="true" onclick="getGif();commentForm('post-text')" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</span></small>
|
||||
|
||||
<label class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn">
|
||||
<div id="emoji-reply-btn" onclick="loadEmojis('post-text')" aria-hidden="true" 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></div>
|
||||
</label>
|
||||
|
||||
<label class="format btn btn-secondary m-0 ml-1 {% if v %}d-inline-block{% else %}d-none{% endif %}" for="file-upload-submit">
|
||||
<div id="filename-show-submit"><i class="far fa-image"></i></div>
|
||||
|
@ -206,10 +181,11 @@
|
|||
</script>
|
||||
{% endif %}
|
||||
|
||||
<script src="/assets/js/marked.js?v=251"></script>
|
||||
<script src="/assets/js/vendor/marked.js?v=251"></script>
|
||||
<script src="/assets/js/marked.custom.js?v=251"></script>
|
||||
<script src="/assets/js/formatting.js?v=240"></script>
|
||||
<script src="/assets/js/submit.js?v=255"></script>
|
||||
{% include "emoji_modal.html" %}
|
||||
|
||||
{% include "gif_modal.html" %}
|
||||
|
||||
</body>
|
||||
|
|
|
@ -189,8 +189,6 @@
|
|||
|
||||
<pre class="btn btn-secondary format d-inline-block m-0 fas fa-quote-right" aria-hidden="true" onclick="makeQuote('input-message')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"></pre>
|
||||
|
||||
<pre class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('input-message')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></pre>
|
||||
|
||||
<input type="submit" value="Submit" class="btn btn-primary">
|
||||
</form>
|
||||
|
||||
|
@ -214,8 +212,6 @@
|
|||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<input maxlength=100 autocomplete="off" id="customtitlebody" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if u.customtitleplain %}{{u.customtitleplain}}{% endif %}">
|
||||
<div class="d-flex mt-2">
|
||||
<a class="format" role="button"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('customtitlebody')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
|
||||
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input autocomplete="off" type="checkbox" class="custom-control-input" id="locked" name="locked" {% if u.flairchanged %}checked{% endif %}>
|
||||
<label class="custom-control-label" for="locked">locked</label>
|
||||
|
@ -248,14 +244,6 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
<pre></pre>
|
||||
|
||||
<form id="agendaposter1" class="{% if u.agendaposter %}d-none{% endif %}" action="/agendaposter/{{u.id}}" method="post">
|
||||
<input type="hidden" name="formkey", value="{{v.formkey}}">
|
||||
<input autocomplete="off" type="number" step="any" name="days" class="form-control" placeholder="Days (0 or blank = permanent)">
|
||||
<input type="submit" class="btn btn-danger" value="Lock Chud Theme">
|
||||
</form>
|
||||
<a id="unagendaposter" class="{% if not u.agendaposter %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast2(this,'/unagendaposter/{{u.id}}','agendaposter1','unagendaposter')">Disable Chud Theme</a>
|
||||
|
||||
<pre></pre>
|
||||
|
||||
<a id="shadowban" class="{% if u.shadowbanned %}d-none{% endif %} btn btn-danger" role="button" onclick="post_toast2(this,'/shadowban/{{u.id}}','shadowban','unshadowban')">Shadowban</a>
|
||||
|
@ -476,8 +464,6 @@
|
|||
|
||||
<pre class="btn btn-secondary format d-inline-block m-0 fas fa-quote-right" aria-hidden="true" onclick="makeQuote('input-message-mobile')" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Quote"></pre>
|
||||
|
||||
<pre class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('input-message-mobile')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></pre>
|
||||
|
||||
<input type="submit" value="Submit" class="btn btn-primary">
|
||||
</form>
|
||||
|
||||
|
@ -497,8 +483,6 @@
|
|||
<input type="hidden" name="formkey" value="{{v.formkey}}">
|
||||
<input maxlength=100 autocomplete="off" id="customtitlebody-mobile" type="text" name="title" class="form-control" placeholder='Enter a flair here' value="{% if u.customtitleplain %}{{u.customtitleplain}}{% endif %}">
|
||||
<div class="d-flex mt-2">
|
||||
<a class="format" role="button"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('customtitlebody-mobile')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></a>
|
||||
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input autocomplete="off" type="checkbox" class="custom-control-input" id="locked-mobile" name="locked" {% if u.flairchanged %}checked{% endif %}>
|
||||
<label class="custom-control-label" for="locked-mobile">locked</label>
|
||||
|
@ -533,14 +517,6 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
<pre></pre>
|
||||
|
||||
<form id="agendaposter2" class="{% if u.agendaposter %}d-none{% endif %}" action="/agendaposter/{{u.id}}" method="post">
|
||||
<input type="hidden" name="formkey", value="{{v.formkey}}">
|
||||
<input autocomplete="off" type="number" step="any" name="days" class="form-control" placeholder="Days (0 or blank = permanent)">
|
||||
<input type="submit" class="btn btn-danger" value="Lock Chud Theme">
|
||||
</form>
|
||||
<a id="unagendaposter2" class="{% if not u.agendaposter %}d-none{% endif %} btn btn-success" role="button" onclick="post_toast2(this,'/unagendaposter/{{u.id}}','agendaposter2','unagendaposter2')">Disable Chud Theme</a>
|
||||
|
||||
<pre></pre>
|
||||
|
||||
<a id="shadowban2" class="{% if u.shadowbanned %}d-none{% endif %} btn btn-danger" role="button" onclick="post_toast2(this,'/shadowban/{{u.id}}','shadowban2','unshadowban2')">Shadowban</a>
|
||||
|
@ -721,12 +697,8 @@
|
|||
</nav>
|
||||
{% endif %}
|
||||
|
||||
<script src="/assets/js/marked.js?v=251"></script>
|
||||
|
||||
|
||||
{% if v and v.id != u.id and '/comments' not in request.path %}
|
||||
{% include "emoji_modal.html" %}
|
||||
{% endif %}
|
||||
<script src="/assets/js/vendor/marked.js?v=251"></script>
|
||||
<script src="/assets/js/marked.custom.js?v=251"></script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -10,7 +10,8 @@ def test_rules():
|
|||
assert response.text.startswith("<!DOCTYPE html>")
|
||||
|
||||
|
||||
def test_signup():
|
||||
def test_signup_and_post():
|
||||
print("\nTesting signup and posting flow")
|
||||
client = app.test_client()
|
||||
with client: # this keeps the session between requests, which we need
|
||||
signup_get_response = client.get("/signup")
|
||||
|
@ -35,6 +36,20 @@ def test_signup():
|
|||
assert "error" not in signup_post_response.location
|
||||
|
||||
# we should now be logged in and able to post
|
||||
submit_get_response = client.get("/submit")
|
||||
assert submit_get_response.status_code == 200
|
||||
|
||||
submit_post_response = client.post("/submit", data={
|
||||
"title": "my_cool_post",
|
||||
"body": "hey_guys",
|
||||
})
|
||||
assert submit_post_response.status_code == 302
|
||||
post_render_result = client.get(submit_post_response.location)
|
||||
assert "my_cool_post" in post_render_result.text
|
||||
assert "hey_guys" in post_render_result.text
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
78
files/tests/test_migrations_up_to_date.py
Normal file
78
files/tests/test_migrations_up_to_date.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
import inspect
|
||||
import migrations.versions
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from files.__main__ import app
|
||||
|
||||
APP_PATH = app.root_path
|
||||
BASE_PATH = os.path.join(*os.path.split(APP_PATH)[:-1])
|
||||
VERSIONS_PATH = migrations.versions.__path__._path[0];
|
||||
|
||||
def test_migrations_up_to_date():
|
||||
def get_versions():
|
||||
all_versions = [f.path for f in os.scandir(VERSIONS_PATH)]
|
||||
filtered_versions = []
|
||||
for entry in all_versions:
|
||||
if not os.path.isfile(entry):
|
||||
continue
|
||||
*dir_parts, filename = os.path.split(entry)
|
||||
base, ext = os.path.splitext(filename)
|
||||
if ext == '.py':
|
||||
filtered_versions.append(entry)
|
||||
return filtered_versions
|
||||
|
||||
def get_method_body_lines(method):
|
||||
method_lines, _ = inspect.getsourcelines(method)
|
||||
return [l.strip() for l in method_lines if not l.strip().startswith('#')][1:]
|
||||
|
||||
versions_before = get_versions()
|
||||
result = subprocess.run(
|
||||
[
|
||||
'python3',
|
||||
'-m',
|
||||
'flask',
|
||||
'db',
|
||||
'revision',
|
||||
'--autogenerate',
|
||||
'--rev-id=ci_verify_empty_revision',
|
||||
'--message=should_be_empty',
|
||||
],
|
||||
cwd=BASE_PATH,
|
||||
env={
|
||||
**os.environ,
|
||||
'FLASK_APP': 'files/cli:app',
|
||||
},
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True
|
||||
)
|
||||
versions_after = get_versions()
|
||||
new_versions = [v for v in versions_after if v not in versions_before]
|
||||
try:
|
||||
for version in new_versions:
|
||||
filename = os.path.split(version)[-1]
|
||||
base, ext = os.path.splitext(filename)
|
||||
__import__(f'migrations.versions.{base}')
|
||||
migration = getattr(migrations.versions, base)
|
||||
upgrade_lines = get_method_body_lines(migration.upgrade)
|
||||
assert ["pass"] == upgrade_lines, "\n".join([
|
||||
"",
|
||||
"Expected upgrade script to be empty (pass) but got",
|
||||
*[f"\t>\t{l}" for l in upgrade_lines],
|
||||
"To fix this issue, please run",
|
||||
"\t$ flask db revision --autogenerate --message='short description of schema changes'",
|
||||
"to generate a candidate migration, and make any necessary changes to that candidate migration (e.g. naming foreign key constraints)",
|
||||
])
|
||||
downgrade_lines = get_method_body_lines(migration.downgrade)
|
||||
assert ["pass"] == downgrade_lines, "\n".join([
|
||||
"",
|
||||
"Expected downgrade script to be empty (pass) but got",
|
||||
*[f"\t>{l}" for l in downgrade_lines],
|
||||
"To fix this issue, please run",
|
||||
"\tflask db revision --autogenerate --message='short description of schema changes'",
|
||||
"to generate a candidate migration, and make any necessary changes to that candidate migration (e.g. naming foreign key constraints)",
|
||||
])
|
||||
finally:
|
||||
for version in new_versions:
|
||||
os.remove(version)
|
1
migrations/README
Normal file
1
migrations/README
Normal file
|
@ -0,0 +1 @@
|
|||
Single-database configuration for Flask.
|
51
migrations/alembic.ini
Normal file
51
migrations/alembic.ini
Normal file
|
@ -0,0 +1,51 @@
|
|||
# A generic, single database configuration.
|
||||
|
||||
[alembic]
|
||||
# template used to generate migration files
|
||||
file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d_%%(minute).2d_%%(second).2d_%%(rev)s_%%(slug)s
|
||||
timezone = UTC
|
||||
|
||||
# set to 'true' to run the environment during
|
||||
# the 'revision' command, regardless of autogenerate
|
||||
# revision_environment = false
|
||||
|
||||
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root,sqlalchemy,alembic,flask_migrate
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
qualname =
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
|
||||
[logger_alembic]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = alembic
|
||||
|
||||
[logger_flask_migrate]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = flask_migrate
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
95
migrations/env.py
Normal file
95
migrations/env.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
from __future__ import with_statement
|
||||
|
||||
from files.classes import *
|
||||
import logging
|
||||
from logging.config import fileConfig
|
||||
|
||||
from flask import current_app
|
||||
|
||||
from alembic import context
|
||||
|
||||
# this is the Alembic Config object, which provides
|
||||
# access to the values within the .ini file in use.
|
||||
connection_string = current_app.config.get('DATABASE_URL')
|
||||
|
||||
config = context.config
|
||||
config.set_main_option('sqlalchemy.url', connection_string)
|
||||
|
||||
# Interpret the config file for Python logging.
|
||||
# This line sets up loggers basically.
|
||||
fileConfig(config.config_file_name)
|
||||
logger = logging.getLogger('alembic.env')
|
||||
|
||||
# add your model's MetaData object here
|
||||
# for 'autogenerate' support
|
||||
from files.__main__ import Base
|
||||
target_metadata = Base.metadata
|
||||
|
||||
config.set_main_option(
|
||||
'sqlalchemy.url',
|
||||
str(current_app.extensions['migrate'].db.get_engine().url).replace(
|
||||
'%', '%%'))
|
||||
|
||||
# other values from the config, defined by the needs of env.py,
|
||||
# can be acquired:
|
||||
# my_important_option = config.get_main_option("my_important_option")
|
||||
# ... etc.
|
||||
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url, target_metadata=target_metadata, literal_binds=True
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
|
||||
# this callback is used to prevent an auto-migration from being generated
|
||||
# when there are no changes to the schema
|
||||
# reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html
|
||||
def process_revision_directives(context, revision, directives):
|
||||
if getattr(config.cmd_opts, 'autogenerate', False):
|
||||
script = directives[0]
|
||||
if script.upgrade_ops.is_empty():
|
||||
directives[:] = []
|
||||
logger.info('No changes in schema detected.')
|
||||
|
||||
connectable = current_app.extensions['migrate'].db.get_engine()
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata,
|
||||
process_revision_directives=process_revision_directives,
|
||||
**current_app.extensions['migrate'].configure_args
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
24
migrations/script.py.mako
Normal file
24
migrations/script.py.mako
Normal file
|
@ -0,0 +1,24 @@
|
|||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
branch_labels = ${repr(branch_labels)}
|
||||
depends_on = ${repr(depends_on)}
|
||||
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
|
@ -0,0 +1,28 @@
|
|||
"""create empty first revision
|
||||
|
||||
Revision ID: 0aef77162269
|
||||
Revises:
|
||||
Create Date: 2022-05-12 02:54:34.564536+00:00
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '0aef77162269'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
pass
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
pass
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,38 @@
|
|||
"""update db to match models at fork time
|
||||
|
||||
Revision ID: 4a1f7859151b
|
||||
Revises: 0aef77162269
|
||||
Create Date: 2022-05-12 03:08:32.417479+00:00
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '4a1f7859151b'
|
||||
down_revision = '0aef77162269'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('submissions', sa.Column('bump_utc', sa.Integer(), server_default=sa.schema.FetchedValue(), nullable=True))
|
||||
op.create_foreign_key('comments_app_id_fkey', 'comments', 'oauth_apps', ['app_id'], ['id'])
|
||||
op.create_foreign_key('commentvotes_app_id_fkey', 'commentvotes', 'oauth_apps', ['app_id'], ['id'])
|
||||
op.create_foreign_key('modactions_user_id_fkey', 'modactions', 'users', ['user_id'], ['id'])
|
||||
op.create_foreign_key('submissions_app_id_fkey', 'submissions', 'oauth_apps', ['app_id'], ['id'])
|
||||
op.create_foreign_key('votes_app_id_fkey', 'votes', 'oauth_apps', ['app_id'], ['id'])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('votes_app_id_fkey', 'votes', type_='foreignkey')
|
||||
op.drop_constraint('submissions_app_id_fkey', 'submissions', type_='foreignkey')
|
||||
op.drop_constraint('modactions_user_id_fkey', 'modactions', type_='foreignkey')
|
||||
op.drop_constraint('commentvotes_app_id_fkey', 'commentvotes', type_='foreignkey')
|
||||
op.drop_constraint('comments_app_id_fkey', 'comments', type_='foreignkey')
|
||||
op.drop_column('submissions', 'bump_utc')
|
||||
# ### end Alembic commands ###
|
|
@ -0,0 +1,46 @@
|
|||
"""add usernotes constraints
|
||||
|
||||
Revision ID: 16d6335dd9a3
|
||||
Revises: 4a1f7859151b
|
||||
Create Date: 2022-05-16 19:42:28.708577+00:00
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '16d6335dd9a3'
|
||||
down_revision = '4a1f7859151b'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('usernotes', 'note',
|
||||
existing_type=sa.VARCHAR(length=10000),
|
||||
nullable=False)
|
||||
op.alter_column('usernotes', 'tag',
|
||||
existing_type=sa.VARCHAR(length=10),
|
||||
nullable=False)
|
||||
op.create_foreign_key('usernotes_author_id_fkey', 'usernotes', 'users', ['author_id'], ['id'])
|
||||
op.create_foreign_key('usernotes_reference_comment_fkey', 'usernotes', 'comments', ['reference_comment'], ['id'], ondelete='SET NULL')
|
||||
op.create_foreign_key('usernotes_reference_post_fkey', 'usernotes', 'submissions', ['reference_post'], ['id'], ondelete='SET NULL')
|
||||
op.create_foreign_key('usernotes_reference_user_fkey', 'usernotes', 'users', ['reference_user'], ['id'], ondelete='CASCADE')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_constraint('usernotes_reference_user_fkey', 'usernotes', type_='foreignkey')
|
||||
op.drop_constraint('usernotes_reference_post_fkey', 'usernotes', type_='foreignkey')
|
||||
op.drop_constraint('usernotes_reference_comment_fkey', 'usernotes', type_='foreignkey')
|
||||
op.drop_constraint('usernotes_author_id_fkey', 'usernotes', type_='foreignkey')
|
||||
op.alter_column('usernotes', 'tag',
|
||||
existing_type=sa.VARCHAR(length=10),
|
||||
nullable=True)
|
||||
op.alter_column('usernotes', 'note',
|
||||
existing_type=sa.VARCHAR(length=10000),
|
||||
nullable=True)
|
||||
# ### end Alembic commands ###
|
|
@ -5,6 +5,7 @@ Flask-Caching
|
|||
Flask-Compress
|
||||
Flask-Limiter
|
||||
Flask-Mail
|
||||
Flask-Migrate
|
||||
Flask-Socketio
|
||||
gevent
|
||||
gevent-websocket
|
||||
|
|
11
run_tests.py
11
run_tests.py
|
@ -33,10 +33,15 @@ subprocess.run([
|
|||
# run the test
|
||||
print("Running test . . .")
|
||||
result = subprocess.run([
|
||||
"docker",
|
||||
"docker-compose",
|
||||
"exec",
|
||||
"themotte",
|
||||
"bash", "-c", "cd service && python3 -m pytest -s"
|
||||
'-T',
|
||||
"files",
|
||||
"bash", "-c", ' && '.join([
|
||||
"cd service",
|
||||
"FLASK_APP=files/cli:app python3 -m flask db upgrade",
|
||||
"python3 -m pytest -s",
|
||||
])
|
||||
])
|
||||
|
||||
if not was_running:
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,7 +5,7 @@ logfile=/tmp/supervisord.log
|
|||
|
||||
[program:service]
|
||||
directory=/service
|
||||
command=gunicorn files.__main__:app -k gevent -w 1 --reload -b 0.0.0.0:80 --max-requests 1000 --max-requests-jitter 500
|
||||
command=sh -c 'FLASK_APP=files/cli:app python3 -m flask db upgrade && gunicorn files.__main__:app -k gevent -w 1 --reload -b 0.0.0.0:80 --max-requests 1000 --max-requests-jitter 500'
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue