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 { .q65-matrix {
grid-template-columns: repeat(5, auto); 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() { $.fn.imageUpload = function() {
var $button = $(this).find('button'); $.each(this, function(){
var $img = $(this).find('img'); var $button = $(this).find('button');
var $input = $(this).find('input'); var $img = $(this).find('img');
var id = $input.prop('id'); var $input = $(this).find('input');
console.info(id); var id = $input.prop('id');
$button.click(function(){ $button.click(function(){
$button.prop('disabled', true); $button.prop('disabled', true);
var input = document.createElement('input'); var input = document.createElement('input');
input.type = 'file'; input.type = 'file';
input.accept = 'image/jpeg, image/png'; input.accept = 'image/jpeg, image/png';
input.onchange = function(e) { input.onchange = function(e) {
var reader = new FileReader() var reader = new FileReader()
// TODO: implement file size check // TODO: implement file size check
reader.readAsArrayBuffer(e.target.files[0]); reader.readAsArrayBuffer(e.target.files[0]);
reader.onload = function(e) { reader.onload = function(e) {
$.ajax({ $.ajax({
url: '/imageupload?id=' + id, url: '/imageupload?id=' + id,
type: 'POST', type: 'POST',
data: e.target.result, data: e.target.result,
processData: false, processData: false,
contentType: 'application/octet-stream', contentType: 'application/octet-stream',
}).done(function(data){ }).done(function(data){
$input.val(data.uuid); $input.val(data.uuid);
$img.prop('src', "/imageupload?id=" + id + "&uuid=" + data.uuid); $img.prop('src', "/imageupload?id=" + id + "&uuid=" + data.uuid);
}).always(function(){ }).always(function(){
$button.prop('disabled', false); $button.prop('disabled', false);
}); });
} }
}; };
input.click(); input.click();
return false; return false;
});
}); });
} }

View File

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

View File

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

View File

@ -2,14 +2,28 @@ from owrx.form import Input
class AvatarInput(Input): class AvatarInput(Input):
def __init__(self, id, label, infotext=None):
super().__init__(id, label, infotext=infotext)
def render_input(self, value): def render_input(self, value):
return """ return """
<div class="imageupload"> <div class="imageupload">
<input type="hidden" id="{id}" name="{id}"> <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> <button class="btn btn-primary">Upload new image...</button>
</div> </div>
""".format( """.format(