add dm images

pull/93/head
Aevann 2023-01-23 11:58:38 +02:00
parent d34f836052
commit 8396126606
12 changed files with 85 additions and 18 deletions

View File

@ -20,6 +20,7 @@ RUN pip3 install -r /etc/requirements.txt
RUN mkdir /images RUN mkdir /images
RUN mkdir /chat_images RUN mkdir /chat_images
RUN mkdir /dm_images
RUN mkdir /songs RUN mkdir /songs
RUN mkdir /videos RUN mkdir /videos
RUN mkdir /audio RUN mkdir /audio

View File

@ -119,7 +119,7 @@ function post_reply(id){
form.append('parent_id', id); form.append('parent_id', id);
form.append('body', document.getElementById('reply-form-body-'+id).value); form.append('body', document.getElementById('reply-form-body-'+id).value);
try { try {
for (const e of document.getElementById('file-upload').files) for (const e of document.getElementById(`file-upload-${id}`).files)
form.append('file', e); form.append('file', e);
} }
catch(e) {} catch(e) {}
@ -144,10 +144,10 @@ function post_reply(id){
document.getElementById('reply-form-body-'+id).value = '' document.getElementById('reply-form-body-'+id).value = ''
document.getElementById('message-reply-'+id).innerHTML = '' document.getElementById('message-reply-'+id).innerHTML = ''
toggleReplyBox('reply-message-c_'+id) toggleReplyBox('reply-message-c_'+id)
const fileupload = document.getElementById('file-upload') const fileupload = document.getElementById(`file-upload-${id}`)
if (fileupload) { if (fileupload) {
fileupload.value = null; fileupload.value = null;
document.getElementById('filename').innerHTML = '<i class="fas fa-file"></i>'; document.getElementById(`filename-${id}`).innerHTML = '<i class="fas fa-file"></i>';
} }
} else { } else {
showToast(false, getMessageFromJsonData(false, data)); showToast(false, getMessageFromJsonData(false, data));

View File

@ -465,7 +465,8 @@ PERMS = { # Minimum admin_level to perform action.
'SITE_CACHE_PURGE_CDN': 3, 'SITE_CACHE_PURGE_CDN': 3,
'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3, 'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3,
'NOTIFICATIONS_MODMAIL': 3, 'NOTIFICATIONS_MODMAIL': 3,
'APPS_MODERATION': 3, 'APPS_MODERATION': 3,
'VIEW_DM_IMAGES': 3,
'POST_EDITING': 4, 'POST_EDITING': 4,
'MODERATE_PENDING_SUBMITTED_ASSETS': 4, 'MODERATE_PENDING_SUBMITTED_ASSETS': 4,
'UPDATE_ASSETS': 4, 'UPDATE_ASSETS': 4,

View File

@ -1,12 +1,13 @@
import os import os
import subprocess import subprocess
import time import time
import requests
from shutil import copyfile from shutil import copyfile
from typing import Optional from typing import Optional
import gevent import gevent
import imagehash import imagehash
from flask import abort, g, has_request_context from flask import abort, g, has_request_context, request
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from PIL import Image from PIL import Image
from PIL import UnidentifiedImageError from PIL import UnidentifiedImageError
@ -15,6 +16,7 @@ from sqlalchemy.orm.session import Session
from files.classes.media import * from files.classes.media import *
from files.helpers.cloudflare import purge_files_in_cache from files.helpers.cloudflare import purge_files_in_cache
from files.helpers.settings import get_setting
from .config.const import * from .config.const import *
@ -216,3 +218,45 @@ def process_image(filename:str, v, resize=0, trim=False, uploader_id:Optional[in
db.add(media) db.add(media)
return filename return filename
def process_dm_images(v):
if not request.files.get("file") or g.is_tor or not get_setting("dm_images"):
return ''
body = ''
files = request.files.getlist('file')[:4]
for file in files:
if file.content_type.startswith('image/'):
filename = f'/dm_images/{time.time()}'.replace('.','') + '.webp'
file.save(filename)
size = os.stat(filename).st_size
patron = bool(v.patron)
if size > MAX_IMAGE_AUDIO_SIZE_MB_PATRON * 1024 * 1024 or not patron and size > MAX_IMAGE_AUDIO_SIZE_MB * 1024 * 1024:
os.remove(filename)
abort(413, f"Max image/audio size is {MAX_IMAGE_AUDIO_SIZE_MB} MB ({MAX_IMAGE_AUDIO_SIZE_MB_PATRON} MB for paypigs)")
with open(filename, 'rb') as f:
os.remove(filename)
try:
req = requests.request(
"POST",
"https://pomf2.lain.la/upload.php",
files={'files[]': f},
timeout=20,
proxies=proxies
).json()
except requests.Timeout:
abort(400, "Image upload timed out, please try again!")
try: url = req['files'][0]['url']
except: abort(400, req['description'])
body += f'\n\n{url}\n\n'
with open(f"{LOG_DIRECTORY}/dm_images.log", "a+", encoding="utf-8") as f:
f.write(body.strip() + '\n')
return body

View File

@ -13,6 +13,7 @@ _SETTINGS = {
"signups": True, "signups": True,
"login_required": False, "login_required": False,
"under_siege": False, "under_siege": False,
"dm_images": True,
} }
def get_setting(setting:str): def get_setting(setting:str):

View File

@ -188,6 +188,12 @@ def loggedout_list(v):
# return redirect(f"/@{olduser.username}") # return redirect(f"/@{olduser.username}")
@app.get('/admin/dm_images')
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)
@admin_level_required(PERMS['VIEW_DM_IMAGES'])
def dm_images(v):
with open(f"{LOG_DIRECTORY}/dm_images.log", "r", encoding="utf-8") as f:
return f.read()
@app.get('/admin/edit_rules') @app.get('/admin/edit_rules')
@limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID) @limiter.limit(DEFAULT_RATELIMIT, key_func=get_ID)

View File

@ -12,7 +12,7 @@ from files.classes.user import User
from files.helpers.assetcache import assetcache_path from files.helpers.assetcache import assetcache_path
from files.helpers.config.const import * from files.helpers.config.const import *
from files.helpers.regex import * from files.helpers.regex import *
from files.helpers.settings import get_settings from files.helpers.settings import get_settings, get_setting
from files.helpers.sorting_and_time import make_age_string from files.helpers.sorting_and_time import make_age_string
from files.routes.routehelpers import get_alt_graph, get_formkey from files.routes.routehelpers import get_alt_graph, get_formkey
from files.__main__ import app, cache from files.__main__ import app, cache
@ -107,7 +107,7 @@ def inject_constants():
"HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED, "HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED,
"GUMROAD_LINK":GUMROAD_LINK, "DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION, "GUMROAD_LINK":GUMROAD_LINK, "DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION,
"has_sidebar":has_sidebar, "has_logo":has_logo, "has_sidebar":has_sidebar, "has_logo":has_logo,
"FP":FP, "patron":patron, "FP":FP, "patron":patron, "get_setting": get_setting,
"SIDEBAR_THREAD":SIDEBAR_THREAD, "BANNER_THREAD":BANNER_THREAD, "SIDEBAR_THREAD":SIDEBAR_THREAD, "BANNER_THREAD":BANNER_THREAD,
"BADGE_THREAD":BADGE_THREAD, "SNAPPY_THREAD":SNAPPY_THREAD, "BADGE_THREAD":BADGE_THREAD, "SNAPPY_THREAD":SNAPPY_THREAD,
"KOFI_TOKEN":KOFI_TOKEN, "KOFI_LINK":KOFI_LINK, "KOFI_TOKEN":KOFI_TOKEN, "KOFI_LINK":KOFI_LINK,

View File

@ -495,6 +495,9 @@ def message2(v:User, username:str):
abort(403, f"@{user.username} is blocking you.") abort(403, f"@{user.username} is blocking you.")
message = sanitize_raw_body(request.values.get("message"), False) message = sanitize_raw_body(request.values.get("message"), False)
message += process_dm_images(v)
if not message: abort(400, "Message is empty!") if not message: abort(400, "Message is empty!")
body_html = sanitize(message) body_html = sanitize(message)
@ -545,7 +548,6 @@ def message2(v:User, username:str):
@auth_required @auth_required
def messagereply(v:User): def messagereply(v:User):
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!")
id = request.values.get("parent_id") id = request.values.get("parent_id")
parent = get_comment(id, v=v) parent = get_comment(id, v=v)
@ -567,11 +569,12 @@ def messagereply(v:User):
and hasattr(user, 'is_blocked') and user.is_blocked): and hasattr(user, 'is_blocked') and user.is_blocked):
abort(403, f"You're blocked by @{user.username}") abort(403, f"You're blocked by @{user.username}")
if parent.sentto == MODMAIL_ID: body += process_dm_images(v)
body += process_files(request.files, v)
body = body.strip() body = body.strip()
if not body: abort(400, "Message is empty!")
body_html = sanitize(body) body_html = sanitize(body)
c = Comment(author_id=v.id, c = Comment(author_id=v.id,

View File

@ -35,6 +35,7 @@
<h4>Content</h4> <h4>Content</h4>
<ul> <ul>
<li><a href="/admin/dm_images">DM Images</a></li>
<li><a href="/log">Moderation Log</a></li> <li><a href="/log">Moderation Log</a></li>
{% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %} {% if v.admin_level >= PERMS['POST_COMMENT_MODERATION'] %}
<li><a href="/admin/image_posts">Image Posts</a></li> <li><a href="/admin/image_posts">Image Posts</a></li>

View File

@ -522,12 +522,12 @@
<div class="comment-format" id="comment-format-bar-{{c.id}}"> <div class="comment-format" id="comment-format-bar-{{c.id}}">
<button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary m-0 mt-3 mr-1" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button> <button type="button" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('reply-form-body-{{c.id}}')" class="btn btn-secondary m-0 mt-3 mr-1" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></button>
{% if c.sentto == MODMAIL_ID %} {% set upload_disabled = g.is_tor or not get_setting('dm_images') %}
<label class="btn btn-secondary m-0 mt-3" for="file-upload">
<div id="filename"><i class="fas fa-file"></i></div> <label class="btn btn-secondary m-0 mt-3 {% if upload_disabled %}disabled{% endif %}" for="file-upload-{{c.id}}">
<input autocomplete="off" id="file-upload" accept="image/*, video/*, audio/*" type="file" name="file" multiple="multiple" {% if g.is_tor %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename','file-upload')" hidden> <div id="filename-{{c.id}}"><i class="fas fa-image"></i></div>
</label> <input autocomplete="off" id="file-upload-{{c.id}}" accept="image/*" type="file" name="file" multiple="multiple" {% if upload_disabled %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename-{{c.id}}','file-upload-{{c.id}}')" hidden>
{% endif %} </label>
</div> </div>
<button type="button" data-nonce="{{g.nonce}}" data-onclick="remove_dialog()" class="btn btn-link text-muted ml-auto" data-toggleelement="reply-message-{{c.fullname}}" data-toggleattr="d-none">Cancel</button> <button type="button" data-nonce="{{g.nonce}}" data-onclick="remove_dialog()" class="btn btn-link text-muted ml-auto" data-toggleelement="reply-message-{{c.fullname}}" data-toggleattr="d-none">Cancel</button>

View File

@ -153,8 +153,17 @@
</div> </div>
<form class="d-none toggleable" id="message" action="/@{{u.username}}/message" data-nonce="{{g.nonce}}" data-onsubmit="sendMessage(this)"> <form class="d-none toggleable" id="message" action="/@{{u.username}}/message" data-nonce="{{g.nonce}}" data-onsubmit="sendMessage(this)">
<input type="hidden" name="formkey" value="{{v|formkey}}"> <input type="hidden" name="formkey" value="{{v|formkey}}">
<textarea autocomplete="off" id="input-message" form="message" name="message" rows="3" minlength="1" maxlength="10000" class="form-control b2 mt-1" data-preview="message-preview" data-nonce="{{g.nonce}}" data-oninput="markdown(this)" required></textarea> <textarea autocomplete="off" id="input-message" form="message" name="message" rows="3" minlength="1" maxlength="10000" class="form-control b2 mt-1" data-preview="message-preview" data-nonce="{{g.nonce}}" data-oninput="markdown(this)"></textarea>
<button type="button" class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('input-message')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></button>
<button type="button" class="btn btn-secondary format d-inline-block m-0 py-2 fas fa-smile-beam" data-nonce="{{g.nonce}}" data-onclick="loadEmojis('input-message')" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></button>
{% set upload_disabled = g.is_tor or not get_setting('dm_images') %}
<label class="btn btn-secondary m-0 py-1 px-2 {% if upload_disabled %}disabled{% endif %}" for="file-upload">
<div id="filename"><i class="fas fa-image"></i></div>
<input autocomplete="off" id="file-upload" accept="image/*" type="file" name="file" multiple="multiple" {% if upload_disabled %}disabled{% endif %} data-nonce="{{g.nonce}}" data-onchange="changename('filename','file-upload')" hidden>
</label>
&nbsp; &nbsp;
<input type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()" value="Submit" class="btn btn-primary"> <input type="submit" data-nonce="{{g.nonce}}" data-onclick="disable(this);remove_dialog()" value="Submit" class="btn btn-primary">
</form> </form>

View File

@ -38,6 +38,7 @@ pip3 install -r requirements.txt
mkdir /images mkdir /images
mkdir /chat_images mkdir /chat_images
mkdir /dm_images
mkdir /songs mkdir /songs
mkdir /videos mkdir /videos
mkdir /audio mkdir /audio