2023-12-04 08:37:53 -07:00
package main
import (
2023-12-20 16:25:19 -07:00
"encoding/json"
2023-12-04 08:37:53 -07:00
"fmt"
"io"
"log"
"net/http"
2023-12-20 16:25:19 -07:00
"path/filepath"
"regexp"
"strings"
2023-12-04 15:03:40 -07:00
"time"
2023-12-04 08:37:53 -07:00
"github.com/gorilla/mux"
)
2023-12-21 10:37:44 -07:00
func MPE_IsProject ( input * Payload ) ( projectnumber string , project_name string ) {
2023-12-20 16:25:19 -07:00
// this will attempt to extract a project number from the "targetpath" element. If it's able to determine a folder contains a project number, we'll return it.
2023-12-21 10:37:44 -07:00
// var path_data map[string]json.RawMessage
2023-12-20 16:25:19 -07:00
project_regex , _ := regexp . Compile ( ` (^[0-9] { 1,3}) ` ) // regex to match against
2023-12-21 10:37:44 -07:00
// err := json.Unmarshal((input.Data), &path_data)
// if err != nil {
// log.Fatal(err)
// fmt.Println("oops")
// return
// }
2023-12-20 16:25:19 -07:00
2023-12-21 10:37:44 -07:00
path := string ( input . Data [ 0 ] . PathData . TargetPath )
2023-12-20 16:25:19 -07:00
split_path , _ := filepath . Split ( path )
split_path = filepath . Clean ( split_path )
separated_path := strings . Split ( split_path , "/" ) //turn this into an array (slice?) to parse
var sb strings . Builder
// iterate through the path_data map. We want to find all strings that start with a number.
for _ , value := range separated_path {
matched := project_regex . MatchString ( value )
if matched {
// if we match the Regex above, write values to SB. This will give us a string like "73|10 Office Of Somone|153 HelpMe|002 Phase 2"
sb . WriteString ( value + "|" )
}
} // end of loop
// now to assemble project number and project name from the resulting values...
project_text := sb . String ( )
project_slice := strings . Split ( project_text , "|" )
// first value should be a digit, if not this can't be a project
2023-12-21 11:52:52 -07:00
isProject0 , _ := regexp . MatchString ( ` (^[0-9]) ` , project_slice [ 0 ] )
isProject1 , _ := regexp . MatchString ( ` (^[0-9]) ` , project_slice [ 1 ] )
isProject2 , _ := regexp . MatchString ( ` (^[0-9]) ` , project_slice [ 2 ] )
// isProject, _ = regexp.MatchString(`(^[0-9])`, project_slice[3])
if isProject0 || isProject1 || isProject2 {
2023-12-20 16:25:19 -07:00
project_regex , _ := regexp . Compile ( ` (^[0-9] { 1,3}) ` ) // regex to match against
regex_tidy_string , _ := regexp . Compile ( ` [-_]+|^\s ` ) //regex to tidy up folder paths
client_section := regex_tidy_string . ReplaceAllString ( project_slice [ 1 ] , "" ) // remove fancy chars from Client Name
project_section := regex_tidy_string . ReplaceAllString ( project_regex . ReplaceAllString ( project_slice [ 2 ] , "" ) , " " ) // remove leading-digits
project_section_digits := strings . Split ( regex_tidy_string . ReplaceAllString ( project_slice [ 2 ] , " " ) , " " ) //split on space for MOST file folders...
sb . Reset ( ) // reset string builder so I can use it again!
sb . WriteString ( project_slice [ 0 ] ) // 73
sb . WriteString ( strings . Split ( client_section , " " ) [ 0 ] + "-" ) // 7310 -- Client Name
sb . WriteString ( project_section_digits [ 0 ] ) // 7310-10
// do we have a third section of the project number?
project_third := strings . Split ( project_slice [ 3 ] , " " ) [ 0 ]
project_third_match , _ := regexp . MatchString ( ` (^[0-9] { 1,3}) ` , project_third )
2023-12-21 11:52:52 -07:00
/ * TODO : Better identification of the third number .
Currently seeing paths such as "/shared/n-data/12/34 test/45 ProjectName/deliverables/05 geotech" generating project numbers of 1234 - 45 - 05 ,
where it should be 1234 - 45
This is due to the RegEx Match looking for all folders that start with digits , and not being concerned about where they are in the string .
* /
2023-12-20 16:25:19 -07:00
if project_third_match {
// if we have a third section, then add another section to the project number, and append to the project name
third_project_name := project_regex . ReplaceAllString ( project_slice [ 3 ] , "" ) // 7310-10-153
project_name = project_section + "-" + regex_tidy_string . ReplaceAllString ( third_project_name , "" ) // remove project digits from beginning of string and append
project_third = regex_tidy_string . ReplaceAllString ( project_third , " " )
sb . WriteString ( "-" + project_third )
} else {
project_name = project_section // remove project digits from beginning of string
}
projectnumber = sb . String ( ) // I should now have a project number!
} else {
return "NotAProject" , "NoPath"
}
return
}
2023-12-21 10:37:44 -07:00
func MPE_ValidateForward ( in * Payload ) bool {
2023-12-20 16:25:19 -07:00
// decode targetPath data. Will return TRUE if the last section of the path contains "External Share" or "ExternalShare". This would indicate that we SHOULD forward this request onward.
2023-12-21 10:37:44 -07:00
// var path_data map[string]json.RawMessage
// err := json.Unmarshal((in.Data), &path_data)
// if err != nil {
// log.Fatal(err)
// fmt.Println("oops")
// return false
// }
path := string ( in . Data [ 0 ] . PathData . TargetPath )
2023-12-20 16:25:19 -07:00
split_path , last := filepath . Split ( path )
split_path = filepath . Clean ( split_path )
2023-12-21 10:37:44 -07:00
matched , _ := regexp . MatchString ( ` ExternalShare|External Share ` , last )
2023-12-20 16:25:19 -07:00
return matched
}
2023-12-04 08:37:53 -07:00
func readDataStream ( resp http . ResponseWriter , request * http . Request ) {
2023-12-20 16:25:19 -07:00
// reqBody, _ := io.ReadAll(request.Body)
2023-12-21 11:52:52 -07:00
var log_values log_data
var request_body Payload // init request_body as data type Payload - uses custom structs
body_string , _ := io . ReadAll ( request . Body ) // ready Body Data
log_values . BodyData = string ( body_string ) // prep for logging
fmt . Printf ( "%+v\n" , log_values ) // debug code to show JASON data coming in
2023-12-20 16:25:19 -07:00
err := json . Unmarshal ( body_string , & request_body )
if err != nil {
2023-12-21 10:37:44 -07:00
var error_sb strings . Builder
error_sb . WriteString ( "ERROR in JSON\n" )
error_sb . WriteString ( string ( body_string ) )
error_sb . WriteString ( "\n--Error from Unmarshal: " )
error_sb . WriteString ( err . Error ( ) )
fmt . Print ( error_sb . String ( ) )
resp . WriteHeader ( http . StatusBadRequest )
resp . Write ( [ ] byte ( error_sb . String ( ) ) )
2023-12-20 16:25:19 -07:00
return
}
2023-12-04 08:37:53 -07:00
2023-12-21 10:37:44 -07:00
log_values . EventID = request_body . Data [ 0 ] . EventID
log_values . EventType = request_body . Data [ 0 ] . EventType
log_values . User = request_body . Data [ 0 ] . User . DisplayName
log_values . TargetPath = request_body . Data [ 0 ] . PathData . TargetPath
2023-12-21 11:52:52 -07:00
fmt . Printf ( "%+v\n" , log_values ) // output log values to stdout - first round
var MPE_ShouldFoward = MPE_ValidateForward ( & request_body )
var MPE_ProjectNumber , MPE_ProjectName = MPE_IsProject ( & request_body )
2023-12-21 10:37:44 -07:00
log_values . ExternalShare = MPE_ShouldFoward
log_values . MPE_ProjectName = MPE_ProjectName
log_values . MPE_ProjectNumber = MPE_ProjectNumber
2023-12-21 11:52:52 -07:00
fmt . Printf ( "%+v\n" , log_values ) // output log values to stdout - second round
// Collect EventID, JSON Content, and return values into data object to be logged to screen. Validate data visually for a bit against "live" webhook data.
2023-12-20 16:25:19 -07:00
// TODO: Once Data validation / Struct is built, pass data off to next Webhook URL for processing.
2023-12-04 08:37:53 -07:00
}
2023-12-04 15:03:40 -07:00
func HealthCheck ( resp http . ResponseWriter , request * http . Request ) {
var t = time . Now ( ) . String ( )
var MessageText = t + ": Health Check from " + request . RemoteAddr
// reqBody, _ := io.ReadAll(request.Body)
2023-12-04 08:37:53 -07:00
2023-12-04 15:03:40 -07:00
fmt . Println ( http . StatusOK , MessageText )
resp . WriteHeader ( http . StatusOK )
resp . Write ( [ ] byte ( MessageText ) )
2023-12-04 08:37:53 -07:00
}
2023-12-12 13:29:55 -07:00
func CatchError ( resp http . ResponseWriter , request * http . Request ) {
var LogText = "got bad request from " + request . RemoteAddr + ". Method: " + request . Method
fmt . Println ( http . StatusBadRequest , LogText )
var MessageText = "Invalid Request, please read the docs..."
resp . WriteHeader ( http . StatusBadRequest )
resp . Write ( [ ] byte ( MessageText ) )
}
2023-12-04 08:37:53 -07:00
func handleRequests ( ) {
// Start new Mux router
mainrouter := mux . NewRouter ( ) . StrictSlash ( true )
mainrouter . HandleFunc ( "/" , readDataStream ) . Methods ( "POST" )
2023-12-04 15:03:40 -07:00
mainrouter . HandleFunc ( "/healthcheck" , HealthCheck ) . Methods ( "GET" )
2023-12-12 13:29:55 -07:00
mainrouter . HandleFunc ( "/" , CatchError )
2023-12-04 08:37:53 -07:00
log . Fatal ( http . ListenAndServe ( ":10000" , mainrouter ) )
}
func main ( ) {
2023-12-12 13:29:55 -07:00
var t = time . Now ( ) . String ( )
fmt . Println ( "MPE x Egnyte x PowerApps - Mux Router starting: " + t )
2023-12-04 08:37:53 -07:00
handleRequests ( )
}
2023-12-20 16:25:19 -07:00
2023-12-21 10:37:44 -07:00
type Payload struct {
Data [ ] EG_Data ` json:"data" `
}
type User struct {
ID int ` json:"id" `
ClientIDHash string ` json:"clientIdHash" `
DisplayName string ` json:"displayName" `
Username string ` json:"username" `
Email string ` json:"email" `
ImpersonatedBy string ` json:"impersonatedBy" `
}
type PathData struct {
SourcePath string ` json:"sourcePath" `
TargetPath string ` json:"targetPath" `
}
type EG_Data struct {
EventID string ` json:"eventId" `
Domain string ` json:"domain" `
Timestamp int64 ` json:"timestamp" `
User User ` json:"user" `
ActionSource string ` json:"actionSource" `
WebhookID string ` json:"webhookId" `
EventType string ` json:"eventType" `
PathData PathData ` json:"data" `
}
type log_data struct {
EventID string
User string
EventType string
TargetPath string
ExternalShare bool
MPE_ProjectNumber string
MPE_ProjectName string
2023-12-21 11:52:52 -07:00
BodyData string
2023-12-20 16:25:19 -07:00
}