Merge branch 'master' into event-manager-2
|
@ -1,22 +1,10 @@
|
|||
image.*
|
||||
video.mp4
|
||||
unsanitized.mp4
|
||||
cache/
|
||||
__pycache__/
|
||||
.idea/
|
||||
.*
|
||||
venv/
|
||||
.vscode/
|
||||
.sass-cache/
|
||||
flask_session/
|
||||
.DS_Store
|
||||
site_settings.json
|
||||
/files/test.py
|
||||
tags
|
||||
__pycache__/
|
||||
|
||||
# Chat environment
|
||||
chat/node_modules
|
||||
chat/build
|
||||
chat/.env
|
||||
|
||||
# Chat artefacts
|
||||
files/assets/css/chat_done.css
|
||||
|
|
|
@ -11,6 +11,7 @@ RUN apt install -y imagemagick
|
|||
RUN apt install -y postgresql
|
||||
RUN apt install -y libpq-dev
|
||||
RUN apt install -y nano
|
||||
RUN apt install -y exiv2
|
||||
|
||||
COPY requirements.txt /etc/requirements.txt
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ export function useEmojis() {
|
|||
|
||||
// Retrieve the list.
|
||||
useEffect(() => {
|
||||
fetch("/marsey_list.json")
|
||||
fetch("/emojis")
|
||||
.then((res) => res.json())
|
||||
.then(setEmojis)
|
||||
.catch(setError);
|
||||
|
|
|
@ -15,12 +15,21 @@ services:
|
|||
depends_on:
|
||||
- redis
|
||||
- postgres
|
||||
logging:
|
||||
options:
|
||||
max-size: "100k"
|
||||
max-file: "1"
|
||||
|
||||
|
||||
redis:
|
||||
container_name: "redis"
|
||||
image: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
logging:
|
||||
options:
|
||||
max-size: "100k"
|
||||
max-file: "1"
|
||||
|
||||
postgres:
|
||||
container_name: "postgres"
|
||||
|
@ -33,9 +42,17 @@ services:
|
|||
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||
ports:
|
||||
- "5432:5432"
|
||||
logging:
|
||||
options:
|
||||
max-size: "100k"
|
||||
max-file: "1"
|
||||
|
||||
opera-proxy:
|
||||
container_name: "opera-proxy"
|
||||
image: yarmak/opera-proxy
|
||||
ports:
|
||||
- "18080:18080"
|
||||
logging:
|
||||
options:
|
||||
max-size: "100k"
|
||||
max-file: "1"
|
||||
|
|
|
@ -1,219 +1,159 @@
|
|||
#awards-container {
|
||||
position:fixed;
|
||||
pointer-events: none;
|
||||
z-index:9999;
|
||||
}
|
||||
|
||||
.stackable-container > div {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.stackable-container div,
|
||||
.stackable-container img, .ricardo {
|
||||
animation-iteration-count: infinite !important;
|
||||
animation-timing-function: linear !important;
|
||||
}
|
||||
|
||||
/*seal*/
|
||||
.wholesome img {
|
||||
width: 100px !important;
|
||||
height: 89.5px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.wholesome img {
|
||||
width: 40px !important;
|
||||
height: 27px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.wholesome {animation: sealX 9s alternate}
|
||||
.wholesome img {animation: sealY 10s alternate}
|
||||
|
||||
.wholesome:nth-child(even),
|
||||
.wholesome:nth-child(n+2):nth-child(n+3) img
|
||||
{animation-direction: alternate-reverse}
|
||||
|
||||
@keyframes sealX {
|
||||
100% {transform: translateX(98vw)}
|
||||
}
|
||||
@keyframes sealY {
|
||||
100% {transform: translateY(85vh)}
|
||||
}
|
||||
|
||||
/*train*/
|
||||
.train img {
|
||||
width: 100px !important;
|
||||
height: 51px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.train img {
|
||||
width: 40px !important;
|
||||
height: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.train:nth-child(1), .scooter:nth-child(1) {top:2%}
|
||||
.train:nth-child(2), .scooter:nth-child(2) {top:27%}
|
||||
.train:nth-child(3), .scooter:nth-child(3) {top:52%}
|
||||
.train:nth-child(4), .scooter:nth-child(4) {top:77%}
|
||||
|
||||
.train {animation: train 12s;}
|
||||
.train:nth-child(odd) {animation-direction: reverse;}
|
||||
.train:nth-child(odd) img {transform: scaleX(-1);}
|
||||
|
||||
@keyframes train {
|
||||
from {transform: translateX(-3vw)}
|
||||
to {transform: translateX(99vw)}
|
||||
}
|
||||
|
||||
/*scooter*/
|
||||
.scooter img {
|
||||
width: 100px !important;
|
||||
height: 135px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.scooter img {
|
||||
width: 40px !important;
|
||||
height: 54px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.scooter {animation: train 14s;}
|
||||
.scooter:nth-child(even) {animation-direction: reverse;}
|
||||
.scooter:nth-child(even) img {transform: scaleX(-1);}
|
||||
|
||||
/*confetti*/
|
||||
#post-award-confetti {
|
||||
position: fixed;
|
||||
z-index: 9998;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none !important;
|
||||
.confetti {
|
||||
background-image: url(/assets/images/confetti2.webp);
|
||||
background-repeat: repeat;
|
||||
}
|
||||
|
||||
/*fireworks*/
|
||||
.firework {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.firework img {
|
||||
max-width: 15rem;
|
||||
}
|
||||
|
||||
/*ricardo*/
|
||||
.ricardo {
|
||||
position: fixed;
|
||||
z-index: 9997;
|
||||
pointer-events: none !important;
|
||||
position: fixed !important;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.ricardo img {
|
||||
max-height: 15rem !important;
|
||||
max-height: min(30vw,15rem) !important;
|
||||
max-height: min(30vw,15rem);
|
||||
}
|
||||
|
||||
.ricardoleft {
|
||||
animation: ricardoleft 2.9s 2 alternate !important;
|
||||
.ricardo1 {animation: ricardo1Xa 5.8s, ricardo1Xb 11.6s, ricardo1Y 23.2s;}
|
||||
.ricardo2 {animation: ricardo2 8.5s;}
|
||||
.ricardo3 {animation: ricardo3 10s;}
|
||||
|
||||
@keyframes ricardo1Xa {
|
||||
0% {right: -200px}
|
||||
50% {right: 200px}
|
||||
100% {right: -200px}
|
||||
}
|
||||
|
||||
.ricardoright {
|
||||
animation: ricardoright 2.9s 2 alternate !important;
|
||||
@keyframes ricardo1Xb {
|
||||
0%{left:unset}
|
||||
49% {left: unset}
|
||||
50% {left: -200px}
|
||||
75% {left:200px}
|
||||
100% {left: -200px}
|
||||
}
|
||||
|
||||
@keyframes ricardoleft {
|
||||
from {}
|
||||
to {transform: translateX(200px);}
|
||||
@keyframes ricardo1Y {
|
||||
0% {bottom:20vh}
|
||||
24% {bottom: 20vh}
|
||||
25% {bottom: 60vh}
|
||||
49% {bottom: 60vh}
|
||||
50% {bottom: 10vh}
|
||||
74% {bottom: 10vh}
|
||||
75% {bottom: 50vh}
|
||||
99% {bottom: 50vh}
|
||||
100% {bottom: 20vh}
|
||||
}
|
||||
|
||||
@keyframes ricardoright {
|
||||
from {transform: translateX(110vw);}
|
||||
to {transform: translateX(95vw);}
|
||||
}
|
||||
|
||||
#ricardo1 {
|
||||
top:70%;
|
||||
left:-10%;
|
||||
}
|
||||
|
||||
#ricardo2 {
|
||||
top:80%;
|
||||
left:50%;
|
||||
animation: ricardo2 1.7s linear infinite !important;
|
||||
max-height:200px;
|
||||
}
|
||||
|
||||
#ricardo3 {
|
||||
top:85%;
|
||||
animation: ricardo3 10s linear infinite !important;
|
||||
max-height:150px;
|
||||
}
|
||||
|
||||
@keyframes ricardo2 {
|
||||
0% {opacity:20%}
|
||||
50% {opacity:100%}
|
||||
100% {opacity:0%}
|
||||
0% { opacity: 1; left: 0; right: unset;}
|
||||
18% {opacity: 0; left: 0; right: unset;}
|
||||
19% {opacity: 0; left: unset; right: 20vw;}
|
||||
20% {opacity: 1; left: unset; right: 20vw;}
|
||||
38% {opacity: 0; left: unset; right: 20vw;}
|
||||
39% {opacity: 0; left: 20vw; right: unset;}
|
||||
40% {opacity: 1; left: 20vw; right: unset;}
|
||||
58% {opacity: 0; left: 20vw; right: unset;}
|
||||
59% {opacity: 0; left: unset;right: 60vw;}
|
||||
60% {opacity: 1; left: unset; right: 60vw;}
|
||||
78% {opacity: 0; left: unset; right: 60vw;}
|
||||
79% {opacity: 0; left: 80vw; right: unset;}
|
||||
80% {opacity: 1; left: 80vw; right: unset;}
|
||||
98% {opacity: 0; left: 80vw; right: unset;}
|
||||
99% {opacity: 0; left: 0; right: unset;}
|
||||
100% {opacity: 1; left: 0; right: unset;}
|
||||
}
|
||||
|
||||
@keyframes ricardo3 {
|
||||
50% {transform: translateX(105vw);}
|
||||
51% {transform: translate(105vw,-86vh) rotate(180deg);}
|
||||
100% {transform: translate(-15vw,-86vh) rotate(180deg);}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@keyframes ricardo3 {
|
||||
50% {transform: translateX(105vw);}
|
||||
51% {transform: translate(105vw,-86vh) rotate(180deg);}
|
||||
100% {transform: translate(-70vw,-86vh) rotate(180deg);}
|
||||
}
|
||||
}
|
||||
|
||||
/*glow*/
|
||||
.glow .post-title, .glow a, .glow .post-meta *, .glow .user-info *, .glow .comment-text, .glow .comment-actions *, .glow {
|
||||
color:lightgreen !important;
|
||||
text-shadow:1px 1px 1px darkgreen, 0 0 5px green;
|
||||
}
|
||||
|
||||
.glow .score-up, .glow .active.arrow-up::before, .glow .arrow-up::after, .glow .arrow-up:hover::before {
|
||||
color: lime !important;
|
||||
}
|
||||
|
||||
.glow .score-down, .glow .active.arrow-down::before, .glow .arrow-down::after, .glow .arrow-down:hover::before {
|
||||
color: lime !important;
|
||||
}
|
||||
|
||||
.glow .arrow-up::before, .glow .arrow-down::before, .glow .score {
|
||||
color: lightgreen;
|
||||
}
|
||||
|
||||
.glow .post-body a, .glow .comment-text a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*train*/
|
||||
.train {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.trainimg {
|
||||
width: 100px !important;
|
||||
height: 51px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.trainimg {
|
||||
width: 40px !important;
|
||||
height: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.train1 {
|
||||
top: 10%
|
||||
}
|
||||
|
||||
.train2 {
|
||||
top: 35%
|
||||
}
|
||||
|
||||
.train3 {
|
||||
top: 60%
|
||||
}
|
||||
|
||||
.train4 {
|
||||
top: 85%
|
||||
}
|
||||
|
||||
/*scooter*/
|
||||
.scooterimg {
|
||||
width: 100px !important;
|
||||
height: 135px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.scooterimg {
|
||||
width: 40px !important;
|
||||
height: 54px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/*seal*/
|
||||
.seal {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.sealimg {
|
||||
width: 100px !important;
|
||||
height: 89.5px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.sealimg {
|
||||
width: 30px !important;
|
||||
height: 27px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes moveX {
|
||||
from {} to {transform: translateX(98vw)}
|
||||
}
|
||||
|
||||
@keyframes moveY {
|
||||
from {} to {transform: translateY(90vh)}
|
||||
}
|
||||
|
||||
.seal1 {
|
||||
animation: moveX 4s linear 0s infinite alternate !important;
|
||||
}
|
||||
|
||||
.seal1 > img {
|
||||
animation: moveY 6.8s linear 0s infinite alternate !important;
|
||||
}
|
||||
|
||||
.seal2 {
|
||||
animation: moveX 5s linear 0s infinite alternate-reverse !important;
|
||||
}
|
||||
|
||||
.seal2 > img {
|
||||
animation: moveY 8s linear 0s infinite alternate-reverse !important;
|
||||
}
|
||||
|
||||
.seal3 {
|
||||
animation: moveX 4s linear 0s infinite alternate !important;
|
||||
}
|
||||
.seal3 > img {
|
||||
animation: moveY 5s linear 0s infinite alternate-reverse !important;
|
||||
}
|
||||
|
||||
.seal4 {
|
||||
animation: moveX 5s linear 0s infinite alternate-reverse !important;
|
||||
}
|
||||
.seal4 > img {
|
||||
animation: moveY 6.8s linear 0s infinite alternate !important;
|
||||
50% {transform: translateX(100vw); top: unset; bottom: 0;}
|
||||
51% {transform: translateX(100vw) rotate(180deg); top: 0; bottom: unset;}
|
||||
100% {transform: translateX(-15vw) rotate(180deg); top: 0; bottom: unset;}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
--gray-100: #E1E1E1;
|
||||
--gray-200: #E1E1E1;
|
||||
--gray-300: #383838;
|
||||
--gray-400: #303030;
|
||||
--gray-400: #262b32;
|
||||
--gray-500: #000000;
|
||||
--gray-600: #000000;
|
||||
--gray-700: #000000;
|
||||
|
@ -95,7 +95,3 @@ pre {
|
|||
h5.post-title a:visited {
|
||||
color: #7a7a7a !important;
|
||||
}
|
||||
|
||||
.empty-state-img {
|
||||
filter: brightness(99);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
--gray-100: #1e1e1e;
|
||||
--gray-200: #1e1e1e;
|
||||
--white: #1e1e1e;
|
||||
--black: #303030;
|
||||
--black: #262b32;
|
||||
--background: #ffffff;
|
||||
}
|
||||
|
||||
|
|
|
@ -1853,7 +1853,7 @@ button.close {
|
|||
color: #fff;
|
||||
text-align: center;
|
||||
background-color: #000;
|
||||
border-radius: 0.35rem;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
.popover {
|
||||
position: absolute;
|
||||
|
@ -4063,11 +4063,6 @@ ul.comment-section {
|
|||
.footer a:hover, .footer a:focus, .footer a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.empty-state-img {
|
||||
width: 200px;
|
||||
opacity: 0.35;
|
||||
filter: brightness(0);
|
||||
}
|
||||
.border-top {
|
||||
border-top: 1px solid var(--gray-400) !important;
|
||||
}
|
||||
|
@ -5027,6 +5022,23 @@ img[src="/i/hand.webp"]+img[glow]:not([data-src]) {
|
|||
pat-pfp-anim .3s infinite;
|
||||
}
|
||||
|
||||
.glow .post-title, .glow a, .glow .post-meta *, .glow .user-info *, .glow .comment-text, .glow .comment-actions *, .glow {
|
||||
color:lightgreen !important;
|
||||
text-shadow:1px 1px 1px darkgreen, 0 0 5px green;
|
||||
}
|
||||
.glow .score-up, .glow .active.arrow-up::before, .glow .arrow-up::after, .glow .arrow-up:hover::before {
|
||||
color: lime !important;
|
||||
}
|
||||
.glow .score-down, .glow .active.arrow-down::before, .glow .arrow-down::after, .glow .arrow-down:hover::before {
|
||||
color: lime !important;
|
||||
}
|
||||
.glow .arrow-up::before, .glow .arrow-down::before, .glow .score {
|
||||
color: lightgreen;
|
||||
}
|
||||
.glow .post-body a, .glow .comment-text a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@keyframes rb {
|
||||
10% { color: red; }
|
||||
20% { color: orange; }
|
||||
|
@ -6060,7 +6072,7 @@ g {
|
|||
.fa-spider-web:before{content:"\f719"}
|
||||
.fa-coffin-cross:before{content:"\e051"}
|
||||
.fa-face-sleeping:before{content:"\e38d"}
|
||||
|
||||
.fa-block-question:before{content:"\e3dd"}
|
||||
|
||||
.pronouns {
|
||||
font-size: 9px;
|
||||
|
@ -6105,11 +6117,11 @@ g {
|
|||
font-size: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 374px) {
|
||||
@media (max-width: 427px) {
|
||||
.smol-fp {
|
||||
font-size: 3.3vw;
|
||||
padding-left: 2.4vw;
|
||||
padding-right: 2.4vw;
|
||||
font-size: 2.7vw;
|
||||
padding-left: 2.5vw;
|
||||
padding-right: 2.1vw;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6385,13 +6397,6 @@ div.markdown {
|
|||
max-height: min(42vh,30vw) !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#twitter-widget-0 {
|
||||
max-height: 50vh;
|
||||
overflow: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
.modlog-action {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -6406,3 +6411,16 @@ div.markdown {
|
|||
.modlog-action:not(:first-of-type) {
|
||||
border-top: 1px solid var(--gray-400) !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--signature-max-height: 250px;
|
||||
}
|
||||
|
||||
.user-signature {
|
||||
max-height: var(--signature-max-height);
|
||||
overflow: clip;
|
||||
}
|
||||
|
||||
.user-signature video {
|
||||
height: var(--signature-max-height);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
--gray-200: #b1bac4;
|
||||
--gray-300: #505961;
|
||||
--gray-400: #6e7681;
|
||||
--gray-500: #21262d;
|
||||
--gray-500: #262b32;
|
||||
--gray-600: #21262d;
|
||||
--gray-700: #21262d;
|
||||
--gray-800: #161b22;
|
||||
|
|
|
@ -1,81 +1,22 @@
|
|||
@charset "UTF-8";
|
||||
@import 'midnight.css?v=4033';
|
||||
|
||||
:root {
|
||||
--dark: #383838;
|
||||
--secondary: #383838;
|
||||
--white: #E1E1E1;
|
||||
--black: #CFCFCF;
|
||||
--light: transparent;
|
||||
--muted: #E1E1E1;
|
||||
--gray: #383838;
|
||||
--gray-100: #E1E1E1;
|
||||
--gray-200: #E1E1E1;
|
||||
--gray-300: #383838;
|
||||
--gray-400: #303030;
|
||||
--gray-500: #21262d;
|
||||
--gray-600: transparent;
|
||||
--gray-700: transparent;
|
||||
--gray-800: transparent;
|
||||
--gray-900: transparent;
|
||||
--background: #21262d;
|
||||
--background: transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
* {
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.border {
|
||||
border-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.form-control:disabled, [readonly] {
|
||||
border-color: var(--primary) !important;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
border-color: #38A169 !important;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
border-color: #E53E3E !important;
|
||||
}
|
||||
|
||||
pre {
|
||||
color: #CFCFCF;
|
||||
}
|
||||
|
||||
.container {
|
||||
.container, #root > div.App {
|
||||
background: rgba(28, 34, 41, 0.90) !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
background-color: var(--gray-500);
|
||||
.fixed-bottom, .popover, .modal-content, .dropdown-menu, .navbar, #userpage > div.container-fluid, body, .form-control {
|
||||
background-color: #21262d !important;
|
||||
}
|
||||
|
||||
.form-inline.search .form-control:active, .form-inline.search .form-control:focus {
|
||||
background-color: var(--gray-500);
|
||||
}
|
||||
|
||||
.form-control:focus, .form-control:active {
|
||||
background-color: var(--gray-500);
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
color: #d8d8d8 !important;
|
||||
background-color: #313131 !important;
|
||||
}
|
||||
|
||||
h5.post-title a:visited {
|
||||
color: #7a7a7a !important;
|
||||
.App-side {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
|
|
@ -664,6 +664,7 @@
|
|||
{"name":"brainletchadmask","class":"Wojak"},
|
||||
{"name":"bruce","class":"Wojak"},
|
||||
{"name":"chadagent","class":"Wojak"},
|
||||
{"name":"chadpostal","class":"Wojak"},
|
||||
{"name":"chadblack2","class":"Wojak"},
|
||||
{"name":"chadsnoo","class":"Wojak"},
|
||||
{"name":"daddysgirl","class":"Wojak"},
|
||||
|
@ -694,6 +695,7 @@
|
|||
{"name":"trumpjaktalking","class":"Wojak"},
|
||||
{"name":"rdramajanny","tags": ["janny"],"class":"Wojak"},
|
||||
{"name":"soyreddit","class":"Wojak"},
|
||||
{"name":"soysnoo","class":"Wojak"},
|
||||
{"name":"doomerboy","class":"Wojak"},
|
||||
{"name":"npcsupport","class":"Wojak"},
|
||||
{"name":"npcoppse","class":"Wojak"},
|
||||
|
@ -761,6 +763,7 @@
|
|||
{"name":"chudgrug","class":"Wojak"},
|
||||
{"name":"chudnazi","class":"Wojak"},
|
||||
{"name":"chudsmug","class":"Wojak"},
|
||||
{"name":"chudglassesglow","class":"Wojak"},
|
||||
{"name":"soy4dchess","class":"Wojak"},
|
||||
{"name":"soyjaktantrum","class":"Wojak"},
|
||||
{"name":"psychojak","class":"Wojak"},
|
||||
|
@ -807,6 +810,7 @@
|
|||
{"name":"chadyescapy", "tags":["capy", "aevann"],"class":"Misc"},
|
||||
{"name":"chadnocapy", "tags":["capy", "aevann"],"class":"Misc"},
|
||||
{"name":"capygitcommit", "tags":["capy", "aevann"],"class":"Misc"},
|
||||
{"name":"capyantischizo", "class":"Misc"},
|
||||
{"name":"capysneedboat", "tags":["capy", "aevann"],"class":"Misc"},
|
||||
{"name":"chadbasedcapy", "tags":["capy", "aevann"],"class":"Misc"},
|
||||
{"name":"chadcopecapy", "tags":["capy", "aevann"],"class":"Misc"},
|
||||
|
@ -842,6 +846,7 @@
|
|||
{"name":"brookscringe","class":"Misc"},
|
||||
{"name":"brooksjustright","class":"Misc"},
|
||||
{"name":"brookskiss","class":"Misc"},
|
||||
{"name":"brooksbailiffunamused","class":"Misc"},
|
||||
{"name":"opperblink","tags":["sue", "opper", "darrell", "brooks", "prosecutor", "district", "attorney", "da", "annoyed", "irritated", "waukesha"],"class":"Misc"},
|
||||
{"name":"gimp","class":"Misc"},
|
||||
{"name":"taddance","class":"Misc","tags":["terry","davis","templeos","dance"]},
|
||||
|
@ -852,6 +857,8 @@
|
|||
{"name":"yotsubafish","class":"Misc"},
|
||||
{"name":"yotsubalol","class":"Misc"},
|
||||
{"name":"sigmatalking","class":"Misc"},
|
||||
{"name":"peoplewhoannoy","class":"Misc"},
|
||||
{"name":"pepedrum", "tags":["football","soccer"], "class":"Misc"},
|
||||
{"name":"zoroarkconfused","class":"Misc"},
|
||||
{"name":"zoroarkhappy","class":"Misc"},
|
||||
{"name":"zoroarkpout","class":"Misc"},
|
||||
|
@ -879,6 +886,7 @@
|
|||
{"name":"gigachad","tags": ["chad"],"class":"Misc"},
|
||||
{"name":"gigachad2", "tags": ["chad"], "class":"Misc"},
|
||||
{"name":"gigachad3", "tags": ["chad"], "class":"Misc"},
|
||||
{"name":"gigachad4", "tags": ["chad"], "class":"Misc"},
|
||||
{"name":"pedobear", "class":"Misc"},
|
||||
{"name":"kippy","class":"Misc"},
|
||||
{"name":"onerat","class":"Misc"},
|
||||
|
@ -886,10 +894,17 @@
|
|||
{"name":"duckdance", "class":"Misc"},
|
||||
{"name":"stoning","class":"Misc"},
|
||||
{"name":"stoningpills","class":"Misc"},
|
||||
{"name":"stoningupvotes","class":"Misc"},
|
||||
{"name":"stoningdownvotes","class":"Misc"},
|
||||
{"name":"stoningbans","class":"Misc"},
|
||||
{"name":"stoningunbans","class":"Misc"},
|
||||
{"name":"stoningpins","class":"Misc"},
|
||||
{"name":"stoningunpins","class":"Misc"},
|
||||
{"name":"srdinepoppy","class":"Misc"},
|
||||
{"name":"gunt","class":"Misc"},
|
||||
{"name":"sneedbuddy","class":"Misc"},
|
||||
{"name":"chuckbuddy","class":"Misc"},
|
||||
{"name":"mallocbuddy","class":"Misc"},
|
||||
{"name":"soren","class":"Misc"},
|
||||
{"name":"upsoren","class":"Misc"},
|
||||
{"name":"downdonger","class":"Misc"},
|
||||
|
|
After Width: | Height: | Size: 183 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 992 KiB |
After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 378 KiB |
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 185 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 9.8 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 38 KiB |
|
@ -342,7 +342,7 @@ function areyousure(t) {
|
|||
else
|
||||
t.innerHTML = t.innerHTML.replace(t.textContent, 'Are you sure?')
|
||||
|
||||
t.setAttribute("onclick", t.dataset.click);
|
||||
t.setAttribute("onclick", t.dataset.click2);
|
||||
|
||||
if (t.dataset.dismiss)
|
||||
t.setAttribute("data-bs-dismiss", t.dataset.dismiss);
|
||||
|
@ -407,9 +407,3 @@ function sendFormXHRSwitch(e) {
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/service-worker.js?v=3")
|
||||
.then((registration) => registration.update())
|
||||
.catch((e) => console.log("Service worker update failed with error", e));
|
||||
}
|
||||
|
|
|
@ -187,10 +187,9 @@ const emojisSearchDictionary = {
|
|||
|
||||
// get public emojis list
|
||||
const emojiRequest = new XMLHttpRequest();
|
||||
emojiRequest.open("GET", '/marsey_list.json');
|
||||
emojiRequest.open("GET", '/emojis');
|
||||
emojiRequest.setRequestHeader('xhr', 'xhr');
|
||||
emojiRequest.onload = async (e) => {
|
||||
console.log("HERE")
|
||||
let emojis = JSON.parse(emojiRequest.response);
|
||||
if(! (emojis instanceof Array ))
|
||||
throw new TypeError("[EMOJI DIALOG] rDrama's server should have sent a JSON-coded Array!");
|
||||
|
|
|
@ -11,6 +11,17 @@ function post(url) {
|
|||
function updatebgselection(){
|
||||
var bgselector = document.getElementById("backgroundSelector");
|
||||
const backgrounds = [
|
||||
{
|
||||
folder: "glitter",
|
||||
backgrounds:
|
||||
[
|
||||
"1.webp",
|
||||
"2.webp",
|
||||
"3.webp",
|
||||
"4.webp",
|
||||
"5.webp",
|
||||
]
|
||||
},
|
||||
{
|
||||
folder: "anime",
|
||||
backgrounds:
|
||||
|
@ -20,7 +31,7 @@ function updatebgselection(){
|
|||
"3.webp",
|
||||
"4.webp",
|
||||
"5.webp",
|
||||
"6.webp"
|
||||
"6.webp",
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -7,15 +7,24 @@ function sort_table(n) {
|
|||
for (let i = 1; i < rows.length; i++) {
|
||||
const ele = rows[i];
|
||||
let x = rows[i].getElementsByTagName("TD")[n];
|
||||
x = x.getElementsByTagName('a')[0] || x;
|
||||
const attr = x.dataset.time ? parseInt(x.dataset.time) : parseInt(x.innerHTML.replace(/,/g, ''));
|
||||
if (!('sortKey' in x.dataset)) {
|
||||
x = x.getElementsByTagName('a')[0] || x;
|
||||
}
|
||||
var attr;
|
||||
if ('sortKey' in x.dataset) {
|
||||
attr = x.dataset.sortKey;
|
||||
} else if ('time' in x.dataset) {
|
||||
attr = parseInt(x.dataset.time);
|
||||
} else {
|
||||
attr = parseInt(x.innerHTML.replace(/,/g, ''));
|
||||
}
|
||||
items.push({ ele, attr });
|
||||
}
|
||||
if (sortAscending[n]) {
|
||||
items.sort((a, b) => a.attr - b.attr);
|
||||
items.sort((a, b) => a.attr > b.attr ? 1 : -1);
|
||||
sortAscending[n] = false;
|
||||
} else {
|
||||
items.sort((a, b) => b.attr - a.attr);
|
||||
items.sort((a, b) => a.attr < b.attr ? 1 : -1);
|
||||
sortAscending[n] = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@ class AwardRelationship(Base):
|
|||
@lazy
|
||||
def type(self):
|
||||
if self.kind in AWARDS: return AWARDS[self.kind]
|
||||
else: return HOUSE_AWARDS[self.kind]
|
||||
elif self.kind in HOUSE_AWARDS: return HOUSE_AWARDS[self.kind]
|
||||
else: return AWARDS["fallback"]
|
||||
|
||||
@property
|
||||
@lazy
|
||||
|
|
|
@ -292,7 +292,10 @@ class Comment(Base):
|
|||
body += f'"> - <a href="/votes/comment/option/{o.id}"><span id="score-comment-{o.id}">{o.upvotes}</span> votes</a></label></div>'''
|
||||
|
||||
if not self.ghost and self.author.show_sig(v):
|
||||
body += f"<hr>{self.author.sig_html}"
|
||||
body += f'<section id="signature-{self.author.id}" class="user-signature"><hr>{self.author.sig_html}</section>'
|
||||
|
||||
if v:
|
||||
body = body.replace("!YOU!", v.username)
|
||||
|
||||
return body
|
||||
|
||||
|
@ -309,6 +312,9 @@ class Comment(Base):
|
|||
|
||||
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
|
||||
|
||||
if v:
|
||||
body = body.replace("!YOU!", v.username)
|
||||
|
||||
return body
|
||||
|
||||
@lazy
|
||||
|
|
|
@ -21,3 +21,20 @@ class Marsey(Base):
|
|||
|
||||
def __repr__(self):
|
||||
return f"<Marsey(name={self.name})>"
|
||||
|
||||
def tags_list(self):
|
||||
return self.tags.split(" ") + [self.name[len("marsey"):]] # type: ignore
|
||||
|
||||
def json(self):
|
||||
data = {
|
||||
"name": self.name,
|
||||
"author_id": self.author_id,
|
||||
"submitter_id": self.submitter_id,
|
||||
"tags": self.tags_list(),
|
||||
"count": self.count,
|
||||
"created_utc": self.created_utc,
|
||||
"class": "Marsey",
|
||||
}
|
||||
if "author" in self.__dict__ and self.author:
|
||||
data["author"] = self.author
|
||||
return data
|
||||
|
|
|
@ -302,7 +302,7 @@ class Submission(Base):
|
|||
body += " - <b>WINNER!</b>"
|
||||
|
||||
if not winner and v and v.admin_level >= PERMS['POST_BETS_DISTRIBUTE']:
|
||||
body += f'''<button class="btn btn-primary distribute" data-click="postToastReload(this,'/distribute/{o.id}')" onclick="areyousure(this)">Declare winner</button>'''
|
||||
body += f'''<button class="btn btn-primary distribute" data-click2="postToastReload(this,'/distribute/{o.id}')" onclick="areyousure(this)">Declare winner</button>'''
|
||||
body += "</div>"
|
||||
else:
|
||||
input_type = 'radio' if o.exclusive else 'checkbox'
|
||||
|
@ -322,7 +322,10 @@ class Submission(Base):
|
|||
|
||||
|
||||
if not listing and not self.ghost and self.author.show_sig(v):
|
||||
body += f"<hr>{self.author.sig_html}"
|
||||
body += f'<section id="signature-{self.author.id}" class="user-signature"><hr>{self.author.sig_html}</section>'
|
||||
|
||||
if v:
|
||||
body = body.replace("!YOU!", v.username)
|
||||
|
||||
return body
|
||||
|
||||
|
@ -337,6 +340,10 @@ class Submission(Base):
|
|||
|
||||
body = censor_slurs(body, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
|
||||
body = normalize_urls_runtime(body, v)
|
||||
|
||||
if v:
|
||||
body = body.replace("!YOU!", v.username)
|
||||
|
||||
return body
|
||||
|
||||
@lazy
|
||||
|
|
|
@ -141,7 +141,6 @@ class User(Base):
|
|||
subscriptions = relationship("Subscription", back_populates="user")
|
||||
following = relationship("Follow", primaryjoin="Follow.user_id==User.id", back_populates="user")
|
||||
followers = relationship("Follow", primaryjoin="Follow.target_id==User.id", back_populates="target")
|
||||
viewers = relationship("ViewerRelationship", primaryjoin="User.id == ViewerRelationship.user_id")
|
||||
blocking = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.user_id", back_populates="user")
|
||||
blocked = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.target_id", back_populates="target")
|
||||
authorizations = relationship("ClientAuth", back_populates="user")
|
||||
|
@ -524,9 +523,9 @@ class User(Base):
|
|||
|
||||
@property
|
||||
@lazy
|
||||
def unban_string(self):
|
||||
def unban_in(self):
|
||||
if self.unban_utc == 0:
|
||||
return "permanently banned"
|
||||
return "never"
|
||||
|
||||
wait = self.unban_utc - int(time.time())
|
||||
|
||||
|
@ -543,9 +542,43 @@ class User(Base):
|
|||
|
||||
text = f"{days}d {hours:02d}h {mins:02d}m"
|
||||
|
||||
return text
|
||||
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def unban_string(self):
|
||||
text = self.unban_in
|
||||
|
||||
if text == "never": return "permanently banned"
|
||||
|
||||
return f"Unban in {text}"
|
||||
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def unchud_in(self):
|
||||
if self.agendaposter == 1:
|
||||
return "never"
|
||||
|
||||
wait = self.agendaposter - int(time.time())
|
||||
|
||||
if wait < 60:
|
||||
text = f"{wait}s"
|
||||
else:
|
||||
days = wait//(24*60*60)
|
||||
wait -= days*24*60*60
|
||||
|
||||
hours = wait//(60*60)
|
||||
wait -= hours*60*60
|
||||
|
||||
mins = wait//60
|
||||
|
||||
text = f"{days}d {hours:02d}h {mins:02d}m"
|
||||
|
||||
return text
|
||||
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def received_awards(self):
|
||||
|
@ -945,17 +978,6 @@ class User(Base):
|
|||
def can_create_hole(self):
|
||||
return self.admin_level >= PERMS['HOLE_CREATE']
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def viewers_recorded(self):
|
||||
if SITE_NAME == 'WPD': # WPD gets profile views
|
||||
return True
|
||||
elif self.admin_level >= PERMS['VIEW_PROFILE_VIEWS']: # Admins get profile views
|
||||
return True
|
||||
elif self.patron: # Patrons get profile views as a perk
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def patron_tooltip(self):
|
||||
|
|
|
@ -360,6 +360,18 @@ def execute_antispam_submission_check(title, v, url):
|
|||
return True
|
||||
|
||||
def execute_blackjack_custom(v, target, body, type):
|
||||
if v.age < (10 * 60):
|
||||
v.shadowbanned = 'AutoJanny'
|
||||
if not v.is_banned: v.ban_reason = f"Under Siege"
|
||||
v.is_muted = True
|
||||
g.db.add(v)
|
||||
with open(f"/under_siege.log", "a", encoding="utf-8") as f:
|
||||
t = str(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(time.time())))
|
||||
f.write(f"[{t}] {v.id} @{v.username} {type} {v.age}s\n")
|
||||
from files.helpers.discord import discord_message_send
|
||||
discord_message_send("1041917843094110239",
|
||||
f"<{SITE_FULL}/id/{v.id}> `@{v.username} {type} {v.age}s`")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute_blackjack(v, target, body, type):
|
||||
|
@ -451,7 +463,7 @@ def execute_lawlz_actions(v:User, p:Submission):
|
|||
if SITE_NAME != 'rDrama': return
|
||||
if not FEATURES['PINS']: return
|
||||
p.stickied_utc = int(time.time()) + 86400
|
||||
p.stickied = v.username
|
||||
p.stickied = AUTOJANNY_ID
|
||||
p.distinguish_level = 6
|
||||
p.flair = filter_emojis_only(":ben10: Required Reading")
|
||||
pin_time = 'for 1 day'
|
||||
|
|
|
@ -42,11 +42,6 @@ FP = environ.get("FP", "").strip()
|
|||
KOFI_TOKEN = environ.get("KOFI_TOKEN", "").strip()
|
||||
KOFI_LINK = environ.get("KOFI_LINK", "").strip()
|
||||
|
||||
PUSHER_ID_CSP = ""
|
||||
if PUSHER_ID != DEFAULT_CONFIG_VALUE:
|
||||
PUSHER_ID_CSP = f" {PUSHER_ID}.pushnotifications.pusher.com"
|
||||
CONTENT_SECURITY_POLICY_DEFAULT = "script-src 'self' 'unsafe-inline' challenges.cloudflare.com; connect-src 'self'; object-src 'none';"
|
||||
CONTENT_SECURITY_POLICY_HOME = f"script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' tls-use1.fpapi.io api.fpjs.io{PUSHER_ID_CSP}; object-src 'none';"
|
||||
|
||||
CLOUDFLARE_COOKIE_VALUE = "yes." # remember to change this in CloudFlare too
|
||||
|
||||
|
@ -63,6 +58,9 @@ IS_LOCALHOST = SITE == "localhost" or SITE == "127.0.0.1" or SITE.startswith("19
|
|||
if IS_LOCALHOST: SITE_FULL = 'http://' + SITE
|
||||
else: SITE_FULL = 'https://' + SITE
|
||||
|
||||
REDDIT_NOTIFS_CACHE_KEY = "reddit_notifications"
|
||||
MARSEYS_CACHE_KEY = "marseys"
|
||||
EMOJIS_CACHE_KEY = "emojis"
|
||||
|
||||
if SITE_NAME == 'PCM': CC = "SPLASH MOUNTAIN"
|
||||
else: CC = "COUNTRY CLUB"
|
||||
|
@ -101,6 +99,7 @@ SLURS = {
|
|||
'nigga': 'neighbor',
|
||||
"faggot": "cute twink",
|
||||
"fag": "strag",
|
||||
"homo ": "king ",
|
||||
"spic ": "hard-working American ",
|
||||
"spics": "hard-working Americans",
|
||||
"trannie": '<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">',
|
||||
|
@ -187,7 +186,7 @@ AGENDAPOSTER_PHRASE = 'trans lives matter'
|
|||
AGENDAPOSTER_MSG = """Hi @{username},\nYour {type} has been automatically removed because you forgot to include `{AGENDAPOSTER_PHRASE}`.\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*This is an automated message; if you need help, you can message us [here](/contact).*"""
|
||||
|
||||
AGENDAPOSTER_MSG_HTML = """<p>Hi <a href="/id/{id}"><img loading="lazy" src="/pp/{id}">@{username}</a>,</p>
|
||||
<p>Your comment has been automatically removed because you forgot to include <code>{AGENDAPOSTER_PHRASE}</code>.</p>
|
||||
<p>Your {type} has been automatically removed because you forgot to include <code>{AGENDAPOSTER_PHRASE}</code>.</p>
|
||||
<p>Don'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 <code>{AGENDAPOSTER_PHRASE}</code> included.</p>
|
||||
<p><em>This is an automated message; if you need help, you can message us <a href="/contact">here</a>.</em></p>"""
|
||||
|
||||
|
@ -196,6 +195,7 @@ WPD_CHANNEL_ID = 1013990963846332456
|
|||
PIN_AWARD_TEXT = " (pin award)"
|
||||
|
||||
THEMES = ["4chan","classic","classic_dark","coffee","dark","dramblr","light","midnight","transparent","tron","win98"]
|
||||
BACKGROUND_CATEGORIES = ["glitter", "anime", "fantasy", "solarpunk", "pixelart"]
|
||||
COMMENT_SORTS = ["hot", "new", "old", "top", "bottom", "controversial"]
|
||||
SORTS = COMMENT_SORTS + ["bump", "comments"]
|
||||
TIME_FILTERS = ["hour", "day", "week", "month", "year", "all"]
|
||||
|
@ -254,7 +254,6 @@ PERMS = { # Minimum admin_level to perform action.
|
|||
'VIEW_CHUDRAMA': 1,
|
||||
'VIEW_PRIVATE_PROFILES': 2,
|
||||
'VIEW_ALTS': 2,
|
||||
'VIEW_PROFILE_VIEWS': 2,
|
||||
'VIEW_ACTIVE_USERS': 2,
|
||||
'VIEW_ALL_USERS': 2,
|
||||
'VIEW_ALT_VOTES': 2,
|
||||
|
@ -284,6 +283,7 @@ PERMS = { # Minimum admin_level to perform action.
|
|||
}
|
||||
|
||||
FEATURES = {
|
||||
'MARSEYS': True,
|
||||
'MARSEYBUX': True,
|
||||
'AWARDS': True,
|
||||
'CHAT': True,
|
||||
|
@ -374,7 +374,6 @@ ERROR_MARSEYS = {
|
|||
500: "marseycarp3",
|
||||
}
|
||||
|
||||
EMOJI_MARSEYS = True
|
||||
EMOJI_SRCS = ['files/assets/emojis.json']
|
||||
|
||||
PIN_LIMIT = 3
|
||||
|
@ -471,16 +470,22 @@ HOUSE_SWITCH_COST = 2000
|
|||
|
||||
DONATE_SERVICE = "Gumroad" if not KOFI_TOKEN or KOFI_TOKEN == DEFAULT_CONFIG_VALUE else "KoFi"
|
||||
DONATE_LINK = GUMROAD_LINK if not KOFI_TOKEN or KOFI_TOKEN == DEFAULT_CONFIG_VALUE else KOFI_LINK
|
||||
|
||||
TIERS_ID_TO_NAME = {
|
||||
1: "Paypig",
|
||||
2: "Renthog",
|
||||
3: "Landchad",
|
||||
4: "Terminally online turboautist",
|
||||
5: "JIDF Bankroller",
|
||||
6: "Rich Bich"
|
||||
1: "Paypig",
|
||||
2: "Renthog",
|
||||
3: "Landchad",
|
||||
4: "Terminally online turboautist",
|
||||
5: "JIDF Bankroller",
|
||||
6: "Rich Bich",
|
||||
}
|
||||
|
||||
BADGE_BLACKLIST = { # only grantable by AEVANN_ID except on PCM
|
||||
16, 17, 21, 22, 23, 24, 25, 26, 27, # Marsey Artist x2 / Patron Tiers
|
||||
94, 95, 96, 97, 98, 109, 67, 68, 83, 84, 87, 90, 140, 179, 185, # Award Status
|
||||
137, # Lottery Winner
|
||||
}
|
||||
BADGE_WHITELIST = None # Falsey allows all non-blacklisted, or set() of permitted IDs
|
||||
|
||||
if SITE == 'rdrama.net':
|
||||
FEATURES['PRONOUNS'] = True
|
||||
FEATURES['HOUSES'] = True
|
||||
|
@ -594,6 +599,9 @@ elif SITE == 'pcmemes.net':
|
|||
LOTTERY_SINK_RATE = -8
|
||||
|
||||
BANNER_THREAD = 28307
|
||||
|
||||
MAX_IMAGE_AUDIO_SIZE_MB_PATRON = 100
|
||||
MAX_VIDEO_SIZE_MB_PATRON = 100
|
||||
elif SITE == 'watchpeopledie.tv':
|
||||
PIN_LIMIT = 4
|
||||
WELCOME_MSG = """Hi, you! Welcome to WatchPeopleDie.tv, this really cool site where you can go to watch people die. I'm @CLiTPEELER! If you have any questions about how things work here, or suggestions on how to make them work better than they already do, definitely slide on into my DMs (no fat chicks).\nThere's an enormously robust suite of fun features we have here and we're always looking for more to add. Way, way too many to go over in an automated welcome message. And you're probably here for the videos of people dying more than any sort of weird, paradoxical digital community aspect anyway, so I won't bore you with a tedious overview of them. Just head on over to [your settings page](https://watchpeopledie.tv/settings/profile) and have a look at some of the basic profile stuff, at least. You can change your profile picture, username, flair, colors, banners, bio, profile anthem (autoplaying song on your page, like it's MySpace or some shit, hell yeah), CSS, all sorts of things.\nOr you can just go back to the main feed and carry on with watching people die. That's what the site is for, after all. Have fun!\nAnyway, in closing, WPD is entirely open source. We don't really need new full-time coders or anything, but if you'd like to take a look at our repo - or even submit a PR to change, fix, or add some things - go right ahead! Our codebase lives at [git.rdrama.net](https://git.rdrama.net/).\nWell, that's all. Thanks again for signing up. It's an automated message and all, but I really do mean that. Thank you, specifically. I love you. Romantically. Deeply. Passionately.\nHave fun!"""
|
||||
|
@ -603,27 +611,32 @@ elif SITE == 'watchpeopledie.tv':
|
|||
PERMS['HOLE_CREATE'] = 2
|
||||
PERMS['POST_EDITING'] = 2
|
||||
PERMS['ADMIN_ADD'] = 4
|
||||
|
||||
ERROR_TITLES[400] = "Bad Request"
|
||||
ERROR_TITLES[401] = "Unauthorized"
|
||||
ERROR_TITLES[403] = "Forbidden"
|
||||
ERROR_TITLES[404] = "Not Found"
|
||||
ERROR_TITLES[405] = "Method Not Allowed"
|
||||
ERROR_TITLES[406] = "Too Many Pings"
|
||||
ERROR_TITLES[409] = "Mortal Conflict"
|
||||
ERROR_TITLES[410] = "Dead"
|
||||
ERROR_TITLES[413] = "Payload Too Large"
|
||||
ERROR_TITLES[415] = "Unsupported Media Type"
|
||||
ERROR_TITLES[500] = "Internal Server Error"
|
||||
ERROR_MSGS[400] = "That request is invalid"
|
||||
ERROR_MSGS[401] = "You need to login or sign up to do that"
|
||||
ERROR_MSGS[403] = "You're not allowed to do that"
|
||||
ERROR_MSGS[404] = "That wasn't found"
|
||||
ERROR_MSGS[405] = "You can't use this method here... if you keep getting this error tell us it's prolly something borked"
|
||||
ERROR_MSGS[409] = "There's a conflict between what you're trying to do and what you or someone else has done and because of that you can't do what you're trying to do."
|
||||
ERROR_MSGS[410] = "This link is dead. Request a new one to try again"
|
||||
ERROR_MSGS[413] = "You need to upload a smaller file please"
|
||||
ERROR_MSGS[429] = "Please wait a bit before doing that"
|
||||
|
||||
ERROR_TITLES.update({
|
||||
400: "Bad Request",
|
||||
401: "Unauthorized",
|
||||
403: "Forbidden",
|
||||
404: "Not Found",
|
||||
405: "Method Not Allowed",
|
||||
406: "Too Many Pings",
|
||||
409: "Mortal Conflict",
|
||||
410: "Dead",
|
||||
413: "Payload Too Large",
|
||||
415: "Unsupported Media Type",
|
||||
500: "Internal Server Error",
|
||||
})
|
||||
|
||||
ERROR_MSGS.update({
|
||||
400: "That request is invalid",
|
||||
401: "You need to login or sign up to do that",
|
||||
403: "You're not allowed to do that",
|
||||
404: "That wasn't found",
|
||||
405: "You can't use this method here... if you keep getting this error tell us it's prolly something borked",
|
||||
409: "There's a conflict between what you're trying to do and what you or someone else has done and because of that you can't do what you're trying to do.",
|
||||
410: "This link is dead. Request a new one to try again",
|
||||
413: "You need to upload a smaller file please",
|
||||
429: "Please wait a bit before doing that",
|
||||
})
|
||||
|
||||
POLL_THREAD = 13225
|
||||
|
||||
|
@ -658,6 +671,12 @@ elif SITE == 'watchpeopledie.tv':
|
|||
6: "Jigsaw"
|
||||
}
|
||||
|
||||
BADGE_WHITELIST = {
|
||||
85, 99, 101, # Sigma, Artist Badges x2
|
||||
59, 60, 66, 104, 108, # Classic Accolades, Nword
|
||||
117, 124, 144, 145, 146, 147, 148, 149, # Census Reused for Fun
|
||||
}
|
||||
|
||||
else: # localhost or testing environment implied
|
||||
FEATURES['ASSET_SUBMISSIONS'] = True
|
||||
FEATURES['PRONOUNS'] = True
|
||||
|
@ -671,9 +690,19 @@ bots = {AUTOJANNY_ID, SNAPPY_ID, LONGPOSTBOT_ID, ZOZBOT_ID, BASEDBOT_ID}
|
|||
|
||||
COLORS = {'ff66ac','805ad5','62ca56','38a169','80ffff','2a96f3','eb4963','ff0000','f39731','30409f','3e98a7','e4432d','7b9ae4','ec72de','7f8fa6', 'f8db58','8cdbe6', DEFAULT_COLOR}
|
||||
|
||||
BAN_EVASION_DOMAIN = 'rdrama.life'
|
||||
BAN_EVASION_DOMAIN = 'stupidpol.site'
|
||||
|
||||
AWARDS = {
|
||||
"fallback": {
|
||||
"kind": "fallback",
|
||||
"title": "Unknown",
|
||||
"description": "",
|
||||
"icon": "fas fa-block-question",
|
||||
"color": "text-white",
|
||||
"price": 0,
|
||||
"deflectable": False,
|
||||
"cosmetic": False
|
||||
},
|
||||
### Deprecated
|
||||
"ghost": {
|
||||
"kind": "ghost",
|
||||
|
@ -1329,7 +1358,7 @@ AWARDS['unpin']['ghost'] = True
|
|||
|
||||
# Disable unused awards, and site-specific award inclusion/exclusion.
|
||||
AWARDS_DISABLED = [
|
||||
'ghost', 'nword', 'lootbox', # Generic
|
||||
'fallback', 'ghost', 'nword', 'lootbox', # Generic
|
||||
'snow', 'gingerbread', 'lights', 'candycane', 'fireplace', 'grinch', # Fistmas
|
||||
'haunt', 'upsidedown', 'stab', 'spiders', 'fog', # Homoween '21
|
||||
'jumpscare', 'hw-bite', 'hw-vax', 'hw-grinch', 'flashlight', # Homoween '22
|
||||
|
|
|
@ -95,6 +95,21 @@ def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, inclu
|
|||
return user
|
||||
|
||||
|
||||
def get_accounts_dict(ids:Union[Iterable[str], Iterable[int]], v:Optional[User]=None, graceful=False, include_shadowbanned=True) -> Optional[dict[int, User]]:
|
||||
if not ids: return {}
|
||||
try:
|
||||
ids = set([int(id) for id in ids])
|
||||
except:
|
||||
if graceful: return None
|
||||
abort(404)
|
||||
|
||||
users = g.db.query(User).filter(User.id.in_(ids))
|
||||
if not (include_shadowbanned or (v and v.can_see_shadowbanned)):
|
||||
users = users.filter(User.shadowbanned == None)
|
||||
users = users.all()
|
||||
if len(users) != len(ids) and not graceful: abort(404)
|
||||
return {u.id:u for u in users}
|
||||
|
||||
def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Optional[Submission]:
|
||||
try: i = int(i)
|
||||
except:
|
||||
|
|
|
@ -54,6 +54,7 @@ def end_lottery_session():
|
|||
|
||||
for user in participating_users:
|
||||
chance_to_win = user.currently_held_lottery_tickets / len(raffle) * 100
|
||||
chance_to_win = str(chance_to_win)[:3]
|
||||
if user.id == winner:
|
||||
notification_text = f'You won {active_lottery.prize} coins in the lottershe! ' \
|
||||
+ f'Congratulations!\nYour odds of winning were: {chance_to_win}%'
|
||||
|
|
|
@ -142,7 +142,7 @@ def process_image(filename:str, v, resize=0, trim=False, uploader_id:Optional[in
|
|||
|
||||
try:
|
||||
with Image.open(filename) as i:
|
||||
params = ["magick", filename, "-strip", "-auto-orient"]
|
||||
params = ["magick", filename]
|
||||
if i.format.lower() != 'webp':
|
||||
params.extend(["-coalesce", "-quality", "88", "-define", "webp:method=5"])
|
||||
if trim and len(list(Iterator(i))) == 1:
|
||||
|
@ -158,14 +158,15 @@ def process_image(filename:str, v, resize=0, trim=False, uploader_id:Optional[in
|
|||
abort(415)
|
||||
return None
|
||||
|
||||
params.append(filename)
|
||||
try:
|
||||
subprocess.run(params, timeout=MAX_IMAGE_CONVERSION_TIMEOUT)
|
||||
except subprocess.TimeoutExpired:
|
||||
if has_request:
|
||||
abort(413, ("An uploaded image took too long to convert to WEBP. "
|
||||
"Consider uploading elsewhere."))
|
||||
return None
|
||||
if len(params) > 2:
|
||||
params.append(filename)
|
||||
try:
|
||||
subprocess.run(params, timeout=MAX_IMAGE_CONVERSION_TIMEOUT)
|
||||
except subprocess.TimeoutExpired:
|
||||
if has_request:
|
||||
abort(413, ("An uploaded image took too long to convert to WEBP. "
|
||||
"Consider uploading elsewhere."))
|
||||
return None
|
||||
|
||||
if resize:
|
||||
if os.stat(filename).st_size > MAX_IMAGE_SIZE_BANNER_RESIZED_KB * 1024:
|
||||
|
@ -216,4 +217,6 @@ def process_image(filename:str, v, resize=0, trim=False, uploader_id:Optional[in
|
|||
)
|
||||
db.add(media)
|
||||
|
||||
subprocess.run(["exiv2", "rm", filename], timeout=MAX_IMAGE_CONVERSION_TIMEOUT)
|
||||
|
||||
return filename
|
||||
|
|
|
@ -40,12 +40,11 @@ def offsite_mentions_task(cache:Cache):
|
|||
notify_mentions([send_user], user_mentions, mention_str='mention of you')
|
||||
|
||||
def get_mentions(cache:Cache, queries:Iterable[str], reddit_notifs_users=False):
|
||||
CACHE_KEY = 'reddit_notifications'
|
||||
kinds = ['submission', 'comment']
|
||||
mentions = []
|
||||
exclude_subreddits = ['PokemonGoRaids', 'SubSimulatorGPT2', 'SubSimGPT2Interactive']
|
||||
try:
|
||||
after = int(cache.get(CACHE_KEY) or time.time())
|
||||
after = int(cache.get(const.REDDIT_NOTIFS_CACHE_KEY) or time.time())
|
||||
except:
|
||||
print("Failed to retrieve last mention time from cache")
|
||||
after = time.time()
|
||||
|
|
|
@ -47,3 +47,4 @@ if FEATURES['ASSET_SUBMISSIONS']:
|
|||
from .asset_submissions import *
|
||||
if FEATURES['STREAMERS']:
|
||||
from .streamers import *
|
||||
from .special import *
|
||||
|
|
|
@ -508,21 +508,32 @@ def under_attack(v):
|
|||
g.db.add(ma)
|
||||
return {"message": f"Under attack mode {enable_disable_str}d!"}
|
||||
|
||||
def admin_badges_grantable_list(v):
|
||||
query = g.db.query(BadgeDef)
|
||||
if BADGE_BLACKLIST and v.id != AEVANN_ID and SITE != 'pcmemes.net':
|
||||
query = query.filter(BadgeDef.id.notin_(BADGE_BLACKLIST))
|
||||
if BADGE_WHITELIST:
|
||||
query = query.filter(BadgeDef.id.in_(BADGE_WHITELIST))
|
||||
badge_types = query.order_by(BadgeDef.id).all()
|
||||
return badge_types
|
||||
|
||||
@app.get("/admin/badge_grant")
|
||||
@app.get("/admin/badge_remove")
|
||||
@feature_required('BADGES')
|
||||
@admin_level_required(PERMS['USER_BADGES'])
|
||||
def badge_grant_get(v):
|
||||
grant = request.url.endswith("grant")
|
||||
badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
|
||||
return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=grant)
|
||||
badge_types = admin_badges_grantable_list(v)
|
||||
|
||||
return render_template("admin/badge_admin.html", v=v,
|
||||
badge_types=badge_types, grant=grant)
|
||||
|
||||
@app.post("/admin/badge_grant")
|
||||
@feature_required('BADGES')
|
||||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||
@admin_level_required(PERMS['USER_BADGES'])
|
||||
def badge_grant_post(v):
|
||||
badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
|
||||
badges = admin_badges_grantable_list(v)
|
||||
|
||||
user = get_user(request.values.get("username").strip(), graceful=True)
|
||||
if not user:
|
||||
|
@ -531,10 +542,7 @@ def badge_grant_post(v):
|
|||
try: badge_id = int(request.values.get("badge_id"))
|
||||
except: abort(400)
|
||||
|
||||
if SITE == 'watchpeopledie.tv' and badge_id not in {99,101}:
|
||||
abort(403)
|
||||
|
||||
if badge_id in {16,17,21,22,23,24,25,26,27,94,95,96,97,98,109,137,67,68,83,84,87,90,140} and v.id != AEVANN_ID and SITE != 'pcmemes.net':
|
||||
if badge_id not in [b.id for b in badges]:
|
||||
abort(403)
|
||||
|
||||
if user.has_badge(badge_id):
|
||||
|
@ -573,7 +581,7 @@ def badge_grant_post(v):
|
|||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||
@admin_level_required(PERMS['USER_BADGES'])
|
||||
def badge_remove_post(v):
|
||||
badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
|
||||
badges = admin_badges_grantable_list(v)
|
||||
|
||||
user = get_user(request.values.get("username").strip(), graceful=True)
|
||||
if not user:
|
||||
|
@ -582,7 +590,7 @@ def badge_remove_post(v):
|
|||
try: badge_id = int(request.values.get("badge_id"))
|
||||
except: abort(400)
|
||||
|
||||
if badge_id in {67,68,83,84,87,90,140} and v.id != AEVANN_ID and SITE != 'pcmemes.net':
|
||||
if badge_id not in [b.id for b in badges]:
|
||||
abort(403)
|
||||
|
||||
badge = user.has_badge(badge_id)
|
||||
|
@ -831,7 +839,7 @@ def admin_removed_comments(v):
|
|||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE).all()
|
||||
ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
|
||||
ids=[x[0] for x in ids]
|
||||
next_exists = len(ids) > PAGE_SIZE
|
||||
ids = ids[:PAGE_SIZE]
|
||||
|
|
|
@ -28,13 +28,10 @@ def before_request():
|
|||
|
||||
if ' firefox/' in ua:
|
||||
g.type = 'firefox'
|
||||
g.inferior_browser = True
|
||||
elif 'iphone' in ua or 'ipad' in ua or 'ipod' in ua or 'mac os' in ua:
|
||||
g.type = 'apple'
|
||||
g.inferior_browser = True
|
||||
else:
|
||||
g.type = 'chromium'
|
||||
g.inferior_browser = False
|
||||
|
||||
g.is_tor = request.headers.get("cf-ipcountry") == "T1"
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ from files.helpers.const import *
|
|||
from files.helpers.get import *
|
||||
from files.helpers.media import *
|
||||
from files.helpers.useractions import *
|
||||
from files.routes.static import marsey_list
|
||||
from files.routes.wrappers import *
|
||||
from files.__main__ import app, cache, limiter
|
||||
|
||||
|
@ -29,7 +28,7 @@ def asset_submissions(path):
|
|||
|
||||
@app.get("/submit/marseys")
|
||||
@auth_required
|
||||
def submit_marseys(v):
|
||||
def submit_marseys(v:User):
|
||||
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_MARSEYS']:
|
||||
marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
|
||||
else:
|
||||
|
@ -44,7 +43,7 @@ def submit_marseys(v):
|
|||
|
||||
@app.post("/submit/marseys")
|
||||
@auth_required
|
||||
def submit_marsey(v):
|
||||
def submit_marsey(v:User):
|
||||
file = request.files["image"]
|
||||
name = request.values.get('name', '').lower().strip()
|
||||
tags = request.values.get('tags', '').lower().strip()
|
||||
|
@ -145,7 +144,8 @@ def approve_marsey(v, name):
|
|||
else:
|
||||
badge_grant(badge_id=17, user=author)
|
||||
purge_files_in_cache(f"https://{SITE}/e/{marsey.name}/webp")
|
||||
cache.delete_memoized(marsey_list)
|
||||
cache.delete(EMOJIS_CACHE_KEY)
|
||||
cache.delete(MARSEYS_CACHE_KEY)
|
||||
move(f"/asset_submissions/marseys/{name}.webp", f"files/assets/images/emojis/{marsey.name}.webp")
|
||||
|
||||
highquality = f"/asset_submissions/marseys/{name}"
|
||||
|
@ -195,12 +195,12 @@ def remove_asset(cls, type_name:str, v:User, name:str) -> dict[str, str]:
|
|||
|
||||
@app.post("/remove/marsey/<name>")
|
||||
@auth_required
|
||||
def remove_marsey(v, name):
|
||||
def remove_marsey(v:User, name):
|
||||
return remove_asset(Marsey, "marsey", v, name)
|
||||
|
||||
@app.get("/submit/hats")
|
||||
@auth_required
|
||||
def submit_hats(v):
|
||||
def submit_hats(v:User):
|
||||
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_HATS']: hats = g.db.query(HatDef).filter(HatDef.submitter_id != None).all()
|
||||
else: hats = g.db.query(HatDef).filter(HatDef.submitter_id == v.id).all()
|
||||
return render_template("submit_hats.html", v=v, hats=hats)
|
||||
|
@ -208,7 +208,7 @@ def submit_hats(v):
|
|||
|
||||
@app.post("/submit/hats")
|
||||
@auth_required
|
||||
def submit_hat(v):
|
||||
def submit_hat(v:User):
|
||||
name = request.values.get('name', '').strip()
|
||||
description = request.values.get('description', '').strip()
|
||||
username = request.values.get('author', '').strip()
|
||||
|
@ -328,7 +328,7 @@ def approve_hat(v, name):
|
|||
|
||||
@app.post("/remove/hat/<name>")
|
||||
@auth_required
|
||||
def remove_hat(v, name):
|
||||
def remove_hat(v:User, name):
|
||||
return remove_asset(HatDef, 'hat', v, name)
|
||||
|
||||
@app.get("/admin/update/marseys")
|
||||
|
|
|
@ -22,7 +22,7 @@ from .front import frontlist
|
|||
@app.get("/shop")
|
||||
@app.get("/settings/shop")
|
||||
@auth_required
|
||||
def shop(v):
|
||||
def shop(v:User):
|
||||
AWARDS = deepcopy(AWARDS2)
|
||||
|
||||
if v.house:
|
||||
|
@ -46,7 +46,7 @@ def shop(v):
|
|||
@app.post("/buy/<award>")
|
||||
@limiter.limit("100/minute;200/hour;1000/day")
|
||||
@auth_required
|
||||
def buy(v, award):
|
||||
def buy(v:User, award):
|
||||
if award == 'benefactor' and not request.values.get("mb"):
|
||||
abort(403, "You can only buy the Benefactor award with marseybux.")
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ from files.__main__ import app, limiter
|
|||
@app.get("/casino")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def casino(v):
|
||||
def casino(v:User):
|
||||
if v.rehab:
|
||||
return render_template("casino/rehab.html", v=v), 403
|
||||
|
||||
|
@ -24,7 +24,7 @@ def casino(v):
|
|||
@app.get("/casino/<game>")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def casino_game_page(v, game):
|
||||
def casino_game_page(v:User, game):
|
||||
if v.rehab:
|
||||
return render_template("casino/rehab.html", v=v), 403
|
||||
elif game not in CASINO_GAME_KINDS:
|
||||
|
@ -53,7 +53,7 @@ def casino_game_page(v, game):
|
|||
@app.get("/casino/<game>/feed")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def casino_game_feed(v, game):
|
||||
def casino_game_feed(v:User, game):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
elif game not in CASINO_GAME_KINDS:
|
||||
|
@ -67,7 +67,7 @@ def casino_game_feed(v, game):
|
|||
@app.get("/lottershe")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def lottershe(v):
|
||||
def lottershe(v:User):
|
||||
if v.rehab:
|
||||
return render_template("casino/rehab.html", v=v)
|
||||
|
||||
|
@ -78,7 +78,7 @@ def lottershe(v):
|
|||
@app.post("/casino/slots")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def pull_slots(v):
|
||||
def pull_slots(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -109,7 +109,7 @@ def pull_slots(v):
|
|||
@app.post("/casino/twentyone/deal")
|
||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def blackjack_deal_to_player(v):
|
||||
def blackjack_deal_to_player(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -128,7 +128,7 @@ def blackjack_deal_to_player(v):
|
|||
@app.post("/casino/twentyone/hit")
|
||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def blackjack_player_hit(v):
|
||||
def blackjack_player_hit(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -143,7 +143,7 @@ def blackjack_player_hit(v):
|
|||
@app.post("/casino/twentyone/stay")
|
||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def blackjack_player_stay(v):
|
||||
def blackjack_player_stay(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -158,7 +158,7 @@ def blackjack_player_stay(v):
|
|||
@app.post("/casino/twentyone/double-down")
|
||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def blackjack_player_doubled_down(v):
|
||||
def blackjack_player_doubled_down(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -173,7 +173,7 @@ def blackjack_player_doubled_down(v):
|
|||
@app.post("/casino/twentyone/buy-insurance")
|
||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def blackjack_player_bought_insurance(v):
|
||||
def blackjack_player_bought_insurance(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -188,7 +188,7 @@ def blackjack_player_bought_insurance(v):
|
|||
@app.get("/casino/roulette/bets")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def roulette_get_bets(v):
|
||||
def roulette_get_bets(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
@ -200,7 +200,7 @@ def roulette_get_bets(v):
|
|||
@app.post("/casino/roulette/place-bet")
|
||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||
@auth_required
|
||||
def roulette_player_placed_bet(v):
|
||||
def roulette_player_placed_bet(v:User):
|
||||
if v.rehab:
|
||||
abort(403, "You are under Rehab award effect!")
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
|
|||
else: template = "submission.html"
|
||||
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
|
||||
|
||||
#- API
|
||||
@app.post("/comment")
|
||||
@limiter.limit("1/second;20/minute;200/hour;1000/day")
|
||||
@auth_required
|
||||
|
@ -91,7 +92,7 @@ def comment(v):
|
|||
id = parent_fullname[2:]
|
||||
parent_comment_id = None
|
||||
rts = False
|
||||
|
||||
|
||||
if parent_fullname.startswith("p_"):
|
||||
parent = get_post(id, v=v)
|
||||
parent_post = parent
|
||||
|
|
|
@ -27,7 +27,7 @@ def feeds_user(sort='hot', t='all'):
|
|||
|
||||
doc, tag, text = Doc().tagtext()
|
||||
|
||||
with tag("feed", ("xmlns:media","http://search.yahoo.com/mrss/"), xmlns="http://www.w3.org/2005/Atom",):
|
||||
with tag("feed", ("xmlns:media","https://search.yahoo.com/mrss/"), xmlns="https://www.w3.org/2005/Atom",):
|
||||
with tag("title", type="text"):
|
||||
text(f"{sort} posts from {SITE}")
|
||||
|
||||
|
|
|
@ -16,31 +16,6 @@ from files.__main__ import app, cache, limiter
|
|||
@limiter.limit("3/second;30/minute;5000/hour;10000/day")
|
||||
@auth_desired_with_logingate
|
||||
def front_all(v, sub=None, subdomain=None):
|
||||
#### WPD TEMP #### special front logic
|
||||
from datetime import datetime
|
||||
|
||||
from files.helpers.security import generate_hash, validate_hash
|
||||
now = datetime.utcnow()
|
||||
if SITE == 'watchpeopledie.co':
|
||||
if v and not v.admin_level and not v.id <= 9: # security: don't auto login admins or bots
|
||||
hash = generate_hash(f'{v.id}+{now.year}+{now.month}+{now.day}+{now.hour}+WPDusermigration')
|
||||
return redirect(f'https://watchpeopledie.tv/?user={v.id}&code={hash}', 301)
|
||||
else:
|
||||
return redirect('https://watchpeopledie.tv/', 301)
|
||||
elif SITE == 'watchpeopledie.tv' and not v: # security: don't try to login people into accounts more than once
|
||||
req_user = request.values.get('user')
|
||||
req_code = request.values.get('code')
|
||||
if req_user and req_code:
|
||||
from files.routes.login import on_login
|
||||
user = get_account(req_user, graceful=True)
|
||||
if user:
|
||||
if user.admin_level or user.id <= 9:
|
||||
abort(401)
|
||||
else:
|
||||
if validate_hash(f'{user.id}+{now.year}+{now.month}+{now.day}+{now.hour}+WPDusermigration', req_code):
|
||||
on_login(user)
|
||||
return redirect('/')
|
||||
#### WPD TEMP #### end special front logic
|
||||
if sub:
|
||||
sub = get_sub_by_name(sub, graceful=True)
|
||||
if sub and not User.can_see(v, sub): abort(403, "You need 5000 truescore to be able to see /h/chudrama")
|
||||
|
@ -179,7 +154,7 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
|
|||
|
||||
@app.get("/random_post")
|
||||
@auth_required
|
||||
def random_post(v):
|
||||
def random_post(v:User):
|
||||
|
||||
p = g.db.query(Submission.id).filter(Submission.deleted_utc == 0, Submission.is_banned == False, Submission.private == False).order_by(func.random()).first()
|
||||
|
||||
|
@ -191,18 +166,18 @@ def random_post(v):
|
|||
|
||||
@app.get("/random_user")
|
||||
@auth_required
|
||||
def random_user(v):
|
||||
def random_user(v:User):
|
||||
u = g.db.query(User.username).filter(User.song != None, User.shadowbanned == None).order_by(func.random()).first()
|
||||
|
||||
if u: u = u[0]
|
||||
else: return "No users have set a profile anthem so far!"
|
||||
else: abort(404, "No users have set a profile anthem so far!")
|
||||
|
||||
return redirect(f"/@{u}")
|
||||
|
||||
|
||||
@app.get("/comments")
|
||||
@auth_required
|
||||
def all_comments(v):
|
||||
def all_comments(v:User):
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ from files.__main__ import app, limiter
|
|||
|
||||
@app.get("/hats")
|
||||
@auth_required
|
||||
def hats(v):
|
||||
def hats(v:User):
|
||||
owned_hat_ids = [x.hat_id for x in v.owned_hats]
|
||||
|
||||
if request.values.get("sort") == 'author_asc':
|
||||
|
@ -34,7 +34,7 @@ def hats(v):
|
|||
@app.post("/buy_hat/<hat_id>")
|
||||
@limiter.limit('100/minute;1000/3 days')
|
||||
@auth_required
|
||||
def buy_hat(v, hat_id):
|
||||
def buy_hat(v:User, hat_id):
|
||||
try: hat_id = int(hat_id)
|
||||
except: abort(404, "Hat not found!")
|
||||
|
||||
|
@ -84,7 +84,7 @@ def buy_hat(v, hat_id):
|
|||
|
||||
@app.post("/equip_hat/<hat_id>")
|
||||
@auth_required
|
||||
def equip_hat(v, hat_id):
|
||||
def equip_hat(v:User, hat_id):
|
||||
try: hat_id = int(hat_id)
|
||||
except: abort(404, "Hat not found!")
|
||||
|
||||
|
@ -98,7 +98,7 @@ def equip_hat(v, hat_id):
|
|||
|
||||
@app.post("/unequip_hat/<hat_id>")
|
||||
@auth_required
|
||||
def unequip_hat(v, hat_id):
|
||||
def unequip_hat(v:User, hat_id):
|
||||
try: hat_id = int(hat_id)
|
||||
except: abort(404, "Hat not found!")
|
||||
|
||||
|
@ -112,7 +112,7 @@ def unequip_hat(v, hat_id):
|
|||
|
||||
@app.get("/hat_owners/<hat_id>")
|
||||
@auth_required
|
||||
def hat_owners(v, hat_id):
|
||||
def hat_owners(v:User, hat_id):
|
||||
try: hat_id = int(hat_id)
|
||||
except: abort(404, "Hat not found!")
|
||||
|
||||
|
|
|
@ -59,12 +59,10 @@ def inject_constants():
|
|||
"site_settings":get_settings(), "EMAIL":EMAIL, "calc_users":calc_users,
|
||||
"max": max, "min": min, "user_can_see":User.can_see,
|
||||
"TELEGRAM_LINK":TELEGRAM_LINK, "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN,
|
||||
"CONTENT_SECURITY_POLICY_DEFAULT":CONTENT_SECURITY_POLICY_DEFAULT,
|
||||
"CONTENT_SECURITY_POLICY_HOME":CONTENT_SECURITY_POLICY_HOME,
|
||||
"TRUESCORE_DONATE_MINIMUM":TRUESCORE_DONATE_MINIMUM,
|
||||
"DONATE_LINK":DONATE_LINK, "DONATE_SERVICE":DONATE_SERVICE, "BAN_EVASION_DOMAIN":BAN_EVASION_DOMAIN,
|
||||
"HOUSE_JOIN_COST":HOUSE_JOIN_COST, "HOUSE_SWITCH_COST":HOUSE_SWITCH_COST, "IMAGE_FORMATS":IMAGE_FORMATS,
|
||||
"PAGE_SIZES":PAGE_SIZES, "THEMES":THEMES, "COMMENT_SORTS":COMMENT_SORTS, "SORTS":SORTS,
|
||||
"TIME_FILTERS":TIME_FILTERS, "HOUSES":HOUSES, "TIERS_ID_TO_NAME":TIERS_ID_TO_NAME,
|
||||
"DEFAULT_CONFIG_VALUE":DEFAULT_CONFIG_VALUE, "IS_LOCALHOST":IS_LOCALHOST,
|
||||
"DEFAULT_CONFIG_VALUE":DEFAULT_CONFIG_VALUE, "IS_LOCALHOST":IS_LOCALHOST, "BACKGROUND_CATEGORIES":BACKGROUND_CATEGORIES, "PAGE_SIZE":PAGE_SIZE,
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ NO_LOGIN_REDIRECT_URLS = ("/login", "/logout", "/signup", "/forgot", "/reset", "
|
|||
|
||||
@app.get("/login")
|
||||
@auth_desired
|
||||
def login_get(v):
|
||||
def login_get(v:Optional[User]):
|
||||
redir = request.values.get("redirect", "/").strip().rstrip('?').lower()
|
||||
if redir:
|
||||
if not is_site_url(redir) or redir in NO_LOGIN_REDIRECT_URLS:
|
||||
|
@ -52,7 +52,7 @@ def login_post():
|
|||
|
||||
if "@" in username:
|
||||
try: account = g.db.query(User).filter(User.email.ilike(username)).one_or_none()
|
||||
except: return "Multiple users use this email!"
|
||||
except: abort(400, "Multiple usernames have this email attached;<br>Please specify the username you want to login to!")
|
||||
else: account = get_user(username, graceful=True)
|
||||
|
||||
if not account:
|
||||
|
@ -131,7 +131,7 @@ def on_login(account, redir=None):
|
|||
@app.get("/me")
|
||||
@app.get("/@me")
|
||||
@auth_required
|
||||
def me(v):
|
||||
def me(v:User):
|
||||
if v.client: return v.json
|
||||
else: return redirect(v.url)
|
||||
|
||||
|
@ -149,7 +149,7 @@ def logout(v):
|
|||
|
||||
@app.get("/signup")
|
||||
@auth_desired
|
||||
def sign_up_get(v):
|
||||
def sign_up_get(v:Optional[User]):
|
||||
if not get_setting('Signups'):
|
||||
abort(403, "New account registration is currently closed. Please come back later.")
|
||||
|
||||
|
@ -199,7 +199,7 @@ def sign_up_get(v):
|
|||
@app.post("/signup")
|
||||
@limiter.limit("1/second;10/day")
|
||||
@auth_desired
|
||||
def sign_up_post(v):
|
||||
def sign_up_post(v:Optional[User]):
|
||||
if not get_setting('Signups'):
|
||||
abort(403, "New account registration is currently closed. Please come back later.")
|
||||
|
||||
|
@ -235,6 +235,7 @@ def sign_up_post(v):
|
|||
return signup_error("There was a problem. Please try again.")
|
||||
|
||||
if not hmac.compare_digest(correct_formkey, form_formkey):
|
||||
if SITE == 'localhost': return signup_error("There was a problem. Please try again!")
|
||||
return signup_error("There was a problem. Please try again.")
|
||||
|
||||
if not request.values.get(
|
||||
|
@ -416,7 +417,7 @@ def get_reset():
|
|||
@app.post("/reset")
|
||||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||
@auth_desired
|
||||
def post_reset(v):
|
||||
def post_reset(v:Optional[User]):
|
||||
if v: return redirect('/')
|
||||
user_id = request.values.get("user_id")
|
||||
timestamp = 0
|
||||
|
@ -454,7 +455,7 @@ def post_reset(v):
|
|||
|
||||
@app.get("/lost_2fa")
|
||||
@auth_desired
|
||||
def lost_2fa(v):
|
||||
def lost_2fa(v:Optional[User]):
|
||||
if v and not v.mfa_secret: abort(400, "You don't have 2FA enabled")
|
||||
return render_template("login/lost_2fa.html", v=v)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ def lottery_start(v):
|
|||
@app.post("/lottery/buy")
|
||||
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
||||
@auth_required
|
||||
def lottery_buy(v):
|
||||
def lottery_buy(v:User):
|
||||
try: quantity = int(request.values.get("quantity"))
|
||||
except: abort(400, "Invalid ticket quantity.")
|
||||
|
||||
|
@ -40,7 +40,7 @@ def lottery_buy(v):
|
|||
@app.get("/lottery/active")
|
||||
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
||||
@auth_required
|
||||
def lottery_active(v):
|
||||
def lottery_active(v:User):
|
||||
lottery, participants = get_active_lottery_stats()
|
||||
|
||||
return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
|
||||
|
|
|
@ -19,7 +19,7 @@ def verify_email(v):
|
|||
|
||||
@app.get("/activate")
|
||||
@auth_required
|
||||
def activate(v):
|
||||
def activate(v:User):
|
||||
email = request.values.get("email", "").strip().lower()
|
||||
|
||||
if not email_regex.fullmatch(email):
|
||||
|
@ -38,7 +38,7 @@ def activate(v):
|
|||
abort(403)
|
||||
|
||||
if user.is_activated and user.email == email:
|
||||
return render_template("message_success.html", v=v, title="Email already verified.", message="Email already verified."), 404
|
||||
abort(400, "Email already verified!")
|
||||
|
||||
user.email = email
|
||||
user.is_activated = True
|
||||
|
|
|
@ -68,7 +68,7 @@ def notifications_modmail(v):
|
|||
|
||||
@app.get("/notifications/messages")
|
||||
@auth_required
|
||||
def notifications_messages(v):
|
||||
def notifications_messages(v:User):
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
||||
|
@ -137,7 +137,7 @@ def notifications_messages(v):
|
|||
|
||||
@app.get("/notifications/posts")
|
||||
@auth_required
|
||||
def notifications_posts(v):
|
||||
def notifications_posts(v:User):
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
||||
|
@ -179,7 +179,7 @@ def notifications_posts(v):
|
|||
|
||||
@app.get("/notifications/modactions")
|
||||
@auth_required
|
||||
def notifications_modactions(v):
|
||||
def notifications_modactions(v:User):
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
||||
|
@ -218,7 +218,7 @@ def notifications_modactions(v):
|
|||
|
||||
@app.get("/notifications/reddit")
|
||||
@auth_required
|
||||
def notifications_reddit(v):
|
||||
def notifications_reddit(v:User):
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
||||
|
@ -263,7 +263,7 @@ def notifications_reddit(v):
|
|||
|
||||
@app.get("/notifications")
|
||||
@auth_required
|
||||
def notifications(v):
|
||||
def notifications(v:User):
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ from files.__main__ import app, limiter
|
|||
|
||||
@app.get("/authorize")
|
||||
@auth_required
|
||||
def authorize_prompt(v):
|
||||
def authorize_prompt(v:User):
|
||||
client_id = request.values.get("client_id")
|
||||
application = g.db.query(OauthApp).filter_by(client_id=client_id).one_or_none()
|
||||
if not application: return {"oauth_error": "Invalid `client_id`"}, 401
|
||||
|
|
|
@ -123,7 +123,7 @@ def publish(pid, v):
|
|||
@app.get("/submit")
|
||||
@app.get("/h/<sub>/submit")
|
||||
@auth_required
|
||||
def submit_get(v, sub=None):
|
||||
def submit_get(v:User, sub=None):
|
||||
sub = get_sub_by_name(sub, graceful=True)
|
||||
if request.path.startswith('/h/') and not sub: abort(404)
|
||||
|
||||
|
@ -155,13 +155,13 @@ def post_id(pid, anything=None, v=None, sub=None):
|
|||
# shadowban check is done in sort_objects
|
||||
# output is needed: see comments.py
|
||||
comments, output = get_comments_v_properties(v, True, None, Comment.parent_submission == post.id, Comment.level < 10)
|
||||
pinned = [c[0] for c in comments.filter(Comment.stickied != None).all()]
|
||||
pinned = [c[0] for c in comments.filter(Comment.stickied != None).order_by(Comment.created_utc.desc()).all()]
|
||||
comments = comments.filter(Comment.level == 1, Comment.stickied == None)
|
||||
comments = sort_objects(sort, comments, Comment,
|
||||
include_shadowbanned=(v and v.can_see_shadowbanned))
|
||||
comments = [c[0] for c in comments.all()]
|
||||
else:
|
||||
pinned = g.db.query(Comment).filter(Comment.parent_submission == post.id, Comment.stickied != None).all()
|
||||
pinned = g.db.query(Comment).filter(Comment.parent_submission == post.id, Comment.stickied != None).order_by(Comment.created_utc.desc()).all()
|
||||
|
||||
comments = g.db.query(Comment).filter(
|
||||
Comment.parent_submission == post.id,
|
||||
|
@ -199,21 +199,20 @@ def post_id(pid, anything=None, v=None, sub=None):
|
|||
else: offset = 1
|
||||
comments = comments2
|
||||
|
||||
pinned2 = set()
|
||||
pinned2 = {}
|
||||
for pin in pinned:
|
||||
if pin.stickied_utc and int(time.time()) > pin.stickied_utc:
|
||||
pin.stickied = None
|
||||
pin.stickied_utc = None
|
||||
g.db.add(pin)
|
||||
elif pin.level > 1:
|
||||
pinned2.add(pin.top_comment(g.db))
|
||||
pinned2[pin.top_comment(g.db)] = ''
|
||||
if pin.top_comment(g.db) in comments:
|
||||
comments.remove(pin.top_comment(g.db))
|
||||
else:
|
||||
pinned2.add(pin)
|
||||
pinned2[pin] = ''
|
||||
|
||||
pinned = list(pinned2)
|
||||
post.replies = pinned + comments
|
||||
post.replies = list(pinned2.keys()) + comments
|
||||
|
||||
post.views += 1
|
||||
g.db.add(post)
|
||||
|
@ -604,7 +603,7 @@ def is_repost():
|
|||
@limiter.limit(POST_RATE_LIMIT)
|
||||
@limiter.limit(POST_RATE_LIMIT, key_func=lambda:f'{SITE}-{session.get("lo_user")}')
|
||||
@auth_required
|
||||
def submit_post(v, sub=None):
|
||||
def submit_post(v:User, sub=None):
|
||||
|
||||
url = request.values.get("url", "").strip()
|
||||
|
||||
|
@ -923,6 +922,10 @@ def submit_post(v, sub=None):
|
|||
|
||||
execute_lawlz_actions(v, post)
|
||||
|
||||
if SITE == 'rdrama.net' and v.id in (IMPASSIONATA_ID, PIZZASHILL_ID, 2008):
|
||||
post.stickied_utc = int(time.time()) + 3600
|
||||
post.stickied = AUTOJANNY_ID
|
||||
|
||||
cache.delete_memoized(frontlist)
|
||||
cache.delete_memoized(userpagelisting)
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ def searchparse(text):
|
|||
|
||||
@app.get("/search/posts")
|
||||
@auth_required
|
||||
def searchposts(v):
|
||||
def searchposts(v:User):
|
||||
|
||||
query = request.values.get("q", '').strip()
|
||||
|
||||
|
@ -181,7 +181,7 @@ def searchposts(v):
|
|||
|
||||
@app.get("/search/comments")
|
||||
@auth_required
|
||||
def searchcomments(v):
|
||||
def searchcomments(v:User):
|
||||
query = request.values.get("q", '').strip()
|
||||
|
||||
try: page = max(1, int(request.values.get("page", 1)))
|
||||
|
@ -276,7 +276,7 @@ def searchcomments(v):
|
|||
|
||||
@app.get("/search/users")
|
||||
@auth_required
|
||||
def searchusers(v):
|
||||
def searchusers(v:User):
|
||||
|
||||
query = request.values.get("q", '').strip()
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@ from files.__main__ import app, cache, limiter
|
|||
|
||||
@app.get("/settings")
|
||||
@auth_required
|
||||
def settings(v):
|
||||
def settings(v:User):
|
||||
return redirect("/settings/personal")
|
||||
|
||||
@app.get("/settings/personal")
|
||||
@auth_required
|
||||
def settings_personal(v):
|
||||
def settings_personal(v:User):
|
||||
return render_template("settings/personal.html", v=v)
|
||||
|
||||
@app.delete('/settings/background')
|
||||
|
@ -41,6 +41,7 @@ def settings_personal(v):
|
|||
def remove_background(v):
|
||||
if v.background:
|
||||
v.background = None
|
||||
if v.theme == 'transparent': v.theme = 'midnight'
|
||||
g.db.add(v)
|
||||
return {"message": "Background removed!"}
|
||||
|
||||
|
@ -91,7 +92,7 @@ def settings_personal_post(v):
|
|||
|
||||
background = request.values.get("background", v.background)
|
||||
if background != v.background and background.endswith(".webp") and len(background) <= 20:
|
||||
v.background = request.values.get("background")
|
||||
v.background = request.values.get("background").replace('.webp', '')
|
||||
updated = True
|
||||
elif request.values.get("reddit", v.reddit) != v.reddit:
|
||||
reddit = request.values.get("reddit")
|
||||
|
@ -301,7 +302,7 @@ def settings_personal_post(v):
|
|||
|
||||
@app.post("/settings/filters")
|
||||
@auth_required
|
||||
def filters(v):
|
||||
def filters(v:User):
|
||||
filters=request.values.get("filters")[:1000].strip()
|
||||
|
||||
if filters == v.custom_filter_list:
|
||||
|
@ -540,7 +541,7 @@ def settings_images_banner(v):
|
|||
|
||||
@app.get("/settings/css")
|
||||
@auth_required
|
||||
def settings_css_get(v):
|
||||
def settings_css_get(v:User):
|
||||
return render_template("settings/css.html", v=v)
|
||||
|
||||
@app.post("/settings/css")
|
||||
|
@ -572,7 +573,7 @@ def settings_profilecss(v):
|
|||
|
||||
@app.get("/settings/security")
|
||||
@auth_required
|
||||
def settings_security(v):
|
||||
def settings_security(v:User):
|
||||
return render_template("settings/security.html",
|
||||
v=v,
|
||||
mfa_secret=pyotp.random_base32() if not v.mfa_secret else None,
|
||||
|
@ -622,12 +623,12 @@ def settings_unblock_user(v):
|
|||
|
||||
@app.get("/settings/apps")
|
||||
@auth_required
|
||||
def settings_apps(v):
|
||||
def settings_apps(v:User):
|
||||
return render_template("settings/apps.html", v=v)
|
||||
|
||||
@app.get("/settings/advanced")
|
||||
@auth_required
|
||||
def settings_advanced_get(v):
|
||||
def settings_advanced_get(v:User):
|
||||
return render_template("settings/advanced.html", v=v)
|
||||
|
||||
@app.post("/settings/name_change")
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
from flask import g, jsonify, render_template
|
||||
from files.helpers.get import get_accounts_dict
|
||||
|
||||
from files.routes.wrappers import auth_required
|
||||
from files.__main__ import app, cache
|
||||
|
||||
_special_leaderboard_query = """
|
||||
WITH bet_options AS (
|
||||
SELECT p.id AS submission_id, so.id AS option_id, so.exclusive, cnt.count
|
||||
FROM submission_options so
|
||||
JOIN submissions p ON so.submission_id = p.id
|
||||
JOIN (
|
||||
SELECT option_id, COUNT(*) FROM submission_option_votes
|
||||
GROUP BY option_id
|
||||
) AS cnt ON so.id = cnt.option_id
|
||||
WHERE p.author_id = 30 AND p.created_utc > 1668953400
|
||||
AND so.exclusive IN (2, 3)
|
||||
),
|
||||
submission_payouts AS (
|
||||
SELECT
|
||||
sq_total.submission_id,
|
||||
sq_winners.sum AS bettors,
|
||||
floor((sq_total.sum * 200) / sq_winners.sum) AS winner_payout
|
||||
FROM (
|
||||
SELECT submission_id, SUM(count)
|
||||
FROM bet_options GROUP BY submission_id
|
||||
) AS sq_total
|
||||
JOIN (
|
||||
SELECT submission_id, SUM(count)
|
||||
FROM bet_options WHERE exclusive = 3 GROUP BY submission_id
|
||||
) AS sq_winners ON sq_total.submission_id = sq_winners.submission_id
|
||||
),
|
||||
bet_votes AS (
|
||||
SELECT
|
||||
opt.option_id AS option_id,
|
||||
opt.exclusive,
|
||||
sov.user_id,
|
||||
CASE
|
||||
WHEN opt.exclusive = 2 THEN -200
|
||||
WHEN opt.exclusive = 3 THEN (submission_payouts.winner_payout - 200)
|
||||
END payout
|
||||
FROM submission_option_votes sov
|
||||
LEFT OUTER JOIN bet_options AS opt
|
||||
ON opt.option_id = sov.option_id
|
||||
LEFT OUTER JOIN submission_payouts
|
||||
ON opt.submission_id = submission_payouts.submission_id
|
||||
WHERE opt.option_id IS NOT NULL
|
||||
),
|
||||
bettors AS (
|
||||
SELECT
|
||||
COALESCE(bet_won.user_id, bet_lost.user_id) AS user_id,
|
||||
(COALESCE(bet_won.count_won, 0)
|
||||
+ COALESCE(bet_lost.count_lost, 0)) AS bets_total,
|
||||
COALESCE(bet_won.count_won, 0) AS bets_won
|
||||
FROM (
|
||||
SELECT user_id, COUNT(*) AS count_won FROM bet_votes
|
||||
WHERE exclusive = 3 GROUP BY user_id) AS bet_won
|
||||
FULL OUTER JOIN (
|
||||
SELECT user_id, COUNT(*) AS count_lost FROM bet_votes
|
||||
WHERE exclusive = 2 GROUP BY user_id
|
||||
) AS bet_lost ON bet_won.user_id = bet_lost.user_id
|
||||
)
|
||||
SELECT
|
||||
bettors.user_id,
|
||||
bettors.bets_won,
|
||||
bettors.bets_total,
|
||||
bet_payout.net AS payout
|
||||
FROM bettors
|
||||
LEFT OUTER JOIN (
|
||||
SELECT user_id, SUM(payout) AS net FROM bet_votes GROUP BY user_id
|
||||
) AS bet_payout ON bettors.user_id = bet_payout.user_id
|
||||
ORDER BY payout DESC, bets_won DESC, bets_total ASC;
|
||||
"""
|
||||
|
||||
@cache.memoize(timeout=60)
|
||||
def _special_leaderboard_get():
|
||||
result = g.db.execute(_special_leaderboard_query).all()
|
||||
return result
|
||||
|
||||
@app.get('/events/worldcup2022/leaderboard')
|
||||
@app.get('/special/worldcup2022/leaderboard')
|
||||
@auth_required
|
||||
def get_leaderboard(v):
|
||||
result = _special_leaderboard_get()
|
||||
if g.is_api_or_xhr: return jsonify(result)
|
||||
users = get_accounts_dict([r[0] for r in result],
|
||||
v=v, include_shadowbanned=False)
|
||||
return render_template("special/worldcup22_leaderboard.html",
|
||||
v=v, result=result, users=users)
|
|
@ -22,65 +22,67 @@ def rdrama(id, title):
|
|||
id = ''.join(f'{x}/' for x in id)
|
||||
return redirect(f'/archives/drama/comments/{id}{title}.html')
|
||||
|
||||
@app.get("/r/<subreddit>")
|
||||
@auth_desired
|
||||
def subreddit(subreddit, v):
|
||||
reddit = v.reddit if v else "old.reddit.com"
|
||||
return redirect(f'https://{reddit}/r/{subreddit}')
|
||||
|
||||
@app.get("/reddit/<subreddit>/comments/<path:path>")
|
||||
@app.get("/r/<subreddit>/comments/<path:path>")
|
||||
@auth_desired
|
||||
def reddit_post(subreddit, v, path):
|
||||
post_id = path.rsplit("/", 1)[0].replace('/', '')
|
||||
reddit = v.reddit if v else "old.reddit.com"
|
||||
return redirect(f'https://{reddit}/{post_id}')
|
||||
|
||||
|
||||
@app.get("/marseys")
|
||||
@auth_required
|
||||
def marseys(v):
|
||||
if SITE == 'rdrama.net':
|
||||
marseys = g.db.query(Marsey, User).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id==None)
|
||||
sort = request.values.get("sort", "usage")
|
||||
if sort == "usage":
|
||||
marseys = marseys.order_by(Marsey.count.desc(), User.username).all()
|
||||
elif sort == "added":
|
||||
marseys = marseys.order_by(nullslast(Marsey.created_utc.desc()), User.username).all()
|
||||
else: # implied sort == "author"
|
||||
marseys = marseys.order_by(User.username, Marsey.count.desc()).all()
|
||||
|
||||
original = os.listdir("/asset_submissions/marseys/original")
|
||||
for marsey, user in marseys:
|
||||
for x in IMAGE_FORMATS:
|
||||
if f'{marsey.name}.{x}' in original:
|
||||
marsey.og = f'{marsey.name}.{x}'
|
||||
break
|
||||
else:
|
||||
marseys = g.db.query(Marsey).filter(Marsey.submitter_id==None).order_by(Marsey.count.desc())
|
||||
def marseys(v:User):
|
||||
|
||||
marseys = get_marseys(g.db)
|
||||
authors = get_accounts_dict([m.author_id for m in marseys], v=v, graceful=True, include_shadowbanned=False)
|
||||
original = os.listdir("/asset_submissions/marseys/original")
|
||||
for marsey in marseys:
|
||||
marsey.user = authors.get(marsey.author_id)
|
||||
for x in IMAGE_FORMATS:
|
||||
if f'{marsey.name}.{x}' in original:
|
||||
marsey.og = f'{marsey.name}.{x}'
|
||||
break
|
||||
return render_template("marseys.html", v=v, marseys=marseys)
|
||||
|
||||
@app.get("/marsey_list.json")
|
||||
@cache.memoize(timeout=600)
|
||||
def marsey_list():
|
||||
emojis = []
|
||||
@app.get("/emojis")
|
||||
def emoji_list():
|
||||
return jsonify(get_emojis(g.db))
|
||||
|
||||
# From database
|
||||
if EMOJI_MARSEYS:
|
||||
emojis = [{
|
||||
"name": emoji.name,
|
||||
"author": author if SITE == 'rdrama.net' or author == "anton-d" else None,
|
||||
# yikes, I don't really like this DB schema. Next time be better
|
||||
"tags": emoji.tags.split(" ") + [emoji.name[len("marsey"):] \
|
||||
if emoji.name.startswith("marsey") else emoji.name],
|
||||
"count": emoji.count,
|
||||
"class": "Marsey"
|
||||
} for emoji, author in g.db.query(Marsey, User.username).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id==None) \
|
||||
.order_by(Marsey.count.desc())]
|
||||
@cache.cached(timeout=86400, key_prefix=MARSEYS_CACHE_KEY)
|
||||
def get_marseys(db:scoped_session):
|
||||
if not FEATURES['MARSEYS']: return []
|
||||
marseys = []
|
||||
for marsey, author in db.query(Marsey, User).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id == None).order_by(Marsey.count.desc()):
|
||||
marsey.author = author.username if FEATURES['ASSET_SUBMISSIONS'] else None
|
||||
setattr(marsey, "class", "Marsey")
|
||||
marseys.append(marsey)
|
||||
return marseys
|
||||
|
||||
# Static shit
|
||||
@cache.cached(timeout=600, key_prefix=EMOJIS_CACHE_KEY)
|
||||
def get_emojis(db:scoped_session):
|
||||
emojis = [m.json() for m in get_marseys(db)]
|
||||
for src in EMOJI_SRCS:
|
||||
with open(src, "r", encoding="utf-8") as f:
|
||||
emojis = emojis + json.load(f)
|
||||
|
||||
return jsonify(emojis)
|
||||
return emojis
|
||||
|
||||
@app.get('/sidebar')
|
||||
@auth_desired
|
||||
def sidebar(v):
|
||||
def sidebar(v:Optional[User]):
|
||||
return render_template('sidebar.html', v=v)
|
||||
|
||||
|
||||
@app.get("/stats")
|
||||
@auth_required
|
||||
def participation_stats(v):
|
||||
def participation_stats(v:User):
|
||||
if v.client: return stats_cached()
|
||||
return render_template("stats.html", v=v, title="Content Statistics", data=stats_cached())
|
||||
|
||||
|
@ -94,12 +96,12 @@ def chart():
|
|||
|
||||
@app.get("/weekly_chart")
|
||||
@auth_required
|
||||
def weekly_chart(v):
|
||||
def weekly_chart(v:User):
|
||||
return send_file(statshelper.chart_path(kind="weekly", site=SITE))
|
||||
|
||||
@app.get("/daily_chart")
|
||||
@auth_required
|
||||
def daily_chart(v):
|
||||
def daily_chart(v:User):
|
||||
return send_file(statshelper.chart_path(kind="daily", site=SITE))
|
||||
|
||||
@app.get("/patrons")
|
||||
|
@ -115,14 +117,14 @@ def patrons(v):
|
|||
@app.get("/admins")
|
||||
@app.get("/badmins")
|
||||
@auth_required
|
||||
def admins(v):
|
||||
def admins(v:User):
|
||||
admins = g.db.query(User).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.truescore.desc()).all()
|
||||
return render_template("admins.html", v=v, admins=admins)
|
||||
|
||||
@app.get("/log")
|
||||
@app.get("/modlog")
|
||||
@auth_required
|
||||
def log(v):
|
||||
def log(v:User):
|
||||
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
except: page = 1
|
||||
|
@ -185,7 +187,7 @@ def log_item(id, v):
|
|||
|
||||
@app.get("/directory")
|
||||
@auth_required
|
||||
def static_megathread_index(v):
|
||||
def static_megathread_index(v:User):
|
||||
return render_template("megathread_index.html", v=v)
|
||||
|
||||
@app.get("/api")
|
||||
|
@ -199,7 +201,7 @@ def api(v):
|
|||
@app.get("/press")
|
||||
@app.get("/media")
|
||||
@auth_desired
|
||||
def contact(v):
|
||||
def contact(v:Optional[User]):
|
||||
return render_template("contact.html", v=v)
|
||||
|
||||
@app.post("/send_admin")
|
||||
|
@ -326,7 +328,7 @@ def badge_list(site):
|
|||
@app.get("/badges")
|
||||
@feature_required('BADGES')
|
||||
@auth_required
|
||||
def badges(v):
|
||||
def badges(v:User):
|
||||
badges, counts = badge_list(SITE)
|
||||
return render_template("badges.html", v=v, badges=badges, counts=counts)
|
||||
|
||||
|
@ -347,8 +349,9 @@ def blocks(v):
|
|||
|
||||
@app.get("/banned")
|
||||
@auth_required
|
||||
def banned(v):
|
||||
users = g.db.query(User).filter(User.is_banned > 0, User.unban_utc == 0)
|
||||
def banned(v:User):
|
||||
after_30_days = int(time.time()) + 86400 * 30
|
||||
users = g.db.query(User).filter(User.is_banned > 0, or_(User.unban_utc == 0, User.unban_utc > after_30_days))
|
||||
if not v.can_see_shadowbanned:
|
||||
users = users.filter(User.shadowbanned == None)
|
||||
users = users.all()
|
||||
|
@ -356,12 +359,12 @@ def banned(v):
|
|||
|
||||
@app.get("/formatting")
|
||||
@auth_required
|
||||
def formatting(v):
|
||||
def formatting(v:User):
|
||||
return render_template("formatting.html", v=v)
|
||||
|
||||
@app.get("/app")
|
||||
@auth_desired
|
||||
def mobile_app(v):
|
||||
def mobile_app(v:Optional[User]):
|
||||
return render_template("app.html", v=v)
|
||||
|
||||
@app.get("/service-worker.js")
|
||||
|
@ -389,7 +392,7 @@ def transfers_id(id, v):
|
|||
|
||||
@app.get("/transfers")
|
||||
@auth_required
|
||||
def transfers(v):
|
||||
def transfers(v:User):
|
||||
|
||||
comments = g.db.query(Comment).filter(Comment.author_id == AUTOJANNY_ID, Comment.parent_submission == None, Comment.body_html.like("%</a> has transferred %")).order_by(Comment.id.desc())
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ def unexile(v, sub, uid):
|
|||
|
||||
@app.post("/h/<sub>/block")
|
||||
@auth_required
|
||||
def block_sub(v, sub):
|
||||
def block_sub(v:User, sub):
|
||||
sub = get_sub_by_name(sub).name
|
||||
existing = g.db.query(SubBlock).filter_by(user_id=v.id, sub=sub).one_or_none()
|
||||
|
||||
|
@ -121,7 +121,7 @@ def block_sub(v, sub):
|
|||
|
||||
@app.post("/h/<sub>/unblock")
|
||||
@auth_required
|
||||
def unblock_sub(v, sub):
|
||||
def unblock_sub(v:User, sub):
|
||||
sub = get_sub_by_name(sub).name
|
||||
if sub == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
block = g.db.query(SubBlock).filter_by(user_id=v.id, sub=sub).one_or_none()
|
||||
|
@ -135,7 +135,7 @@ def unblock_sub(v, sub):
|
|||
|
||||
@app.post("/h/<sub>/subscribe")
|
||||
@auth_required
|
||||
def subscribe_sub(v, sub):
|
||||
def subscribe_sub(v:User, sub):
|
||||
sub = get_sub_by_name(sub).name
|
||||
existing = g.db.query(SubJoin).filter_by(user_id=v.id, sub=sub).one_or_none()
|
||||
|
||||
|
@ -148,7 +148,7 @@ def subscribe_sub(v, sub):
|
|||
|
||||
@app.post("/h/<sub>/unsubscribe")
|
||||
@auth_required
|
||||
def unsubscribe_sub(v, sub):
|
||||
def unsubscribe_sub(v:User, sub):
|
||||
sub = get_sub_by_name(sub).name
|
||||
subscribe = g.db.query(SubJoin).filter_by(user_id=v.id, sub=sub).one_or_none()
|
||||
|
||||
|
@ -160,7 +160,7 @@ def unsubscribe_sub(v, sub):
|
|||
|
||||
@app.post("/h/<sub>/follow")
|
||||
@auth_required
|
||||
def follow_sub(v, sub):
|
||||
def follow_sub(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
existing = g.db.query(SubSubscription).filter_by(user_id=v.id, sub=sub.name).one_or_none()
|
||||
|
@ -173,7 +173,7 @@ def follow_sub(v, sub):
|
|||
|
||||
@app.post("/h/<sub>/unfollow")
|
||||
@auth_required
|
||||
def unfollow_sub(v, sub):
|
||||
def unfollow_sub(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
subscription = g.db.query(SubSubscription).filter_by(user_id=v.id, sub=sub.name).one_or_none()
|
||||
if subscription:
|
||||
|
@ -184,7 +184,7 @@ def unfollow_sub(v, sub):
|
|||
|
||||
@app.get("/h/<sub>/mods")
|
||||
@auth_required
|
||||
def mods(v, sub):
|
||||
def mods(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
users = g.db.query(User, Mod).join(Mod).filter_by(sub=sub.name).order_by(Mod.created_utc).all()
|
||||
|
@ -194,7 +194,7 @@ def mods(v, sub):
|
|||
|
||||
@app.get("/h/<sub>/exilees")
|
||||
@auth_required
|
||||
def sub_exilees(v, sub):
|
||||
def sub_exilees(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
users = g.db.query(User, Exile).join(Exile, Exile.user_id==User.id) \
|
||||
|
@ -206,7 +206,7 @@ def sub_exilees(v, sub):
|
|||
|
||||
@app.get("/h/<sub>/blockers")
|
||||
@auth_required
|
||||
def sub_blockers(v, sub):
|
||||
def sub_blockers(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
users = g.db.query(User, SubBlock).join(SubBlock) \
|
||||
|
@ -219,7 +219,7 @@ def sub_blockers(v, sub):
|
|||
|
||||
@app.get("/h/<sub>/followers")
|
||||
@auth_required
|
||||
def sub_followers(v, sub):
|
||||
def sub_followers(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
users = g.db.query(User, SubSubscription).join(SubSubscription) \
|
||||
|
@ -399,7 +399,7 @@ def post_sub_sidebar(v, sub):
|
|||
|
||||
sub.sidebar = request.values.get('sidebar', '').strip()[:10000]
|
||||
sub.sidebar_html = sanitize(sub.sidebar)
|
||||
if len(sub.sidebar_html) > 20000: return "Sidebar is too big!"
|
||||
if len(sub.sidebar_html) > 20000: abort(400, "Sidebar is too big!")
|
||||
|
||||
g.db.add(sub)
|
||||
|
||||
|
@ -554,7 +554,7 @@ def sub_marsey(v, sub):
|
|||
|
||||
@app.get("/holes")
|
||||
@auth_required
|
||||
def subs(v):
|
||||
def subs(v:User):
|
||||
subs = g.db.query(Sub, func.count(Submission.sub)).outerjoin(Submission, Sub.name == Submission.sub).group_by(Sub.name).order_by(func.count(Submission.sub).desc()).all()
|
||||
total_users = g.db.query(User).count()
|
||||
return render_template('sub/subs.html', v=v, subs=subs, total_users=total_users)
|
||||
|
@ -699,7 +699,7 @@ def mod_unpin(cid, v):
|
|||
@app.get("/h/<sub>/log")
|
||||
@app.get("/h/<sub>/modlog")
|
||||
@auth_required
|
||||
def hole_log(v, sub):
|
||||
def hole_log(v:User, sub):
|
||||
sub = get_sub_by_name(sub)
|
||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||
try: page = max(int(request.values.get("page", 1)), 1)
|
||||
|
|
|
@ -56,25 +56,25 @@ def upvoters_downvoters(v, username, uid, cls, vote_cls, vote_dir, template, sta
|
|||
|
||||
@app.get("/@<username>/upvoters/<uid>/posts")
|
||||
@auth_required
|
||||
def upvoters_posts(v, username, uid):
|
||||
def upvoters_posts(v:User, username, uid):
|
||||
return upvoters_downvoters(v, username, uid, Submission, Vote, 1, "userpage/voted_posts.html", None)
|
||||
|
||||
|
||||
@app.get("/@<username>/upvoters/<uid>/comments")
|
||||
@auth_required
|
||||
def upvoters_comments(v, username, uid):
|
||||
def upvoters_comments(v:User, username, uid):
|
||||
return upvoters_downvoters(v, username, uid, Comment, CommentVote, 1, "userpage/voted_comments.html", True)
|
||||
|
||||
|
||||
@app.get("/@<username>/downvoters/<uid>/posts")
|
||||
@auth_required
|
||||
def downvoters_posts(v, username, uid):
|
||||
def downvoters_posts(v:User, username, uid):
|
||||
return upvoters_downvoters(v, username, uid, Submission, Vote, -1, "userpage/voted_posts.html", None)
|
||||
|
||||
|
||||
@app.get("/@<username>/downvoters/<uid>/comments")
|
||||
@auth_required
|
||||
def downvoters_comments(v, username, uid):
|
||||
def downvoters_comments(v:User, username, uid):
|
||||
return upvoters_downvoters(v, username, uid, Comment, CommentVote, -1, "userpage/voted_comments.html", True)
|
||||
|
||||
def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, standalone):
|
||||
|
@ -107,25 +107,25 @@ def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, sta
|
|||
|
||||
@app.get("/@<username>/upvoting/<uid>/posts")
|
||||
@auth_required
|
||||
def upvoting_posts(v, username, uid):
|
||||
def upvoting_posts(v:User, username, uid):
|
||||
return upvoting_downvoting(v, username, uid, Submission, Vote, 1, "userpage/voted_posts.html", None)
|
||||
|
||||
|
||||
@app.get("/@<username>/upvoting/<uid>/comments")
|
||||
@auth_required
|
||||
def upvoting_comments(v, username, uid):
|
||||
def upvoting_comments(v:User, username, uid):
|
||||
return upvoting_downvoting(v, username, uid, Comment, CommentVote, 1, "userpage/voted_comments.html", True)
|
||||
|
||||
|
||||
@app.get("/@<username>/downvoting/<uid>/posts")
|
||||
@auth_required
|
||||
def downvoting_posts(v, username, uid):
|
||||
def downvoting_posts(v:User, username, uid):
|
||||
return upvoting_downvoting(v, username, uid, Submission, Vote, -1, "userpage/voted_posts.html", None)
|
||||
|
||||
|
||||
@app.get("/@<username>/downvoting/<uid>/comments")
|
||||
@auth_required
|
||||
def downvoting_comments(v, username, uid):
|
||||
def downvoting_comments(v:User, username, uid):
|
||||
return upvoting_downvoting(v, username, uid, Comment, CommentVote, -1, "userpage/voted_comments.html", True)
|
||||
|
||||
def user_voted(v, username, cls, vote_cls, template, standalone):
|
||||
|
@ -158,19 +158,19 @@ def user_voted(v, username, cls, vote_cls, template, standalone):
|
|||
|
||||
@app.get("/@<username>/voted/posts")
|
||||
@auth_required
|
||||
def user_voted_posts(v, username):
|
||||
def user_voted_posts(v:User, username):
|
||||
return user_voted(v, username, Submission, Vote, "userpage/voted_posts.html", None)
|
||||
|
||||
|
||||
@app.get("/@<username>/voted/comments")
|
||||
@auth_required
|
||||
def user_voted_comments(v, username):
|
||||
def user_voted_comments(v:User, username):
|
||||
return user_voted(v, username, Comment, CommentVote, "userpage/voted_comments.html", True)
|
||||
|
||||
|
||||
@app.get("/grassed")
|
||||
@auth_required
|
||||
def grassed(v):
|
||||
def grassed(v:User):
|
||||
users = g.db.query(User).filter(User.ban_reason.like('grass award used by @%'))
|
||||
if not v.can_see_shadowbanned:
|
||||
users = users.filter(User.shadowbanned == None)
|
||||
|
@ -179,8 +179,9 @@ def grassed(v):
|
|||
|
||||
@app.get("/chuds")
|
||||
@auth_required
|
||||
def chuds(v):
|
||||
users = g.db.query(User).filter(User.agendaposter == 1)
|
||||
def chuds(v:User):
|
||||
after_30_days = int(time.time()) + 86400 * 30
|
||||
users = g.db.query(User).filter(or_(User.agendaposter == 1, User.agendaposter > after_30_days))
|
||||
if not v.can_see_shadowbanned:
|
||||
users = users.filter(User.shadowbanned == None)
|
||||
users = users.order_by(User.username).all()
|
||||
|
@ -227,28 +228,35 @@ def all_upvoters_downvoters(v, username, vote_dir, is_who_simps_hates):
|
|||
if total == 1: vote_str = vote_str[:-1] # we want to unpluralize if only 1 vote
|
||||
total = f'{total} {vote_str} {received_given}'
|
||||
|
||||
name2 = f'Who @{username} {simps_haters}' if is_who_simps_hates else f'@{username} biggest {simps_haters}'
|
||||
name2 = f'Who @{username} {simps_haters}' if is_who_simps_hates else f"@{username}'s {simps_haters}"
|
||||
|
||||
return render_template("userpage/voters.html", v=v, users=users[:PAGE_SIZE], pos=pos, name=vote_name, name2=name2, total=total)
|
||||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
users = users[PAGE_SIZE * (page-1):]
|
||||
next_exists = (len(users) > PAGE_SIZE)
|
||||
users = users[:PAGE_SIZE]
|
||||
|
||||
return render_template("userpage/voters.html", v=v, users=users, pos=pos, name=vote_name, name2=name2, total=total, page=page, next_exists=next_exists)
|
||||
|
||||
@app.get("/@<username>/upvoters")
|
||||
@auth_required
|
||||
def upvoters(v, username):
|
||||
def upvoters(v:User, username):
|
||||
return all_upvoters_downvoters(v, username, 1, False)
|
||||
|
||||
@app.get("/@<username>/downvoters")
|
||||
@auth_required
|
||||
def downvoters(v, username):
|
||||
def downvoters(v:User, username):
|
||||
return all_upvoters_downvoters(v, username, -1, False)
|
||||
|
||||
@app.get("/@<username>/upvoting")
|
||||
@auth_required
|
||||
def upvoting(v, username):
|
||||
def upvoting(v:User, username):
|
||||
return all_upvoters_downvoters(v, username, 1, True)
|
||||
|
||||
@app.get("/@<username>/downvoting")
|
||||
@auth_required
|
||||
def downvoting(v, username):
|
||||
def downvoting(v:User, username):
|
||||
return all_upvoters_downvoters(v, username, -1, True)
|
||||
|
||||
@app.post("/@<username>/suicide")
|
||||
|
@ -266,7 +274,7 @@ def suicide(v, username):
|
|||
|
||||
@app.get("/@<username>/coins")
|
||||
@auth_required
|
||||
def get_coins(v, username):
|
||||
def get_coins(v:User, username):
|
||||
user = get_user(username, v=v, include_shadowbanned=False)
|
||||
return {"coins": user.coins}
|
||||
|
||||
|
@ -326,13 +334,13 @@ def transfer_bux(v, username):
|
|||
|
||||
@app.get("/leaderboard")
|
||||
@auth_required
|
||||
def leaderboard(v):
|
||||
def leaderboard(v:User):
|
||||
users = g.db.query(User)
|
||||
if not v.can_see_shadowbanned:
|
||||
users = users.filter(User.shadowbanned == None)
|
||||
|
||||
coins = Leaderboard("Coins", "coins", "coins", "Coins", None, Leaderboard.get_simple_lb, User.coins, v, lambda u:u.coins, g.db, users)
|
||||
subscribers = Leaderboard("Followers", "followers", "followers", "Followers", None, Leaderboard.get_simple_lb, User.stored_subscriber_count, v, lambda u:u.stored_subscriber_count, g.db, users)
|
||||
subscribers = Leaderboard("Followers", "followers", "followers", "Followers", "followers", Leaderboard.get_simple_lb, User.stored_subscriber_count, v, lambda u:u.stored_subscriber_count, g.db, users)
|
||||
posts = Leaderboard("Posts", "post count", "posts", "Posts", "", Leaderboard.get_simple_lb, User.post_count, v, lambda u:u.post_count, g.db, users)
|
||||
comments = Leaderboard("Comments", "comment count", "comments", "Comments", "comments", Leaderboard.get_simple_lb, User.comment_count, v, lambda u:u.comment_count, g.db, users)
|
||||
received_awards = Leaderboard("Awards", "received awards", "awards", "Awards", None, Leaderboard.get_simple_lb, User.received_award_count, v, lambda u:u.received_award_count, g.db, users)
|
||||
|
@ -340,14 +348,16 @@ def leaderboard(v):
|
|||
truescore = Leaderboard("Truescore", "truescore", "truescore", "Truescore", None, Leaderboard.get_simple_lb, User.truescore, v, lambda u:u.truescore, g.db, users)
|
||||
|
||||
badges = Leaderboard("Badges", "badges", "badges", "Badges", None, Leaderboard.get_badge_marsey_lb, Badge.user_id, v, None, g.db, None)
|
||||
marseys = Leaderboard("Marseys", "Marseys made", "marseys", "Marseys", None, Leaderboard.get_badge_marsey_lb, Marsey.author_id, v, None, g.db, None) if SITE_NAME == 'rDrama' else None
|
||||
|
||||
blocks = Leaderboard("Blocked", "most blocked", "blocked", "Blocked By", "blockers", Leaderboard.get_blockers_lb, UserBlock.target_id, v, None, g.db, None)
|
||||
|
||||
owned_hats = Leaderboard("Owned hats", "owned hats", "owned-hats", "Owned Hats", None, Leaderboard.get_hat_lb, User.owned_hats, v, None, g.db, None)
|
||||
designed_hats = Leaderboard("Designed hats", "designed hats", "designed-hats", "Designed Hats", None, Leaderboard.get_hat_lb, User.designed_hats, v, None, g.db, None)
|
||||
|
||||
leaderboards = [coins, coins_spent, truescore, subscribers, posts, comments, received_awards, badges, marseys, blocks, owned_hats, designed_hats]
|
||||
leaderboards = [coins, coins_spent, truescore, subscribers, posts, comments, received_awards, badges, blocks, owned_hats]
|
||||
|
||||
if SITE == 'rdrama.net':
|
||||
leaderboards.append(Leaderboard("Designed hats", "designed hats", "designed-hats", "Designed Hats", None, Leaderboard.get_hat_lb, User.designed_hats, v, None, g.db, None))
|
||||
leaderboards.append(Leaderboard("Marseys", "Marseys made", "marseys", "Marseys", None, Leaderboard.get_badge_marsey_lb, Marsey.author_id, v, None, g.db, None))
|
||||
|
||||
return render_template("leaderboard.html", v=v, leaderboards=leaderboards)
|
||||
|
||||
|
@ -622,25 +632,40 @@ def redditor_moment_redirect(username, v):
|
|||
@auth_required
|
||||
def followers(username, v):
|
||||
u = get_user(username, v=v, include_shadowbanned=False)
|
||||
if u.id == CARP_ID and SITE == 'watchpeopledie.tv': abort(403)
|
||||
|
||||
if not (v.id == u.id or v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']):
|
||||
abort(403)
|
||||
|
||||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
users = g.db.query(Follow, User).join(Follow, Follow.target_id == u.id) \
|
||||
.filter(Follow.user_id == User.id) \
|
||||
.order_by(Follow.created_utc).all()
|
||||
return render_template("userpage/followers.html", v=v, u=u, users=users)
|
||||
.order_by(Follow.created_utc.desc()) \
|
||||
.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
|
||||
|
||||
next_exists = (len(users) > PAGE_SIZE)
|
||||
users = users[:PAGE_SIZE]
|
||||
|
||||
return render_template("userpage/followers.html", v=v, u=u, users=users, page=page, next_exists=next_exists)
|
||||
|
||||
@app.get("/@<username>/blockers")
|
||||
@auth_required
|
||||
def blockers(username, v):
|
||||
u = get_user(username, v=v, include_shadowbanned=False)
|
||||
|
||||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
users = g.db.query(UserBlock, User).join(UserBlock, UserBlock.target_id == u.id) \
|
||||
.filter(UserBlock.user_id == User.id) \
|
||||
.order_by(UserBlock.created_utc).all()
|
||||
return render_template("userpage/blockers.html", v=v, u=u, users=users)
|
||||
.order_by(UserBlock.created_utc.desc()) \
|
||||
.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
|
||||
|
||||
next_exists = (len(users) > PAGE_SIZE)
|
||||
users = users[:PAGE_SIZE]
|
||||
|
||||
return render_template("userpage/blockers.html", v=v, u=u, users=users, page=page, next_exists=next_exists)
|
||||
|
||||
@app.get("/@<username>/following")
|
||||
@auth_required
|
||||
|
@ -649,18 +674,33 @@ def following(username, v):
|
|||
if not (v.id == u.id or v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']):
|
||||
abort(403)
|
||||
|
||||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
users = g.db.query(User).join(Follow, Follow.user_id == u.id) \
|
||||
.filter(Follow.target_id == User.id) \
|
||||
.order_by(Follow.created_utc).all()
|
||||
return render_template("userpage/following.html", v=v, u=u, users=users)
|
||||
.order_by(Follow.created_utc.desc()) \
|
||||
.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
|
||||
|
||||
@app.get("/views")
|
||||
next_exists = (len(users) > PAGE_SIZE)
|
||||
users = users[:PAGE_SIZE]
|
||||
|
||||
return render_template("userpage/following.html", v=v, u=u, users=users, page=page, next_exists=next_exists)
|
||||
|
||||
@app.get("/@<username>/views")
|
||||
@auth_required
|
||||
def visitors(v):
|
||||
if not v.viewers_recorded:
|
||||
return render_template("errors/patron.html", v=v)
|
||||
viewers=sorted(v.viewers, key = lambda x: x.last_view_utc, reverse=True)
|
||||
return render_template("userpage/viewers.html", v=v, viewers=viewers)
|
||||
def visitors(username, v:User):
|
||||
u = get_user(username, v=v, include_shadowbanned=False)
|
||||
|
||||
try: page = int(request.values.get("page", 1))
|
||||
except: page = 1
|
||||
|
||||
views = g.db.query(ViewerRelationship).filter_by(user_id=u.id).order_by(ViewerRelationship.last_view_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
|
||||
|
||||
next_exists = (len(views) > PAGE_SIZE)
|
||||
views = views[:PAGE_SIZE]
|
||||
|
||||
return render_template("userpage/views.html", v=v, u=u, views=views, next_exists=next_exists, page=page)
|
||||
|
||||
@cache.memoize(timeout=86400)
|
||||
def userpagelisting(user:User, site=None, v=None, page:int=1, sort="new", t="all"):
|
||||
|
@ -682,7 +722,7 @@ def u_username(username, v=None):
|
|||
return redirect(SITE_FULL + request.full_path.replace(username, u.username))
|
||||
is_following = v and u.has_follower(v)
|
||||
|
||||
if v and v.id not in (u.id, DAD_ID) and u.viewers_recorded:
|
||||
if v and v.id != u.id:
|
||||
g.db.flush()
|
||||
view = g.db.query(ViewerRelationship).filter_by(viewer_id=v.id, user_id=u.id).one_or_none()
|
||||
|
||||
|
@ -963,7 +1003,7 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone
|
|||
|
||||
@app.get("/@<username>/saved/posts")
|
||||
@auth_required
|
||||
def saved_posts(v, username):
|
||||
def saved_posts(v:User, username):
|
||||
try: page = max(1, int(request.values.get("page", 1)))
|
||||
except: abort(400, "Invalid page input!")
|
||||
|
||||
|
@ -971,7 +1011,7 @@ def saved_posts(v, username):
|
|||
|
||||
@app.get("/@<username>/saved/comments")
|
||||
@auth_required
|
||||
def saved_comments(v, username):
|
||||
def saved_comments(v:User, username):
|
||||
try: page = max(1, int(request.values.get("page", 1)))
|
||||
except: abort(400, "Invalid page input!")
|
||||
|
||||
|
@ -979,7 +1019,7 @@ def saved_comments(v, username):
|
|||
|
||||
@app.get("/@<username>/subscribed/posts")
|
||||
@auth_required
|
||||
def subscribed_posts(v, username):
|
||||
def subscribed_posts(v:User, username):
|
||||
try: page = max(1, int(request.values.get("page", 1)))
|
||||
except: abort(400, "Invalid page input!")
|
||||
|
||||
|
@ -987,7 +1027,7 @@ def subscribed_posts(v, username):
|
|||
|
||||
@app.post("/fp/<fp>")
|
||||
@auth_required
|
||||
def fp(v, fp):
|
||||
def fp(v:User, fp):
|
||||
v.fp = fp
|
||||
users = g.db.query(User).filter(User.fp == fp, User.id != v.id).all()
|
||||
if users: print(f'{v.username}: fp', flush=True)
|
||||
|
@ -1033,7 +1073,7 @@ def toggle_holes():
|
|||
|
||||
@app.get("/badge_owners/<bid>")
|
||||
@auth_required
|
||||
def bid_list(v, bid):
|
||||
def bid_list(v:User, bid):
|
||||
|
||||
try: bid = int(bid)
|
||||
except: abort(400)
|
||||
|
@ -1095,7 +1135,7 @@ kofi_tiers={
|
|||
@app.post("/settings/kofi")
|
||||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||
@auth_required
|
||||
def settings_kofi(v):
|
||||
def settings_kofi(v:User):
|
||||
if not KOFI_TOKEN or KOFI_TOKEN == DEFAULT_CONFIG_VALUE: abort(404)
|
||||
if not (v.email and v.is_activated):
|
||||
abort(400, f"You must have a verified email to verify {patron} status and claim your rewards!")
|
||||
|
|
|
@ -60,8 +60,10 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
|
|||
if v.id == target.author.id:
|
||||
coin_delta = 0
|
||||
|
||||
alt = False
|
||||
if target.author.id in v.alt_ids or v.id in target.author.alt_ids:
|
||||
coin_delta = -1
|
||||
alt = True
|
||||
|
||||
coin_mult = 1
|
||||
|
||||
|
@ -101,7 +103,7 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
|
|||
target.author.truescore += coin_delta
|
||||
g.db.add(target.author)
|
||||
|
||||
real = new != 1 or v.is_votes_real
|
||||
real = alt or new != 1 or v.is_votes_real
|
||||
vote = None
|
||||
if vote_cls == Vote:
|
||||
vote = Vote(user_id=v.id,
|
||||
|
@ -141,7 +143,7 @@ def vote_post_comment(target_id, new, v, cls, vote_cls):
|
|||
target.upvotes = get_vote_count(1, False)
|
||||
target.downvotes = get_vote_count(-1, False)
|
||||
|
||||
if SITE_NAME == 'rDrama':
|
||||
if SITE == 'rdrama.net':
|
||||
target.realupvotes = get_vote_count(0, True) # first arg is ignored here
|
||||
|
||||
mul = 1
|
||||
|
|
|
@ -18,19 +18,10 @@ def session_init():
|
|||
session["session_id"] = secrets.token_hex(49)
|
||||
|
||||
def calc_users(v):
|
||||
# temp logging code
|
||||
if not hasattr(g, 'is_api_or_xhr'):
|
||||
print("calc_users called with missing context data")
|
||||
if request:
|
||||
print(f"while serving {request.method} {request.full_path}")
|
||||
print(f"user agent: {getattr(g, 'agent', '-attribute not present-')}")
|
||||
print(f"xhr? {request.headers.get('xhr')} / API client? {bool(request.headers.get('Authorization'))}")
|
||||
else:
|
||||
print("no request context")
|
||||
print(f"v: {v}")
|
||||
print(f"db?: {hasattr(g, 'db')}")
|
||||
abort(500, "hi!! it's @justcool393! If you get this could you PM me and tell me how you got this? i'm trying to figure something out and if you can help I'll really appreciate it <3")
|
||||
# end temp logging code
|
||||
if g.is_api_or_xhr:
|
||||
g.loggedin_counter = 0
|
||||
g.loggedout_counter = 0
|
||||
return ''
|
||||
loggedin = cache.get(f'{SITE}_loggedin') or {}
|
||||
loggedout = cache.get(f'{SITE}_loggedout') or {}
|
||||
timestamp = int(time.time())
|
||||
|
@ -69,20 +60,20 @@ def get_logged_in_user():
|
|||
if lo_user:
|
||||
id = int(lo_user)
|
||||
v = get_account(id, graceful=True)
|
||||
if not v:
|
||||
session.clear()
|
||||
return None
|
||||
else:
|
||||
if v:
|
||||
v.client = None
|
||||
nonce = session.get("login_nonce", 0)
|
||||
if nonce < v.login_nonce or v.id != id:
|
||||
session.clear()
|
||||
return None
|
||||
session.pop("lo_user")
|
||||
v = None
|
||||
|
||||
if request.method != "GET":
|
||||
if v and request.method != "GET":
|
||||
submitted_key = request.values.get("formkey")
|
||||
if not validate_formkey(v, submitted_key): abort(401)
|
||||
if not validate_formkey(v, submitted_key):
|
||||
v = None
|
||||
else:
|
||||
session.pop("lo_user")
|
||||
|
||||
v.client = None
|
||||
g.is_api_or_xhr = bool((v and v.client) or request.headers.get("xhr"))
|
||||
|
||||
if request.method.lower() != "get" and get_setting('Read-only mode') and not (v and v.admin_level >= PERMS['SITE_BYPASS_READ_ONLY_MODE']):
|
||||
|
|
|
@ -46,9 +46,9 @@
|
|||
{% if v.admin_level >= PERMS['USER_SHADOWBAN'] %}
|
||||
<li><a href="/admin/shadowbanned">Shadowbanned Users</a></li>
|
||||
{% endif %}
|
||||
<li><a href="/banned">Permabanned Users</a></li>
|
||||
<li><a href="/banned">Banned Users</a></li>
|
||||
{% if FEATURES['AWARDS'] -%}
|
||||
<li><a href="/chuds">Permachudded Users</a></li>
|
||||
<li><a href="/chuds">Chudded Users</a></li>
|
||||
<li><a href="/grassed">Currently Grassed Users</a></li>
|
||||
{%- endif %}
|
||||
{% if FEATURES['MARSEYBUX'] and (not AEVANN_ID or v.id in (AEVANN_ID, CARP_ID, SNAKES_ID)) -%}
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<p>Two accounts controlled by different people should have most uniqueness percentages at or above 70-80%</p>
|
||||
<p>A sockpuppet account will have its uniqueness percentages significantly lower.</p>
|
||||
|
||||
<button class="btn btn-danger" data-click="postToastReload(this,'/@{{u1.username}}/alts/?other_username={{u2.username}}')" onclick="areyousure(this)">Link {{u1.username}} and {{u2.username}}</button>
|
||||
<button class="btn btn-danger" data-click2="postToastReload(this,'/@{{u1.username}}/alts/?other_username={{u2.username}}')" onclick="areyousure(this)">Link {{u1.username}} and {{u2.username}}</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
{% for user in alts %}
|
||||
<tr>
|
||||
<td>{{loop.index}}</td>
|
||||
<td>{% include "admin/shadowbanned_tooltip.html" %}{% include "user_in_table.html" %}</td>
|
||||
<td>{% include "user_in_table.html" %}</td>
|
||||
<td>{{user.created_utc|timestamp}}</td>
|
||||
<td>{{user._alt_created_utc|timestamp}}</td>
|
||||
<td>{{user._is_manual}}</td>
|
||||
|
@ -61,8 +61,8 @@
|
|||
<form onsubmit="return false;">
|
||||
<label for="link-input-other">Other Username</label>
|
||||
<input autocomplete="off" id="link-input-other" type="text" class="form-control mb-2" name="other_username" placeholder="Other Username">
|
||||
<button id="add-alt-form-link" class="btn btn-danger mr-3" data-click="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Linked</button>
|
||||
<button id="add-alt-form-delink" class="btn btn-danger" data-click="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Delinked</button>
|
||||
<button id="add-alt-form-link" class="btn btn-danger mr-3" data-click2="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Linked</button>
|
||||
<button id="add-alt-form-delink" class="btn btn-danger" data-click2="submitAddAlt(this)" onclick="areyousure(this)">Add Alt Delinked</button>
|
||||
</form>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,40 +1,53 @@
|
|||
{% if SITE_NAME == 'PCM' %}
|
||||
{% set wholesome = '/i/wholesome.webp' %}
|
||||
{% else %}
|
||||
{% set wholesome = '/e/marseywholesome.webp' %}
|
||||
<div id="awards-container" class="w-100 h-100">
|
||||
{% macro stackable_award(award, src, alt) %}
|
||||
<div class="stackable-container">
|
||||
{% for i in range(min(p.award_count(award, v), 4)) %}
|
||||
<div class="{{award}}">
|
||||
<img alt="{{alt}}" src="{{src}}">
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% if p.award_count("wholesome", v) %}
|
||||
{% set wholesome = '/i/wholesome.webp' if SITE_NAME == 'PCM' else '/e/marseywholesome.webp' %}
|
||||
{{ stackable_award('wholesome', wholesome, ':#marseywholesome:') }}
|
||||
{% endif %}
|
||||
|
||||
{% for i in range(min(p.award_count("wholesome", v), 4)) %}
|
||||
{% if g.inferior_browser %}
|
||||
<div class="seal seal{{i+1}}" height="100%" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
{% if p.award_count("train", v) %}
|
||||
{{ stackable_award('train', '/e/marseytrain.webp', ':#marseytrain:') }}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("scooter", v) %}
|
||||
{{ stackable_award('scooter', '/e/marseyscooter.webp', ':#marseyscooter:') }}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("firework", v) %}
|
||||
<script defer src="{{'js/fireworks.js' | asset}}"></script>
|
||||
{{ stackable_award('firework') }}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("confetti", v) %}
|
||||
<div class="confetti w-100 h-100"></div>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("ricardo", v) %}
|
||||
{% for i in range(min(p.award_count("ricardo", v), 3)) %}
|
||||
<div class="ricardo ricardo{{i+1}}">
|
||||
<img src="/i/ricardo{{i+1}}.webp">
|
||||
</div>
|
||||
{% else %}
|
||||
{% set seal_vertical = 'up' if (i % 2) == 0 else 'down' %}
|
||||
{% set seal_horizontal = 'right' if i < 2 else 'left' %}
|
||||
<marquee class="seal" scrollamount=10 behavior="alternate" direction="{{seal_vertical}}" height="100%">
|
||||
<marquee direction="{{seal_horizontal}}" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% for i in range(min(p.award_count("train", v), 4)) %}
|
||||
{% set train_dir = 'left' if (i % 2) == 0 else 'right' %}
|
||||
{% set train_mirror = ' mirrored' if (i % 2) == 0 else '' %}
|
||||
<marquee class="train train{{i+1}}" direction="{{train_dir}}" scrollamount=10 width="100%">
|
||||
<img alt=":#marseytrain:" class="trainimg{{train_mirror}}" src="/e/marseytrain.webp">
|
||||
</marquee>
|
||||
{% endfor %}
|
||||
{% if p.award_count("shit", v) %}
|
||||
<script defer src="{{'js/vendor/critters.js' | asset}}"></script>
|
||||
<script defer src="{{'js/bugs.js' | asset}}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% for i in range(min(p.award_count("scooter", v), 4)) %}
|
||||
{% set scooter_dir = 'right' if (i % 2) == 0 else 'left' %}
|
||||
{% set scooter_mirror = '' if (i % 2) == 0 else ' mirrored' %}
|
||||
<marquee class="train train{{(i + 2) % 4 + 1}}" direction="{{scooter_dir}}" scrollamount=10 width="100%">
|
||||
<img alt=":#marseyscooter:" class="scooterimg{{scooter_mirror}}" src="/e/marseyscooter.webp">
|
||||
</marquee>
|
||||
{% endfor %}
|
||||
{% if p.award_count("fireflies", v) %}
|
||||
<script defer src="{{'js/vendor/critters.js' | asset}}"></script>
|
||||
<script defer src="{{'js/fireflies.js' | asset}}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("tilt", v) %}
|
||||
<style>
|
||||
|
@ -62,35 +75,8 @@
|
|||
</style>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("confetti", v) %}
|
||||
<div id="post-award-confetti"></div>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("firework", v) %}
|
||||
<script defer src="{{'js/fireworks.js' | asset}}"></script>
|
||||
{% for i in range(min(p.award_count("firework", v), 4)) %}
|
||||
<div class="firework">
|
||||
<img src="">
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("ricardo", v) %}
|
||||
<script defer src="{{'js/ricardo.js' | asset}}"></script>
|
||||
{% for i in range(min(p.award_count("ricardo", v), 3)) %}
|
||||
<div id="ricardo{{i+1}}" class="ricardo">
|
||||
<img src="/i/ricardo{{i+1}}.webp">
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("shit", v) %}
|
||||
<script defer src="{{'js/vendor/critters.js' | asset}}"></script>
|
||||
<script defer src="{{'js/bugs.js' | asset}}"></script>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("fireflies", v) %}
|
||||
<script defer src="{{'js/vendor/critters.js' | asset}}"></script>
|
||||
<script defer src="{{'js/fireflies.js' | asset}}"></script>
|
||||
{% if SITE_NAME == 'PCM' %}
|
||||
{% include "awards_PCM.html" %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -1,199 +1,11 @@
|
|||
{% if p.award_count("croag", v) %}
|
||||
<style>
|
||||
.croag {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
}
|
||||
.croag1 {
|
||||
top: 15%
|
||||
}
|
||||
.croag2 {
|
||||
top: 40%
|
||||
}
|
||||
.croag3 {
|
||||
top: 65%
|
||||
}
|
||||
.croag4 {
|
||||
top: 90%
|
||||
}
|
||||
.croagimg {
|
||||
width: 169px !important;
|
||||
height: 68px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.croagimg {
|
||||
width: 100px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<marquee class="croag croag1" direction="left" scrollamount=10 width="100%">
|
||||
<img alt="croag" class="croagimg mirrored" src="/i/PCM/croag.webp?v=2000">
|
||||
</marquee>
|
||||
|
||||
{% if p.award_count("croag", v) > 1 %}
|
||||
<marquee class="croag croag2" direction="right" scrollamount=10 width="100%">
|
||||
<img alt="croag" class="croagimg" src="/i/PCM/croag.webp?v=2000">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("croag", v) > 2 %}
|
||||
<marquee class="croag croag3" direction="left" scrollamount=10 width="100%">
|
||||
<img alt="croag" class="croagimg mirrored" src="/i/PCM/croag.webp?v=2000">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("croag", v) > 3 %}
|
||||
<marquee class="croag croag4" direction="right" scrollamount=10 width="100%">
|
||||
<img alt="croag" class="croagimg" src="/i/PCM/croag.webp?v=2000">
|
||||
</marquee>
|
||||
{% endif %}
|
||||
{{ stackable_award('croag', '/i/PCM/croag.webp', 'croag') }}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("toe", v) %}
|
||||
{% if g.inferior_browser %}
|
||||
<style>
|
||||
.toeimg {
|
||||
width: 100px !important;
|
||||
height: auto !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.toeimg {
|
||||
width: 30px !important;
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.toe {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
@keyframes moveX {
|
||||
from {} to {transform: translateX(98vw)}
|
||||
}
|
||||
|
||||
@keyframes moveY {
|
||||
from {} to {transform: translateY(90vh)}
|
||||
}
|
||||
|
||||
.toe1 {
|
||||
animation: moveX 4s linear 0s infinite alternate !important;
|
||||
animation-delay:0s;
|
||||
}
|
||||
.toe1 > img {
|
||||
animation: moveY 6.8s linear 0s infinite alternate !important;
|
||||
}
|
||||
</style>
|
||||
<div class="toe toe1" height="100%" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</div>
|
||||
|
||||
{% if p.award_count("toe", v) > 1 %}
|
||||
<style>
|
||||
.toe2 {
|
||||
animation: moveX 5s linear 0s infinite alternate !important;
|
||||
animation-delay:1s;
|
||||
}
|
||||
.toe2 > img {
|
||||
animation: moveY 8s linear 0s infinite alternate !important;
|
||||
animation-delay:1s;
|
||||
}
|
||||
</style>
|
||||
<div class="toe toe2" height="100%" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("toe", v) > 2 %}
|
||||
<style>
|
||||
.toe3 {
|
||||
animation: moveX 4s linear 0s infinite alternate !important;
|
||||
animation-delay:2s;
|
||||
}
|
||||
.toe3 > img {
|
||||
animation: moveY 5s linear 0s infinite alternate !important;
|
||||
animation-delay:2s;
|
||||
}
|
||||
</style>
|
||||
<div class="toe toe3" height="100%" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("toe", v) > 3 %}
|
||||
<style>
|
||||
.toe4 {
|
||||
animation: moveX 5s linear 0s infinite alternate !important;
|
||||
animation-delay:3s;
|
||||
}
|
||||
.toe4 > img {
|
||||
animation: moveY 6.8s linear 0s infinite alternate !important;
|
||||
animation-delay:3s;
|
||||
}
|
||||
</style>
|
||||
<div class="toe toe4" height="100%" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<style>
|
||||
.toe {
|
||||
position:fixed;
|
||||
z-index:9999;
|
||||
pointer-events: none;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
.toeimg {
|
||||
width: 100px !important;
|
||||
height: auto !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.toeimg {
|
||||
width: 30px !important;
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="toe" height="100%" width="100%">
|
||||
<marquee class="toe" scrollamount=10 behavior="alternate" direction="up" height="100%" width="100%">
|
||||
<marquee direction="right" scrollamount=10 behavior="alternate" height="100%" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</marquee>
|
||||
</marquee>
|
||||
</div>
|
||||
|
||||
{% if p.award_count("toe", v) > 1 %}
|
||||
<marquee class="toe" scrollamount=10 behavior="alternate" direction="down" height="100%">
|
||||
<marquee direction="right" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("toe", v) > 2 %}
|
||||
<marquee class="toe" scrollamount=10 behavior="alternate" direction="up" height="100%">
|
||||
<marquee direction="left" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("toe", v) > 3 %}
|
||||
<marquee class="toe" scrollamount=10 behavior="alternate" direction="down" height="100%">
|
||||
<marquee direction="left" scrollamount=10 behavior="alternate" width="100%">
|
||||
<img alt="Blade's toe" class="toeimg" src="/i/PCM/toe.webp?v=2000">
|
||||
</marquee>
|
||||
</marquee>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ stackable_award('toe', '/i/PCM/toe.webp', "Blade's toe") }}
|
||||
{% endif %}
|
||||
|
||||
{% if p.award_count("crab", v) %}
|
||||
<script>
|
||||
let audio = new Audio('/assets/media/crab.mp3');
|
||||
|
@ -207,3 +19,45 @@
|
|||
prepare_to_pause(audio)
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
<style>
|
||||
.toe img {
|
||||
width: 100px !important;
|
||||
height: auto !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.toe img {
|
||||
width: 30px !important;
|
||||
height: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.toe {animation: sealX 8s alternate; animation-delay: -1s}
|
||||
.toe img {animation: sealY 11s alternate-reverse; animation-delay: -1s}
|
||||
|
||||
.toe:nth-child(even) {animation-direction: alternate-reverse}
|
||||
.toe:nth-child(n+2):nth-child(n+3) img {animation-direction: alternate}
|
||||
|
||||
.croag img {
|
||||
width: 169px !important;
|
||||
height: 68px !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.croag img {
|
||||
width: 100px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.croag:nth-child(1) {top:2%}
|
||||
.croag:nth-child(2) {top:27%}
|
||||
.croag:nth-child(3) {top:52%}
|
||||
.croag:nth-child(4) {top:77%}
|
||||
|
||||
.croag {margin-top:10vh; animation-delay:-1s !important}
|
||||
|
||||
.croag {animation: train 14s;}
|
||||
.croag:nth-child(odd) {animation-direction: reverse;}
|
||||
.croag:nth-child(odd) img {transform: scaleX(-1);}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{% extends "settings2.html" %}
|
||||
{% block pagetitle %}Permabanned Users{% endblock %}
|
||||
{% block pagetitle %}Banned Users{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h5 class="my-4">Users who are permabanned or have more than 30 days to be unbanned</h5>
|
||||
<div class="overflow-x-auto"><table class="table table-striped mb-5">
|
||||
<thead class="bg-primary text-white">
|
||||
<tr>
|
||||
|
@ -8,6 +10,7 @@
|
|||
<th>Name</th>
|
||||
<th>Ban reason</th>
|
||||
<th>Banned by</th>
|
||||
<th>Unban in</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for user in users %}
|
||||
|
@ -20,6 +23,9 @@
|
|||
{% include "user_in_table.html" %}
|
||||
{% endwith %}
|
||||
</td>
|
||||
<td>
|
||||
{{user.unban_in}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
{%- extends 'root.html' -%}
|
||||
{% if IS_LOCALHOST %}
|
||||
{% set csp="script-src 'self' 'unsafe-inline' rdrama.net; connect-src 'self'; object-src 'none';" %}
|
||||
{% else %}
|
||||
{% set csp=none %}
|
||||
{% endif %}
|
||||
{% block pagetitle %}Chat{% endblock %}
|
||||
{% block pagetype %}chat{% endblock %}
|
||||
{% block body %}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
{% extends "settings2.html" %}
|
||||
{% block pagetitle %}Chuds{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<h5 class="my-4">Users who are permachudded or have more than 30 days to be unchudded</h5>
|
||||
<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>Unchud in</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{loop.index}}</td>
|
||||
<td>{% include "user_in_table.html" %}</td>
|
||||
<td>{{user.unchud_in}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
{% if c.is_blocking and not c.ghost or (c.is_banned or c.deleted_utc) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id==c.author_id) %}
|
||||
|
||||
<div id="comment-{{c.id}}" class="comment">
|
||||
<span class="comment-collapse-desktop d-mob-none" style="border-left: 2px solid #{{c.author.name_color}}"onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
|
||||
<span class="comment-collapse-desktop d-mob-none" style="border-left: 2px solid #{{c.author.name_color}}" onclick="collapse_comment('{{c.id}}', this.parentElement)"></span>
|
||||
|
||||
<div class="comment-body">
|
||||
|
||||
|
@ -486,7 +486,7 @@
|
|||
{% endif %}
|
||||
|
||||
{% if c.parent_submission and (c.author_id==v.id or v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or (c.post.sub and v.mods(c.post.sub))) %}
|
||||
<button type="button" id="unmark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.over_18 %}d-md-block{% endif %} text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Unmark +18</button>
|
||||
<button type="button" id="unmark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.over_18 %}d-md-block{% endif %} text-success" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-success fa-fw"></i>Unmark +18</button>
|
||||
<button type="button" id="mark-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.over_18 %}d-md-block{% endif %} text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark-{{c.id}}','unmark-{{c.id}}','d-md-block')"><i class="fas fa-eye-evil text-danger fa-fw"></i>Mark +18</button>
|
||||
{% endif %}
|
||||
|
||||
|
@ -646,13 +646,13 @@
|
|||
{% if not c.ghost %}
|
||||
<button type="button" id="unblock2-{{c.id}}" data-bs-dismiss="modal" class="text-success list-group-item {% if not c.is_blocking %}d-none{% endif %}" onclick="postToastSwitch(this,'/settings/unblock?username={{c.author.username}}','block2-{{c.id}}','unblock2-{{c.id}}','d-none')"><i class="fas fa-eye-slash text-success mr-2"></i>Unblock user</button>
|
||||
|
||||
<button type="button" id="block2-{{c.id}}" class="{% if c.is_blocking %}d-none{% endif %} list-group-item text-danger" data-click="postToastSwitch(this,'/settings/block?username={{c.author.username}}','block2-{{c.id}}','unblock2-{{c.id}}','d-none')" onclick="areyousure(this)" data-dismiss="modal"><i class="fas fa-eye-slash fa-fw text-danger mr-2"></i>Block user</button>
|
||||
<button type="button" id="block2-{{c.id}}" class="{% if c.is_blocking %}d-none{% endif %} list-group-item text-danger" data-click2="postToastSwitch(this,'/settings/block?username={{c.author.username}}','block2-{{c.id}}','unblock2-{{c.id}}','d-none')" onclick="areyousure(this)" data-dismiss="modal"><i class="fas fa-eye-slash fa-fw text-danger mr-2"></i>Block user</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if c.author_id == v.id or (c.post.sub and v.mods(c.post.sub)) %}
|
||||
<button type="button" id="mark2-{{c.id}}" class="{% if c.over_18 %}d-none{% endif %} list-group-item text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-danger mr-2"></i>Mark +18</button>
|
||||
<button type="button" id="unmark2-{{c.id}}" class="{% if not c.over_18 %}d-none{% endif %} list-group-item text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-danger mr-2"></i>Unmark +18</button>
|
||||
<button type="button" id="unmark2-{{c.id}}" class="{% if not c.over_18 %}d-none{% endif %} list-group-item text-success" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-success mr-2"></i>Unmark +18</button>
|
||||
{% endif %}
|
||||
|
||||
{% if v.admin_level < PERMS['POST_COMMENT_MODERATION'] %}
|
||||
|
@ -710,7 +710,7 @@
|
|||
<button type="button" id="unpin2-{{c.id}}" class="list-group-item {% if not c.stickied %}d-none{% endif %} text-info" data-bs-target="#adminModal-{{c.id}}" onclick="postToastSwitch(this,'/unsticky_comment/{{c.id}}','pin2-{{c.id}}','unpin2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-info mr-2"></i>Unpin</button>
|
||||
|
||||
<button type="button" id="mark2-{{c.id}}" class="{% if c.over_18 %}d-none{% endif %} list-group-item text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-danger mr-2"></i>Mark +18</button>
|
||||
<button type="button" id="unmark2-{{c.id}}" class="{% if not c.over_18 %}d-none{% endif %} list-group-item text-danger" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-danger mr-2"></i>Unmark +18</button>
|
||||
<button type="button" id="unmark2-{{c.id}}" class="{% if not c.over_18 %}d-none{% endif %} list-group-item text-success" onclick="postToastSwitch(this,'/toggle_comment_nsfw/{{c.id}}','mark2-{{c.id}}','unmark2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-eye-evil text-success mr-2"></i>Unmark +18</button>
|
||||
{% endif %}
|
||||
|
||||
{% if v.id != c.author_id and v.admin_level >= PERMS['USER_BAN'] %}
|
||||
|
@ -879,7 +879,7 @@
|
|||
<div id="viewmore-{{offset}}"><button type="button" id="viewbtn" class="btn btn-primary" onclick="viewmore({{pid}},'{{sort}}',{{offset}},{{ids}})">VIEW MORE COMMENTS</a></div>
|
||||
{% endif %}
|
||||
|
||||
{% if SITE_NAME == 'rDrama' and not request.headers.get("xhr") and v and 'SamsungBrowser' not in g.agent %}
|
||||
{% if SITE_NAME == 'rDrama' and not request.headers.get("xhr") and v and 'SamsungBrowser' not in g.agent and v.theme != 'transparent' %}
|
||||
<div id="detection" style="display:none;background-color:canvas;color-scheme:light"></div>
|
||||
<script>
|
||||
const detectionDiv = document.querySelector('#detection');
|
||||
|
@ -891,7 +891,7 @@
|
|||
color = 'rgba' + color.slice(3,-1) + ', 0.1)'
|
||||
|
||||
const markTemplate = (name) => {
|
||||
return `<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='50px' height='50px'><text transform='translate(10, 50) rotate(-45)' fill='${color}' font-size='20'>${name}</text></svg>`;
|
||||
return `<svg xmlns='https://www.w3.org/2000/svg' version='1.1' width='50px' height='50px'><text transform='translate(10, 50) rotate(-45)' fill='${color}' font-size='20'>${name}</text></svg>`;
|
||||
};
|
||||
const base64Mark = btoa(markTemplate("{{v.id}}"));
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{%- extends 'root.html' -%}
|
||||
{% set csp = CONTENT_SECURITY_POLICY_HOME if request.path == '/' else CONTENT_SECURITY_POLICY_DEFAULT %}
|
||||
{% block body_attributes %}id="{% if request.path != '/comments' %}{% block pagetype %}frontpage{% endblock %}{% endif %}" {% if SITE_NAME == 'rDrama' and v and (v.is_banned or v.agendaposter) %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/anime/1.webp?v=3) center center fixed; background-color: var(--background)"{% elif v and v.background %}style="{% if path != '/formatting' %}overflow-x: hidden; {% endif %} background:url(/assets/images/backgrounds/{{v.background}}?v=3) center center fixed; background-color: var(--background){% if 'anime' not in v.background %};background-size: cover{% endif %}"{% endif %}{% endblock %}
|
||||
{% block body_attributes %}id="{% if request.path != '/comments' %}{% block pagetype %}frontpage{% endblock %}{% endif %}"{% endblock %}
|
||||
{% block body %}
|
||||
{% block banner %}
|
||||
{% include "modals/expanded_image.html" %}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
{% extends "default.html" %}
|
||||
{% block pagetitle %}401 Not Authorized{% endblock %}
|
||||
{% block pagetype %}error-401{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 col-md-5">
|
||||
<div class="text-center px-3 my-8">
|
||||
<img alt=":#marseymerchant:" loading="lazy" class="mb-2" src="/e/marseymerchant.webp">
|
||||
<h5>401 Not Authorized</h5>
|
||||
<p class="text-muted">This page is only available to {% if SITE_NAME == 'rDrama' %}paypigs{% else %}patrons{% endif %}:</p>
|
||||
{% if FEATURES['MARSEYBUX'] and v.truescore -%}
|
||||
{% if KOFI_LINK %}
|
||||
<a rel="nofollow noopener" href="{{KOFI_LINK}}">{{KOFI_LINK}}</a>
|
||||
{% else %}
|
||||
<a rel="nofollow noopener" href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a>
|
||||
{% endif %}
|
||||
{%- endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -118,10 +118,10 @@
|
|||
<td class="shop-table-actions" style="width:unset">
|
||||
{% if hat.id not in owned_hat_ids and hat.is_purchasable %}
|
||||
<div id="if-not-owned-{{hat.id}}">
|
||||
<button type="button" id="buy1-{{hat.id}}" class="btn btn-success {% if v.coins < hat.price %}disabled{% endif %}" data-click="postToastSwitch(this, '/buy_hat/{{hat.id}}', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-coins-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">Buy</span></button>
|
||||
<button type="button" id="buy1-{{hat.id}}" class="btn btn-success {% if v.coins < hat.price %}disabled{% endif %}" data-click2="postToastSwitch(this, '/buy_hat/{{hat.id}}', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-coins-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">Buy</span></button>
|
||||
|
||||
{% if FEATURES['MARSEYBUX'] %}
|
||||
<button type="button" id="buy2-{{hat.id}}" class="marseybux btn btn-success {% if v.marseybux < hat.price %}disabled{% endif %}" data-click="postToastSwitch(this, '/buy_hat/{{hat.id}}?mb=true', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-bux-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">MBux</span></button>
|
||||
<button type="button" id="buy2-{{hat.id}}" class="marseybux btn btn-success {% if v.marseybux < hat.price %}disabled{% endif %}" data-click2="postToastSwitch(this, '/buy_hat/{{hat.id}}?mb=true', 'if-not-owned-{{hat.id}}', 'if-owned-{{hat.id}}', 'd-none', (xhr)=>{if(xhr.status == 200)document.getElementById('user-bux-amount').innerHTML-={{hat.price}}})" onclick="areyousure(this)"><span class="m-auto">MBux</span></button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -284,7 +284,7 @@
|
|||
<form id="searchform" class="form-inline search flex-nowrap mx-0 mx-lg-auto" action="/search/posts" method="get">
|
||||
<input autocomplete="off" class="form-control form-control-sm w-100" type="search" placeholder="{{search_placeholder}}" aria-label="Search" name="q">
|
||||
<span class="input-group-append">
|
||||
<span class="input-group-text border-0 bg-transparent" style="margin-left: -2.5rem"onclick="document.getElementById('searchform').submit()">
|
||||
<span class="input-group-text border-0 bg-transparent" style="margin-left: -2.5rem" onclick="document.getElementById('searchform').submit()">
|
||||
<i class="fa fa-search" aria-hidden="true"></i>
|
||||
</span>
|
||||
</span>
|
||||
|
|
|
@ -175,7 +175,7 @@
|
|||
float: left;
|
||||
font-size: 14px;
|
||||
padding-top: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
padding-right: 0.7rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<form action="/live/remove" method="post">
|
||||
<input type="hidden" name="formkey" value="{{v|formkey}}">
|
||||
<input type="hidden" name="id" value="{{id}}">
|
||||
<input autocomplete="off" class="btn btn-primary ml-auto remove-streamer" data-click="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
|
||||
<input autocomplete="off" class="btn btn-primary ml-auto remove-streamer" data-click2="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
|
||||
</form>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
@ -83,7 +83,7 @@
|
|||
<form action="/live/remove" method="post">
|
||||
<input type="hidden" name="formkey" value="{{v|formkey}}">
|
||||
<input type="hidden" name="id" value="{{id}}">
|
||||
<input autocomplete="off" class="btn btn-primary ml-auto remove-streamer" data-click="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
|
||||
<input autocomplete="off" class="btn btn-primary ml-auto remove-streamer" data-click2="disable(this);this.parentElement.submit()" onclick="areyousure(this)" value="Remove">
|
||||
</form>
|
||||
</td>
|
||||
{% endif %}
|
||||
|
|
|
@ -5,46 +5,41 @@
|
|||
<div class="overflow-x-auto mt-3"><table class="table table-striped mb-5">
|
||||
<thead class="bg-primary text-white">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Name</th>
|
||||
<th onclick="sort_table(0)">#</th>
|
||||
<th onclick="sort_table(1)">Name</th>
|
||||
<th>Marsey</th>
|
||||
<th>Usage</th>
|
||||
{% if SITE == 'rdrama.net' %}
|
||||
<th><a href="?sort=author">Author</a></th>
|
||||
<th><a href="?sort=added">Added on</a></th>
|
||||
<th onclick="sort_table(3)">Usage</th>
|
||||
{% if FEATURES['ASSET_SUBMISSIONS'] %}
|
||||
<th onclick="sort_table(4)">Author</th>
|
||||
{% endif %}
|
||||
<th onclick="sort_table(5)">Added on</th>
|
||||
{% if FEATURES['ASSET_SUBMISSIONS'] %}
|
||||
<th>Original File</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="marseys-table">
|
||||
{% if SITE == 'rdrama.net' %}
|
||||
{% for marsey, user 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>
|
||||
<td>{% include "user_in_table.html" %}</td>
|
||||
<td {% if marsey.created_utc != None %}data-time="{{marsey.created_utc}}"{% endif %}></td>
|
||||
<td>
|
||||
{% if marsey.og %}
|
||||
<a href="/asset_submissions/marseys/original/{{marsey.og}}">{{marsey.og}}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% 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 %}
|
||||
{% endif %}
|
||||
|
||||
{% for marsey in marseys %}
|
||||
<tr>
|
||||
<td>{{loop.index}}</td>
|
||||
<td data-sort-key="{{marsey.name}}">{{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>
|
||||
{% if FEATURES['ASSET_SUBMISSIONS'] %}
|
||||
{% set user = marsey.user %}
|
||||
<td data-sort-key="{{user.username.lower() if user else ''}}">{% include "user_in_table.html" %}</td>
|
||||
{% endif %}
|
||||
<td data-sort-key="{{marsey.created_utc or 0}}" {% if marsey.created_utc != None %}data-time="{{marsey.created_utc}}"{% endif %}></td>
|
||||
{% if FEATURES['ASSET_SUBMISSIONS'] %}
|
||||
<td>
|
||||
{% if marsey.og %}
|
||||
<a href="/asset_submissions/marseys/original/{{marsey.og}}">{{marsey.og}}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<script defer src="{{'js/sort_table.js' | asset}}"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -3,10 +3,8 @@
|
|||
{% block pagetype %}message-success{% endblock %}
|
||||
{% block content %}
|
||||
<div class="text-center py-7 py-md-8">
|
||||
|
||||
<img loading="lazy" src="/i/ruckus.webp" class="empty-state-img mb-3" alt="success state">
|
||||
<img class="mb-3" alt=":#marseyparty:" loading="lazy" src="/e/marseyparty.webp">
|
||||
<div class="font-weight-bold text-muted mb-4">{{title}}</div>
|
||||
<p class="text-muted">{{message}}</p>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
</a>
|
||||
</button>
|
||||
{% if v %}
|
||||
{% if FEATURES['CHAT'] -%}
|
||||
{% if FEATURES['CHAT'] and (SITE_NAME != 'rDrama' or cache.get(ONLINE_STR) >= 10) -%}
|
||||
<button type="button" class="col px-0 btn btn-dead m-0 pt-0" style="background: None !important; border: None;">
|
||||
<a href="/chat" class="text-decoration-none">
|
||||
<div class="text-center {% if request.path=='/chat' %}text-primary{% else %}text-muted{% endif %}">
|
||||
|
|