implement uploading of top panorama, too

This commit is contained in:
Jakob Ketterl 2021-02-09 00:12:53 +01:00
parent ad5daaae95
commit 3b670016be
6 changed files with 80 additions and 51 deletions

View File

@ -32,4 +32,14 @@ h1 {
.q65-matrix {
grid-template-columns: repeat(5, auto);
}
}
.imageupload .image-container {
max-width: 100%;
padding: 7px;
}
.imageupload img.webrx-top-photo {
max-height: 350px;
max-width: 100%;
}

View File

@ -1,36 +1,37 @@
$.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';
$.each(this, function(){
var $button = $(this).find('button');
var $img = $(this).find('img');
var $input = $(this).find('input');
var id = $input.prop('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()
// TODO: implement file size check
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.onchange = function(e) {
var reader = new FileReader()
// TODO: implement file size check
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;
input.click();
return false;
});
});
}

View File

@ -90,11 +90,15 @@ class AssetsController(GzipMixin, ModificationAwareController, metaclass=ABCMeta
class OwrxAssetsController(AssetsController):
def getFilePath(self, file):
mappedFiles = {
"gfx/openwebrx-avatar.png": "receiver_avatar",
"gfx/openwebrx-top-photo.jpg": "receiver_top_photo",
}
config = CoreConfig()
if file == "gfx/openwebrx-avatar.png":
file = config.get_data_directory() + "/receiver_avatar"
if os.path.exists(file) and os.path.isfile(file):
return file
if file in mappedFiles:
user_file = config.get_data_directory() + "/" + mappedFiles[file]
if os.path.exists(user_file) and os.path.isfile(user_file):
return user_file
return pkg_resources.resource_filename("htdocs", file)

View File

@ -28,7 +28,9 @@ class ImageUploadController(AssetsController):
def processImage(self):
self.uuid = uuid.uuid4().hex
# TODO: limit file size
# TODO: check image mime type, if possible
contents = self.get_body()
# TODO: clean up files after timeout or on shutdown
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,7 +19,7 @@ from owrx.form.receiverid import ReceiverKeysConverter
from owrx.form.aprs import AprsBeaconSymbols, AprsAntennaDirections
from owrx.form.wfm import WfmTauValues
from owrx.form.wsjt import Q65ModeMatrix
from owrx.form.gfx import AvatarInput
from owrx.form.gfx import AvatarInput, TopPhotoInput
from urllib.parse import quote
from owrx.wsjt import Fst4Profile, Fst4wProfile
import json
@ -115,6 +115,10 @@ class GeneralSettingsController(AdminController):
"receiver_avatar",
"Receiver Avatar",
),
TopPhotoInput(
"receiver_top_photo",
"Receiver Panorama",
),
),
Section(
"Receiver listings",
@ -303,11 +307,7 @@ class GeneralSettingsController(AdminController):
append="dBi",
converter=OptionalConverter(),
),
DropdownInput(
"aprs_igate_dir",
"Antenna direction",
AprsAntennaDirections
),
DropdownInput("aprs_igate_dir", "Antenna direction", AprsAntennaDirections),
),
Section(
"pskreporter settings",
@ -365,14 +365,11 @@ class GeneralSettingsController(AdminController):
return variables
def handle_image(self, data, image_id):
if image_id not in data:
if image_id not in data or not data[image_id]:
return
config = CoreConfig()
filename = "{}-{}".format(image_id, data[image_id])
shutil.copy(
config.get_temporary_directory() + "/" + filename,
config.get_data_directory() + "/" + image_id
)
shutil.copy(config.get_temporary_directory() + "/" + filename, config.get_data_directory() + "/" + image_id)
del data[image_id]
def processFormData(self):
@ -380,6 +377,7 @@ class GeneralSettingsController(AdminController):
data = {k: v for i in GeneralSettingsController.sections for k, v in i.parse(data).items()}
# Image handling
self.handle_image(data, "receiver_avatar")
self.handle_image(data, "receiver_top_photo")
config = Config.get()
for k, v in data.items():
if v is None:

View File

@ -2,14 +2,28 @@ from owrx.form import Input
class AvatarInput(Input):
def __init__(self, id, label, infotext=None):
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"/>
<div class="image-container">
<img class="webrx-rx-avatar" src="static/gfx/openwebrx-avatar.png" alt="Receiver avatar"/>
</div>
<button class="btn btn-primary">Upload new image...</button>
</div>
""".format(
id=self.id
)
class TopPhotoInput(Input):
def render_input(self, value):
return """
<div class="imageupload">
<input type="hidden" id="{id}" name="{id}">
<div class="image-container">
<img class="webrx-top-photo" src="static/gfx/openwebrx-top-photo.jpg" alt="Receiver Panorama"/>
</div>
<button class="btn btn-primary">Upload new image...</button>
</div>
""".format(