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