diff --git a/.gitignore b/.gitignore index 3a86209..1f25bcd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ *.dll *.so *.dylib -mainsnow +mocksnow build/ # Certificates diff --git a/build/vctp b/build/vctp deleted file mode 100755 index e2a49ad..0000000 Binary files a/build/vctp and /dev/null differ diff --git a/cert.pem b/cert.pem index 6f3fcde..aa4216d 100644 --- a/cert.pem +++ b/cert.pem @@ -1,30 +1,30 @@ -----BEGIN CERTIFICATE----- -MIIFIjCCAwqgAwIBAgIRAJPUpRr9NQCFpDrCPlyM7JYwDQYJKoZIhvcNAQELBQAw -DzENMAsGA1UEChMERFRNUzAeFw0yNDA5MTIwMDU4NDFaFw0yNTA5MTIwMDU4NDFa -MA8xDTALBgNVBAoTBERUTVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDJhxPJHo/SqsEURebiRufmXRDYhl67PdglOGI6JC/VjCaqu42DYMO9tF6vuHBD -4/+/UpMBuOGTw+m6nEKdKKIZBuG0Hvka4bS0YPDHvqHZMWHK9qdPbmrB8q1N8W9F -Z+1gjIdeCK1wBjMTnfSxWOznKjffsz170bhOE6CHB4CP9nLMcShrvDcg0kTSbzM1 -ptlxWGI5vabkx9spPU65NWEjd645Z4kMIutJZJjVKPlAqRr/fFeNgE5A9VhwzBot -5ZupKIZYuUMAMYkXjOhdqxDbWqfc8lkUvk5Jd9XtYB81uzvfpoH28Th4ILAdZd9h -vPh38sB/FyxSeKPHmW0IP1r8+EW/57ZPnQrGAOWs2z8Fp812vwQV0sr8j1B5NiTz -yu7I47vDdKZxulWS48frASxFFz4OojZAsoP6LipAMPolGIrnFn1/6UlOPnSVqkUb -D36PEIkOzE9AzMaSD/qs+k9lVHo+VTHL/qmz6u6COQiPL0u/ZInMcQmzJecCSDm4 -Z8oVGeth+2vzlPo1iQHqptYYbln7oLaQZuCqdm4oNb+Hdyflhv8O78hUq7tcnQ8M -7/0jvlB6m1e4vuAxldBkaWr/cQudtzZnTiwHf2a3TH0h3ID0Gecog+hWb7EcAI2D -IK6Ji3uEBLag39XFuMzF/jLIUtYMz0Mb48v3Opbd8qe3aQIDAQABo3kwdzAOBgNV -HQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUZKrZX7aNZvhyG7HgIPznTYDeQ8QwIAYDVR0RBBkwF4IPbmF0 -aG1icDE0LmxvY2FshwQKAAGhMA0GCSqGSIb3DQEBCwUAA4ICAQCqKmraTwKEGsRz -DqYSu5IDuYiXymBsIgT9A2prnd7ztX35CDi4n2msFKX0njcOAkBnapzSpDM1pbF8 -a7H3F+pBfPZf1Cecgj1vooTImJgsS8SBR/otIjAQrX0G1DqcHoRfTDJ0iZZgE031 -59dqMJOQDUI7KrLm4hhqCsLt9TR1MYi9V5rDZOXBO6rQ78VBrD0q3aJI/27xlPeJ -T5rEmj0HQrNfFs1QQD5JOd5EDILJnioE8wR4l14vfrVhNzr5xt7OQk6GT7txIuyK -l+k0xfClTN7PUZNcO3MnM/XeNZwIy1G0Dfi4BfdVBzR2vK7wZOJnwK02SMUrxez7 -ZbtMra5hlDTT3KAgyYZs/u4rGjxG7r92A1vog3cuoVbrH3oEgqCHV6WId7ipxrmw -/3/S6X8M99jybg6Ac55pamiqx6PcJSnCKFwme1O+6yp0LEAIoRSdB8OkC6FSVmXs -tU5sNl4tqWL3BymVoiz7wpqJdZZEsinC9oE58nTN6k6pcd5pN04A/Uc7VySqN6Br -19v8Tn6JLIb/TLhUFGc25yMsDtgLN+bWC12RN2DXRakeM+330rKFxKgvIjNJzEPm -1HdxlfEMdRP1F3gTgHH8rVkh2a5VWlgnw3qKaOzjtFIdqGob7d1FJoaQgbD81Wqa -nNtoW4JrPFzi9P6EpTqci0IUCapgkQ== +MIIFITCCAwmgAwIBAgIQQDG29y2z55hHFZFmrmgW3jANBgkqhkiG9w0BAQsFADAP +MQ0wCwYDVQQKEwREVE1TMB4XDTI1MDMyNDA0MjM0NloXDTI2MDMyNDA0MjM0Nlow +DzENMAsGA1UEChMERFRNUzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AObGFq98DIBHhZS3/5jynja3WVZIv0Tb92RlYsQkqhA5wfy9AmWtD+7fXAy3Mfy4 +Q38/3RwNONWIRA9tdEhFS+veBPKRyw8HPq4jIMlF+sm+8pbU0Lr+vikMNekcaQMA +tFts6s37RAP7JYBh/IATYIVVibe9d/O0YpWZKHIa/AbyiWYSKpfnsprffBg+YyGC +kGIiqhDbt5ROKOHZloIovsReLyoj5aPDYuvGW6Nznx2PkARD4SMcWx03ytn1MRiN +/yk6ILg4xKWK0F3m97qwKAGSG1MleyfO4uuKsZGlUAjqUFFiCXUxD71YuI3f7yHB +EMPOV3zuv7iL5BDooGumBB8lmYYAbYDclSzSFbL07W6tFKHI9eMAyBiQTrnAiWm3 +EoLHaNtpQsmCdUZkgSyGF8ceK5CA42yHL7vEz8gTU8DpyjShdVOM1iDiaXhMLIyw +ibMmrVjYzqjKFxudkzwDF8g25lqqkZHQHx5U4BjPAwYkApfUQaHsQLp8fyhNQBpp +rNGUe373YplRENf80wGTsgYv4IzxZYMstnG1cRXDXTQwRGRk67kHZq3mF6n7ZIMQ +vsXXnaI2UT0QfjT3krY5lnAL6Pqbe13PccpS/VATBz+ATYmaYQYo6Z+iISNDabp8 +a7XWW8o1uA/+f650hqzm29ePfx/rMhlPwEIqLYXA2d9fAgMBAAGjeTB3MA4GA1Ud +DwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBQV+KDGnmuf2aRaPHrCck/31UZfdzAgBgNVHREEGTAXgg9uYXRo +bWJwMTQubG9jYWyHBAoAAaEwDQYJKoZIhvcNAQELBQADggIBAGQtEg4iaIwzPRVs +m1FX/jAJcqogiWoeNE46a7mbdKFC7LIlKIj/xpEvVBrnyoHs3ZMK9bZkyMgfAtts +oy3t1s7iHrxsiYi9MbKL3XSfslczgFxZm5Z+NgXMCuK5d1p6loxwJ5cTmfB4tvLp +dQMUnHudaUAsVGoGYhGrVQqbkQty5kray6dJMYveUOSOqbKH9ZogOcHU59IsZejn +J3PLdjEBLBd2zAQ05N5wUHBWL7gMfk8gguJqIBGFdBLIc9eVrq78lMh0OD/PpNZS +VsiwlLWqbYozDnygZvooQMn+m9q5sUEbyxj5oAorm3+zfSC3Sxik+te0k81402Aw +C4zJvzWohUFV+GcEsHYwzhnXAN3pHea506itef1tvI7dAJmWKhrdfegRb6HDpMUW +C8VX0rWODsWdFkKW3/ohKeW6Xjoq/hnFSOb5bwSCMfFxA9qy6fzCCvuVzuHsKC24 ++Nmwgk9LYSWzg/TUxQ9/SX+Q03oxlpnRl4hRNxluUtqCcujR/BZJjaRXtM0hv3Eq +bZnuy1yUegsBQYLFKRF0Qmh5iKDd+Q9znemeI6CTXLKqjTFYZCIaz1DoxJ+HfZdo +NrEWOC0sMChcP6Mdmnskf1xJWkFd8giCDxpuf0iY+jRNAJnHoMt1TMXiVTWHUwOj +4GxxaCrOp9+a+wQ0j3rI0c5D1H25 -----END CERTIFICATE----- diff --git a/components/core/footer_templ.go b/components/core/footer_templ.go index 7d4f27b..4ea6ef9 100644 --- a/components/core/footer_templ.go +++ b/components/core/footer_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.2.778 +// templ: version: v0.3.856 package core //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -29,11 +29,11 @@ func Footer() templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - return templ_7745c5c3_Err + return nil }) } diff --git a/components/core/header.templ b/components/core/header.templ index 980c6e6..642fc4b 100644 --- a/components/core/header.templ +++ b/components/core/header.templ @@ -10,5 +10,6 @@ templ Header() { mocksnow API + } \ No newline at end of file diff --git a/components/core/header_templ.go b/components/core/header_templ.go index 1c6c909..9c907d4 100644 --- a/components/core/header_templ.go +++ b/components/core/header_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.2.778 +// templ: version: v0.3.856 package core //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -31,7 +31,7 @@ func Header() templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("mocksnow APImocksnow API") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" rel=\"stylesheet\">") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + return nil }) } diff --git a/components/views/incoming.templ b/components/views/incoming.templ index 40b86d6..acd195d 100644 --- a/components/views/incoming.templ +++ b/components/views/incoming.templ @@ -26,47 +26,47 @@ templ IncomingTable(rows []IncomingRow) { @core.Header() - -
-
-

