diff --git a/app/models/meme.js b/app/models/meme.js index 901a0e99..3b42ba25 100644 --- a/app/models/meme.js +++ b/app/models/meme.js @@ -53,50 +53,41 @@ MEME.virtual("url").get(function () { return "http://" + setup.host + "/meme/" + this._id; }); -/** - * Shared API / Web request job spawn - */ + MEME.statics.spawn = function (fn, options, callback) { const Msa = mongoose.model("Msa"); - var meme = new this(); + const meme = new this(); - let gencodeid = options.gencodeid, - datatype = options.datatype; - - meme.mail = options.mail; + // Dynamically add all options to the meme object + Object.keys(options).forEach((key) => { + meme[key] = options[key]; + }); // Check advanced options - if (!_.isNaN(options.resample)) { - meme.resample = options.resample; - meme.bootstrap = true; - } else { - meme.bootstrap = false; - } + meme.bootstrap = !_.isNaN(options.resample); const connect_callback = function (data) { - if (data == "connected") { + if (data === "connected") { logger.log("connected"); } }; - Msa.parseFile(fn, datatype, gencodeid, (err, msa) => { + Msa.parseFile(fn, options.datatype, options.gencodeid, (err, msa) => { if (err) { callback(err); return; } + // Check if msa exceeds limitations if (msa.sites > meme.max_sites) { - const error = - "Site limit exceeded! Sites must be less than " + meme.max_sites; + const error = `Site limit exceeded! Sites must be less than ${meme.max_sites}`; logger.error(error); callback(error); return; } if (msa.sequences > meme.max_sequences) { - var error = - "Sequence limit exceeded! Sequences must be less than " + - meme.max_sequences; + const error = `Sequence limit exceeded! Sequences must be less than ${meme.max_sequences}`; logger.error(error); callback(error); return; @@ -112,32 +103,25 @@ MEME.statics.spawn = function (fn, options, callback) { return; } - function move_cb(err, result) { + function move_cb(err) { if (err) { logger.error( - "meme rename failed" + - " Errored on line 113~ within models/meme.js :: move_cb " + - err, + `meme rename failed. Error on line 113~ within models/meme.js :: move_cb ${err}`, ); callback(err, null); } else { - var move = Msa.removeTreeFromFile( - meme_result.filepath, - meme_result.filepath, - ); - move.then( - (val) => { - let to_send = meme; - to_send.upload_redirect_path = meme.upload_redirect_path; + Msa.removeTreeFromFile(meme_result.filepath, meme_result.filepath) + .then(() => { + meme.upload_redirect_path = meme.upload_redirect_path; this.submitJob(meme_result, connect_callback); callback(null, meme); - }, - (reason) => { - res.json(500, { error: "issue removing tree from file" }); - }, - ); + }) + .catch(() => { + callback(new Error("issue removing tree from file")); + }); } } + helpers.moveSafely(fn, meme_result.filepath, move_cb.bind(this)); }); }); diff --git a/app/models/msa.js b/app/models/msa.js index c3dfb6eb..a9cb7d86 100644 --- a/app/models/msa.js +++ b/app/models/msa.js @@ -65,12 +65,12 @@ Msa.virtual("genetic_code").get(function () { }); Msa.virtual("day_created_on").get(function () { - var time = moment(this.timestamp); + var time = moment.unix(this.timestamp); return time.format("YYYY-MMM-DD"); }); Msa.virtual("time_created_on").get(function () { - var time = moment(this.timestamp); + var time = moment.unix(this.timestamp); return time.format("HH:mm"); }); diff --git a/public/assets/js/meme/form.js b/public/assets/js/meme/form.js index aa353589..51f56d96 100644 --- a/public/assets/js/meme/form.js +++ b/public/assets/js/meme/form.js @@ -1,68 +1,114 @@ $(function () { + function toggleSiteMultihit() { + const multipleHitsValue = $("#multiple-hits").val(); + const siteMultihitDropdown = $("#site-multihit"); + + if (multipleHitsValue === "None") { + siteMultihitDropdown.prop("disabled", true); + siteMultihitDropdown.val("Estimate"); // Default value when disabled + } else { + siteMultihitDropdown.prop("disabled", false); + } + } + + // Initialize dependent dropdown states on page load + toggleSiteMultihit(); + + // Handle changes in multiple hits selection + $("#multiple-hits").change(function () { + toggleSiteMultihit(); + }); + + // Handle form submission $("form").submit(function (e) { e.preventDefault(); $("#file-progress").removeClass("hidden"); - var formData = new FormData(); - var file = document.getElementById("seq-file").files[0]; - var filename = document.getElementById("seq-file").files[0].name; + const formData = new FormData(); + + // File validation + const fileInput = document.getElementById("seq-file"); + const file = fileInput.files[0]; + if (!file) { + $("#modal-error-msg").text("Please select a file to upload."); + $("#errorModal").modal(); + return; + } formData.append("files", file); - formData.append("datatype", $("select[name='datatype']").val()); + + // Gather and validate form data formData.append("gencodeid", $("select[name='gencodeid']").val()); - formData.append("mail", $("input[name='mail']").val()); + formData.append("multiple_hits", $("#multiple-hits").val()); + formData.append("site_multihit", $("#site-multihit").val()); + formData.append("rates", $("#rates").val()); + formData.append("resample", $("#resample").val()); + formData.append("impute_states", $("#impute-states").val()); - var action_url = $("#msa-form").attr("action"); + const email = $("input[name='mail']").val(); + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (email && !emailRegex.test(email)) { + $("#modal-error-msg").text("Please enter a valid email address."); + $("#errorModal").modal(); + return; + } + formData.append("mail", email); - var xhr = new XMLHttpRequest(); + const actionUrl = $("#msa-form").attr("action"); - xhr.open("post", action_url, true); + // Create XMLHttpRequest + const xhr = new XMLHttpRequest(); + xhr.open("post", actionUrl, true); xhr.upload.onprogress = function (e) { if (e.lengthComputable) { - var percentage = (e.loaded / e.total) * 100; - - $("#seq-file").css("display", "none"); + const percentage = (e.loaded / e.total) * 100; $(".progress .progress-bar").css("width", percentage + "%"); } }; - xhr.onerror = function (e) { - $("#file-progress").html(e); + xhr.onerror = function () { + $("#modal-error-msg").text("An error occurred during the upload."); + $("#errorModal").modal(); }; - xhr.onload = function (res) { - // Replace field with green text, name of file - var result = JSON.parse(this.responseText); + xhr.onload = function () { + try { + const result = JSON.parse(this.responseText); - if (_.has(result, "error")) { - $("#modal-error-msg").text(result.error); - $("#errorModal").modal(); - $("#file-progress").css("display", "none"); - $("#seq-file").css("display", "block"); - $(".progress .progress-bar").css("width", "0%"); - } else if ("error" in result.analysis) { - $("#modal-error-msg").text(result.analysis.error); + if (result.error) { + $("#modal-error-msg").text(result.error); + $("#errorModal").modal(); + } else if (result.upload_redirect_path) { + window.location.href = result.upload_redirect_path; + } else { + $("#modal-error-msg").text( + "Unexpected response format from the server." + ); + $("#errorModal").modal(); + } + } catch (err) { + $("#modal-error-msg").text("Error parsing server response."); $("#errorModal").modal(); - $("#file-progress").css("display", "none"); - $("#seq-file").css("display", "block"); - $(".progress .progress-bar").css("width", "0%"); - } else if ("upload_redirect_path" in result) { - window.location.href = result.upload_redirect_path; - } else { - $("#modal-error-msg").text( - "We received data in an unexpected format from the server." - ); - $("#errorModal").modal(); - $("#file-progress").css("display", "none"); - $("#seq-file").css("display", "block"); + } finally { $(".progress .progress-bar").css("width", "0%"); + $("#file-progress").addClass("hidden"); } }; xhr.send(formData); }); - $(".mail-group").change(datamonkey.helpers.validate_email); + // Email validation on input + $("input[name='mail']").on("input", function () { + const email = $(this).val(); + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + + if (email && !emailRegex.test(email)) { + $(this).addClass("is-invalid"); + } else { + $(this).removeClass("is-invalid"); + } + }); });