]> Repos - mime-chat/commitdiff
Updated smart form
authorAndrew Gundersen <gundersena@xavier.edu>
Mon, 4 Apr 2022 13:02:16 +0000 (08:02 -0500)
committerAndrew Gundersen <gundersena@xavier.edu>
Mon, 4 Apr 2022 13:02:16 +0000 (08:02 -0500)
notarize.js
src/render/components/control/valid.js [new file with mode: 0644]
src/render/components/form.js
src/render/components/login.js

index cd3b19ab94bef02659528fefa7b2f46a49c06ece..10acfcb4d16bf838174a10013fc199c131753d11 100644 (file)
@@ -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 (file)
index 0000000..dbb710e
--- /dev/null
@@ -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
index fbc7b0ef8033e2ae29e69f4748e3fa39ac726e71..ecc02f32b562d773bf48cfc3af8d9c19b8559c15 100644 (file)
@@ -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: `
-        <form id="smart-form" class="smart-form">
+        <form id="smart-form" class="smart-form" v-on:input="preSub">
 
             <div v-for="field in fields" style="display:flex">
 
-                <input type="text" class="text-field"
+                <input type="text" class="text-field" 
+                    v-model="field.value"
                     :name="field.name"
-                    :value="field.value"
                     :placeholder="field.placeholder"
                 />
 
             </div>
 
-            <div class="smart-form-logs"></div>
+            <div class="smart-form-logs">{{ log }}</div>
 
         </form>`
 }
 
 export default SmartForm;
+
+
+
index f9a0f54b24345b88210f2db4e0ed0476e36536a7..d1df74a94d8c9f62e3cb210426d94d6fa0630725 100644 (file)
@@ -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 =
         </div>`
 }
 
-export default Login;
\ No newline at end of file
+export default Login;