Incoming Incidents

-
- - + +
+
+

Incoming API Calls

+
+
+ - - - - - - - - - - - - - - + + + + + + + + + + + + + + for _, row := range rows { - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + } diff --git a/components/views/incoming_templ.go b/components/views/incoming_templ.go index 8d1affd..cb82688 100644 --- a/components/views/incoming_templ.go +++ b/components/views/incoming_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.2.778 +// templ: version: v0.3.856 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -9,8 +9,8 @@ import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" import ( - "strconv" "mocksnow/components/core" + "strconv" ) type IncomingRow struct { @@ -51,7 +51,7 @@ func IncomingTable(rows []IncomingRow) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -59,199 +59,199 @@ func IncomingTable(rows []IncomingRow) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Incoming Incidents

IDIncident #DescriptionShort DescriptionUrgencyImpactStateExternal IDWork NotesAssignment GroupAssigned ToCategorySubcategoryCreated AtIDIncident #DescriptionShort DescriptionUrgencyImpactStateExternal IDWork NotesAssignment GroupAssigned ToCategorySubcategoryCreated At
{ strconv.Itoa(row.ID) }{ row.IncidentNumber }{ row.Description }{ row.ShortDescription }{ row.Urgency }{ row.Impact }{ row.State }{ row.ExternalID }{ row.WorkNotes }{ row.AssignmentGroup }{ row.AssignedTo }{ row.Category }{ row.Subcategory }{ row.CreatedAt }
{ strconv.Itoa(row.ID) }{ row.IncidentNumber }{ row.Description }{ row.ShortDescription }{ row.Urgency }{ row.Impact }{ row.State }{ row.ExternalID }{ row.WorkNotes }{ row.AssignmentGroup }{ row.AssignedTo }{ row.Category }{ row.Subcategory }{ row.CreatedAt }
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

