rework awards #25
|
@ -1,23 +1,9 @@
|
||||||
image.*
|
.*
|
||||||
video.mp4
|
|
||||||
unsanitized.mp4
|
|
||||||
cache/
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
.idea/
|
|
||||||
**/.pytest_cache/
|
|
||||||
venv/
|
|
||||||
.vscode/
|
|
||||||
.sass-cache/
|
|
||||||
flask_session/
|
|
||||||
.DS_Store
|
|
||||||
site_settings.json
|
|
||||||
/files/test.py
|
|
||||||
tags
|
|
||||||
|
|
||||||
# Chat environment
|
# Chat environment
|
||||||
chat/node_modules
|
chat/node_modules
|
||||||
chat/build
|
chat/build
|
||||||
chat/.env
|
|
||||||
|
|
||||||
# Chat artefacts
|
# Chat artefacts
|
||||||
files/assets/css/chat_done.css
|
files/assets/css/chat_done.css
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
.ChatMessage {
|
.ChatMessage {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right: 1.5rem;
|
padding-right: 1.5rem;
|
||||||
overflow: hidden;
|
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +38,7 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding-left: 30px;
|
padding-left: 30px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ChatMessage-content {
|
.ChatMessage-content {
|
||||||
|
|
|
@ -15,17 +15,26 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- postgres
|
- postgres
|
||||||
|
logging:
|
||||||
|
options:
|
||||||
|
max-size: "100k"
|
||||||
|
max-file: "1"
|
||||||
|
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
container_name: "redis"
|
container_name: "redis"
|
||||||
image: redis
|
image: redis
|
||||||
ports:
|
ports:
|
||||||
- "6379:6379"
|
- "6379:6379"
|
||||||
|
logging:
|
||||||
|
options:
|
||||||
|
max-size: "100k"
|
||||||
|
max-file: "1"
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
container_name: "postgres"
|
container_name: "postgres"
|
||||||
image: postgres
|
image: postgres
|
||||||
command: ["postgres", "-c", "log_statement=all"]
|
#command: ["postgres", "-c", "log_statement=all"]
|
||||||
volumes:
|
volumes:
|
||||||
- "./schema.sql:/docker-entrypoint-initdb.d/00-schema.sql"
|
- "./schema.sql:/docker-entrypoint-initdb.d/00-schema.sql"
|
||||||
- "./seed-db.sql:/docker-entrypoint-initdb.d/10-seed-db.sql"
|
- "./seed-db.sql:/docker-entrypoint-initdb.d/10-seed-db.sql"
|
||||||
|
@ -33,9 +42,17 @@ services:
|
||||||
- POSTGRES_HOST_AUTH_METHOD=trust
|
- POSTGRES_HOST_AUTH_METHOD=trust
|
||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
|
logging:
|
||||||
|
options:
|
||||||
|
max-size: "100k"
|
||||||
|
max-file: "1"
|
||||||
|
|
||||||
opera-proxy:
|
opera-proxy:
|
||||||
container_name: "opera-proxy"
|
container_name: "opera-proxy"
|
||||||
image: yarmak/opera-proxy
|
image: yarmak/opera-proxy
|
||||||
ports:
|
ports:
|
||||||
- "18080:18080"
|
- "18080:18080"
|
||||||
|
logging:
|
||||||
|
options:
|
||||||
|
max-size: "100k"
|
||||||
|
max-file: "1"
|
||||||
|
|
|
@ -1,219 +1,159 @@
|
||||||
|
#awards-container {
|
||||||
|
position:fixed;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index:9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#awards-container > div {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*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 linear infinite}
|
||||||
|
.wholesome img {animation: sealY 10s linear infinite}
|
||||||
|
|
||||||
|
.wholesome1 {animation-direction: alternate}
|
||||||
|
.wholesome1 img {animation-direction: alternate}
|
||||||
|
.wholesome2 {animation-direction: alternate-reverse}
|
||||||
|
.wholesome2 img {animation-direction: alternate-reverse}
|
||||||
|
.wholesome3 {animation-direction: alternate}
|
||||||
|
.wholesome3 img {animation-direction: alternate-reverse}
|
||||||
|
.wholesome4 {animation-direction: alternate-reverse}
|
||||||
|
.wholesome4 img {animation-direction: alternate}
|
||||||
|
|
||||||
|
@keyframes sealX {
|
||||||
|
from {} to {transform: translateX(98vw)}
|
||||||
|
}
|
||||||
|
@keyframes sealY {
|
||||||
|
from {} to {transform: translateY(85vh)}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*train common*/
|
||||||
|
.train1, .scooter1 {top:2%}
|
||||||
|
.train2, .scooter2 {top:27%}
|
||||||
|
.train3, .scooter3 {top:52%}
|
||||||
|
.train4, .scooter4 {top:77%}
|
||||||
|
|
||||||
|
@keyframes train {
|
||||||
|
from {transform: translateX(-3vw)}
|
||||||
|
to {transform: translateX(99vw)}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*train*/
|
||||||
|
.train img {
|
||||||
|
width: 100px !important;
|
||||||
|
height: 51px !important;
|
||||||
|
}
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.train img {
|
||||||
|
width: 40px !important;
|
||||||
|
height: 20px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.train{animation: train 11s linear infinite;}
|
||||||
|
.train:nth-of-type(odd) {animation-direction: reverse;}
|
||||||
|
.train:nth-of-type(odd) img {transform: scaleX(-1);}
|
||||||
|
|
||||||
|
/*scooter*/
|
||||||
|
.scooter img {
|
||||||
|
width: 100px !important;
|
||||||
|
height: 135px !important;
|
||||||
|
}
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
.scooter img {
|
||||||
|
width: 40px !important;
|
||||||
|
height: 54px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.scooter {animation: train 11s linear infinite;}
|
||||||
|
.scooter:nth-of-type(even) {animation-direction: reverse;}
|
||||||
|
.scooter:nth-of-type(even) img {transform: scaleX(-1);}
|
||||||
|
|
||||||
/*confetti*/
|
/*confetti*/
|
||||||
#post-award-confetti {
|
.confetti {
|
||||||
position: fixed;
|
|
||||||
z-index: 9998;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
pointer-events: none !important;
|
|
||||||
background-image: url(/assets/images/confetti2.webp);
|
background-image: url(/assets/images/confetti2.webp);
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*fireworks*/
|
/*fireworks*/
|
||||||
.firework {
|
|
||||||
position:fixed;
|
|
||||||
z-index:9999;
|
|
||||||
pointer-events: none;
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
pointer-events: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.firework img {
|
.firework img {
|
||||||
max-width: 15rem;
|
max-width: 15rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*ricardo*/
|
/*ricardo*/
|
||||||
.ricardo {
|
.ricardo {
|
||||||
position: fixed;
|
position: fixed !important;
|
||||||
z-index: 9997;
|
bottom: 0;
|
||||||
pointer-events: none !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ricardo img {
|
.ricardo img {
|
||||||
max-height: 15rem !important;
|
max-height: min(30vw,15rem);
|
||||||
max-height: min(30vw,15rem) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ricardoleft {
|
.ricardo1 {animation: ricardo1Xa 5.8s linear infinite, ricardo1Xb 11.6s linear infinite, ricardo1Y 23.2s linear infinite;}
|
||||||
animation: ricardoleft 2.9s 2 alternate !important;
|
.ricardo2 {animation: ricardo2 8.5s linear infinite;}
|
||||||
|
.ricardo3 {animation: ricardo3 10s linear infinite;}
|
||||||
|
|
||||||
|
@keyframes ricardo1Xa {
|
||||||
|
0% {right: -200px}
|
||||||
|
50% {right: 200px}
|
||||||
|
100% {right: -200px}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ricardoright {
|
@keyframes ricardo1Xb {
|
||||||
animation: ricardoright 2.9s 2 alternate !important;
|
0%{left:unset}
|
||||||
|
49% {left: unset}
|
||||||
|
50% {left: -200px}
|
||||||
|
75% {left:200px}
|
||||||
|
100% {left: -200px}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes ricardoleft {
|
@keyframes ricardo1Y {
|
||||||
from {}
|
0% {bottom:20vh}
|
||||||
to {transform: translateX(200px);}
|
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 {
|
@keyframes ricardo2 {
|
||||||
0% {opacity:20%}
|
0% { opacity: 1; left: 0; right: unset;}
|
||||||
50% {opacity:100%}
|
18% {opacity: 0; left: 0; right: unset;}
|
||||||
100% {opacity:0%}
|
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 {
|
@keyframes ricardo3 {
|
||||||
50% {transform: translateX(105vw);}
|
50% {transform: translateX(100vw); top: unset; bottom: 0;}
|
||||||
51% {transform: translate(105vw,-86vh) rotate(180deg);}
|
51% {transform: translateX(100vw) rotate(180deg); top: 0; bottom: unset;}
|
||||||
100% {transform: translate(-15vw,-86vh) rotate(180deg);}
|
100% {transform: translateX(-15vw) rotate(180deg); top: 0; bottom: unset;}
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1853,7 +1853,7 @@ button.close {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
border-radius: 0.35rem;
|
border-radius: 0.2rem;
|
||||||
}
|
}
|
||||||
.popover {
|
.popover {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -3528,6 +3528,11 @@ small, .small {
|
||||||
.post-meta::-webkit-scrollbar {
|
.post-meta::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ghost-post .post-meta {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.sub-flair {
|
.sub-flair {
|
||||||
padding: 3px 5px 2px 5px;
|
padding: 3px 5px 2px 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
@ -5022,6 +5027,23 @@ img[src="/i/hand.webp"]+img[glow]:not([data-src]) {
|
||||||
pat-pfp-anim .3s infinite;
|
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 {
|
@keyframes rb {
|
||||||
10% { color: red; }
|
10% { color: red; }
|
||||||
20% { color: orange; }
|
20% { color: orange; }
|
||||||
|
@ -6379,3 +6401,18 @@ div.markdown {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
max-height: min(42vh,30vw) !important;
|
max-height: min(42vh,30vw) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modlog-action {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background: var(--gray-600) !important;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
padding: 1rem 1rem 1rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modlog-action:not(:first-of-type) {
|
||||||
|
border-top: 1px solid var(--gray-400) !important;
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 8.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -180,14 +180,18 @@ function smoothScrollTop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Click navbar to scroll back to top
|
// Click navbar to scroll back to top
|
||||||
document.getElementsByTagName('nav')[0].addEventListener('click', (e) => {
|
const nav = document.getElementsByTagName('nav')
|
||||||
if (e.target.id === "navbar" ||
|
|
||||||
e.target.classList.contains("container-fluid") ||
|
if (nav) {
|
||||||
e.target.id == "navbarResponsive" ||
|
nav[0].addEventListener('click', (e) => {
|
||||||
e.target.id == "logo-container" ||
|
if (e.target.id === "navbar" ||
|
||||||
e.target.classList.contains("srd"))
|
e.target.classList.contains("container-fluid") ||
|
||||||
smoothScrollTop();
|
e.target.id == "navbarResponsive" ||
|
||||||
}, false);
|
e.target.id == "logo-container" ||
|
||||||
|
e.target.classList.contains("srd"))
|
||||||
|
smoothScrollTop();
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Dynamic shadow when the user scrolls
|
// Dynamic shadow when the user scrolls
|
||||||
document.addEventListener('scroll',function (event) {
|
document.addEventListener('scroll',function (event) {
|
||||||
|
@ -324,13 +328,12 @@ function formatDate(d) {
|
||||||
const timestamps = document.querySelectorAll('[data-time]');
|
const timestamps = document.querySelectorAll('[data-time]');
|
||||||
|
|
||||||
for (const e of timestamps) {
|
for (const e of timestamps) {
|
||||||
const date = new Date(e.dataset.time*1000);
|
e.innerHTML = formatDate(new Date(e.dataset.time*1000));
|
||||||
e.innerHTML = formatDate(date);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function timestamp(str, ti) {
|
function timestamp(str, ti) {
|
||||||
const date = new Date(ti*1000);
|
const date = formatDate(new Date(ti*1000));
|
||||||
document.getElementById(str).setAttribute("data-bs-original-title", formatDate(date));
|
document.getElementById(str).setAttribute("data-bs-original-title", date);
|
||||||
};
|
};
|
||||||
|
|
||||||
function areyousure(t) {
|
function areyousure(t) {
|
||||||
|
@ -404,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));
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -35,7 +35,7 @@ class OauthApp(Base):
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def permalink(self):
|
def permalink(self):
|
||||||
return f"{SITE_FULL}/admin/app/{self.id}/posts"
|
return f"{SITE_FULL}/admin/app/{self.id}"
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
def idlist(self, db:scoped_session, page=1):
|
def idlist(self, db:scoped_session, page=1):
|
||||||
|
|
|
@ -49,6 +49,7 @@ class Comment(Base):
|
||||||
is_bot = Column(Boolean, default=False)
|
is_bot = Column(Boolean, default=False)
|
||||||
stickied = Column(String)
|
stickied = Column(String)
|
||||||
stickied_utc = Column(Integer)
|
stickied_utc = Column(Integer)
|
||||||
|
stickied_child_id = Column(Integer)
|
||||||
sentto = Column(Integer, ForeignKey("users.id"))
|
sentto = Column(Integer, ForeignKey("users.id"))
|
||||||
app_id = Column(Integer, ForeignKey("oauth_apps.id"))
|
app_id = Column(Integer, ForeignKey("oauth_apps.id"))
|
||||||
upvotes = Column(Integer, default=1)
|
upvotes = Column(Integer, default=1)
|
||||||
|
@ -139,7 +140,7 @@ class Comment(Base):
|
||||||
if self.replies2 != None:
|
if self.replies2 != None:
|
||||||
return self.replies2
|
return self.replies2
|
||||||
|
|
||||||
replies = db.query(Comment).filter_by(parent_comment_id=self.id).order_by(Comment.stickied)
|
replies = db.query(Comment).filter_by(parent_comment_id=self.id).order_by(Comment.stickied, Comment.stickied_child_id)
|
||||||
if not self.parent_submission: sort='old'
|
if not self.parent_submission: sort='old'
|
||||||
return sort_objects(sort, replies, Comment,
|
return sort_objects(sort, replies, Comment,
|
||||||
include_shadowbanned=(v and v.can_see_shadowbanned)).all()
|
include_shadowbanned=(v and v.can_see_shadowbanned)).all()
|
||||||
|
@ -242,7 +243,7 @@ class Comment(Base):
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
def realbody(self, v):
|
def realbody(self, v):
|
||||||
if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))):
|
if self.post and self.post.club and not (v and (v.paid_dues or v.id in {self.author_id, self.post.author_id} or (self.parent_comment and v.id == self.parent_comment.author_id))):
|
||||||
return f"<p>{CC} ONLY</p>"
|
return f"<p>{CC} ONLY</p>"
|
||||||
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
|
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
|
||||||
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
|
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
|
||||||
|
@ -293,11 +294,14 @@ class Comment(Base):
|
||||||
if not self.ghost and self.author.show_sig(v):
|
if not self.ghost and self.author.show_sig(v):
|
||||||
body += f"<hr>{self.author.sig_html}"
|
body += f"<hr>{self.author.sig_html}"
|
||||||
|
|
||||||
|
if v:
|
||||||
|
body = body.replace("!YOU!", v.username)
|
||||||
|
|
||||||
return body
|
return body
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
def plainbody(self, v):
|
def plainbody(self, v):
|
||||||
if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))):
|
if self.post and self.post.club and not (v and (v.paid_dues or v.id in {self.author_id, self.post.author_id} or (self.parent_comment and v.id == self.parent_comment.author_id))):
|
||||||
return f"{CC} ONLY"
|
return f"{CC} ONLY"
|
||||||
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
|
if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]"
|
||||||
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
|
if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return ""
|
||||||
|
@ -308,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:')
|
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
|
return body
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
|
|
|
@ -324,6 +324,9 @@ class Submission(Base):
|
||||||
if not listing and not self.ghost and self.author.show_sig(v):
|
if not listing and not self.ghost and self.author.show_sig(v):
|
||||||
body += f"<hr>{self.author.sig_html}"
|
body += f"<hr>{self.author.sig_html}"
|
||||||
|
|
||||||
|
if v:
|
||||||
|
body = body.replace("!YOU!", v.username)
|
||||||
|
|
||||||
return body
|
return body
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
|
@ -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 = 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)
|
body = normalize_urls_runtime(body, v)
|
||||||
|
|
||||||
|
if v:
|
||||||
|
body = body.replace("!YOU!", v.username)
|
||||||
|
|
||||||
return body
|
return body
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
|
@ -350,6 +357,9 @@ class Submission(Base):
|
||||||
|
|
||||||
title = censor_slurs(title, v)
|
title = censor_slurs(title, v)
|
||||||
|
|
||||||
|
if v:
|
||||||
|
title = title.replace("!YOU!", v.username)
|
||||||
|
|
||||||
return title
|
return title
|
||||||
|
|
||||||
@lazy
|
@lazy
|
||||||
|
@ -361,6 +371,9 @@ class Submission(Base):
|
||||||
|
|
||||||
title = censor_slurs(title, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
|
title = censor_slurs(title, v).replace('<img loading="lazy" data-bs-toggle="tooltip" alt=":marseytrain:" title=":marseytrain:" src="/e/marseytrain.webp">', ':marseytrain:')
|
||||||
|
|
||||||
|
if v:
|
||||||
|
title = title.replace("!YOU!", v.username)
|
||||||
|
|
||||||
return title
|
return title
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -141,7 +141,6 @@ class User(Base):
|
||||||
subscriptions = relationship("Subscription", back_populates="user")
|
subscriptions = relationship("Subscription", back_populates="user")
|
||||||
following = relationship("Follow", primaryjoin="Follow.user_id==User.id", 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")
|
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")
|
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")
|
blocked = relationship("UserBlock", lazy="dynamic", primaryjoin="User.id==UserBlock.target_id", back_populates="target")
|
||||||
authorizations = relationship("ClientAuth", back_populates="user")
|
authorizations = relationship("ClientAuth", back_populates="user")
|
||||||
|
@ -248,7 +247,10 @@ class User(Base):
|
||||||
if self.marsify > 1:
|
if self.marsify > 1:
|
||||||
user_forced_hats.append(val)
|
user_forced_hats.append(val)
|
||||||
elif getattr(self, k):
|
elif getattr(self, k):
|
||||||
user_forced_hats.append(val)
|
if k == 'agendaposter':
|
||||||
|
user_forced_hats.append(random.choice(val))
|
||||||
|
else:
|
||||||
|
user_forced_hats.append(val)
|
||||||
if user_forced_hats: return random.choice(user_forced_hats)
|
if user_forced_hats: return random.choice(user_forced_hats)
|
||||||
else: return None
|
else: return None
|
||||||
|
|
||||||
|
@ -261,7 +263,7 @@ class User(Base):
|
||||||
if self.is_cakeday:
|
if self.is_cakeday:
|
||||||
return '/i/hats/Cakeday.webp'
|
return '/i/hats/Cakeday.webp'
|
||||||
|
|
||||||
if self.age < 86400 * 7:
|
if self.age < NEW_USER_HAT_AGE:
|
||||||
return '/i/new-user.webp'
|
return '/i/new-user.webp'
|
||||||
|
|
||||||
if self.forced_hat:
|
if self.forced_hat:
|
||||||
|
@ -873,6 +875,24 @@ class User(Base):
|
||||||
def userblocks(self):
|
def userblocks(self):
|
||||||
return [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id).all()]
|
return [x[0] for x in g.db.query(UserBlock.target_id).filter_by(user_id=self.id).all()]
|
||||||
|
|
||||||
|
def get_relationship_count(self, relationship_cls):
|
||||||
|
# TODO: deduplicate (see routes/users.py)
|
||||||
|
if relationship_cls in {SaveRelationship, Subscription}:
|
||||||
|
query = relationship_cls.submission_id
|
||||||
|
join = relationship_cls.post
|
||||||
|
cls = Submission
|
||||||
|
elif relationship_cls is CommentSaveRelationship:
|
||||||
|
query = relationship_cls.comment_id
|
||||||
|
join = relationship_cls.comment
|
||||||
|
cls = Comment
|
||||||
|
else:
|
||||||
|
raise TypeError("Relationships supported is SaveRelationship, Subscription, CommentSaveRelationship")
|
||||||
|
|
||||||
|
query = g.db.query(query).join(join).filter(relationship_cls.user_id == self.id)
|
||||||
|
if not self.admin_level >= PERMS['POST_COMMENT_MODERATION']:
|
||||||
|
query = query.filter(cls.is_banned == False, cls.deleted_utc == 0)
|
||||||
|
return query.count()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def saved_idlist(self):
|
def saved_idlist(self):
|
||||||
|
@ -895,17 +915,17 @@ class User(Base):
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def saved_count(self):
|
def saved_count(self):
|
||||||
return g.db.query(SaveRelationship).filter_by(user_id=self.id).count()
|
return self.get_relationship_count(SaveRelationship)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def saved_comment_count(self):
|
def saved_comment_count(self):
|
||||||
return g.db.query(CommentSaveRelationship).filter_by(user_id=self.id).count()
|
return self.get_relationship_count(CommentSaveRelationship)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def subscribed_count(self):
|
def subscribed_count(self):
|
||||||
return g.db.query(Subscription).filter_by(user_id=self.id).count()
|
return self.get_relationship_count(Subscription)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
|
@ -924,17 +944,6 @@ class User(Base):
|
||||||
def can_create_hole(self):
|
def can_create_hole(self):
|
||||||
return self.admin_level >= PERMS['HOLE_CREATE']
|
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
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def patron_tooltip(self):
|
def patron_tooltip(self):
|
||||||
|
@ -982,6 +991,7 @@ class User(Base):
|
||||||
if not cls.can_see(user, other.author): return False
|
if not cls.can_see(user, other.author): return False
|
||||||
if user and user.id == other.author_id: return True
|
if user and user.id == other.author_id: return True
|
||||||
if isinstance(other, Submission):
|
if isinstance(other, Submission):
|
||||||
|
if "!YOU!" in other.title and not user: return False
|
||||||
if other.sub and not cls.can_see(user, other.subr): return False
|
if other.sub and not cls.can_see(user, other.subr): return False
|
||||||
else:
|
else:
|
||||||
if not other.parent_submission:
|
if not other.parent_submission:
|
||||||
|
@ -997,7 +1007,6 @@ class User(Base):
|
||||||
return (user and user.id == other.id) or (user and user.can_see_shadowbanned) or not other.shadowbanned
|
return (user and user.id == other.id) or (user and user.can_see_shadowbanned) or not other.shadowbanned
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def can_see_chudrama(self):
|
def can_see_chudrama(self):
|
||||||
|
@ -1011,10 +1020,10 @@ class User(Base):
|
||||||
@property
|
@property
|
||||||
@lazy
|
@lazy
|
||||||
def can_post_in_ghost_threads(self):
|
def can_post_in_ghost_threads(self):
|
||||||
if not TRUESCORE_GHOST_LIMIT: return True
|
if not TRUESCORE_GHOST_MINIMUM: return True
|
||||||
if self.admin_level >= PERMS['POST_IN_GHOST_THREADS']: return True
|
if self.admin_level >= PERMS['POST_IN_GHOST_THREADS']: return True
|
||||||
if self.club_allowed: return True
|
if self.club_allowed: return True
|
||||||
if self.truescore >= TRUESCORE_GHOST_LIMIT: return True
|
if self.truescore >= TRUESCORE_GHOST_MINIMUM: return True
|
||||||
if self.patron: return True
|
if self.patron: return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -394,14 +394,15 @@ def execute_antispam_duplicate_comment_check(v:User, body_html:str):
|
||||||
'''
|
'''
|
||||||
Sanity check for newfriends
|
Sanity check for newfriends
|
||||||
'''
|
'''
|
||||||
|
ANTISPAM_DUPLICATE_THRESHOLD = 3
|
||||||
if v.id in ANTISPAM_BYPASS_IDS or v.admin_level: return
|
if v.id in ANTISPAM_BYPASS_IDS or v.admin_level: return
|
||||||
if v.age >= NOTIFICATION_SPAM_AGE_THRESHOLD: return
|
if v.age >= NOTIFICATION_SPAM_AGE_THRESHOLD: return
|
||||||
if len(body_html) < 16: return
|
if len(body_html) < 16: return
|
||||||
if body_html == '!wordle': return # wordle
|
if body_html == '!wordle': return # wordle
|
||||||
compare_time = int(time.time()) - 60 * 60 * 24
|
compare_time = int(time.time()) - 60 * 60 * 24
|
||||||
comment = g.db.query(Comment.id).filter(Comment.body_html == body_html,
|
count = g.db.query(Comment.id).filter(Comment.body_html == body_html,
|
||||||
Comment.created_utc >= compare_time).first()
|
Comment.created_utc >= compare_time).count()
|
||||||
if not comment: return
|
if count <= ANTISPAM_DUPLICATE_THRESHOLD: return
|
||||||
v.ban(reason="Spamming.", days=0.0)
|
v.ban(reason="Spamming.", days=0.0)
|
||||||
send_repeatable_notification(v.id, "Your account has been banned **permanently** for the following reason:\n\n> Too much spam!")
|
send_repeatable_notification(v.id, "Your account has been banned **permanently** for the following reason:\n\n> Too much spam!")
|
||||||
g.db.add(v)
|
g.db.add(v)
|
||||||
|
@ -456,18 +457,18 @@ def execute_lawlz_actions(v:User, p:Submission):
|
||||||
pin_time = 'for 1 day'
|
pin_time = 'for 1 day'
|
||||||
ma_1=ModAction(
|
ma_1=ModAction(
|
||||||
kind="pin_post",
|
kind="pin_post",
|
||||||
user_id=v.id,
|
user_id=AUTOJANNY_ID,
|
||||||
target_submission_id=p.id,
|
target_submission_id=p.id,
|
||||||
_note=pin_time
|
_note=pin_time
|
||||||
)
|
)
|
||||||
ma_2=ModAction(
|
ma_2=ModAction(
|
||||||
kind="distinguish_post",
|
kind="distinguish_post",
|
||||||
user_id=v.id,
|
user_id=AUTOJANNY_ID,
|
||||||
target_submission_id=p.id
|
target_submission_id=p.id
|
||||||
)
|
)
|
||||||
ma_3=ModAction(
|
ma_3=ModAction(
|
||||||
kind="flair_post",
|
kind="flair_post",
|
||||||
user_id=v.id,
|
user_id=AUTOJANNY_ID,
|
||||||
target_submission_id=p.id,
|
target_submission_id=p.id,
|
||||||
_note=f'"{p.flair}"'
|
_note=f'"{p.flair}"'
|
||||||
)
|
)
|
||||||
|
|
|
@ -95,6 +95,7 @@ AJ_REPLACEMENTS = {
|
||||||
|
|
||||||
SLURS = {
|
SLURS = {
|
||||||
"nigger": "BIPOC",
|
"nigger": "BIPOC",
|
||||||
|
"negroid": "BIPOC",
|
||||||
"niglet": 'BIPOClet',
|
"niglet": 'BIPOClet',
|
||||||
"negress": "BIPOC woman",
|
"negress": "BIPOC woman",
|
||||||
'nigga': 'neighbor',
|
'nigga': 'neighbor',
|
||||||
|
@ -145,6 +146,8 @@ if SITE_NAME == 'rDrama':
|
||||||
"kys ": "keep yourself safe ",
|
"kys ": "keep yourself safe ",
|
||||||
"republican": 'republiKKKan',
|
"republican": 'republiKKKan',
|
||||||
"america": 'ameriKKKa',
|
"america": 'ameriKKKa',
|
||||||
|
"it's almost as if": "I'm a retard but",
|
||||||
|
"my brother in christ": "my brother in Allah",
|
||||||
}
|
}
|
||||||
SLURS.update(RDRAMA_SLURS)
|
SLURS.update(RDRAMA_SLURS)
|
||||||
|
|
||||||
|
@ -153,7 +156,6 @@ PROFANITIES = {
|
||||||
'fuck': 'frick',
|
'fuck': 'frick',
|
||||||
' ass ': ' butt ',
|
' ass ': ' butt ',
|
||||||
'shitting': 'pooping',
|
'shitting': 'pooping',
|
||||||
'lmao': 'lmbo',
|
|
||||||
'damn': 'darn',
|
'damn': 'darn',
|
||||||
'bastard': 'fatherless child',
|
'bastard': 'fatherless child',
|
||||||
'bitch': 'b-word',
|
'bitch': 'b-word',
|
||||||
|
@ -252,8 +254,6 @@ PERMS = { # Minimum admin_level to perform action.
|
||||||
'VIEW_CHUDRAMA': 1,
|
'VIEW_CHUDRAMA': 1,
|
||||||
'VIEW_PRIVATE_PROFILES': 2,
|
'VIEW_PRIVATE_PROFILES': 2,
|
||||||
'VIEW_ALTS': 2,
|
'VIEW_ALTS': 2,
|
||||||
'VIEW_PROFILE_VIEWS': 2,
|
|
||||||
'VIEW_SORTED_ADMIN_LIST': 3,
|
|
||||||
'VIEW_ACTIVE_USERS': 2,
|
'VIEW_ACTIVE_USERS': 2,
|
||||||
'VIEW_ALL_USERS': 2,
|
'VIEW_ALL_USERS': 2,
|
||||||
'VIEW_ALT_VOTES': 2,
|
'VIEW_ALT_VOTES': 2,
|
||||||
|
@ -387,13 +387,14 @@ COMMENT_MAX_DEPTH = 200
|
||||||
TRANSFER_MESSAGE_LENGTH_LIMIT = 200 # do not make larger than 10000 characters (comment limit) without altering the table
|
TRANSFER_MESSAGE_LENGTH_LIMIT = 200 # do not make larger than 10000 characters (comment limit) without altering the table
|
||||||
MIN_REPOST_CHECK_URL_LENGTH = 9 # also change the constant in checkRepost() of submit.js
|
MIN_REPOST_CHECK_URL_LENGTH = 9 # also change the constant in checkRepost() of submit.js
|
||||||
CHAT_LENGTH_LIMIT = 1000
|
CHAT_LENGTH_LIMIT = 1000
|
||||||
TRUESCORE_DONATE_LIMIT = 100
|
|
||||||
COSMETIC_AWARD_COIN_AWARD_PCT = 0.10
|
COSMETIC_AWARD_COIN_AWARD_PCT = 0.10
|
||||||
TRUESCORE_CHAT_LIMIT = 0
|
TRUESCORE_CHAT_MINIMUM = 0
|
||||||
TRUESCORE_GHOST_LIMIT = 0
|
TRUESCORE_DONATE_MINIMUM = 100
|
||||||
|
TRUESCORE_GHOST_MINIMUM = 0
|
||||||
|
|
||||||
LOGGEDIN_ACTIVE_TIME = 15 * 60
|
LOGGEDIN_ACTIVE_TIME = 15 * 60
|
||||||
PFP_DEFAULT_MARSEY = True
|
PFP_DEFAULT_MARSEY = True
|
||||||
|
NEW_USER_HAT_AGE = 0 # seconds of age to show new-user forced hat
|
||||||
NOTIFICATION_SPAM_AGE_THRESHOLD = 0.5 * 86400
|
NOTIFICATION_SPAM_AGE_THRESHOLD = 0.5 * 86400
|
||||||
COMMENT_SPAM_LENGTH_THRESHOLD = 50
|
COMMENT_SPAM_LENGTH_THRESHOLD = 50
|
||||||
|
|
||||||
|
@ -435,6 +436,7 @@ MODMAIL_ID = 2
|
||||||
|
|
||||||
POLL_THREAD = 0
|
POLL_THREAD = 0
|
||||||
POLL_BET_COINS = 200
|
POLL_BET_COINS = 200
|
||||||
|
POLL_MAX_OPTIONS = 10
|
||||||
WELCOME_MSG = f"Welcome to {SITE_NAME}!"
|
WELCOME_MSG = f"Welcome to {SITE_NAME}!"
|
||||||
|
|
||||||
LOTTERY_TICKET_COST = 12
|
LOTTERY_TICKET_COST = 12
|
||||||
|
@ -456,7 +458,8 @@ MAX_VIDEO_SIZE_MB = 32
|
||||||
MAX_VIDEO_SIZE_MB_PATRON = 64
|
MAX_VIDEO_SIZE_MB_PATRON = 64
|
||||||
MAX_IMAGE_CONVERSION_TIMEOUT = 15 # seconds
|
MAX_IMAGE_CONVERSION_TIMEOUT = 15 # seconds
|
||||||
|
|
||||||
ANTISPAM_BYPASS_IDS = ()
|
ANTISPAM_BYPASS_IDS = set()
|
||||||
|
BOOSTED_USERS_EXCLUDED = set()
|
||||||
|
|
||||||
PAGE_SIZE = 25
|
PAGE_SIZE = 25
|
||||||
LEADERBOARD_LIMIT = PAGE_SIZE
|
LEADERBOARD_LIMIT = PAGE_SIZE
|
||||||
|
@ -490,9 +493,9 @@ if SITE == 'rdrama.net':
|
||||||
NOTIFICATION_THREAD = 6489
|
NOTIFICATION_THREAD = 6489
|
||||||
|
|
||||||
CHAT_LENGTH_LIMIT = 200
|
CHAT_LENGTH_LIMIT = 200
|
||||||
|
TRUESCORE_CHAT_MINIMUM = 10
|
||||||
TRUESCORE_CHAT_LIMIT = 10
|
TRUESCORE_GHOST_MINIMUM = 10
|
||||||
TRUESCORE_GHOST_LIMIT = 10
|
NEW_USER_HAT_AGE = 7 * 86400
|
||||||
|
|
||||||
HOLE_COST = 50000
|
HOLE_COST = 50000
|
||||||
HOLE_INACTIVITY_DELETION = True
|
HOLE_INACTIVITY_DELETION = True
|
||||||
|
@ -525,7 +528,34 @@ if SITE == 'rdrama.net':
|
||||||
GEESE_ID = 1710
|
GEESE_ID = 1710
|
||||||
BLACKJACKBTZ_ID = 12732
|
BLACKJACKBTZ_ID = 12732
|
||||||
|
|
||||||
ANTISPAM_BYPASS_IDS = (1703, 13427)
|
ANTISPAM_BYPASS_IDS = {1703, 13427}
|
||||||
|
|
||||||
|
BOOSTED_HOLES = {
|
||||||
|
'furry',
|
||||||
|
'femboy',
|
||||||
|
'anime',
|
||||||
|
'gaybros',
|
||||||
|
'againsthateholes',
|
||||||
|
'masterbaiters',
|
||||||
|
'changelog',
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOSTED_USERS = {
|
||||||
|
IMPASSIONATA_ID,
|
||||||
|
PIZZASHILL_ID,
|
||||||
|
SNAKES_ID,
|
||||||
|
JUSTCOOL_ID,
|
||||||
|
2008, #TransGirlTradWife
|
||||||
|
29, #QuadNarca
|
||||||
|
JOAN_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOSTED_USERS_EXCLUDED = {
|
||||||
|
8768,
|
||||||
|
3402,
|
||||||
|
5214,
|
||||||
|
12719
|
||||||
|
}
|
||||||
|
|
||||||
GIFT_NOTIF_ID = CARP_ID
|
GIFT_NOTIF_ID = CARP_ID
|
||||||
|
|
||||||
|
@ -556,7 +586,7 @@ elif SITE == 'pcmemes.net':
|
||||||
AEVANN_ID = 1
|
AEVANN_ID = 1
|
||||||
SNAKES_ID = 2279
|
SNAKES_ID = 2279
|
||||||
|
|
||||||
WELCOME_MSG = "Welcome to pcmemes.net! Don't forget to turn off the slur filter [here](/settings/content#slurreplacer)!"
|
WELCOME_MSG = "Welcome to pcmemes.net! Don't forget to turn off the slur filter [here](/settings/content#slurreplacer)"
|
||||||
|
|
||||||
LOTTERY_TICKET_COST = 12
|
LOTTERY_TICKET_COST = 12
|
||||||
LOTTERY_SINK_RATE = -8
|
LOTTERY_SINK_RATE = -8
|
||||||
|
@ -564,42 +594,47 @@ elif SITE == 'pcmemes.net':
|
||||||
BANNER_THREAD = 28307
|
BANNER_THREAD = 28307
|
||||||
elif SITE == 'watchpeopledie.tv':
|
elif SITE == 'watchpeopledie.tv':
|
||||||
PIN_LIMIT = 4
|
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! We are on [GitHub](https://github.com/Aevann1/rDrama).\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!"""
|
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!"""
|
||||||
|
|
||||||
FEATURES['PATRON_ICONS'] = True
|
FEATURES['PATRON_ICONS'] = True
|
||||||
|
|
||||||
PERMS['HOLE_CREATE'] = 2
|
PERMS['HOLE_CREATE'] = 2
|
||||||
PERMS['POST_EDITING'] = 2
|
PERMS['POST_EDITING'] = 2
|
||||||
PERMS['ADMIN_ADD'] = 4
|
PERMS['ADMIN_ADD'] = 4
|
||||||
|
|
||||||
ERROR_TITLES[400] = "Bad Request"
|
ERROR_TITLES.update({
|
||||||
ERROR_TITLES[401] = "Unauthorized"
|
400: "Bad Request",
|
||||||
ERROR_TITLES[403] = "Forbidden"
|
401: "Unauthorized",
|
||||||
ERROR_TITLES[404] = "Not Found"
|
403: "Forbidden",
|
||||||
ERROR_TITLES[405] = "Method Not Allowed"
|
404: "Not Found",
|
||||||
ERROR_TITLES[406] = "Too Many Pings"
|
405: "Method Not Allowed",
|
||||||
ERROR_TITLES[409] = "Mortal Conflict"
|
406: "Too Many Pings",
|
||||||
ERROR_TITLES[410] = "Dead"
|
409: "Mortal Conflict",
|
||||||
ERROR_TITLES[413] = "Payload Too Large"
|
410: "Dead",
|
||||||
ERROR_TITLES[415] = "Unsupported Media Type"
|
413: "Payload Too Large",
|
||||||
ERROR_TITLES[500] = "Internal Server Error"
|
415: "Unsupported Media Type",
|
||||||
ERROR_MSGS[400] = "That request is invalid"
|
500: "Internal Server Error",
|
||||||
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.update({
|
||||||
ERROR_MSGS[405] = "You can't use this method here... if you keep getting this error tell us it's prolly something borked"
|
400: "That request is invalid",
|
||||||
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."
|
401: "You need to login or sign up to do that",
|
||||||
ERROR_MSGS[410] = "This link is dead. Request a new one to try again"
|
403: "You're not allowed to do that",
|
||||||
ERROR_MSGS[413] = "You need to upload a smaller file please"
|
404: "That wasn't found",
|
||||||
ERROR_MSGS[429] = "Please wait a bit before doing that"
|
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
|
POLL_THREAD = 13225
|
||||||
|
|
||||||
SIDEBAR_THREAD = 5403
|
SIDEBAR_THREAD = 5403
|
||||||
BANNER_THREAD = 9869
|
BANNER_THREAD = 9869
|
||||||
|
|
||||||
TRUESCORE_CHAT_LIMIT = 10
|
TRUESCORE_CHAT_MINIMUM = 10
|
||||||
TRUESCORE_GHOST_LIMIT = 10
|
TRUESCORE_GHOST_MINIMUM = 10
|
||||||
|
|
||||||
HOLE_NAME = 'flair'
|
HOLE_NAME = 'flair'
|
||||||
HOLE_STYLE_FLAIR = True
|
HOLE_STYLE_FLAIR = True
|
||||||
|
@ -1397,6 +1432,7 @@ NOTIFIED_USERS = {
|
||||||
'snakes': SNAKES_ID,
|
'snakes': SNAKES_ID,
|
||||||
'sneks': SNAKES_ID,
|
'sneks': SNAKES_ID,
|
||||||
'snekky': SNAKES_ID,
|
'snekky': SNAKES_ID,
|
||||||
|
'snekchad': SNAKES_ID,
|
||||||
'jc': JUSTCOOL_ID,
|
'jc': JUSTCOOL_ID,
|
||||||
'justcool': JUSTCOOL_ID,
|
'justcool': JUSTCOOL_ID,
|
||||||
'geese': GEESE_ID,
|
'geese': GEESE_ID,
|
||||||
|
@ -1413,9 +1449,7 @@ NOTIFIED_USERS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
FORTUNE_REPLIES = ('<b style="color:#6023f8">Your fortune: Allah Wills It</b>','<b style="color:#d302a7">Your fortune: Inshallah, Only Good Things Shall Come To Pass</b>','<b style="color:#e7890c">Your fortune: Allah Smiles At You This Day</b>','<b style="color:#7fec11">Your fortune: Your Bussy Is In For A Blasting</b>','<b style="color:#43fd3b">Your fortune: You Will Be Propositioned By A High-Tier Twink</b>','<b style="color:#9d05da">Your fortune: Repent, You Have Displeased Allah And His Vengeance Is Nigh</b>','<b style="color:#f51c6a">Your fortune: Reply Hazy, Try Again</b>','<b style="color:#00cbb0">Your fortune: lmao you just lost 100 coins</b>','<b style="color:#2a56fb">Your fortune: Yikes 😬</b>','<b style="color:#0893e1">Your fortune: You Will Be Blessed With Many Black Bulls</b>','<b style="color:#16f174">Your fortune: NEETmax, The Day Is Lost If You Venture Outside</b>','<b style="color:#fd4d32">Your fortune: A Taste Of Jannah Awaits You Today</b>','<b style="color:#bac200">Your fortune: Watch Your Back</b>','<b style="color:#6023f8">Your fortune: Outlook good</b>','<b style="color:#d302a7">Your fortune: Godly Luck</b>','<b style="color:#e7890c">Your fortune: Good Luck</b>','<b style="color:#7fec11">Your fortune: Bad Luck</b>','<b style="color:#43fd3b">Your fortune: Good news will come to you by mail</b>','<b style="color:#9d05da">Your fortune: Very Bad Luck</b>','<b style="color:#00cbb0">Your fortune: キタ━━━━━━(゚∀゚)━━━━━━ !!!!</b>','<b style="color:#2a56fb">Your fortune: Better not tell you now</b>','<b style="color:#0893e1">Your fortune: You will meet a dark handsome stranger</b>','<b style="color:#16f174">Your fortune: ( ´_ゝ`)フーン</b>','<b style="color:#fd4d32">Your fortune: Excellent Luck</b>','<b style="color:#bac200">Your fortune: Average Luck</b>')
|
FORTUNE_REPLIES = ('<b style="color:#6023f8">Your fortune: Allah Wills It</b>','<b style="color:#d302a7">Your fortune: Inshallah, Only Good Things Shall Come To Pass</b>','<b style="color:#e7890c">Your fortune: Allah Smiles At You This Day</b>','<b style="color:#7fec11">Your fortune: Your Bussy Is In For A Blasting</b>','<b style="color:#43fd3b">Your fortune: You Will Be Propositioned By A High-Tier Twink</b>','<b style="color:#9d05da">Your fortune: Repent, You Have Displeased Allah And His Vengeance Is Nigh</b>','<b style="color:#f51c6a">Your fortune: Reply Hazy, Try Again</b>','<b style="color:#00cbb0">Your fortune: lmao you just lost 100 coins</b>','<b style="color:#2a56fb">Your fortune: Yikes 😬</b>','<b style="color:#0893e1">Your fortune: You Will Be Blessed With Many Black Bulls</b>','<b style="color:#16f174">Your fortune: NEETmax, The Day Is Lost If You Venture Outside</b>','<b style="color:#fd4d32">Your fortune: A Taste Of Jannah Awaits You Today</b>','<b style="color:#bac200">Your fortune: Watch Your Back</b>','<b style="color:#6023f8">Your fortune: Outlook good</b>','<b style="color:#d302a7">Your fortune: Godly Luck</b>','<b style="color:#e7890c">Your fortune: Good Luck</b>','<b style="color:#7fec11">Your fortune: Bad Luck</b>','<b style="color:#43fd3b">Your fortune: Good news will come to you by mail</b>','<b style="color:#9d05da">Your fortune: Very Bad Luck</b>','<b style="color:#00cbb0">Your fortune: キタ━━━━━━(゚∀゚)━━━━━━ !!!!</b>','<b style="color:#2a56fb">Your fortune: Better not tell you now</b>','<b style="color:#0893e1">Your fortune: You will meet a dark handsome stranger</b>','<b style="color:#16f174">Your fortune: ( ´_ゝ`)フーン</b>','<b style="color:#fd4d32">Your fortune: Excellent Luck</b>','<b style="color:#bac200">Your fortune: Average Luck</b>')
|
||||||
|
|
||||||
FACTCHECK_REPLIES = ('<b style="color:#6023f8">Factcheck: This claim has been confirmed as correct by experts. </b>','<b style="color:#d302a7">Factcheck: This claim has been classified as misogynistic.</b>','<b style="color:#e7890c">Factcheck: This claim is currently being debunked.</b>','<b style="color:#7fec11">Factcheck: This claim is 100% true.</b>','<b style="color:#9d05da">Factcheck: This claim hurts trans lives.</b>','<b style="color:#f51c6a">Factcheck: [REDACTED].</b>','<b style="color:#00cbb0">Factcheck: This claim is both true and false.</b>','<b style="color:#2a56fb">Factcheck: You really believe that shit? Lmao dumbass nigga 🤣</b>','<b style="color:#0893e1">Factcheck: None of this is real.</b>','<b style="color:#16f174">Factcheck: Yes.</b>','<b style="color:#fd4d32">Factcheck: This claim has not been approved by experts.</b>','<b style="color:#bac200">Factcheck: This claim is a gross exageration of reality.</b>','<b style="color:#ff2200">Factcheck: WARNING! THIS CLAIM HAS BEEN CLASSIFIED AS DANGEROUS. PLEASE REMAIN STILL, AN AGENT WILL COME TO MEET YOU SHORTLY.</b>')
|
FACTCHECK_REPLIES = ('<b style="color:#6023f8">Factcheck: This claim has been confirmed as correct by experts. </b>','<b style="color:#d302a7">Factcheck: This claim has been classified as misogynistic.</b>','<b style="color:#e7890c">Factcheck: This claim is currently being debunked.</b>','<b style="color:#7fec11">Factcheck: This claim is 100% true.</b>','<b style="color:#9d05da">Factcheck: This claim hurts trans lives.</b>','<b style="color:#f51c6a">Factcheck: [REDACTED].</b>','<b style="color:#00cbb0">Factcheck: This claim is both true and false.</b>','<b style="color:#2a56fb">Factcheck: You really believe that shit? Lmao dumbass nigga 🤣</b>','<b style="color:#0893e1">Factcheck: None of this is real.</b>','<b style="color:#16f174">Factcheck: Yes.</b>','<b style="color:#fd4d32">Factcheck: This claim has not been approved by experts.</b>','<b style="color:#bac200">Factcheck: This claim is a gross exageration of reality.</b>','<b style="color:#ff2200">Factcheck: WARNING! THIS CLAIM HAS BEEN CLASSIFIED AS DANGEROUS. PLEASE REMAIN STILL, AN AGENT WILL COME TO MEET YOU SHORTLY.</b>')
|
||||||
|
|
||||||
EIGHTBALL_REPLIES = ('<b style="color:#7FEC11">The 8-Ball Says: It is certain.</b>', '<b style="color:#7FEC11">The 8-Ball Says: It is decidedly so.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Without a doubt.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Yes definitely.</b>', '<b style="color:#7FEC11">The 8-Ball Says: You may rely on it.</b>', '<b style="color:#7FEC11">The 8-Ball Says: As I see it, yes.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Most likely.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Outlook good.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Yes.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Signs point to yes.</b>', '<b style="color:#E7890C">The 8-Ball Says: Reply hazy, try again.</b>', '<b style="color:#E7890C">The 8-Ball Says: Ask again later.</b>', '<b style="color:#E7890C">The 8-Ball Says: Better not tell you now.</b>', '<b style="color:#E7890C">The 8-Ball Says: Cannot predict now.</b>', '<b style="color:#E7890C">The 8-Ball Says: Concentrate and ask again.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Don\'t count on it.</b>', '<b style="color:#FD4D32">The 8-Ball Says: My reply is no.</b>', '<b style="color:#FD4D32">The 8-Ball Says: My sources say no.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Outlook not so good.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Very doubtful.</b>')
|
EIGHTBALL_REPLIES = ('<b style="color:#7FEC11">The 8-Ball Says: It is certain.</b>', '<b style="color:#7FEC11">The 8-Ball Says: It is decidedly so.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Without a doubt.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Yes definitely.</b>', '<b style="color:#7FEC11">The 8-Ball Says: You may rely on it.</b>', '<b style="color:#7FEC11">The 8-Ball Says: As I see it, yes.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Most likely.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Outlook good.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Yes.</b>', '<b style="color:#7FEC11">The 8-Ball Says: Signs point to yes.</b>', '<b style="color:#E7890C">The 8-Ball Says: Reply hazy, try again.</b>', '<b style="color:#E7890C">The 8-Ball Says: Ask again later.</b>', '<b style="color:#E7890C">The 8-Ball Says: Better not tell you now.</b>', '<b style="color:#E7890C">The 8-Ball Says: Cannot predict now.</b>', '<b style="color:#E7890C">The 8-Ball Says: Concentrate and ask again.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Don\'t count on it.</b>', '<b style="color:#FD4D32">The 8-Ball Says: My reply is no.</b>', '<b style="color:#FD4D32">The 8-Ball Says: My sources say no.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Outlook not so good.</b>', '<b style="color:#FD4D32">The 8-Ball Says: Very doubtful.</b>')
|
||||||
|
|
||||||
REDDIT_NOTIFS_SITE = set()
|
REDDIT_NOTIFS_SITE = set()
|
||||||
|
@ -1582,7 +1616,12 @@ forced_hats = {
|
||||||
"earlylife": ("The Merchant", "SHUT IT DOWN, the goys know!"),
|
"earlylife": ("The Merchant", "SHUT IT DOWN, the goys know!"),
|
||||||
"marsify": ("Marsified", "I can't pick my own Marseys, help!"),
|
"marsify": ("Marsified", "I can't pick my own Marseys, help!"),
|
||||||
"is_suspended": ("Behind Bars", "This user is banned and needs to do better!"),
|
"is_suspended": ("Behind Bars", "This user is banned and needs to do better!"),
|
||||||
"agendaposter": ("Egg_irl", "This user is getting in touch with xir identity!")
|
"agendaposter": (("Egg_irl", "This user is getting in touch with xir identity!"),
|
||||||
|
("Trans Flag", "Just in case you forgot, trans lives matter."),
|
||||||
|
("Trans Flag II", "Your egg is cracked; wear it with pride!"),
|
||||||
|
("Pride Flag", "Never forget that this is a primarily gay community. Dude bussy lmao."),
|
||||||
|
("Pride Flag II", "This user is a proud supporter of LGBTQ+ rights."))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EMAIL_REGEX_PATTERN = '[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{2,63}\.[A-Za-z]{2,63}'
|
EMAIL_REGEX_PATTERN = '[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{2,63}\.[A-Za-z]{2,63}'
|
||||||
|
@ -1656,6 +1695,7 @@ if SITE_NAME == 'rDrama':
|
||||||
'backloggd.com',
|
'backloggd.com',
|
||||||
'tildes.net',
|
'tildes.net',
|
||||||
'blacktwitterapp.com',
|
'blacktwitterapp.com',
|
||||||
|
'dailystormer.in',
|
||||||
|
|
||||||
#fediverse
|
#fediverse
|
||||||
'rdrama.cc',
|
'rdrama.cc',
|
||||||
|
@ -1670,26 +1710,6 @@ if SITE_NAME == 'rDrama':
|
||||||
'seal.cafe',
|
'seal.cafe',
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOSTED_HOLES = {
|
|
||||||
'furry',
|
|
||||||
'femboy',
|
|
||||||
'anime',
|
|
||||||
'gaybros',
|
|
||||||
'againsthateholes',
|
|
||||||
'masterbaiters',
|
|
||||||
'changelog',
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOSTED_USERS = {
|
|
||||||
IMPASSIONATA_ID,
|
|
||||||
PIZZASHILL_ID,
|
|
||||||
SNAKES_ID,
|
|
||||||
JUSTCOOL_ID,
|
|
||||||
2008, #TransGirlTradWife
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOSTED_USERS_EXCLUDED = {8768, 5214, 12719, 3402}
|
|
||||||
|
|
||||||
IMAGE_FORMATS = ['png','gif','jpg','jpeg','webp']
|
IMAGE_FORMATS = ['png','gif','jpg','jpeg','webp']
|
||||||
VIDEO_FORMATS = ['mp4','webm','mov','avi','mkv','flv','m4v','3gp']
|
VIDEO_FORMATS = ['mp4','webm','mov','avi','mkv','flv','m4v','3gp']
|
||||||
AUDIO_FORMATS = ['mp3','wav','ogg','aac','m4a','flac']
|
AUDIO_FORMATS = ['mp3','wav','ogg','aac','m4a','flac']
|
||||||
|
|
|
@ -2,7 +2,7 @@ from typing import Callable, Iterable, List, Optional, Union
|
||||||
|
|
||||||
from flask import *
|
from flask import *
|
||||||
from sqlalchemy import and_, any_, or_
|
from sqlalchemy import and_, any_, or_
|
||||||
from sqlalchemy.orm import joinedload, selectinload
|
from sqlalchemy.orm import joinedload, selectinload, Query
|
||||||
|
|
||||||
from files.classes import Comment, CommentVote, Hat, Sub, Submission, User, UserBlock, Vote
|
from files.classes import Comment, CommentVote, Hat, Sub, Submission, User, UserBlock, Vote
|
||||||
from files.helpers.const import AUTOJANNY_ID
|
from files.helpers.const import AUTOJANNY_ID
|
||||||
|
@ -145,7 +145,7 @@ def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Option
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> List[Submission]:
|
def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False, extra:Optional[Callable[[Query], Query]]=None) -> List[Submission]:
|
||||||
if not pids: return []
|
if not pids: return []
|
||||||
|
|
||||||
if v:
|
if v:
|
||||||
|
@ -178,6 +178,8 @@ def get_posts(pids:Iterable[int], v:Optional[User]=None, eager:bool=False) -> Li
|
||||||
else:
|
else:
|
||||||
query = g.db.query(Submission).filter(Submission.id.in_(pids))
|
query = g.db.query(Submission).filter(Submission.id.in_(pids))
|
||||||
|
|
||||||
|
if extra: query = extra(query)
|
||||||
|
|
||||||
if eager:
|
if eager:
|
||||||
query = query.options(
|
query = query.options(
|
||||||
selectinload(Submission.author).options(
|
selectinload(Submission.author).options(
|
||||||
|
@ -226,7 +228,7 @@ def add_block_props(target:Union[Submission, Comment, User], v:Optional[User]):
|
||||||
if not v: return target
|
if not v: return target
|
||||||
id = None
|
id = None
|
||||||
|
|
||||||
if any(isinstance(target, cls) for cls in [Submission, Comment]):
|
if any(isinstance(target, cls) for cls in {Submission, Comment}):
|
||||||
id = target.author_id
|
id = target.author_id
|
||||||
elif isinstance(target, User):
|
elif isinstance(target, User):
|
||||||
id = target.id
|
id = target.id
|
||||||
|
@ -276,12 +278,14 @@ def add_vote_and_block_props(target:Union[Submission, Comment], v:Optional[User]
|
||||||
target = add_block_props(target, v)
|
target = add_block_props(target, v)
|
||||||
return add_vote_props(target, v, vote_cls)
|
return add_vote_props(target, v, vote_cls)
|
||||||
|
|
||||||
def get_comments(cids:Iterable[int], v:Optional[User]=None) -> List[Comment]:
|
def get_comments(cids:Iterable[int], v:Optional[User]=None, extra:Optional[Callable[[Query], Query]]=None) -> List[Comment]:
|
||||||
if not cids: return []
|
if not cids: return []
|
||||||
if v:
|
if v:
|
||||||
output = get_comments_v_properties(v, True, None, Comment.id.in_(cids))[1]
|
output = get_comments_v_properties(v, True, None, Comment.id.in_(cids))[1] # TODO: support 'extra' for get_comments_v_properties
|
||||||
else:
|
else:
|
||||||
output = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.id.in_(cids)).all()
|
output = g.db.query(Comment).join(Comment.author)
|
||||||
|
if extra: output = extra(output)
|
||||||
|
output = output.filter(User.shadowbanned == None, Comment.id.in_(cids)).all()
|
||||||
return sorted(output, key=lambda x: cids.index(x.id))
|
return sorted(output, key=lambda x: cids.index(x.id))
|
||||||
|
|
||||||
def get_comments_v_properties(v:User, include_shadowbanned=True, should_keep_func:Optional[Callable[[Comment], bool]]=None, *criterion):
|
def get_comments_v_properties(v:User, include_shadowbanned=True, should_keep_func:Optional[Callable[[Comment], bool]]=None, *criterion):
|
||||||
|
|
|
@ -52,7 +52,7 @@ def allowed_attributes(tag, name, value):
|
||||||
if name == 'style': return True
|
if name == 'style': return True
|
||||||
|
|
||||||
if tag == 'marquee':
|
if tag == 'marquee':
|
||||||
if name in ['direction', 'behavior', 'scrollamount']: return True
|
if name in {'direction', 'behavior', 'scrollamount'}: return True
|
||||||
if name in {'height', 'width'}:
|
if name in {'height', 'width'}:
|
||||||
try: value = int(value.replace('px', ''))
|
try: value = int(value.replace('px', ''))
|
||||||
except: return False
|
except: return False
|
||||||
|
@ -67,11 +67,11 @@ def allowed_attributes(tag, name, value):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if tag == 'img':
|
if tag == 'img':
|
||||||
if name in ['src','data-src']: return is_safe_url(value)
|
if name in {'src','data-src'}: return is_safe_url(value)
|
||||||
if name == 'loading' and value == 'lazy': return True
|
if name == 'loading' and value == 'lazy': return True
|
||||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||||
if name in ['g','b','glow'] and not value: return True
|
if name in {'g','b','glow'} and not value: return True
|
||||||
if name in ['alt','title']: return True
|
if name in {'alt','title'}: return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if tag == 'lite-youtube':
|
if tag == 'lite-youtube':
|
||||||
|
@ -426,8 +426,8 @@ def allowed_attributes_emojis(tag, name, value):
|
||||||
if name == 'src' and value.startswith('/') and '\\' not in value: return True
|
if name == 'src' and value.startswith('/') and '\\' not in value: return True
|
||||||
if name == 'loading' and value == 'lazy': return True
|
if name == 'loading' and value == 'lazy': return True
|
||||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||||
if name in ['g','glow'] and not value: return True
|
if name in {'g','glow'} and not value: return True
|
||||||
if name in ['alt','title']: return True
|
if name in {'alt','title'}: return True
|
||||||
|
|
||||||
if tag == 'span':
|
if tag == 'span':
|
||||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||||
|
|
|
@ -546,9 +546,11 @@ def badge_grant_post(v):
|
||||||
if desc: new_badge.description = desc
|
if desc: new_badge.description = desc
|
||||||
|
|
||||||
url = request.values.get("url")
|
url = request.values.get("url")
|
||||||
if '\\' in url: abort(400)
|
if url:
|
||||||
|
if '\\' in url: abort(400)
|
||||||
if url: new_badge.url = url
|
if url.startswith(SITE_FULL):
|
||||||
|
url = url.split(SITE_FULL, 1)[1]
|
||||||
|
new_badge.url = url
|
||||||
|
|
||||||
g.db.add(new_badge)
|
g.db.add(new_badge)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
@ -829,7 +831,7 @@ def admin_removed_comments(v):
|
||||||
try: page = int(request.values.get("page", 1))
|
try: page = int(request.values.get("page", 1))
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE).all()
|
ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
|
||||||
ids=[x[0] for x in ids]
|
ids=[x[0] for x in ids]
|
||||||
next_exists = len(ids) > PAGE_SIZE
|
next_exists = len(ids) > PAGE_SIZE
|
||||||
ids = ids[:PAGE_SIZE]
|
ids = ids[:PAGE_SIZE]
|
||||||
|
@ -1262,7 +1264,7 @@ def sticky_post(post_id, v):
|
||||||
pin_time = 'for 1 hour'
|
pin_time = 'for 1 hour'
|
||||||
code = 200
|
code = 200
|
||||||
if v.id != post.author_id:
|
if v.id != post.author_id:
|
||||||
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has pinned [{post.title}](/post/{post_id})!")
|
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has pinned [{post.title}](/post/{post_id})")
|
||||||
else:
|
else:
|
||||||
if pins >= PIN_LIMIT + 1:
|
if pins >= PIN_LIMIT + 1:
|
||||||
abort(403, f"Can't exceed {PIN_LIMIT} pinned posts limit!")
|
abort(403, f"Can't exceed {PIN_LIMIT} pinned posts limit!")
|
||||||
|
@ -1307,7 +1309,7 @@ def unsticky_post(post_id, v):
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
if v.id != post.author_id:
|
if v.id != post.author_id:
|
||||||
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has unpinned [{post.title}](/post/{post_id})!")
|
send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has unpinned [{post.title}](/post/{post_id})")
|
||||||
|
|
||||||
cache.delete_memoized(frontlist)
|
cache.delete_memoized(frontlist)
|
||||||
return {"message": "Post unpinned!"}
|
return {"message": "Post unpinned!"}
|
||||||
|
@ -1329,9 +1331,15 @@ def sticky_comment(cid, v):
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
if v.id != comment.author_id:
|
if v.id != comment.author_id:
|
||||||
message = f"@{v.username} (Admin) has pinned your [comment]({comment.shortlink})!"
|
message = f"@{v.username} (Admin) has pinned your [comment]({comment.shortlink})"
|
||||||
send_repeatable_notification(comment.author_id, message)
|
send_repeatable_notification(comment.author_id, message)
|
||||||
|
|
||||||
|
c = comment
|
||||||
|
while c.level > 2:
|
||||||
|
c = c.parent_comment
|
||||||
|
c.stickied_child_id = comment.id
|
||||||
|
g.db.add(c)
|
||||||
|
|
||||||
return {"message": "Comment pinned!"}
|
return {"message": "Comment pinned!"}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1354,9 +1362,14 @@ def unsticky_comment(cid, v):
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
if v.id != comment.author_id:
|
if v.id != comment.author_id:
|
||||||
message = f"@{v.username} (Admin) has unpinned your [comment]({comment.shortlink})!"
|
message = f"@{v.username} (Admin) has unpinned your [comment]({comment.shortlink})"
|
||||||
send_repeatable_notification(comment.author_id, message)
|
send_repeatable_notification(comment.author_id, message)
|
||||||
|
|
||||||
|
cleanup = g.db.query(Comment).filter_by(stickied_child_id=comment.id).all()
|
||||||
|
for c in cleanup:
|
||||||
|
c.stickied_child_id = None
|
||||||
|
g.db.add(c)
|
||||||
|
|
||||||
return {"message": "Comment unpinned!"}
|
return {"message": "Comment unpinned!"}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ def asset_submissions(path):
|
||||||
|
|
||||||
@app.get("/submit/marseys")
|
@app.get("/submit/marseys")
|
||||||
@auth_required
|
@auth_required
|
||||||
def submit_marseys(v):
|
def submit_marseys(v:User):
|
||||||
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_MARSEYS']:
|
if v.admin_level >= PERMS['VIEW_PENDING_SUBMITTED_MARSEYS']:
|
||||||
marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
|
marseys = g.db.query(Marsey).filter(Marsey.submitter_id != None).all()
|
||||||
else:
|
else:
|
||||||
|
@ -44,7 +44,7 @@ def submit_marseys(v):
|
||||||
|
|
||||||
@app.post("/submit/marseys")
|
@app.post("/submit/marseys")
|
||||||
@auth_required
|
@auth_required
|
||||||
def submit_marsey(v):
|
def submit_marsey(v:User):
|
||||||
file = request.files["image"]
|
file = request.files["image"]
|
||||||
name = request.values.get('name', '').lower().strip()
|
name = request.values.get('name', '').lower().strip()
|
||||||
tags = request.values.get('tags', '').lower().strip()
|
tags = request.values.get('tags', '').lower().strip()
|
||||||
|
@ -195,12 +195,12 @@ def remove_asset(cls, type_name:str, v:User, name:str) -> dict[str, str]:
|
||||||
|
|
||||||
@app.post("/remove/marsey/<name>")
|
@app.post("/remove/marsey/<name>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def remove_marsey(v, name):
|
def remove_marsey(v:User, name):
|
||||||
return remove_asset(Marsey, "marsey", v, name)
|
return remove_asset(Marsey, "marsey", v, name)
|
||||||
|
|
||||||
@app.get("/submit/hats")
|
@app.get("/submit/hats")
|
||||||
@auth_required
|
@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()
|
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()
|
else: hats = g.db.query(HatDef).filter(HatDef.submitter_id == v.id).all()
|
||||||
return render_template("submit_hats.html", v=v, hats=hats)
|
return render_template("submit_hats.html", v=v, hats=hats)
|
||||||
|
@ -208,7 +208,7 @@ def submit_hats(v):
|
||||||
|
|
||||||
@app.post("/submit/hats")
|
@app.post("/submit/hats")
|
||||||
@auth_required
|
@auth_required
|
||||||
def submit_hat(v):
|
def submit_hat(v:User):
|
||||||
name = request.values.get('name', '').strip()
|
name = request.values.get('name', '').strip()
|
||||||
description = request.values.get('description', '').strip()
|
description = request.values.get('description', '').strip()
|
||||||
username = request.values.get('author', '').strip()
|
username = request.values.get('author', '').strip()
|
||||||
|
@ -328,7 +328,7 @@ def approve_hat(v, name):
|
||||||
|
|
||||||
@app.post("/remove/hat/<name>")
|
@app.post("/remove/hat/<name>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def remove_hat(v, name):
|
def remove_hat(v:User, name):
|
||||||
return remove_asset(HatDef, 'hat', v, name)
|
return remove_asset(HatDef, 'hat', v, name)
|
||||||
|
|
||||||
@app.get("/admin/update/marseys")
|
@app.get("/admin/update/marseys")
|
||||||
|
|
|
@ -22,7 +22,7 @@ from .front import frontlist
|
||||||
@app.get("/shop")
|
@app.get("/shop")
|
||||||
@app.get("/settings/shop")
|
@app.get("/settings/shop")
|
||||||
@auth_required
|
@auth_required
|
||||||
def shop(v):
|
def shop(v:User):
|
||||||
AWARDS = deepcopy(AWARDS2)
|
AWARDS = deepcopy(AWARDS2)
|
||||||
|
|
||||||
if v.house:
|
if v.house:
|
||||||
|
@ -46,7 +46,7 @@ def shop(v):
|
||||||
@app.post("/buy/<award>")
|
@app.post("/buy/<award>")
|
||||||
@limiter.limit("100/minute;200/hour;1000/day")
|
@limiter.limit("100/minute;200/hour;1000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def buy(v, award):
|
def buy(v:User, award):
|
||||||
if award == 'benefactor' and not request.values.get("mb"):
|
if award == 'benefactor' and not request.values.get("mb"):
|
||||||
abort(403, "You can only buy the Benefactor award with marseybux.")
|
abort(403, "You can only buy the Benefactor award with marseybux.")
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ def award_thing(v, thing_type, id):
|
||||||
author = v
|
author = v
|
||||||
elif kind != 'spider':
|
elif kind != 'spider':
|
||||||
awarded_coins = int(AWARDS[kind]['price'] * COSMETIC_AWARD_COIN_AWARD_PCT) if AWARDS[kind]['cosmetic'] else 0
|
awarded_coins = int(AWARDS[kind]['price'] * COSMETIC_AWARD_COIN_AWARD_PCT) if AWARDS[kind]['cosmetic'] else 0
|
||||||
if AWARDS[kind]['cosmetic']:
|
if AWARDS[kind]['cosmetic'] and kind != 'shit':
|
||||||
author.pay_account('coins', awarded_coins)
|
author.pay_account('coins', awarded_coins)
|
||||||
|
|
||||||
msg = f"@{v.username} has given your [{thing_type}]({thing.shortlink}) the {AWARDS[kind]['title']} Award"
|
msg = f"@{v.username} has given your [{thing_type}]({thing.shortlink}) the {AWARDS[kind]['title']} Award"
|
||||||
|
|
|
@ -14,7 +14,7 @@ from files.__main__ import app, limiter
|
||||||
@app.get("/casino")
|
@app.get("/casino")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def casino(v):
|
def casino(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
return render_template("casino/rehab.html", v=v), 403
|
return render_template("casino/rehab.html", v=v), 403
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ def casino(v):
|
||||||
@app.get("/casino/<game>")
|
@app.get("/casino/<game>")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def casino_game_page(v, game):
|
def casino_game_page(v:User, game):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
return render_template("casino/rehab.html", v=v), 403
|
return render_template("casino/rehab.html", v=v), 403
|
||||||
elif game not in CASINO_GAME_KINDS:
|
elif game not in CASINO_GAME_KINDS:
|
||||||
|
@ -53,7 +53,7 @@ def casino_game_page(v, game):
|
||||||
@app.get("/casino/<game>/feed")
|
@app.get("/casino/<game>/feed")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def casino_game_feed(v, game):
|
def casino_game_feed(v:User, game):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
elif game not in CASINO_GAME_KINDS:
|
elif game not in CASINO_GAME_KINDS:
|
||||||
|
@ -67,7 +67,7 @@ def casino_game_feed(v, game):
|
||||||
@app.get("/lottershe")
|
@app.get("/lottershe")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def lottershe(v):
|
def lottershe(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
return render_template("casino/rehab.html", v=v)
|
return render_template("casino/rehab.html", v=v)
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ def lottershe(v):
|
||||||
@app.post("/casino/slots")
|
@app.post("/casino/slots")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def pull_slots(v):
|
def pull_slots(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ def pull_slots(v):
|
||||||
@app.post("/casino/twentyone/deal")
|
@app.post("/casino/twentyone/deal")
|
||||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def blackjack_deal_to_player(v):
|
def blackjack_deal_to_player(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ def blackjack_deal_to_player(v):
|
||||||
@app.post("/casino/twentyone/hit")
|
@app.post("/casino/twentyone/hit")
|
||||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def blackjack_player_hit(v):
|
def blackjack_player_hit(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ def blackjack_player_hit(v):
|
||||||
@app.post("/casino/twentyone/stay")
|
@app.post("/casino/twentyone/stay")
|
||||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def blackjack_player_stay(v):
|
def blackjack_player_stay(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ def blackjack_player_stay(v):
|
||||||
@app.post("/casino/twentyone/double-down")
|
@app.post("/casino/twentyone/double-down")
|
||||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def blackjack_player_doubled_down(v):
|
def blackjack_player_doubled_down(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ def blackjack_player_doubled_down(v):
|
||||||
@app.post("/casino/twentyone/buy-insurance")
|
@app.post("/casino/twentyone/buy-insurance")
|
||||||
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
@limiter.limit("1/second;100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def blackjack_player_bought_insurance(v):
|
def blackjack_player_bought_insurance(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ def blackjack_player_bought_insurance(v):
|
||||||
@app.get("/casino/roulette/bets")
|
@app.get("/casino/roulette/bets")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def roulette_get_bets(v):
|
def roulette_get_bets(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ def roulette_get_bets(v):
|
||||||
@app.post("/casino/roulette/place-bet")
|
@app.post("/casino/roulette/place-bet")
|
||||||
@limiter.limit("100/minute;2000/hour;12000/day")
|
@limiter.limit("100/minute;2000/hour;12000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def roulette_player_placed_bet(v):
|
def roulette_player_placed_bet(v:User):
|
||||||
if v.rehab:
|
if v.rehab:
|
||||||
abort(403, "You are under Rehab award effect!")
|
abort(403, "You are under Rehab award effect!")
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ user_ids_to_socket_ids = {}
|
||||||
@app.get("/chat")
|
@app.get("/chat")
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
def chat(v):
|
def chat(v):
|
||||||
if TRUESCORE_CHAT_LIMIT and v.truescore < TRUESCORE_CHAT_LIMIT and not v.club_allowed:
|
if TRUESCORE_CHAT_MINIMUM and v.truescore < TRUESCORE_CHAT_MINIMUM and not v.club_allowed:
|
||||||
abort(403, f"Need at least {TRUESCORE_CHAT_LIMIT} truescore for access to chat.")
|
abort(403, f"Need at least {TRUESCORE_CHAT_MINIMUM} truescore for access to chat.")
|
||||||
return render_template("chat.html", v=v, messages=messages)
|
return render_template("chat.html", v=v, messages=messages)
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ def chat(v):
|
||||||
@ratelimit_user("3/second;10/minute")
|
@ratelimit_user("3/second;10/minute")
|
||||||
def speak(data, v):
|
def speak(data, v):
|
||||||
if v.is_banned: return '', 403
|
if v.is_banned: return '', 403
|
||||||
if TRUESCORE_CHAT_LIMIT and v.truescore < TRUESCORE_CHAT_LIMIT and not v.club_allowed: return '', 403
|
if TRUESCORE_CHAT_MINIMUM and v.truescore < TRUESCORE_CHAT_MINIMUM and not v.club_allowed: return '', 403
|
||||||
|
|
||||||
vname = v.username.lower()
|
vname = v.username.lower()
|
||||||
if vname in muted and not v.admin_level >= PERMS['CHAT_BYPASS_MUTE']:
|
if vname in muted and not v.admin_level >= PERMS['CHAT_BYPASS_MUTE']:
|
||||||
|
|
|
@ -79,10 +79,11 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
|
||||||
else: template = "submission.html"
|
else: template = "submission.html"
|
||||||
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
|
return render_template(template, v=v, p=post, sort=sort, comment_info=comment_info, render_replies=True, sub=post.subr)
|
||||||
|
|
||||||
|
#- API
|
||||||
@app.post("/comment")
|
@app.post("/comment")
|
||||||
@limiter.limit("1/second;20/minute;200/hour;1000/day")
|
@limiter.limit("1/second;20/minute;200/hour;1000/day")
|
||||||
@ratelimit_user("1/second;20/minute;200/hour;1000/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("1/second;20/minute;200/hour;1000/day")
|
||||||
def comment(v):
|
def comment(v):
|
||||||
if v.is_suspended: abort(403, "You can't perform this action while banned.")
|
if v.is_suspended: abort(403, "You can't perform this action while banned.")
|
||||||
|
|
||||||
|
@ -91,7 +92,7 @@ def comment(v):
|
||||||
id = parent_fullname[2:]
|
id = parent_fullname[2:]
|
||||||
parent_comment_id = None
|
parent_comment_id = None
|
||||||
rts = False
|
rts = False
|
||||||
|
|
||||||
if parent_fullname.startswith("p_"):
|
if parent_fullname.startswith("p_"):
|
||||||
parent = get_post(id, v=v)
|
parent = get_post(id, v=v)
|
||||||
parent_post = parent
|
parent_post = parent
|
||||||
|
@ -101,7 +102,7 @@ def comment(v):
|
||||||
parent_post = get_post(parent.parent_submission, v=v)
|
parent_post = get_post(parent.parent_submission, v=v)
|
||||||
parent_comment_id = parent.id
|
parent_comment_id = parent.id
|
||||||
if parent.author_id == v.id: rts = True
|
if parent.author_id == v.id: rts = True
|
||||||
if not v.can_post_in_ghost_threads and parent_post.ghost: abort(403, f"You need {TRUESCORE_GHOST_LIMIT} truescore to post in ghost threads")
|
if not v.can_post_in_ghost_threads and parent_post.ghost: abort(403, f"You need {TRUESCORE_GHOST_MINIMUM} truescore to post in ghost threads")
|
||||||
else: abort(400)
|
else: abort(400)
|
||||||
|
|
||||||
level = 1 if isinstance(parent, Submission) else parent.level + 1
|
level = 1 if isinstance(parent, Submission) else parent.level + 1
|
||||||
|
@ -132,12 +133,12 @@ def comment(v):
|
||||||
abort(403, "You can't reply to users who have blocked you or users that you have blocked.")
|
abort(403, "You can't reply to users who have blocked you or users that you have blocked.")
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
for i in poll_regex.finditer(body):
|
for i in list(poll_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||||
options.append(i.group(1))
|
options.append(i.group(1))
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
|
|
||||||
choices = []
|
choices = []
|
||||||
for i in choice_regex.finditer(body):
|
for i in list(choice_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||||
choices.append(i.group(1))
|
choices.append(i.group(1))
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
|
|
||||||
|
@ -359,6 +360,13 @@ def comment(v):
|
||||||
|
|
||||||
check_slots_command(v, v, c)
|
check_slots_command(v, v, c)
|
||||||
|
|
||||||
|
if c.level > 5:
|
||||||
|
n = g.db.query(Notification).filter_by(
|
||||||
|
comment_id=c.parent_comment.parent_comment.parent_comment.parent_comment_id,
|
||||||
|
user_id=c.parent_comment.author_id,
|
||||||
|
).one_or_none()
|
||||||
|
if n: g.db.delete(n)
|
||||||
|
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
||||||
if v.client: return c.json(db=g.db)
|
if v.client: return c.json(db=g.db)
|
||||||
|
@ -368,8 +376,8 @@ def comment(v):
|
||||||
|
|
||||||
@app.post("/edit_comment/<cid>")
|
@app.post("/edit_comment/<cid>")
|
||||||
@limiter.limit("1/second;10/minute;100/hour;200/day")
|
@limiter.limit("1/second;10/minute;100/hour;200/day")
|
||||||
@ratelimit_user("1/second;10/minute;100/hour;200/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;10/minute;100/hour;200/day")
|
||||||
def edit_comment(cid, v):
|
def edit_comment(cid, v):
|
||||||
c = get_comment(cid, v=v)
|
c = get_comment(cid, v=v)
|
||||||
|
|
||||||
|
@ -390,7 +398,7 @@ def edit_comment(cid, v):
|
||||||
elif v.bird and len(body) > 140:
|
elif v.bird and len(body) > 140:
|
||||||
abort(403, "You have to type less than 140 characters!")
|
abort(403, "You have to type less than 140 characters!")
|
||||||
|
|
||||||
for i in poll_regex.finditer(body):
|
for i in list(poll_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
body_html = filter_emojis_only(i.group(1))
|
body_html = filter_emojis_only(i.group(1))
|
||||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||||
|
@ -401,7 +409,7 @@ def edit_comment(cid, v):
|
||||||
)
|
)
|
||||||
g.db.add(option)
|
g.db.add(option)
|
||||||
|
|
||||||
for i in choice_regex.finditer(body):
|
for i in list(choice_regex.finditer(body))[:POLL_MAX_OPTIONS]:
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
body_html = filter_emojis_only(i.group(1))
|
body_html = filter_emojis_only(i.group(1))
|
||||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||||
|
@ -514,8 +522,8 @@ def pin_comment(cid, v):
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
||||||
if v.id != comment.author_id:
|
if v.id != comment.author_id:
|
||||||
if comment.post.ghost: message = f"OP has pinned your [comment]({comment.shortlink})!"
|
if comment.post.ghost: message = f"OP has pinned your [comment]({comment.shortlink})"
|
||||||
else: message = f"@{v.username} (OP) has pinned your [comment]({comment.shortlink})!"
|
else: message = f"@{v.username} (OP) has pinned your [comment]({comment.shortlink})"
|
||||||
send_repeatable_notification(comment.author_id, message)
|
send_repeatable_notification(comment.author_id, message)
|
||||||
|
|
||||||
return {"message": "Comment pinned!"}
|
return {"message": "Comment pinned!"}
|
||||||
|
@ -537,7 +545,7 @@ def unpin_comment(cid, v):
|
||||||
g.db.add(comment)
|
g.db.add(comment)
|
||||||
|
|
||||||
if v.id != comment.author_id:
|
if v.id != comment.author_id:
|
||||||
message = f"@{v.username} (OP) has unpinned your [comment]({comment.shortlink})!"
|
message = f"@{v.username} (OP) has unpinned your [comment]({comment.shortlink})"
|
||||||
send_repeatable_notification(comment.author_id, message)
|
send_repeatable_notification(comment.author_id, message)
|
||||||
return {"message": "Comment unpinned!"}
|
return {"message": "Comment unpinned!"}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ def front_all(v, sub=None, subdomain=None):
|
||||||
#### WPD TEMP #### end special front logic
|
#### WPD TEMP #### end special front logic
|
||||||
if sub:
|
if sub:
|
||||||
sub = get_sub_by_name(sub, graceful=True)
|
sub = get_sub_by_name(sub, graceful=True)
|
||||||
if sub and not User.can_see(v, sub): abort(403)
|
if sub and not User.can_see(v, sub): abort(403, "You need 5000 truescore to be able to see /h/chudrama")
|
||||||
|
|
||||||
if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404)
|
if (request.path.startswith('/h/') or request.path.startswith('/s/')) and not sub: abort(404)
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, filter_words='
|
||||||
|
|
||||||
@app.get("/random_post")
|
@app.get("/random_post")
|
||||||
@auth_required
|
@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()
|
p = g.db.query(Submission.id).filter(Submission.deleted_utc == 0, Submission.is_banned == False, Submission.private == False).order_by(func.random()).first()
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ def random_post(v):
|
||||||
|
|
||||||
@app.get("/random_user")
|
@app.get("/random_user")
|
||||||
@auth_required
|
@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()
|
u = g.db.query(User.username).filter(User.song != None, User.shadowbanned == None).order_by(func.random()).first()
|
||||||
|
|
||||||
if u: u = u[0]
|
if u: u = u[0]
|
||||||
|
@ -202,7 +202,7 @@ def random_user(v):
|
||||||
|
|
||||||
@app.get("/comments")
|
@app.get("/comments")
|
||||||
@auth_required
|
@auth_required
|
||||||
def all_comments(v):
|
def all_comments(v:User):
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from files.__main__ import app, limiter
|
||||||
|
|
||||||
@app.get("/hats")
|
@app.get("/hats")
|
||||||
@auth_required
|
@auth_required
|
||||||
def hats(v):
|
def hats(v:User):
|
||||||
owned_hat_ids = [x.hat_id for x in v.owned_hats]
|
owned_hat_ids = [x.hat_id for x in v.owned_hats]
|
||||||
|
|
||||||
if request.values.get("sort") == 'author_asc':
|
if request.values.get("sort") == 'author_asc':
|
||||||
|
@ -34,7 +34,7 @@ def hats(v):
|
||||||
@app.post("/buy_hat/<hat_id>")
|
@app.post("/buy_hat/<hat_id>")
|
||||||
@limiter.limit('100/minute;1000/3 days')
|
@limiter.limit('100/minute;1000/3 days')
|
||||||
@auth_required
|
@auth_required
|
||||||
def buy_hat(v, hat_id):
|
def buy_hat(v:User, hat_id):
|
||||||
try: hat_id = int(hat_id)
|
try: hat_id = int(hat_id)
|
||||||
except: abort(404, "Hat not found!")
|
except: abort(404, "Hat not found!")
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ def buy_hat(v, hat_id):
|
||||||
|
|
||||||
@app.post("/equip_hat/<hat_id>")
|
@app.post("/equip_hat/<hat_id>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def equip_hat(v, hat_id):
|
def equip_hat(v:User, hat_id):
|
||||||
try: hat_id = int(hat_id)
|
try: hat_id = int(hat_id)
|
||||||
except: abort(404, "Hat not found!")
|
except: abort(404, "Hat not found!")
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ def equip_hat(v, hat_id):
|
||||||
|
|
||||||
@app.post("/unequip_hat/<hat_id>")
|
@app.post("/unequip_hat/<hat_id>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def unequip_hat(v, hat_id):
|
def unequip_hat(v:User, hat_id):
|
||||||
try: hat_id = int(hat_id)
|
try: hat_id = int(hat_id)
|
||||||
except: abort(404, "Hat not found!")
|
except: abort(404, "Hat not found!")
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ def unequip_hat(v, hat_id):
|
||||||
|
|
||||||
@app.get("/hat_owners/<hat_id>")
|
@app.get("/hat_owners/<hat_id>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def hat_owners(v, hat_id):
|
def hat_owners(v:User, hat_id):
|
||||||
try: hat_id = int(hat_id)
|
try: hat_id = int(hat_id)
|
||||||
except: abort(404, "Hat not found!")
|
except: abort(404, "Hat not found!")
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ def inject_constants():
|
||||||
"TELEGRAM_LINK":TELEGRAM_LINK, "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN,
|
"TELEGRAM_LINK":TELEGRAM_LINK, "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN,
|
||||||
"CONTENT_SECURITY_POLICY_DEFAULT":CONTENT_SECURITY_POLICY_DEFAULT,
|
"CONTENT_SECURITY_POLICY_DEFAULT":CONTENT_SECURITY_POLICY_DEFAULT,
|
||||||
"CONTENT_SECURITY_POLICY_HOME":CONTENT_SECURITY_POLICY_HOME,
|
"CONTENT_SECURITY_POLICY_HOME":CONTENT_SECURITY_POLICY_HOME,
|
||||||
"TRUESCORE_DONATE_LIMIT":TRUESCORE_DONATE_LIMIT,
|
"TRUESCORE_DONATE_MINIMUM":TRUESCORE_DONATE_MINIMUM,
|
||||||
"DONATE_LINK":DONATE_LINK, "DONATE_SERVICE":DONATE_SERVICE, "BAN_EVASION_DOMAIN":BAN_EVASION_DOMAIN,
|
"DONATE_LINK":DONATE_LINK, "DONATE_SERVICE":DONATE_SERVICE, "BAN_EVASION_DOMAIN":BAN_EVASION_DOMAIN,
|
||||||
"HOUSE_JOIN_COST":HOUSE_JOIN_COST, "HOUSE_SWITCH_COST":HOUSE_SWITCH_COST, "IMAGE_FORMATS":IMAGE_FORMATS,
|
"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,
|
"PAGE_SIZES":PAGE_SIZES, "THEMES":THEMES, "COMMENT_SORTS":COMMENT_SORTS, "SORTS":SORTS,
|
||||||
|
|
|
@ -21,7 +21,7 @@ NO_LOGIN_REDIRECT_URLS = ("/login", "/logout", "/signup", "/forgot", "/reset", "
|
||||||
|
|
||||||
@app.get("/login")
|
@app.get("/login")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def login_get(v):
|
def login_get(v:Optional[User]):
|
||||||
redir = request.values.get("redirect", "/").strip().rstrip('?').lower()
|
redir = request.values.get("redirect", "/").strip().rstrip('?').lower()
|
||||||
if redir:
|
if redir:
|
||||||
if not is_site_url(redir) or redir in NO_LOGIN_REDIRECT_URLS:
|
if not is_site_url(redir) or redir in NO_LOGIN_REDIRECT_URLS:
|
||||||
|
@ -106,14 +106,14 @@ def login_post():
|
||||||
|
|
||||||
redir = request.values.get("redirect", "").strip().rstrip('?').lower()
|
redir = request.values.get("redirect", "").strip().rstrip('?').lower()
|
||||||
if redir:
|
if redir:
|
||||||
if is_site_url(redir) and redir in NO_LOGIN_REDIRECT_URLS:
|
if is_site_url(redir) and redir not in NO_LOGIN_REDIRECT_URLS:
|
||||||
return redirect(redir)
|
return redirect(redir)
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
|
|
||||||
def log_failed_admin_login_attempt(account:User, type:str):
|
def log_failed_admin_login_attempt(account:User, type:str):
|
||||||
if not account or account.admin_level < PERMS['SITE_WARN_ON_INVALID_AUTH']: return
|
if not account or account.admin_level < PERMS['SITE_WARN_ON_INVALID_AUTH']: return
|
||||||
ip = get_CF()
|
ip = get_CF()
|
||||||
print(f"Admin user from {ip} failed to login to account @{account.user_name} (invalid {type})!")
|
print(f"Admin user from {ip} failed to login to account @{account.user_name} (invalid {type})")
|
||||||
try:
|
try:
|
||||||
with open("/admin_failed_logins", "a+", encoding="utf-8") as f:
|
with open("/admin_failed_logins", "a+", encoding="utf-8") as f:
|
||||||
t = str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time())))
|
t = str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time())))
|
||||||
|
@ -131,7 +131,7 @@ def on_login(account, redir=None):
|
||||||
@app.get("/me")
|
@app.get("/me")
|
||||||
@app.get("/@me")
|
@app.get("/@me")
|
||||||
@auth_required
|
@auth_required
|
||||||
def me(v):
|
def me(v:User):
|
||||||
if v.client: return v.json
|
if v.client: return v.json
|
||||||
else: return redirect(v.url)
|
else: return redirect(v.url)
|
||||||
|
|
||||||
|
@ -149,9 +149,9 @@ def logout(v):
|
||||||
|
|
||||||
@app.get("/signup")
|
@app.get("/signup")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def sign_up_get(v):
|
def sign_up_get(v:Optional[User]):
|
||||||
if not get_setting('Signups'):
|
if not get_setting('Signups'):
|
||||||
return {"error": "New account registration is currently closed. Please come back later."}, 403
|
abort(403, "New account registration is currently closed. Please come back later.")
|
||||||
|
|
||||||
if v: return redirect(SITE_FULL)
|
if v: return redirect(SITE_FULL)
|
||||||
|
|
||||||
|
@ -199,9 +199,9 @@ def sign_up_get(v):
|
||||||
@app.post("/signup")
|
@app.post("/signup")
|
||||||
@limiter.limit("1/second;10/day")
|
@limiter.limit("1/second;10/day")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def sign_up_post(v):
|
def sign_up_post(v:Optional[User]):
|
||||||
if not get_setting('Signups'):
|
if not get_setting('Signups'):
|
||||||
return {"error": "New account registration is currently closed. Please come back later."}, 403
|
abort(403, "New account registration is currently closed. Please come back later.")
|
||||||
|
|
||||||
if v: abort(403)
|
if v: abort(403)
|
||||||
|
|
||||||
|
@ -235,6 +235,7 @@ def sign_up_post(v):
|
||||||
return signup_error("There was a problem. Please try again.")
|
return signup_error("There was a problem. Please try again.")
|
||||||
|
|
||||||
if not hmac.compare_digest(correct_formkey, form_formkey):
|
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.")
|
return signup_error("There was a problem. Please try again.")
|
||||||
|
|
||||||
if not request.values.get(
|
if not request.values.get(
|
||||||
|
@ -339,7 +340,7 @@ def sign_up_post(v):
|
||||||
|
|
||||||
redir = request.values.get("redirect", "").strip().rstrip('?').lower()
|
redir = request.values.get("redirect", "").strip().rstrip('?').lower()
|
||||||
if redir:
|
if redir:
|
||||||
if is_site_url(redir) or redir in NO_LOGIN_REDIRECT_URLS:
|
if is_site_url(redir) or redir not in NO_LOGIN_REDIRECT_URLS:
|
||||||
return redirect(redir)
|
return redirect(redir)
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
|
|
||||||
|
@ -416,7 +417,7 @@ def get_reset():
|
||||||
@app.post("/reset")
|
@app.post("/reset")
|
||||||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def post_reset(v):
|
def post_reset(v:Optional[User]):
|
||||||
if v: return redirect('/')
|
if v: return redirect('/')
|
||||||
user_id = request.values.get("user_id")
|
user_id = request.values.get("user_id")
|
||||||
timestamp = 0
|
timestamp = 0
|
||||||
|
@ -454,7 +455,7 @@ def post_reset(v):
|
||||||
|
|
||||||
@app.get("/lost_2fa")
|
@app.get("/lost_2fa")
|
||||||
@auth_desired
|
@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")
|
if v and not v.mfa_secret: abort(400, "You don't have 2FA enabled")
|
||||||
return render_template("login/lost_2fa.html", v=v)
|
return render_template("login/lost_2fa.html", v=v)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ def lottery_start(v):
|
||||||
@app.post("/lottery/buy")
|
@app.post("/lottery/buy")
|
||||||
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def lottery_buy(v):
|
def lottery_buy(v:User):
|
||||||
try: quantity = int(request.values.get("quantity"))
|
try: quantity = int(request.values.get("quantity"))
|
||||||
except: abort(400, "Invalid ticket quantity.")
|
except: abort(400, "Invalid ticket quantity.")
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ def lottery_buy(v):
|
||||||
@app.get("/lottery/active")
|
@app.get("/lottery/active")
|
||||||
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
@limiter.limit("3/second;100/minute;500/hour;1000/day")
|
||||||
@auth_required
|
@auth_required
|
||||||
def lottery_active(v):
|
def lottery_active(v:User):
|
||||||
lottery, participants = get_active_lottery_stats()
|
lottery, participants = get_active_lottery_stats()
|
||||||
|
|
||||||
return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
|
return {"message": "", "stats": {"user": v.lottery_stats, "lottery": lottery, "participants": participants}}
|
||||||
|
|
|
@ -19,7 +19,7 @@ def verify_email(v):
|
||||||
|
|
||||||
@app.get("/activate")
|
@app.get("/activate")
|
||||||
@auth_required
|
@auth_required
|
||||||
def activate(v):
|
def activate(v:User):
|
||||||
email = request.values.get("email", "").strip().lower()
|
email = request.values.get("email", "").strip().lower()
|
||||||
|
|
||||||
if not email_regex.fullmatch(email):
|
if not email_regex.fullmatch(email):
|
||||||
|
|
|
@ -68,7 +68,7 @@ def notifications_modmail(v):
|
||||||
|
|
||||||
@app.get("/notifications/messages")
|
@app.get("/notifications/messages")
|
||||||
@auth_required
|
@auth_required
|
||||||
def notifications_messages(v):
|
def notifications_messages(v:User):
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ def notifications_messages(v):
|
||||||
|
|
||||||
@app.get("/notifications/posts")
|
@app.get("/notifications/posts")
|
||||||
@auth_required
|
@auth_required
|
||||||
def notifications_posts(v):
|
def notifications_posts(v:User):
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
@ -179,7 +179,7 @@ def notifications_posts(v):
|
||||||
|
|
||||||
@app.get("/notifications/modactions")
|
@app.get("/notifications/modactions")
|
||||||
@auth_required
|
@auth_required
|
||||||
def notifications_modactions(v):
|
def notifications_modactions(v:User):
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ def notifications_modactions(v):
|
||||||
|
|
||||||
@app.get("/notifications/reddit")
|
@app.get("/notifications/reddit")
|
||||||
@auth_required
|
@auth_required
|
||||||
def notifications_reddit(v):
|
def notifications_reddit(v:User):
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ def notifications_reddit(v):
|
||||||
|
|
||||||
@app.get("/notifications")
|
@app.get("/notifications")
|
||||||
@auth_required
|
@auth_required
|
||||||
def notifications(v):
|
def notifications(v:User):
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from files.__main__ import app, limiter
|
||||||
|
|
||||||
@app.get("/authorize")
|
@app.get("/authorize")
|
||||||
@auth_required
|
@auth_required
|
||||||
def authorize_prompt(v):
|
def authorize_prompt(v:User):
|
||||||
client_id = request.values.get("client_id")
|
client_id = request.values.get("client_id")
|
||||||
application = g.db.query(OauthApp).filter_by(client_id=client_id).one_or_none()
|
application = g.db.query(OauthApp).filter_by(client_id=client_id).one_or_none()
|
||||||
if not application: return {"oauth_error": "Invalid `client_id`"}, 401
|
if not application: return {"oauth_error": "Invalid `client_id`"}, 401
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
import html
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from os import path
|
from os import path
|
||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
|
@ -122,7 +123,7 @@ def publish(pid, v):
|
||||||
@app.get("/submit")
|
@app.get("/submit")
|
||||||
@app.get("/h/<sub>/submit")
|
@app.get("/h/<sub>/submit")
|
||||||
@auth_required
|
@auth_required
|
||||||
def submit_get(v, sub=None):
|
def submit_get(v:User, sub=None):
|
||||||
sub = get_sub_by_name(sub, graceful=True)
|
sub = get_sub_by_name(sub, graceful=True)
|
||||||
if request.path.startswith('/h/') and not sub: abort(404)
|
if request.path.startswith('/h/') and not sub: abort(404)
|
||||||
|
|
||||||
|
@ -310,8 +311,8 @@ def morecomments(v, cid):
|
||||||
|
|
||||||
@app.post("/edit_post/<pid>")
|
@app.post("/edit_post/<pid>")
|
||||||
@limiter.limit("1/second;10/minute;100/hour;200/day")
|
@limiter.limit("1/second;10/minute;100/hour;200/day")
|
||||||
@ratelimit_user("1/second;10/minute;100/hour;200/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;10/minute;100/hour;200/day")
|
||||||
def edit_post(pid, v):
|
def edit_post(pid, v):
|
||||||
p = get_post(pid)
|
p = get_post(pid)
|
||||||
if v.id != p.author_id and v.admin_level < PERMS['POST_EDITING']:
|
if v.id != p.author_id and v.admin_level < PERMS['POST_EDITING']:
|
||||||
|
@ -360,7 +361,7 @@ def edit_post(pid, v):
|
||||||
)
|
)
|
||||||
g.db.add(bet)
|
g.db.add(bet)
|
||||||
|
|
||||||
for i in poll_regex.finditer(body):
|
for i in list(poll_regex.finditer(body))[:10]:
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
body_html = filter_emojis_only(i.group(1))
|
body_html = filter_emojis_only(i.group(1))
|
||||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||||
|
@ -371,7 +372,7 @@ def edit_post(pid, v):
|
||||||
)
|
)
|
||||||
g.db.add(option)
|
g.db.add(option)
|
||||||
|
|
||||||
for i in choice_regex.finditer(body):
|
for i in list(choice_regex.finditer(body))[:10]:
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
body_html = filter_emojis_only(i.group(1))
|
body_html = filter_emojis_only(i.group(1))
|
||||||
if len(body_html) > 500: abort(400, "Poll option too long!")
|
if len(body_html) > 500: abort(400, "Poll option too long!")
|
||||||
|
@ -392,7 +393,7 @@ def edit_post(pid, v):
|
||||||
|
|
||||||
p.body = body
|
p.body = body
|
||||||
|
|
||||||
for text in [p.body, p.title, p.url]:
|
for text in {p.body, p.title, p.url}:
|
||||||
if not execute_blackjack(v, p, text, 'submission'): break
|
if not execute_blackjack(v, p, text, 'submission'): break
|
||||||
|
|
||||||
if len(body_html) > POST_BODY_HTML_LENGTH_LIMIT:
|
if len(body_html) > POST_BODY_HTML_LENGTH_LIMIT:
|
||||||
|
@ -603,7 +604,7 @@ def is_repost():
|
||||||
@limiter.limit(POST_RATE_LIMIT)
|
@limiter.limit(POST_RATE_LIMIT)
|
||||||
@limiter.limit(POST_RATE_LIMIT, key_func=lambda:f'{SITE}-{session.get("lo_user")}')
|
@limiter.limit(POST_RATE_LIMIT, key_func=lambda:f'{SITE}-{session.get("lo_user")}')
|
||||||
@auth_required
|
@auth_required
|
||||||
def submit_post(v, sub=None):
|
def submit_post(v:User, sub=None):
|
||||||
|
|
||||||
url = request.values.get("url", "").strip()
|
url = request.values.get("url", "").strip()
|
||||||
|
|
||||||
|
@ -754,12 +755,12 @@ def submit_post(v, sub=None):
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
|
|
||||||
options = []
|
options = []
|
||||||
for i in poll_regex.finditer(body):
|
for i in list(poll_regex.finditer(body))[:10]:
|
||||||
options.append(i.group(1))
|
options.append(i.group(1))
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
|
|
||||||
choices = []
|
choices = []
|
||||||
for i in choice_regex.finditer(body):
|
for i in list(choice_regex.finditer(body))[:10]:
|
||||||
choices.append(i.group(1))
|
choices.append(i.group(1))
|
||||||
body = body.replace(i.group(0), "")
|
body = body.replace(i.group(0), "")
|
||||||
|
|
||||||
|
@ -810,7 +811,7 @@ def submit_post(v, sub=None):
|
||||||
g.db.add(post)
|
g.db.add(post)
|
||||||
g.db.flush()
|
g.db.flush()
|
||||||
|
|
||||||
for text in [post.body, post.title, post.url]:
|
for text in {post.body, post.title, post.url}:
|
||||||
if not execute_blackjack(v, post, text, 'submission'): break
|
if not execute_blackjack(v, post, text, 'submission'): break
|
||||||
|
|
||||||
if v and v.admin_level >= PERMS['POST_BETS']:
|
if v and v.admin_level >= PERMS['POST_BETS']:
|
||||||
|
@ -1072,9 +1073,10 @@ extensions = IMAGE_FORMATS + VIDEO_FORMATS + AUDIO_FORMATS
|
||||||
|
|
||||||
@app.get("/submit/title")
|
@app.get("/submit/title")
|
||||||
@limiter.limit("3/minute")
|
@limiter.limit("3/minute")
|
||||||
@ratelimit_user("3/minute")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("3/minute")
|
||||||
def get_post_title(v):
|
def get_post_title(v):
|
||||||
|
POST_TITLE_TIMEOUT = 5
|
||||||
url = request.values.get("url")
|
url = request.values.get("url")
|
||||||
if not url or '\\' in url: abort(400)
|
if not url or '\\' in url: abort(400)
|
||||||
url = url.strip()
|
url = url.strip()
|
||||||
|
@ -1084,7 +1086,8 @@ def get_post_title(v):
|
||||||
if any((checking_url.endswith(f'.{x}') for x in extensions)):
|
if any((checking_url.endswith(f'.{x}') for x in extensions)):
|
||||||
abort(400)
|
abort(400)
|
||||||
|
|
||||||
try: x = requests.get(url, headers=titleheaders, timeout=5, proxies=proxies)
|
try:
|
||||||
|
x = gevent.with_timeout(POST_TITLE_TIMEOUT, requests.get, url, headers=titleheaders, timeout=POST_TITLE_TIMEOUT, proxies=proxies)
|
||||||
except: abort(400)
|
except: abort(400)
|
||||||
|
|
||||||
content_type = x.headers.get("Content-Type")
|
content_type = x.headers.get("Content-Type")
|
||||||
|
@ -1096,4 +1099,6 @@ def get_post_title(v):
|
||||||
title = match.group(1)
|
title = match.group(1)
|
||||||
else: abort(400)
|
else: abort(400)
|
||||||
|
|
||||||
|
title = html.unescape(title)
|
||||||
|
|
||||||
return {"url": url, "title": title}
|
return {"url": url, "title": title}
|
||||||
|
|
|
@ -45,7 +45,7 @@ def searchparse(text):
|
||||||
|
|
||||||
@app.get("/search/posts")
|
@app.get("/search/posts")
|
||||||
@auth_required
|
@auth_required
|
||||||
def searchposts(v):
|
def searchposts(v:User):
|
||||||
|
|
||||||
query = request.values.get("q", '').strip()
|
query = request.values.get("q", '').strip()
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ def searchposts(v):
|
||||||
|
|
||||||
@app.get("/search/comments")
|
@app.get("/search/comments")
|
||||||
@auth_required
|
@auth_required
|
||||||
def searchcomments(v):
|
def searchcomments(v:User):
|
||||||
query = request.values.get("q", '').strip()
|
query = request.values.get("q", '').strip()
|
||||||
|
|
||||||
try: page = max(1, int(request.values.get("page", 1)))
|
try: page = max(1, int(request.values.get("page", 1)))
|
||||||
|
@ -276,7 +276,7 @@ def searchcomments(v):
|
||||||
|
|
||||||
@app.get("/search/users")
|
@app.get("/search/users")
|
||||||
@auth_required
|
@auth_required
|
||||||
def searchusers(v):
|
def searchusers(v:User):
|
||||||
|
|
||||||
query = request.values.get("q", '').strip()
|
query = request.values.get("q", '').strip()
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,12 @@ from files.__main__ import app, cache, limiter
|
||||||
|
|
||||||
@app.get("/settings")
|
@app.get("/settings")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings(v):
|
def settings(v:User):
|
||||||
return redirect("/settings/personal")
|
return redirect("/settings/personal")
|
||||||
|
|
||||||
@app.get("/settings/personal")
|
@app.get("/settings/personal")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_personal(v):
|
def settings_personal(v:User):
|
||||||
return render_template("settings/personal.html", v=v)
|
return render_template("settings/personal.html", v=v)
|
||||||
|
|
||||||
@app.delete('/settings/background')
|
@app.delete('/settings/background')
|
||||||
|
@ -301,7 +301,7 @@ def settings_personal_post(v):
|
||||||
|
|
||||||
@app.post("/settings/filters")
|
@app.post("/settings/filters")
|
||||||
@auth_required
|
@auth_required
|
||||||
def filters(v):
|
def filters(v:User):
|
||||||
filters=request.values.get("filters")[:1000].strip()
|
filters=request.values.get("filters")[:1000].strip()
|
||||||
|
|
||||||
if filters == v.custom_filter_list:
|
if filters == v.custom_filter_list:
|
||||||
|
@ -540,7 +540,7 @@ def settings_images_banner(v):
|
||||||
|
|
||||||
@app.get("/settings/css")
|
@app.get("/settings/css")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_css_get(v):
|
def settings_css_get(v:User):
|
||||||
return render_template("settings/css.html", v=v)
|
return render_template("settings/css.html", v=v)
|
||||||
|
|
||||||
@app.post("/settings/css")
|
@app.post("/settings/css")
|
||||||
|
@ -572,7 +572,7 @@ def settings_profilecss(v):
|
||||||
|
|
||||||
@app.get("/settings/security")
|
@app.get("/settings/security")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_security(v):
|
def settings_security(v:User):
|
||||||
return render_template("settings/security.html",
|
return render_template("settings/security.html",
|
||||||
v=v,
|
v=v,
|
||||||
mfa_secret=pyotp.random_base32() if not v.mfa_secret else None,
|
mfa_secret=pyotp.random_base32() if not v.mfa_secret else None,
|
||||||
|
@ -581,8 +581,8 @@ def settings_security(v):
|
||||||
|
|
||||||
@app.post("/settings/block")
|
@app.post("/settings/block")
|
||||||
@limiter.limit("1/second;20/day")
|
@limiter.limit("1/second;20/day")
|
||||||
@ratelimit_user("1/second;20/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("1/second;20/day")
|
||||||
def settings_block_user(v):
|
def settings_block_user(v):
|
||||||
user = get_user(request.values.get("username"), graceful=True)
|
user = get_user(request.values.get("username"), graceful=True)
|
||||||
if not user: abort(404, "This user doesn't exist.")
|
if not user: abort(404, "This user doesn't exist.")
|
||||||
|
@ -622,12 +622,12 @@ def settings_unblock_user(v):
|
||||||
|
|
||||||
@app.get("/settings/apps")
|
@app.get("/settings/apps")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_apps(v):
|
def settings_apps(v:User):
|
||||||
return render_template("settings/apps.html", v=v)
|
return render_template("settings/apps.html", v=v)
|
||||||
|
|
||||||
@app.get("/settings/advanced")
|
@app.get("/settings/advanced")
|
||||||
@auth_required
|
@auth_required
|
||||||
def settings_advanced_get(v):
|
def settings_advanced_get(v:User):
|
||||||
return render_template("settings/advanced.html", v=v)
|
return render_template("settings/advanced.html", v=v)
|
||||||
|
|
||||||
@app.post("/settings/name_change")
|
@app.post("/settings/name_change")
|
||||||
|
@ -671,8 +671,8 @@ def settings_name_change(v):
|
||||||
@app.post("/settings/song_change_mp3")
|
@app.post("/settings/song_change_mp3")
|
||||||
@feature_required('USERS_PROFILE_SONG')
|
@feature_required('USERS_PROFILE_SONG')
|
||||||
@limiter.limit("3/second;10/day")
|
@limiter.limit("3/second;10/day")
|
||||||
@ratelimit_user("3/second;10/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("3/second;10/day")
|
||||||
def settings_song_change_mp3(v):
|
def settings_song_change_mp3(v):
|
||||||
file = request.files['file']
|
file = request.files['file']
|
||||||
if file.content_type != 'audio/mpeg':
|
if file.content_type != 'audio/mpeg':
|
||||||
|
@ -699,8 +699,8 @@ def settings_song_change_mp3(v):
|
||||||
@app.post("/settings/song_change")
|
@app.post("/settings/song_change")
|
||||||
@feature_required('USERS_PROFILE_SONG')
|
@feature_required('USERS_PROFILE_SONG')
|
||||||
@limiter.limit("3/second;10/day")
|
@limiter.limit("3/second;10/day")
|
||||||
@ratelimit_user("3/second;10/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("3/second;10/day")
|
||||||
def settings_song_change(v):
|
def settings_song_change(v):
|
||||||
song=request.values.get("song").strip()
|
song=request.values.get("song").strip()
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ def rdrama(id, title):
|
||||||
|
|
||||||
@app.get("/marseys")
|
@app.get("/marseys")
|
||||||
@auth_required
|
@auth_required
|
||||||
def marseys(v):
|
def marseys(v:User):
|
||||||
if SITE == 'rdrama.net':
|
if SITE == 'rdrama.net':
|
||||||
marseys = g.db.query(Marsey, User).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id==None)
|
marseys = g.db.query(Marsey, User).join(User, Marsey.author_id == User.id).filter(Marsey.submitter_id==None)
|
||||||
sort = request.values.get("sort", "usage")
|
sort = request.values.get("sort", "usage")
|
||||||
|
@ -74,13 +74,13 @@ def marsey_list():
|
||||||
|
|
||||||
@app.get('/sidebar')
|
@app.get('/sidebar')
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def sidebar(v):
|
def sidebar(v:Optional[User]):
|
||||||
return render_template('sidebar.html', v=v)
|
return render_template('sidebar.html', v=v)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/stats")
|
@app.get("/stats")
|
||||||
@auth_required
|
@auth_required
|
||||||
def participation_stats(v):
|
def participation_stats(v:User):
|
||||||
if v.client: return stats_cached()
|
if v.client: return stats_cached()
|
||||||
return render_template("stats.html", v=v, title="Content Statistics", data=stats_cached())
|
return render_template("stats.html", v=v, title="Content Statistics", data=stats_cached())
|
||||||
|
|
||||||
|
@ -94,12 +94,12 @@ def chart():
|
||||||
|
|
||||||
@app.get("/weekly_chart")
|
@app.get("/weekly_chart")
|
||||||
@auth_required
|
@auth_required
|
||||||
def weekly_chart(v):
|
def weekly_chart(v:User):
|
||||||
return send_file(statshelper.chart_path(kind="weekly", site=SITE))
|
return send_file(statshelper.chart_path(kind="weekly", site=SITE))
|
||||||
|
|
||||||
@app.get("/daily_chart")
|
@app.get("/daily_chart")
|
||||||
@auth_required
|
@auth_required
|
||||||
def daily_chart(v):
|
def daily_chart(v:User):
|
||||||
return send_file(statshelper.chart_path(kind="daily", site=SITE))
|
return send_file(statshelper.chart_path(kind="daily", site=SITE))
|
||||||
|
|
||||||
@app.get("/patrons")
|
@app.get("/patrons")
|
||||||
|
@ -115,18 +115,14 @@ def patrons(v):
|
||||||
@app.get("/admins")
|
@app.get("/admins")
|
||||||
@app.get("/badmins")
|
@app.get("/badmins")
|
||||||
@auth_required
|
@auth_required
|
||||||
def admins(v):
|
def admins(v:User):
|
||||||
if v.admin_level >= PERMS['VIEW_SORTED_ADMIN_LIST']:
|
admins = g.db.query(User).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.truescore.desc()).all()
|
||||||
admins = g.db.query(User).filter(User.admin_level>1).order_by(User.truescore.desc()).all()
|
|
||||||
admins += g.db.query(User).filter(User.admin_level==1).order_by(User.truescore.desc()).all()
|
|
||||||
else: admins = g.db.query(User).filter(User.admin_level>0).order_by(User.truescore.desc()).all()
|
|
||||||
return render_template("admins.html", v=v, admins=admins)
|
return render_template("admins.html", v=v, admins=admins)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/log")
|
@app.get("/log")
|
||||||
@app.get("/modlog")
|
@app.get("/modlog")
|
||||||
@auth_required
|
@auth_required
|
||||||
def log(v):
|
def log(v:User):
|
||||||
|
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
try: page = max(int(request.values.get("page", 1)), 1)
|
||||||
except: page = 1
|
except: page = 1
|
||||||
|
@ -189,7 +185,7 @@ def log_item(id, v):
|
||||||
|
|
||||||
@app.get("/directory")
|
@app.get("/directory")
|
||||||
@auth_required
|
@auth_required
|
||||||
def static_megathread_index(v):
|
def static_megathread_index(v:User):
|
||||||
return render_template("megathread_index.html", v=v)
|
return render_template("megathread_index.html", v=v)
|
||||||
|
|
||||||
@app.get("/api")
|
@app.get("/api")
|
||||||
|
@ -203,13 +199,13 @@ def api(v):
|
||||||
@app.get("/press")
|
@app.get("/press")
|
||||||
@app.get("/media")
|
@app.get("/media")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def contact(v):
|
def contact(v:Optional[User]):
|
||||||
return render_template("contact.html", v=v)
|
return render_template("contact.html", v=v)
|
||||||
|
|
||||||
@app.post("/send_admin")
|
@app.post("/send_admin")
|
||||||
@limiter.limit("1/second;1/2 minutes;10/day")
|
@limiter.limit("1/second;1/2 minutes;10/day")
|
||||||
@ratelimit_user("1/second;1/2 minutes;10/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("1/second;1/2 minutes;10/day")
|
||||||
def submit_contact(v):
|
def submit_contact(v):
|
||||||
body = request.values.get("message")
|
body = request.values.get("message")
|
||||||
if not body: abort(400)
|
if not body: abort(400)
|
||||||
|
@ -235,9 +231,7 @@ def submit_contact(v):
|
||||||
execute_blackjack(v, new_comment, new_comment.body_html, 'modmail')
|
execute_blackjack(v, new_comment, new_comment.body_html, 'modmail')
|
||||||
new_comment.top_comment_id = new_comment.id
|
new_comment.top_comment_id = new_comment.id
|
||||||
|
|
||||||
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'])
|
admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != AEVANN_ID)
|
||||||
if SITE == 'watchpeopledie.tv':
|
|
||||||
admins = admins.filter(User.id != AEVANN_ID)
|
|
||||||
|
|
||||||
for admin in admins.all():
|
for admin in admins.all():
|
||||||
notif = Notification(comment_id=new_comment.id, user_id=admin.id)
|
notif = Notification(comment_id=new_comment.id, user_id=admin.id)
|
||||||
|
@ -332,7 +326,7 @@ def badge_list(site):
|
||||||
@app.get("/badges")
|
@app.get("/badges")
|
||||||
@feature_required('BADGES')
|
@feature_required('BADGES')
|
||||||
@auth_required
|
@auth_required
|
||||||
def badges(v):
|
def badges(v:User):
|
||||||
badges, counts = badge_list(SITE)
|
badges, counts = badge_list(SITE)
|
||||||
return render_template("badges.html", v=v, badges=badges, counts=counts)
|
return render_template("badges.html", v=v, badges=badges, counts=counts)
|
||||||
|
|
||||||
|
@ -353,7 +347,7 @@ def blocks(v):
|
||||||
|
|
||||||
@app.get("/banned")
|
@app.get("/banned")
|
||||||
@auth_required
|
@auth_required
|
||||||
def banned(v):
|
def banned(v:User):
|
||||||
users = g.db.query(User).filter(User.is_banned > 0, User.unban_utc == 0)
|
users = g.db.query(User).filter(User.is_banned > 0, User.unban_utc == 0)
|
||||||
if not v.can_see_shadowbanned:
|
if not v.can_see_shadowbanned:
|
||||||
users = users.filter(User.shadowbanned == None)
|
users = users.filter(User.shadowbanned == None)
|
||||||
|
@ -362,12 +356,12 @@ def banned(v):
|
||||||
|
|
||||||
@app.get("/formatting")
|
@app.get("/formatting")
|
||||||
@auth_required
|
@auth_required
|
||||||
def formatting(v):
|
def formatting(v:User):
|
||||||
return render_template("formatting.html", v=v)
|
return render_template("formatting.html", v=v)
|
||||||
|
|
||||||
@app.get("/app")
|
@app.get("/app")
|
||||||
@auth_desired
|
@auth_desired
|
||||||
def mobile_app(v):
|
def mobile_app(v:Optional[User]):
|
||||||
return render_template("app.html", v=v)
|
return render_template("app.html", v=v)
|
||||||
|
|
||||||
@app.get("/service-worker.js")
|
@app.get("/service-worker.js")
|
||||||
|
@ -395,7 +389,7 @@ def transfers_id(id, v):
|
||||||
|
|
||||||
@app.get("/transfers")
|
@app.get("/transfers")
|
||||||
@auth_required
|
@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())
|
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")
|
@app.post("/h/<sub>/block")
|
||||||
@auth_required
|
@auth_required
|
||||||
def block_sub(v, sub):
|
def block_sub(v:User, sub):
|
||||||
sub = get_sub_by_name(sub).name
|
sub = get_sub_by_name(sub).name
|
||||||
existing = g.db.query(SubBlock).filter_by(user_id=v.id, sub=sub).one_or_none()
|
existing = g.db.query(SubBlock).filter_by(user_id=v.id, sub=sub).one_or_none()
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ def block_sub(v, sub):
|
||||||
|
|
||||||
@app.post("/h/<sub>/unblock")
|
@app.post("/h/<sub>/unblock")
|
||||||
@auth_required
|
@auth_required
|
||||||
def unblock_sub(v, sub):
|
def unblock_sub(v:User, sub):
|
||||||
sub = get_sub_by_name(sub).name
|
sub = get_sub_by_name(sub).name
|
||||||
if sub == "chudrama" and not v.can_see_chudrama: abort(403)
|
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()
|
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")
|
@app.post("/h/<sub>/subscribe")
|
||||||
@auth_required
|
@auth_required
|
||||||
def subscribe_sub(v, sub):
|
def subscribe_sub(v:User, sub):
|
||||||
sub = get_sub_by_name(sub).name
|
sub = get_sub_by_name(sub).name
|
||||||
existing = g.db.query(SubJoin).filter_by(user_id=v.id, sub=sub).one_or_none()
|
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")
|
@app.post("/h/<sub>/unsubscribe")
|
||||||
@auth_required
|
@auth_required
|
||||||
def unsubscribe_sub(v, sub):
|
def unsubscribe_sub(v:User, sub):
|
||||||
sub = get_sub_by_name(sub).name
|
sub = get_sub_by_name(sub).name
|
||||||
subscribe = g.db.query(SubJoin).filter_by(user_id=v.id, sub=sub).one_or_none()
|
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")
|
@app.post("/h/<sub>/follow")
|
||||||
@auth_required
|
@auth_required
|
||||||
def follow_sub(v, sub):
|
def follow_sub(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
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()
|
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")
|
@app.post("/h/<sub>/unfollow")
|
||||||
@auth_required
|
@auth_required
|
||||||
def unfollow_sub(v, sub):
|
def unfollow_sub(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
subscription = g.db.query(SubSubscription).filter_by(user_id=v.id, sub=sub.name).one_or_none()
|
subscription = g.db.query(SubSubscription).filter_by(user_id=v.id, sub=sub.name).one_or_none()
|
||||||
if subscription:
|
if subscription:
|
||||||
|
@ -184,7 +184,7 @@ def unfollow_sub(v, sub):
|
||||||
|
|
||||||
@app.get("/h/<sub>/mods")
|
@app.get("/h/<sub>/mods")
|
||||||
@auth_required
|
@auth_required
|
||||||
def mods(v, sub):
|
def mods(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
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()
|
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")
|
@app.get("/h/<sub>/exilees")
|
||||||
@auth_required
|
@auth_required
|
||||||
def sub_exilees(v, sub):
|
def sub_exilees(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
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) \
|
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")
|
@app.get("/h/<sub>/blockers")
|
||||||
@auth_required
|
@auth_required
|
||||||
def sub_blockers(v, sub):
|
def sub_blockers(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||||
users = g.db.query(User, SubBlock).join(SubBlock) \
|
users = g.db.query(User, SubBlock).join(SubBlock) \
|
||||||
|
@ -219,7 +219,7 @@ def sub_blockers(v, sub):
|
||||||
|
|
||||||
@app.get("/h/<sub>/followers")
|
@app.get("/h/<sub>/followers")
|
||||||
@auth_required
|
@auth_required
|
||||||
def sub_followers(v, sub):
|
def sub_followers(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||||
users = g.db.query(User, SubSubscription).join(SubSubscription) \
|
users = g.db.query(User, SubSubscription).join(SubSubscription) \
|
||||||
|
@ -232,8 +232,8 @@ def sub_followers(v, sub):
|
||||||
|
|
||||||
@app.post("/h/<sub>/add_mod")
|
@app.post("/h/<sub>/add_mod")
|
||||||
@limiter.limit("1/second;30/day")
|
@limiter.limit("1/second;30/day")
|
||||||
@ratelimit_user("1/second;30/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;30/day")
|
||||||
def add_mod(v, sub):
|
def add_mod(v, sub):
|
||||||
if SITE_NAME == 'WPD': abort(403)
|
if SITE_NAME == 'WPD': abort(403)
|
||||||
sub = get_sub_by_name(sub).name
|
sub = get_sub_by_name(sub).name
|
||||||
|
@ -457,8 +457,8 @@ def get_sub_css(sub):
|
||||||
|
|
||||||
@app.post("/h/<sub>/banner")
|
@app.post("/h/<sub>/banner")
|
||||||
@limiter.limit("1/second;10/day")
|
@limiter.limit("1/second;10/day")
|
||||||
@ratelimit_user("1/second;10/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;10/day")
|
||||||
def sub_banner(v, sub):
|
def sub_banner(v, sub):
|
||||||
if g.is_tor: abort(403, "Image uploads are not allowed through TOR.")
|
if g.is_tor: abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
|
@ -490,8 +490,8 @@ def sub_banner(v, sub):
|
||||||
|
|
||||||
@app.post("/h/<sub>/sidebar_image")
|
@app.post("/h/<sub>/sidebar_image")
|
||||||
@limiter.limit("1/second;10/day")
|
@limiter.limit("1/second;10/day")
|
||||||
@ratelimit_user("1/second;10/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;10/day")
|
||||||
def sub_sidebar(v, sub):
|
def sub_sidebar(v, sub):
|
||||||
if g.is_tor: abort(403, "Image uploads are not allowed through TOR.")
|
if g.is_tor: abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
|
@ -522,8 +522,8 @@ def sub_sidebar(v, sub):
|
||||||
|
|
||||||
@app.post("/h/<sub>/marsey_image")
|
@app.post("/h/<sub>/marsey_image")
|
||||||
@limiter.limit("1/second;10/day")
|
@limiter.limit("1/second;10/day")
|
||||||
@ratelimit_user("1/second;10/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;10/day")
|
||||||
def sub_marsey(v, sub):
|
def sub_marsey(v, sub):
|
||||||
if g.is_tor: abort(403, "Image uploads are not allowed through TOR.")
|
if g.is_tor: abort(403, "Image uploads are not allowed through TOR.")
|
||||||
|
|
||||||
|
@ -554,7 +554,7 @@ def sub_marsey(v, sub):
|
||||||
|
|
||||||
@app.get("/holes")
|
@app.get("/holes")
|
||||||
@auth_required
|
@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()
|
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()
|
total_users = g.db.query(User).count()
|
||||||
return render_template('sub/subs.html', v=v, subs=subs, total_users=total_users)
|
return render_template('sub/subs.html', v=v, subs=subs, total_users=total_users)
|
||||||
|
@ -665,7 +665,7 @@ def mod_pin(cid, v):
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
if v.id != comment.author_id:
|
if v.id != comment.author_id:
|
||||||
message = f"@{v.username} (/h/{comment.post.sub} Mod) has pinned your [comment]({comment.shortlink})!"
|
message = f"@{v.username} (/h/{comment.post.sub} Mod) has pinned your [comment]({comment.shortlink})"
|
||||||
send_repeatable_notification(comment.author_id, message)
|
send_repeatable_notification(comment.author_id, message)
|
||||||
|
|
||||||
return {"message": "Comment pinned!"}
|
return {"message": "Comment pinned!"}
|
||||||
|
@ -691,7 +691,7 @@ def mod_unpin(cid, v):
|
||||||
g.db.add(ma)
|
g.db.add(ma)
|
||||||
|
|
||||||
if v.id != comment.author_id:
|
if v.id != comment.author_id:
|
||||||
message = f"@{v.username} (/h/{comment.post.sub} Mod) has unpinned your [comment]({comment.shortlink})!"
|
message = f"@{v.username} (/h/{comment.post.sub} Mod) has unpinned your [comment]({comment.shortlink})"
|
||||||
send_repeatable_notification(comment.author_id, message)
|
send_repeatable_notification(comment.author_id, message)
|
||||||
return {"message": "Comment unpinned!"}
|
return {"message": "Comment unpinned!"}
|
||||||
|
|
||||||
|
@ -699,7 +699,7 @@ def mod_unpin(cid, v):
|
||||||
@app.get("/h/<sub>/log")
|
@app.get("/h/<sub>/log")
|
||||||
@app.get("/h/<sub>/modlog")
|
@app.get("/h/<sub>/modlog")
|
||||||
@auth_required
|
@auth_required
|
||||||
def hole_log(v, sub):
|
def hole_log(v:User, sub):
|
||||||
sub = get_sub_by_name(sub)
|
sub = get_sub_by_name(sub)
|
||||||
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
if sub.name == "chudrama" and not v.can_see_chudrama: abort(403)
|
||||||
try: page = max(int(request.values.get("page", 1)), 1)
|
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")
|
@app.get("/@<username>/upvoters/<uid>/posts")
|
||||||
@auth_required
|
@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)
|
return upvoters_downvoters(v, username, uid, Submission, Vote, 1, "userpage/voted_posts.html", None)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/upvoters/<uid>/comments")
|
@app.get("/@<username>/upvoters/<uid>/comments")
|
||||||
@auth_required
|
@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)
|
return upvoters_downvoters(v, username, uid, Comment, CommentVote, 1, "userpage/voted_comments.html", True)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/downvoters/<uid>/posts")
|
@app.get("/@<username>/downvoters/<uid>/posts")
|
||||||
@auth_required
|
@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)
|
return upvoters_downvoters(v, username, uid, Submission, Vote, -1, "userpage/voted_posts.html", None)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/downvoters/<uid>/comments")
|
@app.get("/@<username>/downvoters/<uid>/comments")
|
||||||
@auth_required
|
@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)
|
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):
|
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")
|
@app.get("/@<username>/upvoting/<uid>/posts")
|
||||||
@auth_required
|
@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)
|
return upvoting_downvoting(v, username, uid, Submission, Vote, 1, "userpage/voted_posts.html", None)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/upvoting/<uid>/comments")
|
@app.get("/@<username>/upvoting/<uid>/comments")
|
||||||
@auth_required
|
@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)
|
return upvoting_downvoting(v, username, uid, Comment, CommentVote, 1, "userpage/voted_comments.html", True)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/downvoting/<uid>/posts")
|
@app.get("/@<username>/downvoting/<uid>/posts")
|
||||||
@auth_required
|
@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)
|
return upvoting_downvoting(v, username, uid, Submission, Vote, -1, "userpage/voted_posts.html", None)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/downvoting/<uid>/comments")
|
@app.get("/@<username>/downvoting/<uid>/comments")
|
||||||
@auth_required
|
@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)
|
return upvoting_downvoting(v, username, uid, Comment, CommentVote, -1, "userpage/voted_comments.html", True)
|
||||||
|
|
||||||
def user_voted(v, username, cls, vote_cls, template, standalone):
|
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")
|
@app.get("/@<username>/voted/posts")
|
||||||
@auth_required
|
@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)
|
return user_voted(v, username, Submission, Vote, "userpage/voted_posts.html", None)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/@<username>/voted/comments")
|
@app.get("/@<username>/voted/comments")
|
||||||
@auth_required
|
@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)
|
return user_voted(v, username, Comment, CommentVote, "userpage/voted_comments.html", True)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/grassed")
|
@app.get("/grassed")
|
||||||
@auth_required
|
@auth_required
|
||||||
def grassed(v):
|
def grassed(v:User):
|
||||||
users = g.db.query(User).filter(User.ban_reason.like('grass award used by @%'))
|
users = g.db.query(User).filter(User.ban_reason.like('grass award used by @%'))
|
||||||
if not v.can_see_shadowbanned:
|
if not v.can_see_shadowbanned:
|
||||||
users = users.filter(User.shadowbanned == None)
|
users = users.filter(User.shadowbanned == None)
|
||||||
|
@ -179,7 +179,7 @@ def grassed(v):
|
||||||
|
|
||||||
@app.get("/chuds")
|
@app.get("/chuds")
|
||||||
@auth_required
|
@auth_required
|
||||||
def chuds(v):
|
def chuds(v:User):
|
||||||
users = g.db.query(User).filter(User.agendaposter == 1)
|
users = g.db.query(User).filter(User.agendaposter == 1)
|
||||||
if not v.can_see_shadowbanned:
|
if not v.can_see_shadowbanned:
|
||||||
users = users.filter(User.shadowbanned == None)
|
users = users.filter(User.shadowbanned == None)
|
||||||
|
@ -233,32 +233,30 @@ def all_upvoters_downvoters(v, username, vote_dir, is_who_simps_hates):
|
||||||
|
|
||||||
@app.get("/@<username>/upvoters")
|
@app.get("/@<username>/upvoters")
|
||||||
@auth_required
|
@auth_required
|
||||||
def upvoters(v, username):
|
def upvoters(v:User, username):
|
||||||
return all_upvoters_downvoters(v, username, 1, False)
|
return all_upvoters_downvoters(v, username, 1, False)
|
||||||
|
|
||||||
@app.get("/@<username>/downvoters")
|
@app.get("/@<username>/downvoters")
|
||||||
@auth_required
|
@auth_required
|
||||||
def downvoters(v, username):
|
def downvoters(v:User, username):
|
||||||
return all_upvoters_downvoters(v, username, -1, False)
|
return all_upvoters_downvoters(v, username, -1, False)
|
||||||
|
|
||||||
@app.get("/@<username>/upvoting")
|
@app.get("/@<username>/upvoting")
|
||||||
@auth_required
|
@auth_required
|
||||||
def upvoting(v, username):
|
def upvoting(v:User, username):
|
||||||
return all_upvoters_downvoters(v, username, 1, True)
|
return all_upvoters_downvoters(v, username, 1, True)
|
||||||
|
|
||||||
@app.get("/@<username>/downvoting")
|
@app.get("/@<username>/downvoting")
|
||||||
@auth_required
|
@auth_required
|
||||||
def downvoting(v, username):
|
def downvoting(v:User, username):
|
||||||
return all_upvoters_downvoters(v, username, -1, True)
|
return all_upvoters_downvoters(v, username, -1, True)
|
||||||
|
|
||||||
@app.post("/@<username>/suicide")
|
@app.post("/@<username>/suicide")
|
||||||
@feature_required('USERS_SUICIDE')
|
@feature_required('USERS_SUICIDE')
|
||||||
@limiter.limit("1/second;5/day")
|
@limiter.limit("1/second;5/day")
|
||||||
@ratelimit_user("1/second;5/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("1/second;5/day")
|
||||||
def suicide(v, username):
|
def suicide(v, username):
|
||||||
|
|
||||||
|
|
||||||
user = get_user(username)
|
user = get_user(username)
|
||||||
suicide = f"Hi there,\n\nA [concerned user](/id/{v.id}) reached out to us about you.\n\nWhen you're in the middle of something painful, it may feel like you don't have a lot of options. But whatever you're going through, you deserve help and there are people who are here for you.\n\nThere are resources available in your area that are free, confidential, and available 24/7:\n\n- Call, Text, or Chat with Canada's [Crisis Services Canada](https://www.crisisservicescanada.ca/en/)\n- Call, Email, or Visit the UK's [Samaritans](https://www.samaritans.org/)\n- Text CHAT to America's [Crisis Text Line](https://www.crisistextline.org/) at 741741.\nIf you don't see a resource in your area above, the moderators keep a comprehensive list of resources and hotlines for people organized by location. Find Someone Now\n\nIf you think you may be depressed or struggling in another way, don't ignore it or brush it aside. Take yourself and your feelings seriously, and reach out to someone.\n\nIt may not feel like it, but you have options. There are people available to listen to you, and ways to move forward.\n\nYour fellow users care about you and there are people who want to help."
|
suicide = f"Hi there,\n\nA [concerned user](/id/{v.id}) reached out to us about you.\n\nWhen you're in the middle of something painful, it may feel like you don't have a lot of options. But whatever you're going through, you deserve help and there are people who are here for you.\n\nThere are resources available in your area that are free, confidential, and available 24/7:\n\n- Call, Text, or Chat with Canada's [Crisis Services Canada](https://www.crisisservicescanada.ca/en/)\n- Call, Email, or Visit the UK's [Samaritans](https://www.samaritans.org/)\n- Text CHAT to America's [Crisis Text Line](https://www.crisistextline.org/) at 741741.\nIf you don't see a resource in your area above, the moderators keep a comprehensive list of resources and hotlines for people organized by location. Find Someone Now\n\nIf you think you may be depressed or struggling in another way, don't ignore it or brush it aside. Take yourself and your feelings seriously, and reach out to someone.\n\nIt may not feel like it, but you have options. There are people available to listen to you, and ways to move forward.\n\nYour fellow users care about you and there are people who want to help."
|
||||||
if not v.shadowbanned:
|
if not v.shadowbanned:
|
||||||
|
@ -268,7 +266,7 @@ def suicide(v, username):
|
||||||
|
|
||||||
@app.get("/@<username>/coins")
|
@app.get("/@<username>/coins")
|
||||||
@auth_required
|
@auth_required
|
||||||
def get_coins(v, username):
|
def get_coins(v:User, username):
|
||||||
user = get_user(username, v=v, include_shadowbanned=False)
|
user = get_user(username, v=v, include_shadowbanned=False)
|
||||||
return {"coins": user.coins}
|
return {"coins": user.coins}
|
||||||
|
|
||||||
|
@ -328,13 +326,13 @@ def transfer_bux(v, username):
|
||||||
|
|
||||||
@app.get("/leaderboard")
|
@app.get("/leaderboard")
|
||||||
@auth_required
|
@auth_required
|
||||||
def leaderboard(v):
|
def leaderboard(v:User):
|
||||||
users = g.db.query(User)
|
users = g.db.query(User)
|
||||||
if not v.can_see_shadowbanned:
|
if not v.can_see_shadowbanned:
|
||||||
users = users.filter(User.shadowbanned == None)
|
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)
|
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)
|
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)
|
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)
|
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)
|
||||||
|
@ -342,14 +340,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)
|
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)
|
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)
|
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)
|
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)
|
return render_template("leaderboard.html", v=v, leaderboards=leaderboards)
|
||||||
|
|
||||||
|
@ -414,8 +414,8 @@ def unsubscribe(v, post_id):
|
||||||
|
|
||||||
@app.post("/@<username>/message")
|
@app.post("/@<username>/message")
|
||||||
@limiter.limit("1/second;10/minute;20/hour;50/day")
|
@limiter.limit("1/second;10/minute;20/hour;50/day")
|
||||||
@ratelimit_user("1/second;10/minute;20/hour;50/day")
|
|
||||||
@is_not_permabanned
|
@is_not_permabanned
|
||||||
|
@ratelimit_user("1/second;10/minute;20/hour;50/day")
|
||||||
def message2(v, username):
|
def message2(v, username):
|
||||||
user = get_user(username, v=v, include_blocks=True, include_shadowbanned=False)
|
user = get_user(username, v=v, include_blocks=True, include_shadowbanned=False)
|
||||||
|
|
||||||
|
@ -479,8 +479,8 @@ def message2(v, username):
|
||||||
|
|
||||||
@app.post("/reply")
|
@app.post("/reply")
|
||||||
@limiter.limit("1/second;6/minute;50/hour;200/day")
|
@limiter.limit("1/second;6/minute;50/hour;200/day")
|
||||||
@ratelimit_user("1/second;6/minute;50/hour;200/day")
|
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ratelimit_user("1/second;6/minute;50/hour;200/day")
|
||||||
def messagereply(v):
|
def messagereply(v):
|
||||||
body = sanitize_raw_body(request.values.get("body"), False)
|
body = sanitize_raw_body(request.values.get("body"), False)
|
||||||
if not body and not request.files.get("file"): abort(400, "Message is empty!")
|
if not body and not request.files.get("file"): abort(400, "Message is empty!")
|
||||||
|
@ -550,9 +550,7 @@ def messagereply(v):
|
||||||
top_comment = c.top_comment(g.db)
|
top_comment = c.top_comment(g.db)
|
||||||
|
|
||||||
if top_comment.sentto == MODMAIL_ID:
|
if top_comment.sentto == MODMAIL_ID:
|
||||||
admins = g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id)
|
admins = g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id, User.id != AEVANN_ID)
|
||||||
if SITE == 'watchpeopledie.tv':
|
|
||||||
admins = admins.filter(User.id != AEVANN_ID)
|
|
||||||
|
|
||||||
admins = [x[0] for x in admins.all()]
|
admins = [x[0] for x in admins.all()]
|
||||||
|
|
||||||
|
@ -626,25 +624,40 @@ def redditor_moment_redirect(username, v):
|
||||||
@auth_required
|
@auth_required
|
||||||
def followers(username, v):
|
def followers(username, v):
|
||||||
u = get_user(username, v=v, include_shadowbanned=False)
|
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']):
|
if not (v.id == u.id or v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']):
|
||||||
abort(403)
|
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) \
|
users = g.db.query(Follow, User).join(Follow, Follow.target_id == u.id) \
|
||||||
.filter(Follow.user_id == User.id) \
|
.filter(Follow.user_id == User.id) \
|
||||||
.order_by(Follow.created_utc).all()
|
.order_by(Follow.created_utc.desc()) \
|
||||||
return render_template("userpage/followers.html", v=v, u=u, users=users)
|
.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")
|
@app.get("/@<username>/blockers")
|
||||||
@auth_required
|
@auth_required
|
||||||
def blockers(username, v):
|
def blockers(username, v):
|
||||||
u = get_user(username, v=v, include_shadowbanned=False)
|
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) \
|
users = g.db.query(UserBlock, User).join(UserBlock, UserBlock.target_id == u.id) \
|
||||||
.filter(UserBlock.user_id == User.id) \
|
.filter(UserBlock.user_id == User.id) \
|
||||||
.order_by(UserBlock.created_utc).all()
|
.order_by(UserBlock.created_utc.desc()) \
|
||||||
return render_template("userpage/blockers.html", v=v, u=u, users=users)
|
.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")
|
@app.get("/@<username>/following")
|
||||||
@auth_required
|
@auth_required
|
||||||
|
@ -653,18 +666,33 @@ def following(username, v):
|
||||||
if not (v.id == u.id or v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']):
|
if not (v.id == u.id or v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']):
|
||||||
abort(403)
|
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) \
|
users = g.db.query(User).join(Follow, Follow.user_id == u.id) \
|
||||||
.filter(Follow.target_id == User.id) \
|
.filter(Follow.target_id == User.id) \
|
||||||
.order_by(Follow.created_utc).all()
|
.order_by(Follow.created_utc.desc()) \
|
||||||
return render_template("userpage/following.html", v=v, u=u, users=users)
|
.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
|
@auth_required
|
||||||
def visitors(v):
|
def visitors(username, v:User):
|
||||||
if not v.viewers_recorded:
|
u = get_user(username, v=v, include_shadowbanned=False)
|
||||||
return render_template("errors/patron.html", v=v)
|
|
||||||
viewers=sorted(v.viewers, key = lambda x: x.last_view_utc, reverse=True)
|
try: page = int(request.values.get("page", 1))
|
||||||
return render_template("userpage/viewers.html", v=v, viewers=viewers)
|
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)
|
@cache.memoize(timeout=86400)
|
||||||
def userpagelisting(user:User, site=None, v=None, page:int=1, sort="new", t="all"):
|
def userpagelisting(user:User, site=None, v=None, page:int=1, sort="new", t="all"):
|
||||||
|
@ -686,7 +714,7 @@ def u_username(username, v=None):
|
||||||
return redirect(SITE_FULL + request.full_path.replace(username, u.username))
|
return redirect(SITE_FULL + request.full_path.replace(username, u.username))
|
||||||
is_following = v and u.has_follower(v)
|
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()
|
g.db.flush()
|
||||||
view = g.db.query(ViewerRelationship).filter_by(viewer_id=v.id, user_id=u.id).one_or_none()
|
view = g.db.query(ViewerRelationship).filter_by(viewer_id=v.id, user_id=u.id).one_or_none()
|
||||||
|
|
||||||
|
@ -937,8 +965,7 @@ def user_profile_name(username):
|
||||||
return redirect(x.profile_url)
|
return redirect(x.profile_url)
|
||||||
|
|
||||||
def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone=False):
|
def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone=False):
|
||||||
PAGE_SIZE = 25
|
if relationship_cls in {SaveRelationship, Subscription}:
|
||||||
if relationship_cls in [SaveRelationship, Subscription]:
|
|
||||||
query = relationship_cls.submission_id
|
query = relationship_cls.submission_id
|
||||||
join = relationship_cls.post
|
join = relationship_cls.post
|
||||||
cls = Submission
|
cls = Submission
|
||||||
|
@ -951,18 +978,24 @@ def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone
|
||||||
ids = [x[0] for x in g.db.query(query).join(join).filter(relationship_cls.user_id == v.id).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()]
|
ids = [x[0] for x in g.db.query(query).join(join).filter(relationship_cls.user_id == v.id).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()]
|
||||||
next_exists = len(ids) > PAGE_SIZE
|
next_exists = len(ids) > PAGE_SIZE
|
||||||
ids = ids[:PAGE_SIZE]
|
ids = ids[:PAGE_SIZE]
|
||||||
|
|
||||||
|
extra = None
|
||||||
|
if not v.admin_level >= PERMS['POST_COMMENT_MODERATION']:
|
||||||
|
extra = lambda q:q.filter(cls.is_banned == False, cls.deleted_utc == 0)
|
||||||
|
|
||||||
if cls is Submission:
|
if cls is Submission:
|
||||||
listing = get_posts(ids, v=v, eager=True)
|
listing = get_posts(ids, v=v, eager=True, extra=extra)
|
||||||
elif cls is Comment:
|
elif cls is Comment:
|
||||||
listing = get_comments(ids, v=v)
|
listing = get_comments(ids, v=v, extra=extra)
|
||||||
else:
|
else:
|
||||||
raise TypeError("Only supports Submissions and Comments. This is probably the result of a bug with *this* function")
|
raise TypeError("Only supports Submissions and Comments. This is probably the result of a bug with *this* function")
|
||||||
|
|
||||||
if v.client: return {"data": [x.json(g.db) for x in listing]}
|
if v.client: return {"data": [x.json(g.db) for x in listing]}
|
||||||
return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone)
|
return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone)
|
||||||
|
|
||||||
@app.get("/@<username>/saved/posts")
|
@app.get("/@<username>/saved/posts")
|
||||||
@auth_required
|
@auth_required
|
||||||
def saved_posts(v, username):
|
def saved_posts(v:User, username):
|
||||||
try: page = max(1, int(request.values.get("page", 1)))
|
try: page = max(1, int(request.values.get("page", 1)))
|
||||||
except: abort(400, "Invalid page input!")
|
except: abort(400, "Invalid page input!")
|
||||||
|
|
||||||
|
@ -970,7 +1003,7 @@ def saved_posts(v, username):
|
||||||
|
|
||||||
@app.get("/@<username>/saved/comments")
|
@app.get("/@<username>/saved/comments")
|
||||||
@auth_required
|
@auth_required
|
||||||
def saved_comments(v, username):
|
def saved_comments(v:User, username):
|
||||||
try: page = max(1, int(request.values.get("page", 1)))
|
try: page = max(1, int(request.values.get("page", 1)))
|
||||||
except: abort(400, "Invalid page input!")
|
except: abort(400, "Invalid page input!")
|
||||||
|
|
||||||
|
@ -978,7 +1011,7 @@ def saved_comments(v, username):
|
||||||
|
|
||||||
@app.get("/@<username>/subscribed/posts")
|
@app.get("/@<username>/subscribed/posts")
|
||||||
@auth_required
|
@auth_required
|
||||||
def subscribed_posts(v, username):
|
def subscribed_posts(v:User, username):
|
||||||
try: page = max(1, int(request.values.get("page", 1)))
|
try: page = max(1, int(request.values.get("page", 1)))
|
||||||
except: abort(400, "Invalid page input!")
|
except: abort(400, "Invalid page input!")
|
||||||
|
|
||||||
|
@ -986,7 +1019,7 @@ def subscribed_posts(v, username):
|
||||||
|
|
||||||
@app.post("/fp/<fp>")
|
@app.post("/fp/<fp>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def fp(v, fp):
|
def fp(v:User, fp):
|
||||||
v.fp = fp
|
v.fp = fp
|
||||||
users = g.db.query(User).filter(User.fp == fp, User.id != v.id).all()
|
users = g.db.query(User).filter(User.fp == fp, User.id != v.id).all()
|
||||||
if users: print(f'{v.username}: fp', flush=True)
|
if users: print(f'{v.username}: fp', flush=True)
|
||||||
|
@ -1032,7 +1065,7 @@ def toggle_holes():
|
||||||
|
|
||||||
@app.get("/badge_owners/<bid>")
|
@app.get("/badge_owners/<bid>")
|
||||||
@auth_required
|
@auth_required
|
||||||
def bid_list(v, bid):
|
def bid_list(v:User, bid):
|
||||||
|
|
||||||
try: bid = int(bid)
|
try: bid = int(bid)
|
||||||
except: abort(400)
|
except: abort(400)
|
||||||
|
@ -1094,7 +1127,7 @@ kofi_tiers={
|
||||||
@app.post("/settings/kofi")
|
@app.post("/settings/kofi")
|
||||||
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
@limiter.limit(DEFAULT_RATELIMIT_SLOWER)
|
||||||
@auth_required
|
@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 KOFI_TOKEN or KOFI_TOKEN == DEFAULT_CONFIG_VALUE: abort(404)
|
||||||
if not (v.email and v.is_activated):
|
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!")
|
abort(400, f"You must have a verified email to verify {patron} status and claim your rewards!")
|
||||||
|
|
|
@ -42,7 +42,7 @@ def vote_info_get(v, link):
|
||||||
|
|
||||||
def vote_post_comment(target_id, new, v, cls, vote_cls):
|
def vote_post_comment(target_id, new, v, cls, vote_cls):
|
||||||
if new == "-1" and DISABLE_DOWNVOTES: abort(403)
|
if new == "-1" and DISABLE_DOWNVOTES: abort(403)
|
||||||
if new not in ["-1", "0", "1"]: abort(400)
|
if new not in {"-1", "0", "1"}: abort(400)
|
||||||
if v.client and v.id not in PRIVILEGED_USER_BOTS: abort(403)
|
if v.client and v.id not in PRIVILEGED_USER_BOTS: abort(403)
|
||||||
new = int(new)
|
new = int(new)
|
||||||
target = None
|
target = None
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
|
|
||||||
<ul class="nav post-nav py-2">
|
<ul class="nav post-nav py-2">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if request.path.endswith('/posts') %} active{% endif %}" href="{{request.path.replace('/posts','/comments')}}">
|
<a class="nav-link {% if request.path.endswith('/posts') %} active{% endif %}" href="{{request.path.replace('/comments','/posts')}}">
|
||||||
<div>Posts</div>
|
<div>Posts</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<div class="settings-section rounded">
|
<div class="settings-section rounded">
|
||||||
<div class="d-lg-flex">
|
<div class="d-lg-flex">
|
||||||
<div class="title w-lg-25">
|
<div class="title w-lg-25">
|
||||||
<label for="over18"><a href="{{app.permalink}}" {% if v and v.newtab %}data-target="t"target="_blank"{% endif %}>{{app.app_name}}</a></label>
|
<label for="over18"><a href="{{app.permalink}}/posts" {% if v and v.newtab %}data-target="t"target="_blank"{% endif %}>{{app.app_name}}</a></label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="body w-lg-100">
|
<div class="body w-lg-100">
|
||||||
|
|
|
@ -1,40 +1,51 @@
|
||||||
{% if SITE_NAME == 'PCM' %}
|
<div id="awards-container" class="w-100 h-100">
|
||||||
{% set wholesome = '/i/wholesome.webp' %}
|
{% macro stackable_award(award, src, alt) %}
|
||||||
{% else %}
|
{% for i in range(min(p.award_count(award, v), 4)) %}
|
||||||
{% set wholesome = '/e/marseywholesome.webp' %}
|
<div class="{{award}} {{award}}{{i+1}}">
|
||||||
|
<img alt="{{alt}}" src="{{src}}">
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% 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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% for i in range(min(p.award_count("wholesome", v), 4)) %}
|
{% if p.award_count("train", v) %}
|
||||||
{% if g.inferior_browser %}
|
{{ stackable_award('train', '/e/marseytrain.webp', ':#marseytrain:') }}
|
||||||
<div class="seal seal{{i+1}}" height="100%" width="100%">
|
{% endif %}
|
||||||
<img alt=":#marseywholesome:" class="sealimg" src="{{wholesome}}">
|
|
||||||
|
{% 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', i) }}
|
||||||
|
{% 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>
|
</div>
|
||||||
{% else %}
|
{% endfor %}
|
||||||
{% set seal_vertical = 'up' if (i % 2) == 0 else 'down' %}
|
{% endif %}
|
||||||
{% 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 %}
|
|
||||||
|
|
||||||
{% for i in range(min(p.award_count("train", v), 4)) %}
|
{% if p.award_count("shit", v) %}
|
||||||
{% set train_dir = 'left' if (i % 2) == 0 else 'right' %}
|
<script defer src="{{'js/vendor/critters.js' | asset}}"></script>
|
||||||
{% set train_mirror = ' mirrored' if (i % 2) == 0 else '' %}
|
<script defer src="{{'js/bugs.js' | asset}}"></script>
|
||||||
<marquee class="train train{{i+1}}" direction="{{train_dir}}" scrollamount=10 width="100%">
|
{% endif %}
|
||||||
<img alt=":#marseytrain:" class="trainimg{{train_mirror}}" src="/e/marseytrain.webp">
|
|
||||||
</marquee>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% for i in range(min(p.award_count("scooter", v), 4)) %}
|
{% if p.award_count("fireflies", v) %}
|
||||||
{% set scooter_dir = 'right' if (i % 2) == 0 else 'left' %}
|
<script defer src="{{'js/vendor/critters.js' | asset}}"></script>
|
||||||
{% set scooter_mirror = '' if (i % 2) == 0 else ' mirrored' %}
|
<script defer src="{{'js/fireflies.js' | asset}}"></script>
|
||||||
<marquee class="train train{{(i + 2) % 4 + 1}}" direction="{{scooter_dir}}" scrollamount=10 width="100%">
|
{% endif %}
|
||||||
<img alt=":#marseyscooter:" class="scooterimg{{scooter_mirror}}" src="/e/marseyscooter.webp">
|
|
||||||
</marquee>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if p.award_count("tilt", v) %}
|
{% if p.award_count("tilt", v) %}
|
||||||
<style>
|
<style>
|
||||||
|
@ -62,35 +73,4 @@
|
||||||
</style>
|
</style>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if p.award_count("confetti", v) %}
|
</div>
|
||||||
<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>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
|
@ -438,6 +438,10 @@
|
||||||
<button type="button" style="margin-top:0.2rem" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
|
<button type="button" style="margin-top:0.2rem" class="btn caction py-0 nobackground px-1 text-muted" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
|
||||||
|
{% if v.admin_level >= PERMS['APPS_MODERATION'] and c.oauth_app %}
|
||||||
|
<a href="{{c.oauth_app.permalink}}/comments" class="dropdown-item list-inline-item d-mob-none text-primary"><i class="fas fa-code text-primary fa-fw"></i>API App</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] and (v.id == c.author_id or v.admin_level >= PERMS['POST_COMMENT_MODERATION']) %}
|
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] and (v.id == c.author_id or v.admin_level >= PERMS['POST_COMMENT_MODERATION']) %}
|
||||||
<button type="button" id="undistinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.distinguish_level %}d-md-block{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','d-md-block')"><i class="fas fa-id-badge text-info fa-fw"></i>Undistinguish</button>
|
<button type="button" id="undistinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if c.distinguish_level %}d-md-block{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','d-md-block')"><i class="fas fa-id-badge text-info fa-fw"></i>Undistinguish</button>
|
||||||
<button type="button" id="distinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.distinguish_level %}d-md-block{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','d-md-block')"><i class="fas fa-id-badge text-info fa-fw"></i>Distinguish</button>
|
<button type="button" id="distinguish-{{c.id}}" class="dropdown-item list-inline-item d-none {% if not c.distinguish_level %}d-md-block{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish-{{c.id}}','undistinguish-{{c.id}}','d-md-block')"><i class="fas fa-id-badge text-info fa-fw"></i>Distinguish</button>
|
||||||
|
@ -482,7 +486,7 @@
|
||||||
{% endif %}
|
{% 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))) %}
|
{% 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>
|
<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 %}
|
{% endif %}
|
||||||
|
|
||||||
|
@ -496,9 +500,6 @@
|
||||||
<button type="button" id="chud-{{c.fullname}}" class="dropdown-item list-inline-item d-none {% if not c.author.agendaposter %}d-md-block{% endif %} text-danger" data-bs-toggle="modal" data-bs-target="#chudModal" onclick="chudModal('/comment/{{c.id}}', '{{c.author.id}}', '{{c.author_name}}', '{{c.fullname}}','d-md-block')"><i class="fas fa-face-sleeping text-danger fa-fw"></i>Chud user</button>
|
<button type="button" id="chud-{{c.fullname}}" class="dropdown-item list-inline-item d-none {% if not c.author.agendaposter %}d-md-block{% endif %} text-danger" data-bs-toggle="modal" data-bs-target="#chudModal" onclick="chudModal('/comment/{{c.id}}', '{{c.author.id}}', '{{c.author_name}}', '{{c.fullname}}','d-md-block')"><i class="fas fa-face-sleeping text-danger fa-fw"></i>Chud user</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.admin_level >= PERMS['APPS_MODERATION'] and c.oauth_app %}
|
|
||||||
<a href="{{c.oauth_app.permalink}}/comments" class="dropdown-item list-inline-item d-mob-none text-primary"><i class="fas fa-code text-primary fa-fw"></i>API App</a>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
|
@ -651,7 +652,7 @@
|
||||||
|
|
||||||
{% if c.author_id == v.id or (c.post.sub and v.mods(c.post.sub)) %}
|
{% 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="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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.admin_level < PERMS['POST_COMMENT_MODERATION'] %}
|
{% if v.admin_level < PERMS['POST_COMMENT_MODERATION'] %}
|
||||||
|
@ -696,6 +697,10 @@
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ul class="list-group comment-actions">
|
<ul class="list-group comment-actions">
|
||||||
{% if c.parent_submission %}
|
{% if c.parent_submission %}
|
||||||
|
{% if v.admin_level >= PERMS['APPS_MODERATION'] and c.oauth_app %}
|
||||||
|
<a href="{{c.oauth_app.permalink}}/comments" class="list-group-item text-info"><i class="fas fa-code text-info mr-2"></i>API App</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if v.id == c.author_id %}
|
{% if v.id == c.author_id %}
|
||||||
<button type="button" id="distinguish2-{{c.id}}" class="list-group-item {% if c.distinguish_level %}d-none{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish2-{{c.id}}','undistinguish2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-id-badge text-info mr-2"></i>Distinguish</button>
|
<button type="button" id="distinguish2-{{c.id}}" class="list-group-item {% if c.distinguish_level %}d-none{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish2-{{c.id}}','undistinguish2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-id-badge text-info mr-2"></i>Distinguish</button>
|
||||||
<button type="button" id="undistinguish2-{{c.id}}" class="list-group-item {% if not c.distinguish_level %}d-none{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish2-{{c.id}}','undistinguish2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-id-badge text-info mr-2"></i>Undistinguish</button>
|
<button type="button" id="undistinguish2-{{c.id}}" class="list-group-item {% if not c.distinguish_level %}d-none{% endif %} text-info" onclick="postToastSwitch(this,'/distinguish_comment/{{c.id}}','distinguish2-{{c.id}}','undistinguish2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-id-badge text-info mr-2"></i>Undistinguish</button>
|
||||||
|
@ -705,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="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="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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.id != c.author_id and v.admin_level >= PERMS['USER_BAN'] %}
|
{% if v.id != c.author_id and v.admin_level >= PERMS['USER_BAN'] %}
|
||||||
|
@ -722,10 +727,6 @@
|
||||||
<button type="button" id="remove2-{{c.id}}" class="{% if c.is_banned %}d-none{% endif %} list-group-item text-danger" onclick="removeComment(this,'{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</button>
|
<button type="button" id="remove2-{{c.id}}" class="{% if c.is_banned %}d-none{% endif %} list-group-item text-danger" onclick="removeComment(this,'{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-ban text-danger mr-2"></i>Remove</button>
|
||||||
<button type="button" id="approve2-{{c.id}}" class="{% if not c.is_banned and request.path != '/admin/reported/comments' %}d-none{% endif %} list-group-item text-success" onclick="approveComment(this,'{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</button>
|
<button type="button" id="approve2-{{c.id}}" class="{% if not c.is_banned and request.path != '/admin/reported/comments' %}d-none{% endif %} list-group-item text-success" onclick="approveComment(this,'{{c.id}}','approve2-{{c.id}}','remove2-{{c.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-check text-success mr-2"></i>Approve</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if c.oauth_app and v.admin_level >= PERMS['APPS_MODERATION'] %}
|
|
||||||
<a href="{{c.oauth_app.permalink}}/comments" class="list-group-item text-info"><i class="fas fa-code text-info mr-2"></i>API App</a>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table table-striped mb-5">
|
<table class="table table-striped mb-5">
|
||||||
<tbody>
|
<tbody>
|
||||||
{% if v and v.truescore >= TRUESCORE_DONATE_LIMIT %}
|
{% if v and v.truescore >= TRUESCORE_DONATE_MINIMUM %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Kofi</td>
|
<td>Kofi</td>
|
||||||
<td><a rel="nofollow noopener" href="{{KOFI_LINK}}">{{KOFI_LINK}}</a></td>
|
<td><a rel="nofollow noopener" href="{{KOFI_LINK}}">{{KOFI_LINK}}</a></td>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table table-striped mb-5">
|
<table class="table table-striped mb-5">
|
||||||
<tbody>
|
<tbody>
|
||||||
{% if v and v.truescore >= TRUESCORE_DONATE_LIMIT %}
|
{% if v and v.truescore >= TRUESCORE_DONATE_MINIMUM %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Gumroad</td>
|
<td>Gumroad</td>
|
||||||
<td><a rel="nofollow noopener" href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a></td>
|
<td><a rel="nofollow noopener" href="{{GUMROAD_LINK}}">{{GUMROAD_LINK}}</a></td>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<h5 class=" mt-1">{{code}} {{title}}</h5>
|
<h5 class=" mt-1">{{code}} {{title}}</h5>
|
||||||
<p class="text-muted error-description">{{msg|safe}}</p>
|
<p class="text-muted error-description">{{msg|safe}}</p>
|
||||||
{% if details -%}
|
{% if details -%}
|
||||||
<blockquote class="error-details mb-5 py-2">{{details|safe}}</blockquote>
|
<blockquote class="error-details mb-4 py-2">{{details|safe}}</blockquote>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
<div><a href="/" class="btn btn-primary">Go to frontpage</a></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col col-md-5">
|
<div class="col col-md-5">
|
||||||
<div class="text-center px-3 mt-5">
|
<div class="text-center px-3 mt-3">
|
||||||
<img alt=":#marseytwerking:" loading="lazy" src="/e/marseytwerking.webp">
|
<img alt=":#marseytwerking:" loading="lazy" src="/e/marseytwerking.webp">
|
||||||
<h5>Are you over 18?</h5>
|
<h5>Are you over 18?</h5>
|
||||||
<p class="mb-5">This post is rated +18 (Adult-Only). You must be 18 or older to continue. Are you sure you want to proceed?</p>
|
<p class="mb-3">This post is rated +18 (Adult-Only). You must be 18 or older to continue. Are you sure you want to proceed?</p>
|
||||||
<div class="btn-toolbar justify-content-center mb-4">
|
<div class="btn-toolbar justify-content-center mb-4">
|
||||||
|
|
||||||
<form action="/allow_nsfw" method="post">
|
<form action="/allow_nsfw" method="post">
|
||||||
|
|
|
@ -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 %}
|
|
|
@ -175,7 +175,7 @@
|
||||||
float: left;
|
float: left;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding-top: 0.25rem;
|
padding-top: 0.25rem;
|
||||||
padding-right: 0.25rem;
|
padding-right: 0.7rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
|
|
||||||
<div class="rounded border bg-white mx-auto">
|
<div class="rounded border bg-white mx-auto">
|
||||||
{% for ma in actions %}
|
{% for ma in actions %}
|
||||||
<div id="action-{{ma.id}}" class="{% if ma.unread %}unread{% endif %} position-relative d-flex justify-content-between flex-wrap align-items-center h-min-16 px-3 py-3 bg-white{% if loop.index > 1 %} border-top{% endif %}">
|
<div id="action-{{ma.id}}" class="modlog-action{% if ma.unread %} unread{% endif %}">
|
||||||
<div class="d-flex flex-grow-1 align-items-center">
|
<div class="d-flex flex-grow-1 align-items-center">
|
||||||
<div class="d-flex align-items-center justify-content-center {{ma.color}} mr-3 rounded-lg flex-shrink-0" style="width: 32px;height: 32px;"><i class="far text-center {{ma.icon}} text-lg text-white fa-fw"></i></div>
|
<div class="d-flex align-items-center justify-content-center {{ma.color}} mr-3 rounded-lg flex-shrink-0" style="width: 32px;height: 32px;"><i class="far text-center {{ma.icon}} text-lg text-white fa-fw"></i></div>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% if v and v.id==p.author_id and p.private %}
|
{% if v and v.id==p.author_id and p.private %}
|
||||||
<form action="/publish/{{p.id}}" method="post">
|
<form action="/publish/{{p.id}}" method="post" class="d-flex">
|
||||||
<input type="hidden" name="formkey", value="{{v|formkey}}">
|
<input type="hidden" name="formkey", value="{{v|formkey}}">
|
||||||
<button type="submit" class="list-inline-item text-small p-0 m-0 mr-3 border-0 nobackground font-weight-bold" type="submit" onclick="disable(this)"><i class="fas fa-globe"></i>Publish</button>
|
<button type="submit" class="list-inline-item text-small p-0 m-0 mr-3 border-0 nobackground font-weight-bold" type="submit" onclick="disable(this)"><i class="fas fa-globe"></i>Publish</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -40,6 +40,10 @@
|
||||||
{% if v %}
|
{% if v %}
|
||||||
<button type="button" class="list-inline-item" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
|
<button type="button" class="list-inline-item" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-ellipsis-h fa-fw"></i></button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
|
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] and p.oauth_app %}
|
||||||
|
<a class="dropdown-item list-inline-item text-info" href="{{p.oauth_app.permalink}}/posts"><i class="fas fa-code"></i>API App</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] %}
|
{% if v.admin_level >= PERMS['POST_COMMENT_DISTINGUISH'] %}
|
||||||
<button type="button" id="distinguish-{{p.id}}" class="dropdown-item {% if p.distinguish_level %}d-none{% endif %} list-inline-item text-info" onclick="postToastSwitch(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}','d-none')"><i class="fas fa-crown"></i>Distinguish</button>
|
<button type="button" id="distinguish-{{p.id}}" class="dropdown-item {% if p.distinguish_level %}d-none{% endif %} list-inline-item text-info" onclick="postToastSwitch(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}','d-none')"><i class="fas fa-crown"></i>Distinguish</button>
|
||||||
<button type="button" id="undistinguish-{{p.id}}" class="dropdown-item {% if not p.distinguish_level %}d-none{% endif %} list-inline-item text-info" onclick="postToastSwitch(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}','d-none')"><i class="fas fa-crown"></i>Undistinguish</button>
|
<button type="button" id="undistinguish-{{p.id}}" class="dropdown-item {% if not p.distinguish_level %}d-none{% endif %} list-inline-item text-info" onclick="postToastSwitch(this,'/distinguish/{{p.id}}','distinguish-{{p.id}}','undistinguish-{{p.id}}','d-none')"><i class="fas fa-crown"></i>Undistinguish</button>
|
||||||
|
@ -63,10 +67,6 @@
|
||||||
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
|
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
|
||||||
<button type="button" id="remove-{{p.id}}" class="dropdown-item {% if p.is_banned %}d-none{% endif %} list-inline-item text-danger" onclick="removePost(this,'{{p.id}}','remove-{{p.id}}','approve-{{p.id}}','d-none')"><i class="fas fa-ban"></i>Remove</button>
|
<button type="button" id="remove-{{p.id}}" class="dropdown-item {% if p.is_banned %}d-none{% endif %} list-inline-item text-danger" onclick="removePost(this,'{{p.id}}','remove-{{p.id}}','approve-{{p.id}}','d-none')"><i class="fas fa-ban"></i>Remove</button>
|
||||||
<button type="button" id="approve-{{p.id}}" class="dropdown-item {% if not p.is_banned and request.path != '/admin/reported/posts' %}d-none{% endif %} list-inline-item text-success" onclick="approvePost(this,'{{p.id}}','remove-{{p.id}}','approve-{{p.id}}','d-none')"><i class="fas fa-check"></i>Approve</button>
|
<button type="button" id="approve-{{p.id}}" class="dropdown-item {% if not p.is_banned and request.path != '/admin/reported/posts' %}d-none{% endif %} list-inline-item text-success" onclick="approvePost(this,'{{p.id}}','remove-{{p.id}}','approve-{{p.id}}','d-none')"><i class="fas fa-check"></i>Approve</button>
|
||||||
|
|
||||||
{% if p.oauth_app %}
|
|
||||||
<a class="dropdown-item list-inline-item" href="{{p.oauth_app.permalink}}"><i class="fas fa-code"></i>API App</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
<button type="button" id="unsave2-{{p.id}}" class="{% if not p.id in v.saved_idlist %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-muted" onclick="postToastSwitch(this,'/unsave_post/{{p.id}}','save2-{{p.id}}','unsave2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-save text-center text-muted mr-2"></i>Unsave</button>
|
<button type="button" id="unsave2-{{p.id}}" class="{% if not p.id in v.saved_idlist %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-muted" onclick="postToastSwitch(this,'/unsave_post/{{p.id}}','save2-{{p.id}}','unsave2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-save text-center text-muted mr-2"></i>Unsave</button>
|
||||||
|
|
||||||
{% if p.sub and v.mods(p.sub) %}
|
{% if p.sub and v.mods(p.sub) %}
|
||||||
<button type="button" id="hole-pin2-{{p.id}}" class="{% if p.hole_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-muted" onclick="postToastSwitch(this,'/hole_pin/{{p.id}}','hole-pin2-{{p.id}}','hole-unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-muted mr-2"></i>Pin to /h/{{p.sub}}</button>
|
<button type="button" id="hole-pin2-{{p.id}}" class="{% if p.hole_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-info" onclick="postToastSwitch(this,'/hole_pin/{{p.id}}','hole-pin2-{{p.id}}','hole-unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-info mr-2"></i>Pin to /h/{{p.sub}}</button>
|
||||||
<button type="button" id="hole-unpin2-{{p.id}}" class="{% if not p.hole_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-muted" onclick="postToastSwitch(this,'/hole_unpin/{{p.id}}','hole-pin2-{{p.id}}','hole-unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-muted mr-2"></i>Unpin from /h/{{p.sub}}</button>
|
<button type="button" id="hole-unpin2-{{p.id}}" class="{% if not p.hole_pinned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-info" onclick="postToastSwitch(this,'/hole_unpin/{{p.id}}','hole-pin2-{{p.id}}','hole-unpin2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="fas fa-thumbtack fa-rotate--45 text-center text-info mr-2"></i>Unpin from /h/{{p.sub}}</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v.id==p.author_id %}
|
{% if v.id==p.author_id %}
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ul class="list-group post-actions">
|
<ul class="list-group post-actions">
|
||||||
|
{% if v.admin_level >= PERMS['APPS_MODERATION'] and p.oauth_app %}
|
||||||
|
<a href="{{p.oauth_app.permalink}}/posts" class="nobackground btn btn-link btn-block btn-lg text-muted text-left text-info"><i class="far fa-code text-center text-info mr-2"></i>API App</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if (request.path.startswith('/post/') or request.path.startswith('/h/')) and v.admin_level >= PERMS['POST_EDITING'] and p.id %}
|
{% if (request.path.startswith('/post/') or request.path.startswith('/h/')) and v.admin_level >= PERMS['POST_EDITING'] and p.id %}
|
||||||
<button type="button" class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-dismiss="modal" onclick="togglePostEdit('{{p.id}}')"><i class="far fa-edit text-center text-muted mr-2"></i>Edit</button>
|
<button type="button" class="nobackground btn btn-link btn-block btn-lg text-left text-muted" data-bs-dismiss="modal" onclick="togglePostEdit('{{p.id}}')"><i class="far fa-edit text-center text-muted mr-2"></i>Edit</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -28,12 +32,9 @@
|
||||||
<button type="button" id="remove2-{{p.id}}" class="{% if p.is_banned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" onclick="removePost(this,'{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-2"></i>Remove</button>
|
<button type="button" id="remove2-{{p.id}}" class="{% if p.is_banned %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left" onclick="removePost(this,'{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-ban text-center mr-2"></i>Remove</button>
|
||||||
<button type="button" id="approve2-{{p.id}}" class="{% if not p.is_banned and request.path != '/admin/reported/posts' %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" onclick="approvePost(this,'{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-2"></i>Approve</button>
|
<button type="button" id="approve2-{{p.id}}" class="{% if not p.is_banned and request.path != '/admin/reported/posts' %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-success text-left" onclick="approvePost(this,'{{p.id}}','remove2-{{p.id}}','approve2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-check text-center mr-2"></i>Approve</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if p.oauth_app and v.admin_level >= PERMS['APPS_MODERATION'] %}
|
|
||||||
<a href="{{p.oauth_app.permalink}}"><button type="button" class="nobackground btn btn-link btn-block btn-lg text-muted text-left"><i class="far fa-code text-center text-info mr-2"></i>API App</button></a>
|
|
||||||
{% endif %}
|
|
||||||
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
|
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
|
||||||
<button type="button" id="mark2-{{p.id}}" class="{% if p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="postToastSwitch(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Mark +18</button>
|
<button type="button" id="mark2-{{p.id}}" class="{% if p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="postToastSwitch(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Mark +18</button>
|
||||||
<button type="button" id="unmark2-{{p.id}}" class="{% if not p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-danger" onclick="postToastSwitch(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-danger mr-2"></i>Unmark +18</button>
|
<button type="button" id="unmark2-{{p.id}}" class="{% if not p.over_18 %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-left text-success" onclick="postToastSwitch(this,'/toggle_post_nsfw/{{p.id}}','mark2-{{p.id}}','unmark2-{{p.id}}','d-none')" data-bs-dismiss="modal"><i class="far fa-eye-evil text-center text-success mr-2"></i>Unmark +18</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if v.id != p.author_id and v.admin_level >= PERMS['USER_BAN'] %}
|
{% if v.id != p.author_id and v.admin_level >= PERMS['USER_BAN'] %}
|
||||||
<button type="button" id="ban2-{{p.fullname}}" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/post/{{p.id}}', '{{p.author.id}}', '{{p.author_name}}', '{{p.fullname}}','d-none')" class="{% if p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left"><i class="fas fa-user-minus mr-2"></i>Ban user</button>
|
<button type="button" id="ban2-{{p.fullname}}" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#banModal" onclick="banModal('/post/{{p.id}}', '{{p.author.id}}', '{{p.author_name}}', '{{p.fullname}}','d-none')" class="{% if p.author.is_suspended %}d-none{% endif %} nobackground btn btn-link btn-block btn-lg text-danger text-left"><i class="fas fa-user-minus mr-2"></i>Ban user</button>
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="body w-lg-100">
|
<div class="body w-lg-100">
|
||||||
<p>You're a {{TIERS_ID_TO_NAME[v.patron] if v.patron else "freeloader"}}!</p>{% if v.patron %} Thanks ily! <3{% endif %}
|
<p>You're a {{TIERS_ID_TO_NAME[v.patron] if v.patron else "freeloader"}}!</p>{% if v.patron %} Thanks ily! <3{% endif %}
|
||||||
{% if not v.patron and v.truescore >= TRUESCORE_DONATE_LIMIT %}
|
{% if not v.patron and v.truescore >= TRUESCORE_DONATE_MINIMUM %}
|
||||||
<p class="font-italic">To stop freeloading, first <a href="/settings/security#new_email">verify your email</a>, support us on <a href="{{DONATE_LINK}}">{{DONATE_SERVICE}}</a> with the same email, and click "Claim {{patron}} Rewards"</p>
|
<p class="font-italic">To stop freeloading, first <a href="/settings/security#new_email">verify your email</a>, support us on <a href="{{DONATE_LINK}}">{{DONATE_SERVICE}}</a> with the same email, and click "Claim {{patron}} Rewards"</p>
|
||||||
{% elif not v.patron %}
|
{% elif not v.patron %}
|
||||||
<p class="font-italic">To stop freeloading, you can <a href="/donate">donate via crypto</a>. Please let us know first beforehand by <a href="/contact">sending us a modmail.</a> Thanks!</p>
|
<p class="font-italic">To stop freeloading, you can <a href="/donate">donate via crypto</a>. Please let us know first beforehand by <a href="/contact">sending us a modmail.</a> Thanks!</p>
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% if FEATURES['MARSEYBUX'] %}
|
{% if FEATURES['MARSEYBUX'] %}
|
||||||
<span class="text-small text-muted pl-1">Must be same email as the one you used to donate
|
<span class="text-small text-muted pl-1">Must be same email as the one you used to donate
|
||||||
{% if v.truescore >= TRUESCORE_DONATE_LIMIT %}
|
{% if v.truescore >= TRUESCORE_DONATE_MINIMUM %}
|
||||||
on
|
on
|
||||||
{% if KOFI_TOKEN %}
|
{% if KOFI_TOKEN %}
|
||||||
<a rel="nofollow noopener" class="text-primary" href="{{KOFI_LINK}}">Kofi</a>
|
<a rel="nofollow noopener" class="text-primary" href="{{KOFI_LINK}}">Kofi</a>
|
||||||
|
|
|
@ -102,9 +102,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% block mobilenavbar %}{% include "mobile_navigation_bar.html" %}{% endblock %}
|
{% block mobilenavbar %}{% include "mobile_navigation_bar.html" %}{% endblock %}
|
||||||
{% block invitationModal %}{% endblock %}
|
|
||||||
{% block exileModal %}{% endblock %}
|
|
||||||
{% block approveModal %}{% endblock %}
|
|
||||||
{% block errorToasts %}{% endblock %}
|
|
||||||
{% block scripts %}{% endblock %}
|
{% block scripts %}{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -54,8 +54,28 @@
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
<div class="sidebar--rules">
|
<div class="sidebar--rules">
|
||||||
<h3 class="sidebar--rules-head mt-4 mb-3">Rules</h3>
|
<p>Drama: any incident, scene, gaffe, rumor, opinion, or disagreement that is blown entirely out of proportion.</p>
|
||||||
<ol class="sidebar--rules-list sidebar--rules-list--rdrama">
|
|
||||||
|
<p><strong>Do your part to keep our community healthy by blowing everything out of proportion and making literally everything as dramatic as possible.</strong></p>
|
||||||
|
|
||||||
|
<p>rdrama.net caters to drama in all forms such as: <strong>Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™</strong>. There isn't drama we won't touch, and we want it all.</p>
|
||||||
|
|
||||||
|
<h3>What we want:</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Arguments.</li>
|
||||||
|
<li>Gossip.</li>
|
||||||
|
<li>Scandals.</li>
|
||||||
|
<li>Lolcows.</li>
|
||||||
|
<li>Assholes.</li>
|
||||||
|
<li>Trainwrecks.</li>
|
||||||
|
<li>Meltdowns.</li>
|
||||||
|
<li>Dramatic news articles.</li>
|
||||||
|
<li>Dramatic rumours (with context).</li>
|
||||||
|
<li>Dramatic everything from <strong>anywhere</strong></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>A couple things to remember:</h3>
|
||||||
|
<ul>
|
||||||
<li class="font-weight-bold" style="color: red"><a href="/post/19711/a-short-guide-on-how-to" style="color: inherit">NO RIGHTWING AGENDAPOSTING.</a></li>
|
<li class="font-weight-bold" style="color: red"><a href="/post/19711/a-short-guide-on-how-to" style="color: inherit">NO RIGHTWING AGENDAPOSTING.</a></li>
|
||||||
<li>Don't post anything illegal.</li>
|
<li>Don't post anything illegal.</li>
|
||||||
<li>No sexualizing minors.</li>
|
<li>No sexualizing minors.</li>
|
||||||
|
@ -67,8 +87,44 @@
|
||||||
<li class="font-weight-bold">Absolutely NO misgendering.</li>
|
<li class="font-weight-bold">Absolutely NO misgendering.</li>
|
||||||
<li class="font-weight-bold">Absolutely NO antisemitism.</li>
|
<li class="font-weight-bold">Absolutely NO antisemitism.</li>
|
||||||
<li class="font-weight-bold">Absolutely NO vaccine misinformation.</li>
|
<li class="font-weight-bold">Absolutely NO vaccine misinformation.</li>
|
||||||
</ol>
|
<li>You are encouraged to post drama you are involved in.</li>
|
||||||
<p class="font-italic text-small">This is an entertainment comedy website. Any and all posts and comments are parody with no basis in reality.</p>
|
<li>This is a mod playground.</li>
|
||||||
|
<li>Participation implies enthusiastic consent to being mod abused by unstable alcoholic bullies.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Related subreddits:</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://old.reddit.com/r/AgainstHateSubreddits">/r/AgainstHateSubreddits</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/SubredditDrama">/r/SubredditDrama</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/HobbyDrama">/r/HobbyDrama</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/internetdrama">/r/internetdrama</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/youtubedrama">/r/youtubedrama</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/facebookdrama">/r/facebookdrama</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/theElon">/r/theElon</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/BanVideoGames">/r/BanVideoGames</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/LoveForLandlords">/r/LoveForLandlords</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/LoveForAnimesexuals">/r/LoveForAnimesexuals</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/LoveForScalpers">/r/LoveForScalpers</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/MelvinCapitalLove">/r/MelvinCapitalLove</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/banime">/r/banime</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/LoveForAmazon">/r/LoveForAmazon</a><br></li>
|
||||||
|
<li><a href="https://old.reddit.com/r/LoveForDronePilots">/r/LoveForDronePilots</a><br></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Off-site drama whoring websites:</h3>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://ohnotheydidnt.livejournal.com">ONTD</a></li>
|
||||||
|
<li><a href="https://radaronline.com">Radar Online</a></li>
|
||||||
|
<li><a href="https://tmz.com">TMZ</a></li>
|
||||||
|
<li><a href="https://encyclopediadramatica.online">Encyclopedia Dramatica</a></li>
|
||||||
|
<li><a href="https://4chan.org">4Chan</a></li>
|
||||||
|
<li><a href="https://twitter.com">Twitter</a></li>
|
||||||
|
<li><a href="https://8kun.top">8Chan</a></li>
|
||||||
|
<li><a href="https://lolcow.farm/">Lolcow.farm</a></li>
|
||||||
|
<li><a href="https://lmgtfy.com/?q=local+news+website">Your local shitty news website</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="font-italic text-small mt-4">This is an entertainment comedy website. Any and all posts and comments are parody with no basis in reality.</p>
|
||||||
<p style="color: hotpink">𝐜𝐚𝐫𝐩 𝐰𝐨𝐳 𝐞𝐫𝐞</p>
|
<p style="color: hotpink">𝐜𝐚𝐫𝐩 𝐰𝐨𝐳 𝐞𝐫𝐞</p>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -78,7 +78,7 @@
|
||||||
<div id="post-root" class="col-12">
|
<div id="post-root" class="col-12">
|
||||||
|
|
||||||
<div class="card border-0 mt-3 {% if p.stickied %}stickied{% endif %} {% if voted==1 %}upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
<div class="card border-0 mt-3 {% if p.stickied %}stickied{% endif %} {% if voted==1 %}upvoted{% elif voted==-1 %} downvoted{% endif %}">
|
||||||
<div id="post-{{p.id}}" class="actual-post {% if p.is_banned %}banned{% endif %} {% if p.deleted_utc %}deleted {% endif %} {% if p.award_count('tilt', v) %}p-3{% endif %} {% if p.award_count('glowie', v) %}glow{% endif %} d-flex flex-row-reverse flex-nowrap justify-content-end">
|
<div id="post-{{p.id}}" class="actual-post {% if p.ghost %}ghost-post{% endif %} {% if p.is_banned %}banned{% endif %} {% if p.deleted_utc %}deleted {% endif %} {% if p.award_count('tilt', v) %}p-3{% endif %} {% if p.award_count('glowie', v) %}glow{% endif %} d-flex flex-row-reverse flex-nowrap justify-content-end">
|
||||||
|
|
||||||
{% if not p.is_image and p.thumb_url and not p.embed_url %}
|
{% if not p.is_image and p.thumb_url and not p.embed_url %}
|
||||||
<div class="card-header bg-transparent border-0 d-none d-md-flex flex-row flex-nowrap pl-3 p-0">
|
<div class="card-header bg-transparent border-0 d-none d-md-flex flex-row flex-nowrap pl-3 p-0">
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="post-{{p.id}}" class="actual-post {% if p.unread %}unread{% else %}card{% endif %} {% if p.is_banned %} banned{% endif %}{% if p.deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
<div id="post-{{p.id}}" class="actual-post {% if p.ghost %}ghost-post{% endif %} {% if p.unread %}unread{% else %}card{% endif %} {% if p.is_banned %} banned{% endif %}{% if p.deleted_utc %} deleted{% endif %}{% if p.stickied %} stickied{% endif %}{% if voted==1 %} upvoted{% elif voted==-1 %} downvoted{% endif %}{% if p.over_18 %} nsfw{% endif %}">
|
||||||
|
|
||||||
<div class="d-flex flex-row-reverse flex-md-row flex-nowrap" style="align-items:flex-start">
|
<div class="d-flex flex-row-reverse flex-md-row flex-nowrap" style="align-items:flex-start">
|
||||||
<div class="voting my-2 d-none d-md-flex pr-2">
|
<div class="voting my-2 d-none d-md-flex pr-2">
|
||||||
|
@ -245,17 +245,17 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if p.is_image and not p.over_18 and ((v and v.cardview) or (not v and CARD_VIEW)) %}
|
{% if p.is_image and not p.over_18 and ((v and v.cardview) or (not v and CARD_VIEW)) %}
|
||||||
<div style="text-align: center" class="mt-3 mb-4">
|
<div class="ml-5 mt-3 mb-4">
|
||||||
<a {% if v and v.newtab %}data-target="t"target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
|
<a {% if v and v.newtab %}data-target="t"target="_blank"{% endif %} rel="nofollow noopener" href="{{p.realurl(v)}}">
|
||||||
<img loading="lazy" data-src="{{p.realurl(v)}}" src="/i/l.webp" class="img-fluid" style="max-height:20rem" alt="Unable to load image">
|
<img loading="lazy" data-src="{{p.realurl(v)}}" src="/i/l.webp" class="img-fluid" style="max-height:20rem" alt="Unable to load image">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% elif p.is_video %}
|
{% elif p.is_video %}
|
||||||
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-4">
|
<div id="video-{{p.id}}" class="ml-5 {% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-4">
|
||||||
<video id="video2-{{p.id}}" controls preload="none" src="{{p.realurl(v)}}"></video>
|
<video id="video2-{{p.id}}" controls preload="none" src="{{p.realurl(v)}}"></video>
|
||||||
</div>
|
</div>
|
||||||
{% elif p.is_audio %}
|
{% elif p.is_audio %}
|
||||||
<div id="video-{{p.id}}" style="text-align: center" class="{% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-4">
|
<div id="video-{{p.id}}" class="ml-5 {% if p.over_18 or not ((v and v.cardview) or (not v and CARD_VIEW)) %}d-none{% endif %} mt-4">
|
||||||
<audio id="video2-{{p.id}}" controls preload="none" src="{{p.realurl(v)}}"></audio>
|
<audio id="video2-{{p.id}}" controls preload="none" src="{{p.realurl(v)}}"></audio>
|
||||||
</div>
|
</div>
|
||||||
{% elif p.is_youtube %}
|
{% elif p.is_youtube %}
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col text-right">
|
<div class="col text-right">
|
||||||
{% if error %}<span class="text-danger text-large mr-2">{{error | safe}}</span>{% endif %}
|
{% if error %}<span class="text-danger text-large mr-2">{{error | safe}}</span>{% endif %}
|
||||||
<button type="submit" class="btn btn-primary" id="create_button" type="submit" onclick="disable(this)" disabled>Post</button>
|
<button type="submit" class="btn btn-primary" id="create_button" type="submit" onclick="disable(this)">Post</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -70,7 +70,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%}
|
{% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%}
|
||||||
<div class="font-weight-bolder mb-2" id="profile--simphate"><a class="mr-1" href="/@{{u.username}}/upvoters">Simps</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Haters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Simps For</a> | <a class="mx-1" href="/@{{u.username}}/downvoting">Hates</a> | <a class="ml-1" href="/@{{u.username}}/voted/posts">Voted</a></div>
|
<div class="font-weight-bolder mb-2" id="profile--simphate">
|
||||||
|
<a class="mr-1" href="/@{{u.username}}/views">Profile Views</a> | <a class="mx-1" href="/@{{u.username}}/upvoters">Simps</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Haters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Simps For</a> | <a class="mx-1" href="/@{{u.username}}/downvoting">Hates</a> | <a class="ml-1" href="/@{{u.username}}/voted/posts">Voted</a>
|
||||||
|
</div>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
<div class="font-weight-bolder">
|
<div class="font-weight-bolder">
|
||||||
|
@ -188,7 +190,6 @@
|
||||||
<div class="actionbtns">
|
<div class="actionbtns">
|
||||||
{% if v and v.id == u.id %}
|
{% if v and v.id == u.id %}
|
||||||
<a href="/settings/personal" class="btn btn-secondary">Edit profile</a>
|
<a href="/settings/personal" class="btn btn-secondary">Edit profile</a>
|
||||||
<a href="/views" class="btn btn-secondary">Profile views</a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %}
|
{% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %}
|
||||||
|
@ -196,7 +197,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2" id="profile--info">
|
<div class="mt-3" id="profile--info">
|
||||||
<p id="profile--info--id">User ID: {{u.id}}</p>
|
<p id="profile--info--id">User ID: {{u.id}}</p>
|
||||||
<p id="profile--info--spent">Coins spent: {{u.coins_spent}}</p>
|
<p id="profile--info--spent">Coins spent: {{u.coins_spent}}</p>
|
||||||
<p id="profile--info--truescore">True score: {{u.truescore}}</p>
|
<p id="profile--info--truescore">True score: {{u.truescore}}</p>
|
||||||
|
@ -302,7 +303,9 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%}
|
{% if v and (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']) -%}
|
||||||
<div class="font-weight-bolder mb-2" id="profile-mobile--simphate"><a class="mr-1" href="/@{{u.username}}/upvoters">Simps</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Haters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Simps For</a> | <a class="mx-1" href="/@{{u.username}}/downvoting">Hates</a> | <a class="ml-1" href="/@{{u.username}}/voted/posts">Voted</a></div>
|
<div class="font-weight-bolder mb-2" id="profile-mobile--simphate">
|
||||||
|
<a class="mr-1" href="/@{{u.username}}/views">Profile Views</a> | <a class="mx-1" href="/@{{u.username}}/upvoters">Simps</a> | <a class="mx-1" href="/@{{u.username}}/downvoters">Haters</a> | <a class="mx-1" href="/@{{u.username}}/upvoting">Simps For</a> | <a class="mx-1" href="/@{{u.username}}/downvoting">Hates</a> | <a class="ml-1" href="/@{{u.username}}/voted/posts">Voted</a>
|
||||||
|
</div>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
|
||||||
<div class="font-weight-normal">
|
<div class="font-weight-normal">
|
||||||
|
@ -385,7 +388,6 @@
|
||||||
<div class="actionbtns">
|
<div class="actionbtns">
|
||||||
{% if v and v.id == u.id %}
|
{% if v and v.id == u.id %}
|
||||||
<a href="/settings/personal" class="btn btn-secondary ">Edit profile</a>
|
<a href="/settings/personal" class="btn btn-secondary ">Edit profile</a>
|
||||||
<a href="/views" class="btn btn-secondary">Profile views</a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %}
|
{% if FEATURES['USERS_PROFILE_SONG'] and u.song and v and (v.id == u.id or v.mute and not u.unmutable) %}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
{% extends "default.html" %}
|
{% extends "default.html" %}
|
||||||
{% block pagetitle %}@{{u.username}}'s blockers{% endblock %}
|
{% block pagetitle %}@{{u.username}}'s blockers{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h5 class="mt-3">@{{u.username}}'s blockers</h5>
|
<h5 class="my-3">@{{u.username}}'s blockers</h5>
|
||||||
<div class="overflow-x-auto mt-1"><table class="table table-striped mb-5">
|
<div class="overflow-x-auto mt-1"><table class="table table-striped mb-5">
|
||||||
<thead class="bg-primary text-white">
|
<thead class="bg-primary text-white">
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<td>Blocking since</td>
|
<td>Blocking since</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -13,7 +12,6 @@
|
||||||
<tbody id="blockers-table">
|
<tbody id="blockers-table">
|
||||||
{% for block, user in users %}
|
{% for block, user in users %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{loop.index}}</td>
|
|
||||||
<td>{% include "user_in_table.html" %}</td>
|
<td>{% include "user_in_table.html" %}</td>
|
||||||
<td {% if block.created_utc > 1599343262 %}data-time="{{block.created_utc}}"{% endif %}></td>
|
<td {% if block.created_utc > 1599343262 %}data-time="{{block.created_utc}}"{% endif %}></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -24,3 +22,24 @@
|
||||||
<script defer src="{{'js/blockers.js' | asset}}"></script>
|
<script defer src="{{'js/blockers.js' | asset}}"></script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block pagenav %}
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination pagination-sm py-3 pl-3 mb-0">
|
||||||
|
{% if page>1 %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page-1}}" tabindex="-1">Prev</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Prev</span></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if next_exists %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page+1}}">Next</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Next</span></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
{% extends "default.html" %}
|
{% extends "default.html" %}
|
||||||
{% block pagetitle %}@{{u.username}}'s followers{% endblock %}
|
{% block pagetitle %}@{{u.username}}'s followers{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h5 class="mt-2">@{{u.username}}'s followers</h5>
|
<h5 class="my-3">@{{u.username}}'s followers</h5>
|
||||||
<div class="overflow-x-auto mt-1"><table class="table table-striped mb-5">
|
<div class="overflow-x-auto mt-1"><table class="table table-striped mb-5">
|
||||||
<thead class="bg-primary text-white">
|
<thead class="bg-primary text-white">
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<td>Following since</td>
|
<td>Following since</td>
|
||||||
{% if v.id == u.id %}
|
{% if v.id == u.id %}
|
||||||
|
@ -16,7 +15,6 @@
|
||||||
<tbody id="followers-table">
|
<tbody id="followers-table">
|
||||||
{% for follow, user in users %}
|
{% for follow, user in users %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{loop.index}}</td>
|
|
||||||
<td>{% include "user_in_table.html" %}</td>
|
<td>{% include "user_in_table.html" %}</td>
|
||||||
<td {% if follow.created_utc > 1599343262 %}data-time="{{follow.created_utc}}"{% endif %}></td>
|
<td {% if follow.created_utc > 1599343262 %}data-time="{{follow.created_utc}}"{% endif %}></td>
|
||||||
{% if v.id == u.id %}
|
{% if v.id == u.id %}
|
||||||
|
@ -30,3 +28,24 @@
|
||||||
<script defer src="{{'js/followers.js' | asset}}"></script>
|
<script defer src="{{'js/followers.js' | asset}}"></script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block pagenav %}
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination pagination-sm py-3 pl-3 mb-0">
|
||||||
|
{% if page>1 %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page-1}}" tabindex="-1">Prev</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Prev</span></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if next_exists %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page+1}}">Next</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Next</span></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
{% extends "default.html" %}
|
{% extends "default.html" %}
|
||||||
{% block pagetitle %}Users followed by @{{u.username}}{% endblock %}
|
{% block pagetitle %}Users followed by @{{u.username}}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h5 class="mt-3 mb-1">Users followed by @{{u.username}}</h5>
|
<h5 class="my-3">Users followed by @{{u.username}}</h5>
|
||||||
<div class="overflow-x-auto"><table class="table table-striped mb-5">
|
<div class="overflow-x-auto"><table class="table table-striped mb-5">
|
||||||
<thead class="bg-primary text-white">
|
<thead class="bg-primary text-white">
|
||||||
<tr>
|
<tr>
|
||||||
<th>#</th>
|
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
{% if v.id == u.id %}
|
{% if v.id == u.id %}
|
||||||
<th></th>
|
<th></th>
|
||||||
|
@ -15,7 +14,6 @@
|
||||||
<tbody id="followers-table">
|
<tbody id="followers-table">
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{loop.index}}</td>
|
|
||||||
<td>{% include "user_in_table.html" %}</td>
|
<td>{% include "user_in_table.html" %}</td>
|
||||||
{% if v.id == u.id %}
|
{% if v.id == u.id %}
|
||||||
<td><div class="btn btn-danger" onclick="removeFollowing(this, '{{user.username}}')">Unfollow</div></td>
|
<td><div class="btn btn-danger" onclick="removeFollowing(this, '{{user.username}}')">Unfollow</div></td>
|
||||||
|
@ -28,3 +26,24 @@
|
||||||
<script defer src="{{'js/following.js' | asset}}"></script>
|
<script defer src="{{'js/following.js' | asset}}"></script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block pagenav %}
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination pagination-sm py-3 pl-3 mb-0">
|
||||||
|
{% if page>1 %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page-1}}" tabindex="-1">Prev</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Prev</span></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if next_exists %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page+1}}">Next</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Next</span></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
{% extends "default.html" %}
|
|
||||||
{% block pagetitle %}Profile Viewers{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<h5 class="pt-4 pl-2 my-1">Users who viewed your profile</h5>
|
|
||||||
<div class="overflow-x-auto"><table class="table table-striped mb-5">
|
|
||||||
<thead class="bg-primary text-white">
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Last visit</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
{% for view in viewers %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
{% with user=view.viewer %}
|
|
||||||
{% include "user_in_table.html" %}
|
|
||||||
{% endwith %}
|
|
||||||
</td>
|
|
||||||
<td>{{view.last_view_string}}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
{% extends "default.html" %}
|
||||||
|
{% block pagetitle %}Profile Views{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h5 class="pt-4 pl-2 pb-3">Users who viewed @{{u.username}}'s profile</h5>
|
||||||
|
<div class="overflow-x-auto"><table class="table table-striped mb-5">
|
||||||
|
<thead class="bg-primary text-white">
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Last visit</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{% for view in views %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{% with user=view.viewer %}
|
||||||
|
{% include "user_in_table.html" %}
|
||||||
|
{% endwith %}
|
||||||
|
</td>
|
||||||
|
<td>{{view.last_view_string}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block pagenav %}
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination pagination-sm py-3 pl-3 mb-0">
|
||||||
|
{% if page>1 %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page-1}}" tabindex="-1">Prev</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Prev</span></li>
|
||||||
|
{% endif %}
|
||||||
|
{% if next_exists %}
|
||||||
|
<li class="page-item">
|
||||||
|
<small><a class="page-link" href="?page={{page+1}}">Next</a></small>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled"><span class="page-link">Next</span></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
|
@ -13,6 +13,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends "default.html" %}
|
{% extends "default.html" %}
|
||||||
{% block pagetitle %}{{name2}}{% endblock %}
|
{% block pagetitle %}{{name2}}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h3 class="mt-3" style="text-align: center">{{name2}}</h3>
|
<h3 class="my-3" style="text-align: center">{{name2}}</h3>
|
||||||
<h5 class="font-weight-bold text-center mt-3">Total: {{total}}</h5>
|
<h5 class="font-weight-bold text-center mt-3">Total: {{total}}</h5>
|
||||||
<div class="mt-1 overflow-x-auto"><table class="table table-striped mb-5">
|
<div class="mt-1 overflow-x-auto"><table class="table table-striped mb-5">
|
||||||
<thead class="bg-primary text-white">
|
<thead class="bg-primary text-white">
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
from time import time, sleep
|
|
||||||
from files.__main__ import app
|
|
||||||
|
|
||||||
# these tests require `docker-compose up` first
|
|
||||||
|
|
||||||
def test_rules():
|
|
||||||
response = app.test_client().get("/sidebar")
|
|
||||||
assert response.status_code == 200
|
|
||||||
assert response.text.startswith("<!DOCTYPE html>")
|
|
||||||
|
|
||||||
|
|
||||||
def test_signup():
|
|
||||||
client = app.test_client()
|
|
||||||
with client: # this keeps the session between requests, which we need
|
|
||||||
signup_get_response = client.get("/signup")
|
|
||||||
assert signup_get_response.status_code == 200
|
|
||||||
soup = BeautifulSoup(signup_get_response.text, 'html.parser')
|
|
||||||
# these hidden input values seem to be used for anti-bot purposes and need to be submitted
|
|
||||||
formkey = next(tag for tag in soup.find_all("input") if tag.get("name") == "formkey").get("value")
|
|
||||||
form_timestamp = next(tag for tag in soup.find_all("input") if tag.get("name") == "now").get("value")
|
|
||||||
|
|
||||||
sleep(5) # too-fast submissions are rejected (bot check?)
|
|
||||||
username = "testuser" + str(round(time()))
|
|
||||||
signup_post_response = client.post("/signup", data={
|
|
||||||
"username": username,
|
|
||||||
"password": "password",
|
|
||||||
"password_confirm": "password",
|
|
||||||
"email": "",
|
|
||||||
"formkey": formkey,
|
|
||||||
"now": form_timestamp
|
|
||||||
})
|
|
||||||
print(f"Signing up as {username}", flush=True)
|
|
||||||
assert signup_post_response.status_code == 302
|
|
||||||
assert "error" not in signup_post_response.location
|
|
||||||
|
|
||||||
# we should now be logged in and able to post
|
|
|
@ -1,18 +1,13 @@
|
||||||
[![Build status](https://img.shields.io/github/workflow/status/TheMotte/rDrama/run_tests.py/frost)](https://github.com/Aevann1/rDrama/actions?query=workflow%3Arun_tests.py+branch%3Afrost)
|
|
||||||
|
|
||||||
|
|
||||||
This code runs https://rdrama.net, https://pcmemes.net and https://watchpeopledie.tv
|
This code runs https://rdrama.net, https://pcmemes.net and https://watchpeopledie.tv
|
||||||
|
|
||||||
# Installation (Windows/Linux/MacOS)
|
# Installation (Windows/Linux/MacOS)
|
||||||
|
|
||||||
1- Install Docker on your machine.
|
1- Install Docker on your machine. [Docker installation](https://docs.docker.com/get-docker/)
|
||||||
|
|
||||||
[Docker installation](https://docs.docker.com/get-docker/)
|
|
||||||
|
|
||||||
2- Run the following commands in the terminal:
|
2- Run the following commands in the terminal:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/Aevann1/rDrama/
|
git clone https://fsdfsd.net/rDrama/rDrama.git
|
||||||
|
|
||||||
cd rDrama
|
cd rDrama
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ tldextract
|
||||||
user-agents
|
user-agents
|
||||||
psycopg2-binary
|
psycopg2-binary
|
||||||
pusher_push_notifications
|
pusher_push_notifications
|
||||||
pytest
|
|
||||||
youtube-dl
|
youtube-dl
|
||||||
yattag
|
yattag
|
||||||
webptools
|
webptools
|
||||||
|
|
52
run_tests.py
52
run_tests.py
|
@ -1,52 +0,0 @@
|
||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# we want to leave the container in whatever state it currently is, so check to see if it's running
|
|
||||||
docker_inspect = subprocess.run([
|
|
||||||
"docker",
|
|
||||||
"container",
|
|
||||||
"inspect",
|
|
||||||
"-f", "{{.State.Status}}",
|
|
||||||
"rDrama",
|
|
||||||
],
|
|
||||||
capture_output = True,
|
|
||||||
).stdout.decode("utf-8").strip()
|
|
||||||
|
|
||||||
was_running = docker_inspect == "running"
|
|
||||||
|
|
||||||
# update containers, just in case they're out of date
|
|
||||||
if was_running:
|
|
||||||
print("Updating containers . . .", flush=True)
|
|
||||||
else:
|
|
||||||
print("Starting containers . . .", flush=True)
|
|
||||||
subprocess.run([
|
|
||||||
"docker-compose",
|
|
||||||
"up",
|
|
||||||
"--build",
|
|
||||||
"-d",
|
|
||||||
],
|
|
||||||
check = True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# run the test
|
|
||||||
print("Running test . . .", flush=True)
|
|
||||||
result = subprocess.run([
|
|
||||||
"docker",
|
|
||||||
"exec",
|
|
||||||
"rDrama",
|
|
||||||
"bash", "-c", "cd service && python3 -m pytest -s"
|
|
||||||
])
|
|
||||||
|
|
||||||
if not was_running:
|
|
||||||
# shut down, if we weren't running in the first place
|
|
||||||
print("Shutting down containers . . .", flush=True)
|
|
||||||
subprocess.run([
|
|
||||||
"docker-compose",
|
|
||||||
"stop",
|
|
||||||
],
|
|
||||||
check = True,
|
|
||||||
)
|
|
||||||
|
|
||||||
sys.exit(result.returncode)
|
|
11
schema.sql
11
schema.sql
|
@ -395,7 +395,8 @@ CREATE TABLE public.comments (
|
||||||
wordle_result character varying(115),
|
wordle_result character varying(115),
|
||||||
body_ts tsvector GENERATED ALWAYS AS (to_tsvector('english'::regconfig, (body)::text)) STORED,
|
body_ts tsvector GENERATED ALWAYS AS (to_tsvector('english'::regconfig, (body)::text)) STORED,
|
||||||
casino_game_id integer,
|
casino_game_id integer,
|
||||||
chuddedfor character varying(40)
|
chuddedfor character varying(40),
|
||||||
|
stickied_child_id integer
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -2466,6 +2467,14 @@ ALTER TABLE ONLY public.save_relationship
|
||||||
ADD CONSTRAINT save_relationship_user_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) MATCH FULL;
|
ADD CONSTRAINT save_relationship_user_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) MATCH FULL;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: comments stickied_child_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY public.comments
|
||||||
|
ADD CONSTRAINT stickied_child_fkey FOREIGN KEY (stickied_child_id) REFERENCES public.comments(id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: sub_blocks sub_blocks_sub_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: sub_blocks sub_blocks_sub_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
13
seed-db.sql
13
seed-db.sql
|
@ -226,6 +226,7 @@ SET row_security = off;
|
||||||
--
|
--
|
||||||
|
|
||||||
INSERT INTO public.hat_defs VALUES (716, 'Baked Beans Bucket Hat', 'This neighbor is wearing beans!', 2, 500, NULL, 1663647585);
|
INSERT INTO public.hat_defs VALUES (716, 'Baked Beans Bucket Hat', 'This neighbor is wearing beans!', 2, 500, NULL, 1663647585);
|
||||||
|
|
||||||
INSERT INTO public.hat_defs VALUES (1002, 'Hearty Hands', 'I dont think hands should do that...', 2, 500, NULL, 1667084251);
|
INSERT INTO public.hat_defs VALUES (1002, 'Hearty Hands', 'I dont think hands should do that...', 2, 500, NULL, 1667084251);
|
||||||
INSERT INTO public.hat_defs VALUES (1003, 'Dragged', 'HELLLLLLLLLLPPPPPPPPPPPPPPPPP', 2, 500, NULL, 1667084272);
|
INSERT INTO public.hat_defs VALUES (1003, 'Dragged', 'HELLLLLLLLLLPPPPPPPPPPPPPPPPP', 2, 500, NULL, 1667084272);
|
||||||
INSERT INTO public.hat_defs VALUES (718, 'Literally Me', 'Sving music, jazz? PTOOEY!', 2, 500, NULL, 1663801724);
|
INSERT INTO public.hat_defs VALUES (718, 'Literally Me', 'Sving music, jazz? PTOOEY!', 2, 500, NULL, 1663801724);
|
||||||
|
@ -623,6 +624,7 @@ INSERT INTO public.hat_defs VALUES (1074, 'Scottish Sticky Note', 'idk why its s
|
||||||
INSERT INTO public.hat_defs VALUES (1076, 'Snow Globe', 'Snow globe full of partially transparent webp flakes', 2, 1000, NULL, 1668755503);
|
INSERT INTO public.hat_defs VALUES (1076, 'Snow Globe', 'Snow globe full of partially transparent webp flakes', 2, 1000, NULL, 1668755503);
|
||||||
INSERT INTO public.hat_defs VALUES (1075, 'Jerma Approval', 'Who? What? I haven''t understood a hat submission in so fucking long', 2, 1000, NULL, 1668727612);
|
INSERT INTO public.hat_defs VALUES (1075, 'Jerma Approval', 'Who? What? I haven''t understood a hat submission in so fucking long', 2, 1000, NULL, 1668727612);
|
||||||
INSERT INTO public.hat_defs VALUES (1079, 'Spinning Christmas Elf Hat', 'It''s time to go green.', 2, 1000, NULL, 1668755556);
|
INSERT INTO public.hat_defs VALUES (1079, 'Spinning Christmas Elf Hat', 'It''s time to go green.', 2, 1000, NULL, 1668755556);
|
||||||
|
INSERT INTO public.hat_defs VALUES (1100, 'World Cup Mascot', 'This user supports the 2022 World Cup and watched it for Jungkook!', 2, 500, NULL, 1669007389);
|
||||||
INSERT INTO public.hat_defs VALUES (874, 'Carp', 'My 100th hat and a Thank you to carp. Now 150 more!', 2, 500, NULL, 1665272718);
|
INSERT INTO public.hat_defs VALUES (874, 'Carp', 'My 100th hat and a Thank you to carp. Now 150 more!', 2, 500, NULL, 1665272718);
|
||||||
INSERT INTO public.hat_defs VALUES (1077, 'Premium Snow Globe', 'Snow globe with a more premium base.', 2, 1000, NULL, 1668755505);
|
INSERT INTO public.hat_defs VALUES (1077, 'Premium Snow Globe', 'Snow globe with a more premium base.', 2, 1000, NULL, 1668755505);
|
||||||
INSERT INTO public.hat_defs VALUES (93, 'Wizard I', 'Three decades a KHHV', 2, 500, NULL, 1662167687);
|
INSERT INTO public.hat_defs VALUES (93, 'Wizard I', 'Three decades a KHHV', 2, 500, NULL, 1662167687);
|
||||||
|
@ -1168,7 +1170,7 @@ INSERT INTO public.hat_defs VALUES (911, 'Racecar Hat', 'I sleep in a hat with m
|
||||||
-- Name: hat_defs_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
|
-- Name: hat_defs_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
|
||||||
SELECT pg_catalog.setval('public.hat_defs_id_seq', 1099, true);
|
SELECT pg_catalog.setval('public.hat_defs_id_seq', 1103, true);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
|
@ -1202,6 +1204,7 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marsey1984',2,'orwell book ingsoc big brother fascist',NULL),
|
('marsey1984',2,'orwell book ingsoc big brother fascist',NULL),
|
||||||
('marsey300',2,'leonidas shield armor thermopylae spear greek spartan',NULL),
|
('marsey300',2,'leonidas shield armor thermopylae spear greek spartan',NULL),
|
||||||
('marsey3d',2,'poly 3d print alive spin animated',NULL),
|
('marsey3d',2,'poly 3d print alive spin animated',NULL),
|
||||||
|
('marsey403',2,'error http unauthorized forbidden access',1669055713),
|
||||||
('marsey404',2,'missing 404 error html page notfound',1668930304),
|
('marsey404',2,'missing 404 error html page notfound',1668930304),
|
||||||
('marsey40k',2,'warhammer 40k 40000 space space marine marine ultramarine smurf',NULL),
|
('marsey40k',2,'warhammer 40k 40000 space space marine marine ultramarine smurf',NULL),
|
||||||
('marsey420',2,'marijuana weed dude weed lmao ganja drugs pot reggae joint jamaican',NULL),
|
('marsey420',2,'marijuana weed dude weed lmao ganja drugs pot reggae joint jamaican',NULL),
|
||||||
|
@ -1372,6 +1375,7 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marseybiting',2,'reaction datass lip bite dat ass',NULL),
|
('marseybiting',2,'reaction datass lip bite dat ass',NULL),
|
||||||
('marseyblack',2,'basketball black african american bipoc coon fade jersey sports kang gang jogger',NULL),
|
('marseyblack',2,'basketball black african american bipoc coon fade jersey sports kang gang jogger',NULL),
|
||||||
('marseyblack2',2,'nigger african coon ape monkey bipoc excited happy',NULL),
|
('marseyblack2',2,'nigger african coon ape monkey bipoc excited happy',NULL),
|
||||||
|
('marseyblackandwhite',2,'black mixed white shredded manlet cat cute',1669229303),
|
||||||
('marseyblackcat',2,'cat black halloween homoween',1666656250),
|
('marseyblackcat',2,'cat black halloween homoween',1666656250),
|
||||||
('marseyblackcock',2,'cock chicken poultry bbc black ride mount cowgirl',NULL),
|
('marseyblackcock',2,'cock chicken poultry bbc black ride mount cowgirl',NULL),
|
||||||
('marseyblackcop',2,'police officer acab thin blue line pig bipoc',NULL),
|
('marseyblackcop',2,'police officer acab thin blue line pig bipoc',NULL),
|
||||||
|
@ -1585,6 +1589,7 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marseychonkerbutch',2,'fat obese brap bitch dyke dangerhair lesbian',NULL),
|
('marseychonkerbutch',2,'fat obese brap bitch dyke dangerhair lesbian',NULL),
|
||||||
('marseychonkerfoid',2,'female woman fds fat obese hambeast landwhale porker pig bleeder birthing person bangs',NULL),
|
('marseychonkerfoid',2,'female woman fds fat obese hambeast landwhale porker pig bleeder birthing person bangs',NULL),
|
||||||
('marseychonkerfoidpuke',2,'fat huge sick yuck eat barf',1664574968),
|
('marseychonkerfoidpuke',2,'fat huge sick yuck eat barf',1664574968),
|
||||||
|
('marseychonkernoticeme',2,'attention fat foid annoying',1669407871),
|
||||||
('marseychristmas',2,'candy cane santa christmas holiday',NULL),
|
('marseychristmas',2,'candy cane santa christmas holiday',NULL),
|
||||||
('marseychristmasbulb',2,'ornament christmas happy holiday china',NULL),
|
('marseychristmasbulb',2,'ornament christmas happy holiday china',NULL),
|
||||||
('marseychristmasbulb2',2,'ornament holiday christmas',NULL),
|
('marseychristmasbulb2',2,'ornament holiday christmas',NULL),
|
||||||
|
@ -2025,6 +2030,8 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marseyhitler2',2,'adolf adolph nazi germany kraut axis mustache genocide dictator authright chud conservative trump',NULL),
|
('marseyhitler2',2,'adolf adolph nazi germany kraut axis mustache genocide dictator authright chud conservative trump',NULL),
|
||||||
('marseyhmm',2,'confused reaction thinking thunk thonk judgment',NULL),
|
('marseyhmm',2,'confused reaction thinking thunk thonk judgment',NULL),
|
||||||
('marseyhmmm',2,'confused reaction thinking thunk thonk judgment',NULL),
|
('marseyhmmm',2,'confused reaction thinking thunk thonk judgment',NULL),
|
||||||
|
('marseyhobbes',2,'calvin hobbes waterson tiger comic',1669097969),
|
||||||
|
('marseyholocaust',2,'jew nazi adl merchant genocide chud rightoid hitler train auschwitz 109',1669064577),
|
||||||
('marseyhomestar',2,'homestar runner fast everybody 2000s',NULL),
|
('marseyhomestar',2,'homestar runner fast everybody 2000s',NULL),
|
||||||
('marseyhomochingchong',2,'asian chinese jap gook chink rice gay strawhat glasses squint rainbow tiedie tyedye tyedie tiedye',1663248780),
|
('marseyhomochingchong',2,'asian chinese jap gook chink rice gay strawhat glasses squint rainbow tiedie tyedye tyedie tiedye',1663248780),
|
||||||
('marseyhomofascist',2,'lgbt faggot ss fash nazi homocracy gay queer sodomy wholesome kiss',NULL),
|
('marseyhomofascist',2,'lgbt faggot ss fash nazi homocracy gay queer sodomy wholesome kiss',NULL),
|
||||||
|
@ -2531,6 +2538,8 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marseypusheen',2,'grey gray',NULL),
|
('marseypusheen',2,'grey gray',NULL),
|
||||||
('marseypussyhat',2,'feminist feminism activism activist protester protesting foid gussy woman birthing person roasty roastie thot slut whore',NULL),
|
('marseypussyhat',2,'feminist feminism activism activist protester protesting foid gussy woman birthing person roasty roastie thot slut whore',NULL),
|
||||||
('marseyputin',2,'vladimir russian kgb moscow ukraine dictator leader',NULL),
|
('marseyputin',2,'vladimir russian kgb moscow ukraine dictator leader',NULL),
|
||||||
|
('marseyqatarworldcup',2,'soccer football sports muslim islam allah sand bipoc robe ghost',1669146805),
|
||||||
|
('marseyqatarworldcup2',2,'soccer football sports muslim islam allah sand bipoc robe ghost',1669146826),
|
||||||
('marseyqoomer',2,'shaman viking qanon jan6 capitol january6',NULL),
|
('marseyqoomer',2,'shaman viking qanon jan6 capitol january6',NULL),
|
||||||
('marseyqr',2,'qr code',1663646718),
|
('marseyqr',2,'qr code',1663646718),
|
||||||
('marseyqr2',2,'cryptographic qrcode',1663944616),
|
('marseyqr2',2,'cryptographic qrcode',1663944616),
|
||||||
|
@ -2668,6 +2677,7 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marseyschizochadseethecapylove',2,'animated schizo schizocel rare love chad seethe capy aevann',NULL),
|
('marseyschizochadseethecapylove',2,'animated schizo schizocel rare love chad seethe capy aevann',NULL),
|
||||||
('marseyschizochadthankscapylove',2,'animated schizo schizocel rare love chad thanks queen capy aevann',NULL),
|
('marseyschizochadthankscapylove',2,'animated schizo schizocel rare love chad thanks queen capy aevann',NULL),
|
||||||
('marseyschizochadyescapylove',2,'animated schizo schizocel rare love chad yes capy aevann',NULL),
|
('marseyschizochadyescapylove',2,'animated schizo schizocel rare love chad yes capy aevann',NULL),
|
||||||
|
('marseyschizochiobulove',2,'chink asian tangerine feline singapore',1669161511),
|
||||||
('marseyschizodoggilove',2,'animated schizo schizocel rare love dussy doggi',NULL),
|
('marseyschizodoggilove',2,'animated schizo schizocel rare love dussy doggi',NULL),
|
||||||
('marseyschizodongerlove',2,'animated schizo schizocel rare love kaiser uraniumdonger donger',NULL),
|
('marseyschizodongerlove',2,'animated schizo schizocel rare love kaiser uraniumdonger donger',NULL),
|
||||||
('marseyschizoducklove',2,'animated schizo schizocel rare love duck',NULL),
|
('marseyschizoducklove',2,'animated schizo schizocel rare love duck',NULL),
|
||||||
|
@ -2934,6 +2944,7 @@ INSERT INTO public.marseys (name, author_id, tags, created_utc) VALUES
|
||||||
('marseytranspearlclutch',2,'transgender upset snowflake clutching',1666994064),
|
('marseytranspearlclutch',2,'transgender upset snowflake clutching',1666994064),
|
||||||
('marseytransrentfree',2,'transgender lgbt rent free wojak chud',NULL),
|
('marseytransrentfree',2,'transgender lgbt rent free wojak chud',NULL),
|
||||||
('marseytree',2,'tree nature outdoors cosplay',NULL),
|
('marseytree',2,'tree nature outdoors cosplay',NULL),
|
||||||
|
('marseytribute',2,'cum cumshot semen ropes load facial nsfw',1669095975),
|
||||||
('marseytrickortreat',2,'candy trick or treat halloween holiday',NULL),
|
('marseytrickortreat',2,'candy trick or treat halloween holiday',NULL),
|
||||||
('marseytrickrtreat',2,'halloween horror mask sam',1667697001),
|
('marseytrickrtreat',2,'halloween horror mask sam',1667697001),
|
||||||
('marseytrogdor',2,'burninator strongbad internet meme dragon marsdor',NULL),
|
('marseytrogdor',2,'burninator strongbad internet meme dragon marsdor',NULL),
|
||||||
|
|
|
@ -1093,7 +1093,7 @@ Yawn, another brigade from Drama? They must be tired of disrespecting the trans
|
||||||
{[para]}
|
{[para]}
|
||||||
I'm not a homosexual because I have straight sex with a man and I like men. But I'm straight because I prefer women's dicks and love having sex with them. I'm a homophobe because I can't have it.
|
I'm not a homosexual because I have straight sex with a man and I like men. But I'm straight because I prefer women's dicks and love having sex with them. I'm a homophobe because I can't have it.
|
||||||
{[para]}
|
{[para]}
|
||||||
Hello refugee, welcome to rDrama.net.
|
Hello refugee, welcome to rdrama.net.
|
||||||
In order to continue posting, please submit a timestamped photograph of your anus (known colloquially as 'bussy') to one of our immigration officers for detailed inspection. Failure to do so would mean immediate deportation
|
In order to continue posting, please submit a timestamped photograph of your anus (known colloquially as 'bussy') to one of our immigration officers for detailed inspection. Failure to do so would mean immediate deportation
|
||||||
{[para]}
|
{[para]}
|
||||||
Since when is promotion of gangbang considered as "sexual threat"?
|
Since when is promotion of gangbang considered as "sexual threat"?
|
||||||
|
@ -1705,7 +1705,7 @@ Watch what you want, but when I can't see something like First Reformed or Portr
|
||||||
{[para]}
|
{[para]}
|
||||||
This is outrageous. My criticism of Israel has very little to do with my rabid anti-semitism.
|
This is outrageous. My criticism of Israel has very little to do with my rabid anti-semitism.
|
||||||
{[para]}
|
{[para]}
|
||||||
This is rDrama.net sweaty.
|
This is rdrama.net sweaty.
|
||||||
You're ALL awful. I'm awful too.
|
You're ALL awful. I'm awful too.
|
||||||
You think that the mentally unstable we make fun of would be as miserable and unstable as they are without us?
|
You think that the mentally unstable we make fun of would be as miserable and unstable as they are without us?
|
||||||
They wouldn't.
|
They wouldn't.
|
||||||
|
@ -1719,7 +1719,7 @@ This IS horrible.
|
||||||
ALL of this is HORRIBLE.
|
ALL of this is HORRIBLE.
|
||||||
And you're part of it.
|
And you're part of it.
|
||||||
Fuck you, you stupid bitch.
|
Fuck you, you stupid bitch.
|
||||||
And fuck you all, rDrama.net. I'm out.
|
And fuck you all, rdrama.net. I'm out.
|
||||||
{[para]}
|
{[para]}
|
||||||
Being white and playing video games is a short pipeline that leads to learning Japanese and raping your sister
|
Being white and playing video games is a short pipeline that leads to learning Japanese and raping your sister
|
||||||
{[para]}
|
{[para]}
|
||||||
|
@ -2938,7 +2938,7 @@ I'm here to show your audience that you don't have the secret of anything, not e
|
||||||
Respond however you want, and I'll be back later to laugh about how once again, the angry impotent hate-ragers you all enjoy are not only sad, but ruining your life, when all you really need to do is take a shower and clean your room.
|
Respond however you want, and I'll be back later to laugh about how once again, the angry impotent hate-ragers you all enjoy are not only sad, but ruining your life, when all you really need to do is take a shower and clean your room.
|
||||||
Just think about how many of you actually killed yourself and just stopped posting, while everyone else failed to notice or were simply glad you disappeared. I hope it's you next. You're all a worthless drain on society.
|
Just think about how many of you actually killed yourself and just stopped posting, while everyone else failed to notice or were simply glad you disappeared. I hope it's you next. You're all a worthless drain on society.
|
||||||
{[para]}
|
{[para]}
|
||||||
To be fair, you have to be very neurodivergent to understand rDrama.net. The bait is extremely obvious, and without a solid grasp of satire most of the jokes will go over a typical viewer's head. There's also Carp's racist outlook, which is deftly woven into his characterisation - his personal philosophy draws heavily from MDE literature, for instance. The fans understand this stuff; they have the intellectual capacity to truly appreciate the depths of these jokes, to realize that they're not just funny- they say something deep about THE INTERNET. As a consequence people who dislike rDrama truly ARE zoomers- of course they wouldn't appreciate, for instance, the humour in Janny's existential catchphrase "Y'all can't behave," which itself is a cryptic reference to Aldous Huxley's dystopian epic Brave New World. I'm smirking right now just imagining one of those seriousposting wingtards scratching their heads in confusion as Aevann's genius unfolds itself on their mobile phone screens. What fools... how I pity them. :marseylaugh: And yes by the way, I DO have a Marsey tattoo. And no, you cannot see it. It's for the ladies' eyes only- And even they have to demonstrate that they're within 5 IQ points of my own (preferably lower) beforehand.
|
To be fair, you have to be very neurodivergent to understand rdrama.net. The bait is extremely obvious, and without a solid grasp of satire most of the jokes will go over a typical viewer's head. There's also Carp's racist outlook, which is deftly woven into his characterisation - his personal philosophy draws heavily from MDE literature, for instance. The fans understand this stuff; they have the intellectual capacity to truly appreciate the depths of these jokes, to realize that they're not just funny- they say something deep about THE INTERNET. As a consequence people who dislike rDrama truly ARE zoomers- of course they wouldn't appreciate, for instance, the humour in Janny's existential catchphrase "Y'all can't behave," which itself is a cryptic reference to Aldous Huxley's dystopian epic Brave New World. I'm smirking right now just imagining one of those seriousposting wingtards scratching their heads in confusion as Aevann's genius unfolds itself on their mobile phone screens. What fools... how I pity them. :marseylaugh: And yes by the way, I DO have a Marsey tattoo. And no, you cannot see it. It's for the ladies' eyes only- And even they have to demonstrate that they're within 5 IQ points of my own (preferably lower) beforehand.
|
||||||
{[para]}
|
{[para]}
|
||||||
I don't know, but I'll make sure not to get on your bad side lest I begin molesting children. Like a Pascal's wager kind of thing.
|
I don't know, but I'll make sure not to get on your bad side lest I begin molesting children. Like a Pascal's wager kind of thing.
|
||||||
{[para]}
|
{[para]}
|
||||||
|
@ -2993,7 +2993,7 @@ https://media.giphy.com/media/3oz8xLd9DJq2l2VFtu/giphy.webp
|
||||||
{[para]}
|
{[para]}
|
||||||
Rape
|
Rape
|
||||||
{[para]}
|
{[para]}
|
||||||
Here is the Contributors listing for the github project: https://github.com/Aevann1/rDrama
|
Here is the Contributors listing for the github project: https://fsdfsd.net/rDrama/rDrama/activity
|
||||||
|
|
||||||
That list shows CarpathianFlorist as a contributor. CarpathianFlorist is a Racially Motivated Violent Extremist - a White Identity Extremist - who was involved in /r/MillionDollarExtreme and its many hundreds of spinoffs and descendants. I've collected dozens of his Reddit accts.
|
That list shows CarpathianFlorist as a contributor. CarpathianFlorist is a Racially Motivated Violent Extremist - a White Identity Extremist - who was involved in /r/MillionDollarExtreme and its many hundreds of spinoffs and descendants. I've collected dozens of his Reddit accts.
|
||||||
|
|
||||||
|
@ -3173,4 +3173,7 @@ Normies can't understand the thrill of pinning the Weasel. Night spent chasing a
|
||||||
{[para]}
|
{[para]}
|
||||||
I am the “office manager” of AHS. I’ve spent the past three years keeping spreadsheets and have inboxes full of ticket closures, and have written reports characterizing the response accuracy of Reddit AEO.
|
I am the “office manager” of AHS. I’ve spent the past three years keeping spreadsheets and have inboxes full of ticket closures, and have written reports characterizing the response accuracy of Reddit AEO.
|
||||||
|
|
||||||
Would you like to escalate and mansplain my field of expertise to me more?
|
Would you like to escalate and mansplain my field of expertise to me more?
|
||||||
|
|
||||||
|
{[para]}
|
||||||
|
Normies can't understand the thrill of pinning the capybara. Night spent chasing an over amphetamined Aevann around the bean bag forts. His squealing and gibbering, pouring sweat and on the verge of seizing. Dramatards build up an intoxicating, delerious state with "dude bussy lmbo" chantings at the sidelines, hitting the Aevann-toy with brooms if he tries to escape. Carp would be giggling and laughing as the waves of methamphetamine pleasure seem to harmonize with the droning r-slur verses. He runs through the bean bag maze skinny and malnourished, with his viagra powered peepee a divining rod for the capybara. Sweat gushing down his, face around his unfocused eyes he laughs and chortles until he gasps "Found you!”. The Codescapybara screeches defensively but Whorist Florist is upon him in seconds. His peepee thrusting blindly into his flank, leg, stomach and ribs unconcemed about anything but the motion. Eventually serendepity finds his mouth and the Cocktube Rodent is placated, suckling contently on the Carp's dehydrated peepee.
|
Loading…
Reference in New Issue