implement dynamic file upload

This commit is contained in:
Jakob Ketterl 2021-02-08 23:29:24 +01:00
parent 2d72055070
commit a1c024bfe2
7 changed files with 95 additions and 5 deletions

View File

@ -0,0 +1,35 @@
$.fn.imageUpload = function() {
var $button = $(this).find('button');
var $img = $(this).find('img');
var $input = $(this).find('input');
var id = $input.prop('id');
console.info(id);
$button.click(function(){
$button.prop('disabled', true);
var input = document.createElement('input');
input.type = 'file';
input.accept = 'image/jpeg, image/png';
input.onchange = function(e) {
var reader = new FileReader()
reader.readAsArrayBuffer(e.target.files[0]);
reader.onload = function(e) {
$.ajax({
url: '/imageupload?id=' + id,
type: 'POST',
data: e.target.result,
processData: false,
contentType: 'application/octet-stream',
}).done(function(data){
$input.val(data.uuid);
$img.prop('src', "/imageupload?id=" + id + "&uuid=" + data.uuid);
}).always(function(){
$button.prop('disabled', false);
});
}
};
input.click();
return false;
});
}

View File

@ -22,4 +22,5 @@ $(function(){
}); });
$(".sdrdevice").sdrdevice(); $(".sdrdevice").sdrdevice();
$(".imageupload").imageUpload();
}); });

View File

@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
class GzipMixin(object): class GzipMixin(object):
def send_response(self, content, headers=None, content_type="text/html", *args, **kwargs): def send_response(self, content, code=200, headers=None, content_type="text/html", *args, **kwargs):
if self.zipable(content_type) and "accept-encoding" in self.request.headers: if self.zipable(content_type) and "accept-encoding" in self.request.headers:
accepted = [s.strip().lower() for s in self.request.headers["accept-encoding"].split(",")] accepted = [s.strip().lower() for s in self.request.headers["accept-encoding"].split(",")]
if "gzip" in accepted: if "gzip" in accepted:
@ -23,7 +23,7 @@ class GzipMixin(object):
if headers is None: if headers is None:
headers = {} headers = {}
headers["Content-Encoding"] = "gzip" headers["Content-Encoding"] = "gzip"
super().send_response(content, headers=headers, content_type=content_type, *args, **kwargs) super().send_response(content, code, headers=headers, content_type=content_type, *args, **kwargs)
def zipable(self, content_type): def zipable(self, content_type):
types = ["application/javascript", "text/css", "text/html"] types = ["application/javascript", "text/css", "text/html"]
@ -78,7 +78,7 @@ class AssetsController(GzipMixin, ModificationAwareController, metaclass=ABCMeta
f.close() f.close()
if content_type is None: if content_type is None:
(content_type, encoding) = mimetypes.MimeTypes().guess_type(file) (content_type, encoding) = mimetypes.MimeTypes().guess_type(self.getFilePath(file))
self.send_response(data, content_type=content_type, last_modified=modified, max_age=3600) self.send_response(data, content_type=content_type, last_modified=modified, max_age=3600)
except FileNotFoundError: except FileNotFoundError:
self.send_response("file not found", code=404) self.send_response("file not found", code=404)
@ -137,6 +137,7 @@ class CompiledAssetsController(GzipMixin, ModificationAwareController):
"lib/Header.js", "lib/Header.js",
"lib/settings/Input.js", "lib/settings/Input.js",
"lib/settings/SdrDevice.js", "lib/settings/SdrDevice.js",
"lib/settings/ImageUpload.js",
"settings.js", "settings.js",
], ],
} }

View File

@ -0,0 +1,32 @@
from owrx.controllers.assets import AssetsController
from owrx.config import CoreConfig
import uuid
import json
class ImageUploadController(AssetsController):
def __init__(self, handler, request, options):
super().__init__(handler, request, options)
self.uuid = request.query["uuid"][0] if "uuid" in request.query else None
self.id = request.query["id"][0] if "id" in request.query else None
def getFilePath(self, file=None):
if self.uuid is None:
raise FileNotFoundError("missing uuid")
if self.id is None:
raise FileNotFoundError("missing id")
return "{tmp}/{file}-{uuid}".format(
tmp=CoreConfig().get_temporary_directory(),
file=self.id,
uuid=self.uuid,
)
def indexAction(self):
self.serve_file(None)
def processImage(self):
self.uuid = uuid.uuid4().hex
contents = self.get_body()
with open(self.getFilePath(), 'wb') as f:
f.write(contents)
self.send_response(json.dumps({"uuid": self.uuid}), content_type="application/json")

View File

@ -19,6 +19,7 @@ from owrx.form.receiverid import ReceiverKeysConverter
from owrx.form.aprs import AprsBeaconSymbols, AprsAntennaDirections from owrx.form.aprs import AprsBeaconSymbols, AprsAntennaDirections
from owrx.form.wfm import WfmTauValues from owrx.form.wfm import WfmTauValues
from owrx.form.wsjt import Q65ModeMatrix from owrx.form.wsjt import Q65ModeMatrix
from owrx.form.gfx import AvatarInput
from urllib.parse import quote from urllib.parse import quote
from owrx.wsjt import Fst4Profile, Fst4wProfile from owrx.wsjt import Fst4Profile, Fst4wProfile
import json import json
@ -107,6 +108,13 @@ class GeneralSettingsController(AdminController):
TextInput("photo_title", "Photo title"), TextInput("photo_title", "Photo title"),
TextAreaInput("photo_desc", "Photo description"), TextAreaInput("photo_desc", "Photo description"),
), ),
Section(
"Receiver images",
AvatarInput(
"receiver_avatar",
"Receiver Avatar",
),
),
Section( Section(
"Receiver listings", "Receiver listings",
TextAreaInput( TextAreaInput(

View File

@ -2,6 +2,16 @@ from owrx.form import Input
class AvatarInput(Input): class AvatarInput(Input):
def render_input(self, value): def __init__(self, id, label, infotext=None):
pass super().__init__(id, label, infotext=infotext)
def render_input(self, value):
return """
<div class="imageupload">
<input type="hidden" id="{id}" name="{id}">
<img class="webrx-rx-avatar" src="static/gfx/openwebrx-avatar.png" alt="Receiver avatar"/>
<button class="btn btn-primary">Upload new image...</button>
</div>
""".format(
id=self.id
)

View File

@ -7,6 +7,7 @@ from owrx.controllers.metrics import MetricsController
from owrx.controllers.settings import SettingsController, GeneralSettingsController, SdrSettingsController from owrx.controllers.settings import SettingsController, GeneralSettingsController, SdrSettingsController
from owrx.controllers.session import SessionController from owrx.controllers.session import SessionController
from owrx.controllers.profile import ProfileController from owrx.controllers.profile import ProfileController
from owrx.controllers.imageupload import ImageUploadController
from http.server import BaseHTTPRequestHandler from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
import re import re
@ -112,6 +113,8 @@ class Router(object):
StaticRoute("/logout", SessionController, options={"action": "logoutAction"}), StaticRoute("/logout", SessionController, options={"action": "logoutAction"}),
StaticRoute("/pwchange", ProfileController), StaticRoute("/pwchange", ProfileController),
StaticRoute("/pwchange", ProfileController, method="POST", options={"action": "processPwChange"}), StaticRoute("/pwchange", ProfileController, method="POST", options={"action": "processPwChange"}),
StaticRoute("/imageupload", ImageUploadController),
StaticRoute("/imageupload", ImageUploadController, method="POST", options={"action": "processImage"}),
] ]
def find_route(self, request): def find_route(self, request):