Incoming Incidents

IDIncident #DescriptionShort DescriptionUrgencyImpactStateExternal IDWork NotesAssignment GroupAssigned ToCategorySubcategoryCreated At
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } for _, row := range rows { - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
IDIncident #DescriptionShort DescriptionUrgencyImpactStateExternal IDWork NotesAssignment GroupAssigned ToCategorySubcategoryCreated At
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(strconv.Itoa(row.ID)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 56, Col: 80} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 56, Col: 62} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(row.IncidentNumber) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 57, Col: 78} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 57, Col: 60} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(row.Description) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 58, Col: 75} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 58, Col: 57} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var5 string templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(row.ShortDescription) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 59, Col: 80} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 59, Col: 62} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var6 string templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(row.Urgency) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 60, Col: 71} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 60, Col: 53} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var7 string templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(row.Impact) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 61, Col: 70} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 61, Col: 52} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var8 string templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(row.State) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 62, Col: 69} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 62, Col: 51} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var9 string templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(row.ExternalID) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 63, Col: 74} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 63, Col: 56} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var10 string templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(row.WorkNotes) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 64, Col: 73} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 64, Col: 55} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var11 string templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(row.AssignmentGroup) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 65, Col: 79} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 65, Col: 61} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var12 string templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(row.AssignedTo) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 66, Col: 74} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 66, Col: 56} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var13 string templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(row.Category) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 67, Col: 72} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 67, Col: 54} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var14 string templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(row.Subcategory) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 68, Col: 75} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 68, Col: 57} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } var templ_7745c5c3_Var15 string templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(row.CreatedAt) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 69, Col: 73} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `views/incoming.templ`, Line: 69, Col: 55} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -259,11 +259,11 @@ func IncomingTable(rows []IncomingRow) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - return templ_7745c5c3_Err + return nil }) } diff --git a/components/views/index_templ.go b/components/views/index_templ.go index 4dcf9f8..d3859d2 100644 --- a/components/views/index_templ.go +++ b/components/views/index_templ.go @@ -1,6 +1,6 @@ // Code generated by templ - DO NOT EDIT. -// templ: version: v0.2.778 +// templ: version: v0.3.856 package views //lint:file-ignore SA4006 This context is only used if a nested component is present. @@ -39,7 +39,7 @@ func Index(info BuildInfo) templ.Component { templ_7745c5c3_Var1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -47,7 +47,7 @@ func Index(info BuildInfo) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Build Information

Build Time: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "

Build Information

Build Time: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -60,7 +60,7 @@ func Index(info BuildInfo) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

SHA1 Version: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "

SHA1 Version: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -73,7 +73,7 @@ func Index(info BuildInfo) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Go Runtime Version: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

