From 78eb4050ae5ef5ff20e0676a704fb5b9c8df17f9 Mon Sep 17 00:00:00 2001 From: Andrew Gundersen Date: Mon, 4 Apr 2022 08:02:16 -0500 Subject: [PATCH] Updated smart form --- notarize.js | 43 ++++++++---- src/render/components/control/valid.js | 23 +++++++ src/render/components/form.js | 93 +++++++++++++------------- src/render/components/login.js | 12 ++-- 4 files changed, 109 insertions(+), 62 deletions(-) create mode 100644 src/render/components/control/valid.js diff --git a/notarize.js b/notarize.js index cd3b19a..10acfcb 100644 --- a/notarize.js +++ b/notarize.js @@ -2,8 +2,9 @@ const exec = require('child_process').exec; const sign = require("electron-osx-sign").signAsync; const notarize = require("electron-notarize").notarize; -const app = "Crimata.app"; -const dir = `${app}/Contents/Resources/app`; +const name = "Crimata"; +const dir = `${name}.app/Contents/Resources/app`; +const registry = "https://gitlab.com/api/v4/projects/25637892/packages/generic/crimata/0.0.1/Crimata.zip"; const runShellCommand = (cmd) => (new Promise((resolve, reject) => { exec(cmd, (error, stdout, stderr) => { @@ -11,8 +12,11 @@ const runShellCommand = (cmd) => (new Promise((resolve, reject) => { }); })); +// /projects/:id/packages/generic/:package_name/:package_version/:file_name?status=:status + + const signConfig = { - "app": app, + "app": name + ".app", "hardened-runtime": true, "gatekeeper-assess": false, "signature-flags": "library", @@ -21,7 +25,7 @@ const signConfig = { }; const notarizeConfig = { - appPath: app, + appPath: name + ".app", appleId: "gundersena@crimata.com", appBundleId: "com.crimata.CrimataMessenger", appleIdPassword: process.env["AC_PASSWORD"] @@ -31,18 +35,24 @@ const notarizeConfig = { try { - console.log("Building..."); - await runShellCommand(`rm -rf ${dir} && mkdir ${dir} && cp -r {package.json,src,node_modules} ${dir} - `); + // console.log("Building..."); + // await runShellCommand(`rm -rf ${dir} && mkdir ${dir} && cp -r {package.json,src,node_modules} ${dir} + // `); + + // console.log("Cleaning..."); + // await runShellCommand(`xattr -cr ${name}.app`); - console.log("Cleaning..."); - await runShellCommand(`xattr -cr ${app}`); + // console.log("Signing..."); + // await sign(signConfig); - console.log("Signing..."); - await sign(signConfig); + // console.log("Notarizing..."); + // await notarize(notarizeConfig); - console.log("Notarizing..."); - await notarize(notarizeConfig); + // console.log("Compressing..."); + // await runShellCommand(`zip -vr ${name}.zip ${name}.app`); + + console.log("Uploading to Gitlab..."); + await runShellCommand(`curl --header "PRIVATE-TOKEN: ${process.env["API_TOKEN"]}" --upload-file ${name}.zip "${registry}"`); } catch (e) { @@ -50,3 +60,10 @@ const notarizeConfig = { } })(); + + +/** + * Copy file from local to remote: + * + * scp -r Electron.app gundersena@crimata-server:~/Desktop/crimata/website/assets + */ \ No newline at end of file diff --git a/src/render/components/control/valid.js b/src/render/components/control/valid.js new file mode 100644 index 0000000..dbb710e --- /dev/null +++ b/src/render/components/control/valid.js @@ -0,0 +1,23 @@ +export const isEmail = (value) => { + console.log(value); + if (!/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(value)) { + return "Not a valid email." + } +} + +export const isPassword = (value) => { + if (!/^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/.test(value)) { + return "Password must have symbol, number, uppercase and be 6-16 length."; + } +} + +/** + * Name is optional and therefore doesn't return error if no value. + */ +export const isName = (value) => { + if (value) { + if (!/^([a-zA-Z ]){5,30}$/.test(value)) { + return "Name must be at least 5 long."; + } + } +} \ No newline at end of file diff --git a/src/render/components/form.js b/src/render/components/form.js index fbc7b0e..ecc02f3 100644 --- a/src/render/components/form.js +++ b/src/render/components/form.js @@ -1,83 +1,86 @@ -const debounce = (fn, delay) => { +// Basic debounce implentation +const debounce = (fn, delay) => { let timeoutId; - - const wrapper = (...args) => { - - if (timeoutId) { - clearTimeout(timeoutId); - } - + return (...args) => { + if (timeoutId) clearTimeout(timeoutId); timeoutId = setTimeout(() => { fn(...args); }, delay); - } - - return wrapper; } - - -const SmartForm = +/** + * Dynamic form component with auto submission and validation. + * + * props + * .fields => List of field objects + * .channel => e.g. "/login" + * .modifier => Form description + */ +const SmartForm = { props: ["fields", "channel", "modifier"], setup(props) { - let logsEl; - - const submit = debounce(async (data) => { - - let object = {}; - data.forEach(function(value, key){ - object[key] = value; - }); - - const err = await window.mainApi.invoke(props.channel, object) - - if (err) { - logsEl.innerText = err; - logsEl.style.color = "red"; - return; + // Error log below form + const log = Vue.ref(props.modifier); + + /** + * Valid and submit form data to channel. + */ + const submit = async () => { + + // Validate each field + for (let field of props.fields) { + const error = field.valid(field.value); + if (error) return error; } - logsEl.style.color = "green"; - logsEl.innerText = props.modifier; - - }, 2000); + // Reduce fields into the form + const form = props.fields.reduce((v, n) => { + v[n.name] = n.value; + return v; + }, {}); - Vue.onMounted(() => { + console.log("Submitting =>", form); + return await window.mainApi.invoke(props.channel, form); + } - const el = document.getElementById("smart-form"); + /** + * Wrapper for submit that is debounced and updates UI elements + */ + const preSub = debounce(async () => { - logsEl = el.querySelector(".smart-form-logs"); + const error = await submit(); - logsEl.innerText = props.modifier; + log.value = error ? error : props.modifier - el.addEventListener("input", () => { - submit(new FormData(el)) - }); + }, 2000); - }); + return { preSub, log }; }, template: ` -
+
-
-
+
{{ log }}
` } export default SmartForm; + + + diff --git a/src/render/components/login.js b/src/render/components/login.js index f9a0f54..d1df74a 100644 --- a/src/render/components/login.js +++ b/src/render/components/login.js @@ -1,4 +1,5 @@ import SmartForm from "./form.js"; +import { isEmail, isPassword, isName } from "./control/valid.js"; const Login = { @@ -8,7 +9,7 @@ const Login = setup() { - return; + return { isEmail, isPassword, isName }; }, template: ` @@ -19,16 +20,19 @@ const Login = name: 'email', value: null, placeholder: 'Email', + valid: isEmail }, { name: 'password', value: null, - placeholder: 'Password' + placeholder: 'Password', + valid: isPassword }, { name: 'name', value: null, - placeholder: 'Name' + placeholder: 'Name', + valid: isName }]" :channel="'auth'" :modifier="'Login or enter name to register.'" @@ -37,4 +41,4 @@ const Login = ` } -export default Login; \ No newline at end of file +export default Login; -- 2.43.0