diff --git a/assets/js/common/api.js b/assets/js/common/api.js index 30ada2dc..97f79a71 100644 --- a/assets/js/common/api.js +++ b/assets/js/common/api.js @@ -10,7 +10,7 @@ const APIClient = { * * @returns {Promise} */ - exec: function(apiURI, args, withLogin){ + exec: function(apiURI, args, withLogin) { if(!args) args = {}; @@ -29,6 +29,24 @@ const APIClient = { }); }, + /** + * @returns {Promise} + */ + execFormData: function(uri, data, withLogin) { + if (!data) + data = new FormData(); + + return new Promise((res, rej) => { + this.makeFormDatarequest(uri, data, withLogin, (result) => { + if (result.error) + reject(result.error); + + else + res(result); + }) + }); + }, + /** * Make an API request * diff --git a/assets/js/common/utils.js b/assets/js/common/utils.js index 74b36d69..e6847193 100644 --- a/assets/js/common/utils.js +++ b/assets/js/common/utils.js @@ -833,4 +833,13 @@ function rpad(str, len, fill) { while(str.length < len) str = fill + str return str +} + +/** + * Format file size to human readable format + * + * @param {number} size The size to format + */ +function fileSizeToHuman(size) { + return Math.round(ServerConfig.conf.conversation_files_max_size/(1000*1000)*100)/100 + "MB"; } \ No newline at end of file diff --git a/assets/js/components/conversations/interface.js b/assets/js/components/conversations/interface.js index 2decfbb0..0e3820cc 100644 --- a/assets/js/components/conversations/interface.js +++ b/assets/js/components/conversations/interface.js @@ -245,47 +245,37 @@ const ConversationsInterface = { /** * Send a new message * - * @param {Object} infos Informations about the message to send - * @info {Integer} conversationID The ID of the conversation - * @info {String} message The message to send - * @info {HTMLElement} image Optionnal, input field with an image - * @info {function} callback What to do once the image was successfully sent - * @return {Boolean} true for a success + * @param {number} convID The ID of the conversation + * @param {string} message The message to send (if not a file) + * @param {HTMLInputElement} file The file to send (if any) */ - sendMessage: function(infos){ + sendMessage: async function(convID, message, file){ //Perform an API request var apiURI = "conversations/sendMessage"; - var hasImage = false; - if(infos.image){ - if(infos.image.files[0]) - hasImage = true; - } - - //Check wether an image has to be included or not - if(!hasImage){ + // Check whether a file has to be sent or not + if(!file){ //Prepare request var params = { - message: infos.message, - conversationID: infos.conversationID, + message: message, + conversationID: convID, }; //Perform an API request - ComunicWeb.common.api.makeAPIrequest(apiURI, params, true, infos.callback); + await api(apiURI, params, true); } - //If we have an image, we must do a formdata request + //If we have a file, we must do a formdata request else { var fd = new FormData(); - fd.append("message", infos.message); - fd.append("conversationID", infos.conversationID); - fd.append("image", infos.image.files[0], infos.image.files[0].name); + fd.append("conversationID", convID); + fd.append("file", file.files[0], file.files[0].name); //Perform an API request - ComunicWeb.common.api.makeFormDatarequest(apiURI, fd, true, infos.callback); + await APIClient.execFormData(apiURI, fd, true); } }, diff --git a/assets/js/pages/conversations/conversation.js b/assets/js/pages/conversations/conversation.js index 9514aa4d..8479d3b8 100644 --- a/assets/js/pages/conversations/conversation.js +++ b/assets/js/pages/conversations/conversation.js @@ -401,6 +401,82 @@ const ConversationPageConvPart = { class: "input-group" }); + + // ==== FILE INPUT ==== + + // File button group + let fileButtonGroup = createElem2({ + appendTo: inputGroup, + type: "span", + class: "input-group-btn", + }); + + //Create image input (for optionnal image) + var fileInput = document.createElement("input"); + fileInput.type = "file"; + fileInput.accept = ServerConfig.conf.allowed_conversation_files_type.join(", "); + + // Send file button + var fileButton = createElem2({ + appendTo: fileButtonGroup, + type: "button", + elemType: "button", + class: "btn btn-flat btn-add-image", + }); + fileButton.addEventListener("click", (e) => { + e.preventDefault(); + + //Call file selector + fileInput.click(); + }); + + //Add image icon + createElem2({ + type: "i", + appendTo: fileButton, + class: "fa fa-plus" + }); + + fileInput.addEventListener("change", async (e) => { + e.preventDefault(); + + let el; + + try { + + if(fileInput.files.length == 0) + return; + + const file = fileInput.files[0]; + + if (ServerConfig.conf.allowed_conversation_files_type.indexOf(file.type) < 0) { + notify(tr("This file type is not allowed!"), "danger") + return; + } + + + if (file.size > ServerConfig.conf.conversation_files_max_size) { + notify(tr("This file is too big (max file size: %1%)", {"1": fileSizeToHuman(ServerConfig.conf.conversation_files_max_size)}), "danger"); + return; + } + + el = Page.showTransparentWaitSplashScreen(); + + await ConversationsInterface.sendMessage(this._conv_info.id, null, fileInput); + } + + catch(e) { + console.error(e); + notify(tr("Failed to send file!"), "danger"); + } + + el.remove(); + + }); + // ==== /FILE INPUT ==== + + + //Create text input (for message) var inputText = createElem2({ appendTo: inputGroup, @@ -420,13 +496,6 @@ const ConversationPageConvPart = { autosize: true, }); - //Create image input (for optionnal image) - var inputImage = createElem2({ - type: "input", - elemType: "file", - }); - - //Create button group var buttonGroup = createElem2({ appendTo: inputGroup, @@ -452,24 +521,6 @@ const ConversationPageConvPart = { //Make emojie button lives ComunicWeb.components.emoji.picker.addPicker(inputText, emojiButton); - //Add image button - var imageButton = createElem2({ - appendTo: buttonGroup, - type: "button", - elemType: "button", - class: "btn btn-flat btn-add-image", - }); - imageButton.onclick = function(){ - //Call file selector - inputImage.click(); - }; - - //Add image icon - createElem2({ - type: "i", - appendTo: imageButton, - class: "fa fa-image" - }); //Add send button var sendButton = createElem2({ @@ -495,38 +546,37 @@ const ConversationPageConvPart = { }); //Make form lives - formContainer.onsubmit = function(){ + formContainer.addEventListener("submit", async (e) => { + e.preventDefault(); - //Check if message is empty - if(!checkString(inputText.value) && !inputImage.files[0]){ - ComunicWeb.common.notificationSystem.showNotification("Please type a valid message before trying to send it !", "danger", 2); - return false; + try { + let message = inputText.value; + + //Check if message is empty + if(message.length > ServerConfig.conf.max_conversation_message_len + || message.length < ServerConfig.conf.min_conversation_message_len){ + notify(tr("Invalid message length!"), "danger", 2); + return; + } + + // Lock send button + sendButton.disabled = true; + + //Send the message throught the interface + await ConversationsInterface.sendMessage(this._conv_info.id, message); + + // Reset the form + inputText.value = ""; } - //Lock send button - sendButton.disabled = true; + catch(e) { + console.error(e); + notify("An error occurred while trying to send your message!", "danger"); + } - //Send the message throught the interface - ComunicWeb.components.conversations.interface.sendMessage({ - conversationID: ComunicWeb.pages.conversations.conversation._conv_info.id, - message: inputText.value, - image: inputImage, - callback: function(result){ - - //Unlock send button - sendButton.disabled = false; - - //Check for errors - if(result.error) - return notify("An error occurred while trying to send your message!", "danger"); - - //Reset the form - ComunicWeb.pages.conversations.conversation.addSendMessageForm(); - } - }); - - return false; - } + // Unlock send button + sendButton.disabled = false; + }); }, /** diff --git a/assets/js/typings/ServerConfig.d.ts b/assets/js/typings/ServerConfig.d.ts index 0539f9a8..4a17e251 100644 --- a/assets/js/typings/ServerConfig.d.ts +++ b/assets/js/typings/ServerConfig.d.ts @@ -21,7 +21,7 @@ declare interface DataConservationPolicySettings { min_comments_lifetime: number, min_posts_lifetime: number, min_conversation_messages_lifetime: number, - min_likes_lifetime: number0 + min_likes_lifetime: number } declare interface StaticServerConfig { @@ -30,5 +30,10 @@ declare interface StaticServerConfig { play_store_url: string, android_direct_download_url: string, password_policy: PasswordPolicy, - data_conservation_policy: DataConservationPolicySettings; + data_conservation_policy: DataConservationPolicySettings, + + min_conversation_message_len: number, + max_conversation_message_len: number, + allowed_conversation_files_type: String[], + conversation_files_max_size: number, } \ No newline at end of file