Go Runtime Version: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -86,7 +86,7 @@ func Index(info BuildInfo) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -94,11 +94,11 @@ func Index(info BuildInfo) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - return templ_7745c5c3_Err + return nil }) } diff --git a/db/migrations/20250324011119_extend_incidents.sql b/db/migrations/20250324011119_extend_incidents.sql new file mode 100644 index 0000000..4049138 --- /dev/null +++ b/db/migrations/20250324011119_extend_incidents.sql @@ -0,0 +1,30 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE incidents ADD COLUMN incident_number TEXT; +ALTER TABLE incidents ADD COLUMN description TEXT; +ALTER TABLE incidents ADD COLUMN short_description TEXT; +ALTER TABLE incidents ADD COLUMN urgency INTEGER; +ALTER TABLE incidents ADD COLUMN impact INTEGER; +ALTER TABLE incidents ADD COLUMN state INTEGER; +-- ALTER TABLE incidents ADD COLUMN work_notes TEXT; +ALTER TABLE incidents ADD COLUMN assignment_group TEXT; +ALTER TABLE incidents ADD COLUMN assigned_to TEXT; +ALTER TABLE incidents ADD COLUMN category TEXT; +ALTER TABLE incidents ADD COLUMN subcategory TEXT; +ALTER TABLE incidents ADD COLUMN sys_id TEXT; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE incidents DROP COLUMN incident_number; +ALTER TABLE incidents DROP COLUMN description; +ALTER TABLE incidents DROP COLUMN short_description; +ALTER TABLE incidents DROP COLUMN urgency; +ALTER TABLE incidents DROP COLUMN impact; +ALTER TABLE incidents DROP COLUMN state; +ALTER TABLE incidents DROP COLUMN assignment_group; +ALTER TABLE incidents DROP COLUMN assigned_to; +ALTER TABLE incidents DROP COLUMN category; +ALTER TABLE incidents DROP COLUMN subcategory; +ALTER TABLE incidents DROP COLUMN sys_id; +-- +goose StatementEnd diff --git a/db/migrations/20250324011340_worknotes.sql b/db/migrations/20250324011340_worknotes.sql new file mode 100644 index 0000000..a010219 --- /dev/null +++ b/db/migrations/20250324011340_worknotes.sql @@ -0,0 +1,13 @@ +-- +goose Up +-- +goose StatementBegin +CREATE TABLE worknotes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + incident_number TEXT NOT NULL, -- must map to an incidents.incident_number + note TEXT +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +DROP TABLE IF EXISTS worknotes; +-- +goose StatementEnd diff --git a/db/queries/models.go b/db/queries/models.go index 92a815f..e62fd85 100644 --- a/db/queries/models.go +++ b/db/queries/models.go @@ -9,9 +9,20 @@ import ( ) type Incident struct { - ID int64 - ExternalID string - CreatedAt sql.NullTime + ID int64 + ExternalID string + CreatedAt sql.NullTime + IncidentNumber sql.NullString + Description sql.NullString + ShortDescription sql.NullString + Urgency sql.NullInt64 + Impact sql.NullInt64 + State sql.NullInt64 + AssignmentGroup sql.NullString + AssignedTo sql.NullString + Category sql.NullString + Subcategory sql.NullString + SysID sql.NullString } type Incoming struct { @@ -30,3 +41,9 @@ type Incoming struct { Subcategory sql.NullString CreatedAt sql.NullTime } + +type Worknote struct { + ID int64 + IncidentNumber string + Note sql.NullString +} diff --git a/db/queries/query.sql b/db/queries/query.sql index a311b0d..1a9963b 100644 --- a/db/queries/query.sql +++ b/db/queries/query.sql @@ -2,7 +2,6 @@ SELECT * FROM "Incoming" ORDER BY "id"; - -- name: CreateIncoming :one INSERT INTO "Incoming" ( "incident_number", "description", "short_description", "urgency", "impact", "state", "external_id", "work_notes", "assignment_group", "assigned_to", "category", "subcategory", "created_at" @@ -12,6 +11,49 @@ INSERT INTO "Incoming" ( RETURNING *; -- name: CreateIncident :one -INSERT INTO incidents (external_id) -VALUES (?) -RETURNING id; +INSERT INTO incidents ( + "description", "short_description", "urgency", "impact", "state", "external_id", "assignment_group", "assigned_to", "category", "subcategory", "created_at", "sys_id" +) VALUES( + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? +) +RETURNING *; + +-- name: UpdateIncidentNumber :exec +UPDATE incidents +SET incident_number = sqlc.arg('incidentNumber') +WHERE external_id = sqlc.arg('externalId'); + +-- name: UpdateIncidentState :exec +UPDATE incidents +SET state = sqlc.arg('state') +WHERE incident_number = sqlc.arg('incidentNumber'); + +-- name: UpdateIncident :exec +UPDATE incidents +SET + external_id = ?, + description = ?, + short_description = ?, + urgency = ?, + impact = ?, + state = ?, + assignment_group = ?, + assigned_to = ?, + category = ?, + subcategory = ? +WHERE incident_number = ?; + +-- name: GetIncident :one +SELECT * from incidents +WHERE incident_number = sqlc.arg('incidentNumber'); + +-- name: ListIncidents :many +SELECT * FROM incidents; + +-- name: CreateWorkNote :one +INSERT into worknotes ( + "incident_number", "note" +) VALUES( + ?, ? +) +RETURNING *; \ No newline at end of file diff --git a/db/queries/query.sql.go b/db/queries/query.sql.go index ac5289c..e3e087d 100644 --- a/db/queries/query.sql.go +++ b/db/queries/query.sql.go @@ -11,16 +11,62 @@ import ( ) const createIncident = `-- name: CreateIncident :one -INSERT INTO incidents (external_id) -VALUES (?) -RETURNING id +INSERT INTO incidents ( + "description", "short_description", "urgency", "impact", "state", "external_id", "assignment_group", "assigned_to", "category", "subcategory", "created_at", "sys_id" +) VALUES( + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? +) +RETURNING id, external_id, created_at, incident_number, description, short_description, urgency, impact, state, assignment_group, assigned_to, category, subcategory, sys_id ` -func (q *Queries) CreateIncident(ctx context.Context, externalID string) (int64, error) { - row := q.db.QueryRowContext(ctx, createIncident, externalID) - var id int64 - err := row.Scan(&id) - return id, err +type CreateIncidentParams struct { + Description sql.NullString + ShortDescription sql.NullString + Urgency sql.NullInt64 + Impact sql.NullInt64 + State sql.NullInt64 + ExternalID string + AssignmentGroup sql.NullString + AssignedTo sql.NullString + Category sql.NullString + Subcategory sql.NullString + CreatedAt sql.NullTime + SysID sql.NullString +} + +func (q *Queries) CreateIncident(ctx context.Context, arg CreateIncidentParams) (Incident, error) { + row := q.db.QueryRowContext(ctx, createIncident, + arg.Description, + arg.ShortDescription, + arg.Urgency, + arg.Impact, + arg.State, + arg.ExternalID, + arg.AssignmentGroup, + arg.AssignedTo, + arg.Category, + arg.Subcategory, + arg.CreatedAt, + arg.SysID, + ) + var i Incident + err := row.Scan( + &i.ID, + &i.ExternalID, + &i.CreatedAt, + &i.IncidentNumber, + &i.Description, + &i.ShortDescription, + &i.Urgency, + &i.Impact, + &i.State, + &i.AssignmentGroup, + &i.AssignedTo, + &i.Category, + &i.Subcategory, + &i.SysID, + ) + return i, err } const createIncoming = `-- name: CreateIncoming :one @@ -84,6 +130,96 @@ func (q *Queries) CreateIncoming(ctx context.Context, arg CreateIncomingParams) return i, err } +const createWorkNote = `-- name: CreateWorkNote :one +INSERT into worknotes ( + "incident_number", "note" +) VALUES( + ?, ? +) +RETURNING id, incident_number, note +` + +type CreateWorkNoteParams struct { + IncidentNumber string + Note sql.NullString +} + +func (q *Queries) CreateWorkNote(ctx context.Context, arg CreateWorkNoteParams) (Worknote, error) { + row := q.db.QueryRowContext(ctx, createWorkNote, arg.IncidentNumber, arg.Note) + var i Worknote + err := row.Scan(&i.ID, &i.IncidentNumber, &i.Note) + return i, err +} + +const getIncident = `-- name: GetIncident :one +SELECT id, external_id, created_at, incident_number, description, short_description, urgency, impact, state, assignment_group, assigned_to, category, subcategory, sys_id from incidents +WHERE incident_number = ?1 +` + +func (q *Queries) GetIncident(ctx context.Context, incidentnumber sql.NullString) (Incident, error) { + row := q.db.QueryRowContext(ctx, getIncident, incidentnumber) + var i Incident + err := row.Scan( + &i.ID, + &i.ExternalID, + &i.CreatedAt, + &i.IncidentNumber, + &i.Description, + &i.ShortDescription, + &i.Urgency, + &i.Impact, + &i.State, + &i.AssignmentGroup, + &i.AssignedTo, + &i.Category, + &i.Subcategory, + &i.SysID, + ) + return i, err +} + +const listIncidents = `-- name: ListIncidents :many +SELECT id, external_id, created_at, incident_number, description, short_description, urgency, impact, state, assignment_group, assigned_to, category, subcategory, sys_id FROM incidents +` + +func (q *Queries) ListIncidents(ctx context.Context) ([]Incident, error) { + rows, err := q.db.QueryContext(ctx, listIncidents) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Incident + for rows.Next() { + var i Incident + if err := rows.Scan( + &i.ID, + &i.ExternalID, + &i.CreatedAt, + &i.IncidentNumber, + &i.Description, + &i.ShortDescription, + &i.Urgency, + &i.Impact, + &i.State, + &i.AssignmentGroup, + &i.AssignedTo, + &i.Category, + &i.Subcategory, + &i.SysID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const listIncoming = `-- name: ListIncoming :many SELECT id, incident_number, description, short_description, urgency, impact, state, external_id, work_notes, assignment_group, assigned_to, category, subcategory, created_at FROM "Incoming" ORDER BY "id" @@ -126,3 +262,35 @@ func (q *Queries) ListIncoming(ctx context.Context) ([]Incoming, error) { } return items, nil } + +const updateIncidentNumber = `-- name: UpdateIncidentNumber :exec +UPDATE incidents +SET incident_number = ?1 +WHERE external_id = ?2 +` + +type UpdateIncidentNumberParams struct { + IncidentNumber sql.NullString + ExternalId string +} + +func (q *Queries) UpdateIncidentNumber(ctx context.Context, arg UpdateIncidentNumberParams) error { + _, err := q.db.ExecContext(ctx, updateIncidentNumber, arg.IncidentNumber, arg.ExternalId) + return err +} + +const updateIncidentState = `-- name: UpdateIncidentState :exec +UPDATE incidents +SET state = ?1 +WHERE incident_number = ?2 +` + +type UpdateIncidentStateParams struct { + State sql.NullInt64 + IncidentNumber sql.NullString +} + +func (q *Queries) UpdateIncidentState(ctx context.Context, arg UpdateIncidentStateParams) error { + _, err := q.db.ExecContext(ctx, updateIncidentState, arg.State, arg.IncidentNumber) + return err +} diff --git a/dist/.!31629!.DS_Store b/dist/.!31629!.DS_Store deleted file mode 100644 index e69de29..0000000 diff --git a/dist/assets/.!31631!.DS_Store b/dist/assets/.!31631!.DS_Store deleted file mode 100644 index e69de29..0000000 diff --git a/go.mod b/go.mod index c59399b..23c899b 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module mocksnow go 1.24.1 require ( - github.com/a-h/templ v0.3.833 + github.com/a-h/templ v0.3.856 github.com/go-co-op/gocron/v2 v2.16.1 github.com/google/uuid v1.6.0 github.com/jmoiron/sqlx v1.4.0 diff --git a/go.sum b/go.sum index f505c56..27d9ca1 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/a-h/templ v0.3.833 h1:L/KOk/0VvVTBegtE0fp2RJQiBm7/52Zxv5fqlEHiQUU= -github.com/a-h/templ v0.3.833/go.mod h1:cAu4AiZhtJfBjMY0HASlyzvkrtjnHWPeEsyGK2YYmfk= +github.com/a-h/templ v0.3.856 h1:rMSlGIaQCqctylqM49VinpN7LlrptrFj0dMbYDj9GEQ= +github.com/a-h/templ v0.3.856/go.mod h1:qhrhAkRFubE7khxLZHsBFHfX+gWwVNKbzKeF9GlPV4M= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 1812646..03e5581 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -30,6 +30,7 @@ func GetFilePath(path string) string { } binaryPath := filepath.Dir(ex) path = filepath.Join(binaryPath, path) + slog.Info("Found file", "path", path) } return path } diff --git a/server/handler/getIncident.go b/server/handler/getIncident.go index 9cfbeb8..035eba7 100644 --- a/server/handler/getIncident.go +++ b/server/handler/getIncident.go @@ -1,6 +1,9 @@ package handler import ( + "database/sql" + "encoding/json" + "errors" "fmt" "net/http" "strings" @@ -8,8 +11,9 @@ import ( // GetIncident responds to the link generated in the response to a New Snow func (h *Handler) GetIncident(w http.ResponseWriter, r *http.Request) { - h.Logger.Debug("GetIncident Request received", "method", r.Method, "path", r.URL.Path) - // TODO + h.Logger.Debug("GetIncident Request received", "method", r.Method, "url", r.URL, "path", r.URL.Path, "query", r.URL.Query()) + + ctx := r.Context() path := r.URL.Path // Expected format: /api/now/table/incident/{id} @@ -30,17 +34,54 @@ func (h *Handler) GetIncident(w http.ResponseWriter, r *http.Request) { } if len(parts) == 6 && strings.HasPrefix(path, "/api/now/table/incident/") { - // Requested a single incident - id := parts[5] // Extract {id} - h.Logger.Debug("GetIncident called for specific incident", "id", id) + + // Handle the specific 'number' query parameter + number := query.Get("number") + if number != "" { + h.Logger.Debug("GetIncident called for specific incident number", "number", number) + + // Query record from database and return that + + } else { + // Requested a single incident + id := parts[5] // Extract {id} + h.Logger.Debug("GetIncident called for specific incident", "id", id) + + incResult, err := h.Database.Queries().GetIncident(ctx, nullStr(number)) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + h.Logger.Debug("No incident record found", "number", number) + } else { + h.Logger.Error("Unable to query database for incident number", "error", err) + //return err + } + } + + b, err := json.Marshal(incResult) + if err != nil { + h.Logger.Error("Unable to convert database record into json", "error", err) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode(map[string]string{ + "status": "ERROR", + "message": fmt.Sprintf("Unable to convert database record into json: '%s'", err), + }) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, string(b)) + return + } + } else if strings.HasPrefix(path, "/api/now/table/incident") { h.Logger.Debug("GetIncident called for list of incidents") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "{\"result\": [{}]}") } // TODO - provide an incident list if necessary - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "{\"result\": [{}]}") } diff --git a/server/handler/newSnow.go b/server/handler/newSnow.go index 21695e7..6f7630a 100644 --- a/server/handler/newSnow.go +++ b/server/handler/newSnow.go @@ -10,6 +10,8 @@ import ( "mocksnow/server/models" "net/http" "os" + "strconv" + "time" "github.com/google/uuid" ) @@ -29,95 +31,181 @@ func (h *Handler) NewSnow(w http.ResponseWriter, r *http.Request) { } // Decode the JSON body - var incident models.Incident - if err := json.Unmarshal(reqBody, &incident); err != nil { + var incoming models.Incoming + if err := json.Unmarshal(reqBody, &incoming); err != nil { h.Logger.Error("unable to decode json", "error", err) http.Error(w, "Invalid JSON body", http.StatusBadRequest) return } else { h.Logger.Debug("successfully decoded JSON") - prettyPrint(incident) + prettyPrint(incoming) } ctx := r.Context() + createdTime := time.Now() - // 1. Insert into incoming table + // Always insert data into incoming table params := queries.CreateIncomingParams{ - IncidentNumber: nullStr(incident.IncidentNumber), - Description: nullStr(incident.Description), - ShortDescription: nullStr(incident.ShortDescription), - Urgency: nullStr(incident.Urgency), - Impact: nullStr(incident.Impact), - State: nullStr(incident.State), - ExternalID: nullStr(incident.ExternalID), - WorkNotes: nullStr(incident.WorkNotes), - AssignmentGroup: nullStr(incident.AssignmentGroup), - AssignedTo: nullStr(incident.AssignedTo), - Category: nullStr(incident.Category), - Subcategory: nullStr(incident.SubCategory), + IncidentNumber: nullStr(incoming.IncidentNumber), + Description: nullStr(incoming.Description), + ShortDescription: nullStr(incoming.ShortDescription), + Urgency: nullStr(incoming.Urgency), + Impact: nullStr(incoming.Impact), + State: nullStr(incoming.State), + ExternalID: nullStr(incoming.ExternalID), + WorkNotes: nullStr(incoming.WorkNotes), + AssignmentGroup: nullStr(incoming.AssignmentGroup), + AssignedTo: nullStr(incoming.AssignedTo), + Category: nullStr(incoming.Category), + Subcategory: nullStr(incoming.SubCategory), + CreatedAt: sql.NullTime{Time: createdTime, Valid: true}, } h.Logger.Debug("database params", "params", params) - - // Insert the new inventory record into the database result, err := h.Database.Queries().CreateIncoming(ctx, params) if err != nil { - h.Logger.Error("unable to perform database insert", "error", err) + h.Logger.Error("unable to log incoming data", "error", err) w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "Error : %v\n", err) return } else { - h.Logger.Debug("created database record", "insert_result", result) + h.Logger.Debug("created incoming database record", "insert_result", result) } - // Create record in incidents table - incidentRecord, err := h.Database.Queries().CreateIncident(ctx, incident.ExternalID) - if err != nil { - h.Logger.Error("failed to create incident", "error", err) - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprintf(w, "Error : %v\n", err) - return - } else { - h.Logger.Debug("created database record", "incident_record", incidentRecord) - } + // TODO: + // check to see if this record is already in incidents table + // if it is then: + // - add a worknotes entry in worknotes table + // - update status in incidents table + // otherwise, create a new incident - // Simulate response - ticket := fmt.Sprintf("TKT%06d", incidentRecord) - sysID := uuid.New().String() + // External ID only provided when incident not yet created - this might not be correct? + if len(incoming.ExternalID) > 0 && len(incoming.IncidentNumber) == 0 { + // Create record in incidents table + urgency, _ := strconv.ParseInt(incoming.Urgency, 10, 64) + impact, _ := strconv.ParseInt(incoming.Impact, 10, 64) + state, _ := strconv.ParseInt(incoming.State, 10, 64) + sysID := uuid.New().String() - // Produce dummy record link - hostname, err = os.Hostname() - if err != nil { - h.Logger.Error("failed to lookup hostname", "error", err) - hostname = "localhost" - } + params2 := queries.CreateIncidentParams{ + //IncidentNumber: nullStr(incoming.IncidentNumber), + Description: nullStr(incoming.Description), + ShortDescription: nullStr(incoming.ShortDescription), + Urgency: nullInt64(urgency), + Impact: nullInt64(impact), + State: nullInt64(state), + ExternalID: incoming.ExternalID, + //WorkNotes: nullStr(incoming.WorkNotes), + AssignmentGroup: nullStr(incoming.AssignmentGroup), + AssignedTo: nullStr(incoming.AssignedTo), + Category: nullStr(incoming.Category), + Subcategory: nullStr(incoming.SubCategory), + SysID: nullStr(sysID), + CreatedAt: sql.NullTime{Time: createdTime, Valid: true}, + } + incidentRecord, err := h.Database.Queries().CreateIncident(ctx, params2) + if err != nil { + h.Logger.Error("failed to create incident", "error", err) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error : %v\n", err) + return + } else { + h.Logger.Debug("created incident database record", "incident_record", incidentRecord) + } - recordLink := fmt.Sprintf("https://%s/api/now/table/incident/%s", hostname, sysID) + // Use the returned incidentRecordId to generate the ticket number, and update the database correspondingly + ticket := fmt.Sprintf("TKT%06d", incidentRecord.ID) - response := models.IncidentResponse{ - ImportSet: randomImportSet(), - StagingTable: "x_dusa2_itom_inc_imp", - Result: []models.IncidentResultItem{ - { - TransformMap: "Incident Import", - Table: "incident", - DisplayName: "number", - DisplayValue: ticket, - RecordLink: recordLink, - Status: "inserted", - SysID: sysID, + incNumParams := queries.UpdateIncidentNumberParams{ + ExternalId: incoming.ExternalID, + IncidentNumber: nullStr(ticket), + } + err = h.Database.Queries().UpdateIncidentNumber(ctx, incNumParams) + if err != nil { + h.Logger.Error("failed to update incident with incident number", "number", ticket, "error", err) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error : %v\n", err) + return + } else { + h.Logger.Debug("updated incident database record") + } + + // Create the worknotes entry + wnParms := queries.CreateWorkNoteParams{ + IncidentNumber: ticket, + Note: nullStr(incoming.WorkNotes), + } + _, err = h.Database.Queries().CreateWorkNote(ctx, wnParms) + if err != nil { + h.Logger.Error("failed to create worknotes for incident with incident number", "number", ticket, "error", err) + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Error : %v\n", err) + return + } else { + h.Logger.Debug("created worknotes database record") + } + + // Send the response + + // Produce dummy record link + hostname, err = os.Hostname() + if err != nil { + h.Logger.Error("failed to lookup hostname", "error", err) + hostname = "localhost" + } + + recordLink := fmt.Sprintf("https://%s/api/now/table/incident/%s", hostname, sysID) + + response := models.IncidentResponse{ + ImportSet: randomImportSet(), + StagingTable: "x_dusa2_itom_inc_imp", + Result: []models.IncidentResultItem{ + { + TransformMap: "Incident Import", + Table: "incident", + DisplayName: "number", + DisplayValue: ticket, + RecordLink: recordLink, + Status: "inserted", + SysID: sysID, + }, }, - }, + } + + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(response) + + } else if len(incoming.IncidentNumber) > 0 { + // Incident already exists because we know the incident number, so update status or worknotes + h.Logger.Debug("updating incident database record") + + // TODO + } else { + // Unexpected condition + // TODO - return error + h.Logger.Error("Logic error, did not expect to reach here") + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusInternalServerError) + json.NewEncoder(w).Encode(map[string]string{ + "status": "ERROR", + "message": fmt.Sprintf("Logic error, unexpected condition"), + }) + return } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "{\"result\": [{}]}") } func nullStr(s string) sql.NullString { return sql.NullString{String: s, Valid: s != ""} } +func nullInt64(i int64) sql.NullInt64 { + return sql.NullInt64{Int64: i, Valid: i > 0} +} + // Helper to generate random import_set ID func randomImportSet() string { const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" diff --git a/server/models/models.go b/server/models/models.go index 35e5b5c..a93e8e6 100644 --- a/server/models/models.go +++ b/server/models/models.go @@ -16,7 +16,16 @@ type IncidentResultItem struct { SysID string `json:"sys_id"` } -type Incident struct { +// TODO - populate more fields here +type SingleIncidentResponse struct { + IncidentNumber string `json:"incident_number,omitempty"` // The incident number in ServiceNow. If blank, creates a new incident, if populated with a valid value it updates that record. + State string `json:"state,omitempty"` // integer value, 1-6 (6 is resolved) + // Associated DeviceID (UUID from CPDB) + ExternalID string `json:"external_id,omitempty"` // CPDB UUID for the configuration item + SysID string `json:"sys_id,omitempty"` +} + +type Incoming struct { IncidentNumber string `json:"incident_number,omitempty"` // The incident number in ServiceNow. If blank, creates a new incident, if populated with a valid value it updates that record. Description string `json:"description,omitempty"` ShortDescription string `json:"short_description,omitempty"` diff --git a/styles/.!31660!.DS_Store b/styles/.!31660!.DS_Store deleted file mode 100644 index e69de29..0000000