implement uploading of top panorama, too
This commit is contained in:
parent
ad5daaae95
commit
3b670016be
@ -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%;
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
@ -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:
|
||||||
|
@ -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(
|
||||||
|
Loading…
Reference in New Issue
Block a user