diff --git a/README.md b/README.md index f2d817b00..060e18d04 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,10 @@ Welcome to the Headstorm interview challenge! This repository is designed for c ### Challenges These are domain specific problems that can be submitted individually. You can choose from backend, frontend, databases, or data-science. You can submit a PR for one, many, or all the challenges. +*** SERVER RUNS ON PORT 3000 *** +Frontend Challenge -> Contact page available at /contact.html +Backend Challenge -> requires a json input with key "numbers" and value being a list of integers +Database Challenge -> In order to start migration function hit endpoint /migrate with GET + ### Interviews These are language specific interview questions and you can choose the language in which you implement your solution. diff --git a/backend_challenge.txt b/backend_challenge.txt new file mode 100644 index 000000000..3666bf1a2 --- /dev/null +++ b/backend_challenge.txt @@ -0,0 +1,29 @@ +Relational Data Model + + + + +Customers ++--------------+--------------+--------------+--------------+-------------+------------+ +|RecordID |Name |Cell |Work |Email |Address | ++--------------+--------------+--------------+--------------+-------------+------------+ + ^ + | + | + | +Options | ++--------------+--------------------+---------------------+ +|RecordID |Basic Widget Order |Advanced Widget Order| ++--------------+--------------------+---------------------+ + ^ + | + | + | +Plans | ++--------------+--------------------+ +|RecordID |Protection Plan | ++--------------+--------------------+ + +INSERT INTO Customers(RecordID, Name, Cell, Work, Email, Address) Values(v1, v2, v3, v4, v5, v6) +INSERT INTO Options(RecordID, Basic Widget Order, Advanced Widget Order) Values(v1, v2, v3) +INSERT INTO Plans(RecordID, Protection Plan) Values(v1, v2) \ No newline at end of file diff --git a/customers.json b/customers.json new file mode 100644 index 000000000..6669f007d --- /dev/null +++ b/customers.json @@ -0,0 +1,59 @@ +{ + "customers" : [ + { + "RecordID" : 1, + "Name" : "Joe Smith", + "CellPhone" : "405.867.5309", + "WorkPhone" : "405.867.5309", + "Email" : "joe_s@gmail.com", + "Address" : "123 Vic Way, Dallas TX 75001", + "BasicWidgetOrder" : 37, + "AdvancedWidgetOrder" : 12, + "ProtectionPlan" : "True" + }, + { + "RecordID" : 2, + "Name" : "Luke Skywalker", + "CellPhone" : "405.867.5309", + "WorkPhone" : "405.867.5309", + "Email" : "joe_s@gmail.com", + "Address" : "123 Vic Way, Dallas TX 75001", + "BasicWidgetOrder" : 37, + "AdvancedWidgetOrder" : 12, + "ProtectionPlan" : "False" + }, + { + "RecordID" : 3, + "Name" : "Darth Vader", + "CellPhone" : "405.867.5309", + "WorkPhone" : "405.867.5309", + "Email" : "dv@gmail.com", + "Address" : "Death Star, Space", + "BasicWidgetOrder" : 37, + "AdvancedWidgetOrder" : 12, + "ProtectionPlan" : "False" + }, + { + "RecordID" : 4, + "Name" : "Han Solo", + "CellPhone" : "405.867.5309", + "WorkPhone" : "405.867.5309", + "Email" : "hs@gmail.com", + "Address" : "123 test Way, Dallas TX 75001", + "BasicWidgetOrder" : 37, + "AdvancedWidgetOrder" : 12, + "ProtectionPlan" : "False" + }, + { + "RecordID" : 5, + "Name" : "Chewbacca", + "CellPhone" : "405.867.5309", + "WorkPhone" : "405.867.5309", + "Email" : "cw@gmail.com", + "Address" : "123 fake Way, Dallas TX 75001", + "BasicWidgetOrder" : 37, + "AdvancedWidgetOrder" : 12, + "ProtectionPlan" : "False" + } + ] +} \ No newline at end of file diff --git a/main.exe b/main.exe new file mode 100644 index 000000000..1dc42b656 Binary files /dev/null and b/main.exe differ diff --git a/main.go b/main.go new file mode 100644 index 000000000..31be0e01a --- /dev/null +++ b/main.go @@ -0,0 +1,163 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "sort" + "strings" + + "github.com/gofiber/fiber/v2" +) + +//DATABASE CHALLENGE STRUCTS + +type Customers struct { + Customers []Customer `json:"customers"` +} + +type Customer struct { + RecordID int `json:"RecordID"` + Name string `json:"Name"` + Cell string `json:"CellPhone"` + Work string `json:"WorkPhone"` + Email string `json:"Email"` + Address string `json:"Address"` + BasicWidgetOrder int `json:"BasicWidgetOrder"` + AdvancedWidgetOrder int `json:"AdvancedWidgetOrder"` + ProtectionPlan string `json:"ProtectionPlan"` +} + +//BACKEND CHALLENGE STRUCTS + +type ErrorResponse struct { + Status string `json:"status"` + StatusCode string `json:"status_code"` + Message string `json:"message"` +} + +type SuccessResponse struct { + Status string `json:"status"` + StatusCode string `json:"status_code"` + Data []int `json:"data"` +} + +type NumberList struct { + Numbers []int `json:"numbers"` +} + +var n NumberList + +func main() { + app := fiber.New() + + //Create struct from list of numbers sent through POST + app.Post("/data", func(c *fiber.Ctx) error { + c.Accepts("application/json") + + //error if not sending a list of ints + if err := c.BodyParser(&n); err != nil { + e := ErrorResponse{ + Status: "ERROR", + StatusCode: "INCORRECT-TYPE", + Message: "Numbers can only accept a list of integers", + } + fmt.Println(err) + return c.JSON(e) + } + //error if list is less thatn 500 + if len(n.Numbers) < 500 { + e := ErrorResponse{ + Status: "ERROR", + StatusCode: "INCORRECT-SIZE", + Message: "The list of numbers sent is under the required amount of 500.", + } + return c.JSON(e) + } + //error if list is greater than 500 + if len(n.Numbers) > 500 { + e := ErrorResponse{ + Status: "ERROR", + StatusCode: "INCORRECT-SIZE", + Message: "The list of numbers sent is over the required amount of 500.", + } + return c.JSON(e) + } + + success := SuccessResponse{ + Status: "success", + StatusCode: "RECIEVED", + Data: n.Numbers, + } + return c.JSON(success) + }) + + //GET list of numbers from previous post request + app.Get("/data", func(c *fiber.Ctx) error { + //error if array of 500 ints does not exist or is not the correct size + if len(n.Numbers) != 500 { + e := ErrorResponse{ + Status: "ERROR", + StatusCode: "INCORRECT-SIZE", + Message: "The list of numbers does not meet the required size amount of 500. Please send a new list.", + } + return c.JSON(e) + } + //sort array from previous request + sort.Slice(n.Numbers, func(i, j int) bool { + return n.Numbers[i] < n.Numbers[j] + }) + + success := SuccessResponse{ + Status: "success", + StatusCode: "SORTED", + Data: n.Numbers, + } + return c.JSON(success) // => ✋ register + }) + + app.Get("/migrate", func(c *fiber.Ctx) error { + //Migrate data + fmt.Println("Migrating Customers") + dbMigrate() + return c.JSON("Migrating Customers...") + }) + + //serve all static public files + app.Static("/", "./public") + //listen on port 3000 + app.Listen(":3000") + +} + +func dbMigrate() { + var customers Customers + //open json file + jsonFile, err := os.Open("customers.json") + if err != nil { + fmt.Println(err) + } + fmt.Println("Successfully Opened customers.json") + //defer close to parse later + defer jsonFile.Close() + + byteVal, _ := ioutil.ReadAll(jsonFile) + json.Unmarshal(byteVal, &customers) + + for _, c := range customers.Customers { + fmt.Printf("*** MIGRATION FOR CUSTOMER# %v ***\n", c.RecordID) + //insertion for customer table// + fmt.Printf("INSERT INTO customers (record_id, name, cell_phone, work_phone, email, address) VALUES (%v, %v, %v, %v, %v, %v)\n", c.RecordID, c.Name, c.Cell, c.Work, c.Email, c.Address) + //insertion for options table// + fmt.Printf("INSERT INTO options (record_id, basic_widget_order, advanced_widget_order) VALUES (%v, %v, %v)\n", c.RecordID, c.BasicWidgetOrder, c.AdvancedWidgetOrder) + //convert boolean protection plan value to int + prot_plan := 0 + if strings.ToLower(c.ProtectionPlan) == "true" { + prot_plan = 1 + } + //insertion for plans table// + fmt.Printf("INSERT INTO plans (record_id, protection_plan) VALUES (%v, %v)\n", c.RecordID, prot_plan) + fmt.Printf("\n") + } +} diff --git a/public/contact.html b/public/contact.html new file mode 100644 index 000000000..85ab06300 --- /dev/null +++ b/public/contact.html @@ -0,0 +1,109 @@ + + + + + + + + Headstorm + + + + + + + + + + + + + +
+
+
Contact Us
+
+
+
+ + +
+
+ + +
+
+
+
+
+ + + +
+
+ + +
+
We'll never share your contact information with anyone else.
+
+
+
+
+ + +
+
+
+ +
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js new file mode 100644 index 000000000..a9e4baa72 --- /dev/null +++ b/public/js/main.js @@ -0,0 +1,40 @@ +$(function() { + + //VALIDATES AND PRINTS DATA + $.fn.validate = function(elem) { + //get form values + submission.fname = $("#firstname").val(); + submission.lname = $("#lastname").val(); + submission.email = $("#email").val(); + submission.phone = $("#phone").val(); + submission.msg = $("#message").val(); + //validate object + for (var key in submission) { + if (submission[key] == null || submission[key] == "") + return alert("Please complete the form"); + } + //Dump form info into the browser developer console + console.log("Client First Name: " + submission.fname); + console.log("Client Last Name: " + submission.lname); + console.log("Client Email: " + submission.email); + console.log("Client Phone: " + submission.phone); + console.log("Client Message: " + submission.msg); + + //success and clear form + alert("We will be in contact with you shortly!"); + $.fn.clearForm(); + } + + //RESETS CONTACT FORM// + $.fn.clearForm = function() { + $("#firstname").val(""); + $("#lastname").val(""); + $("#email").val(""); + $("#phone").val(""); + $("#message").val(""); + grecaptcha.reset(); + $("#submit").prop("disabled", true); + + } + +}); \ No newline at end of file