diff --git a/src/api.go b/src/api.go index 4e266eb..1507289 100644 --- a/src/api.go +++ b/src/api.go @@ -88,6 +88,7 @@ func RegisterRedirectionAPIs(authRouter *auth.RouterDef) { authRouter.HandleFunc("/api/redirect/list", handleListRedirectionRules) authRouter.HandleFunc("/api/redirect/add", handleAddRedirectionRule) authRouter.HandleFunc("/api/redirect/delete", handleDeleteRedirectionRule) + authRouter.HandleFunc("/api/redirect/edit", handleEditRedirectionRule) authRouter.HandleFunc("/api/redirect/regex", handleToggleRedirectRegexpSupport) } diff --git a/src/mod/dynamicproxy/redirection/redirection.go b/src/mod/dynamicproxy/redirection/redirection.go index 8cb0b15..abd163e 100644 --- a/src/mod/dynamicproxy/redirection/redirection.go +++ b/src/mod/dynamicproxy/redirection/redirection.go @@ -2,7 +2,6 @@ package redirection import ( "encoding/json" - "fmt" "log" "os" "path" @@ -111,6 +110,42 @@ func (t *RuleTable) AddRedirectRule(redirectURL string, destURL string, forwardP return nil } +// Edit an existing redirection rule, the oldRedirectURL is used to find the rule to be edited +func (t *RuleTable) EditRedirectRule(oldRedirectURL string, newRedirectURL string, destURL string, forwardPathname bool, statusCode int) error { + newRule := &RedirectRules{ + RedirectURL: newRedirectURL, + TargetURL: destURL, + ForwardChildpath: forwardPathname, + StatusCode: statusCode, + } + + //Remove the old rule + t.DeleteRedirectRule(oldRedirectURL) + + // Convert the redirectURL to a valid filename by replacing "/" with "-" and "." with "_" + filename := utils.ReplaceSpecialCharacters(newRedirectURL) + ".json" + filepath := path.Join(t.configPath, filename) + + // Create a new file for writing the JSON data + file, err := os.Create(filepath) + if err != nil { + t.log("Error creating file "+filepath, err) + return err + } + defer file.Close() + + err = json.NewEncoder(file).Encode(newRule) + if err != nil { + t.log("Error encoding JSON to file "+filepath, err) + return err + } + + // Update the runtime map + t.rules.Store(newRedirectURL, newRule) + + return nil +} + func (t *RuleTable) DeleteRedirectRule(redirectURL string) error { // Convert the redirectURL to a valid filename by replacing "/" with "-" and "." with "_" filename := utils.ReplaceSpecialCharacters(redirectURL) + ".json" @@ -118,7 +153,6 @@ func (t *RuleTable) DeleteRedirectRule(redirectURL string) error { // Create the full file path by joining the t.configPath with the filename filepath := path.Join(t.configPath, filename) - fmt.Println(redirectURL, filename, filepath) // Check if the file exists if _, err := os.Stat(filepath); os.IsNotExist(err) { return nil // File doesn't exist, nothing to delete diff --git a/src/redirect.go b/src/redirect.go index fa0a5c2..4e0920b 100644 --- a/src/redirect.go +++ b/src/redirect.go @@ -78,6 +78,49 @@ func handleDeleteRedirectionRule(w http.ResponseWriter, r *http.Request) { utils.SendOK(w) } +func handleEditRedirectionRule(w http.ResponseWriter, r *http.Request) { + originalRedirectUrl, err := utils.PostPara(r, "originalRedirectUrl") + if err != nil { + utils.SendErrorResponse(w, "original redirect url cannot be empty") + return + } + + newRedirectUrl, err := utils.PostPara(r, "newRedirectUrl") + if err != nil { + utils.SendErrorResponse(w, "redirect url cannot be empty") + return + } + destUrl, err := utils.PostPara(r, "destUrl") + if err != nil { + utils.SendErrorResponse(w, "destination url cannot be empty") + } + + forwardChildpath, err := utils.PostPara(r, "forwardChildpath") + if err != nil { + //Assume true + forwardChildpath = "true" + } + + redirectTypeString, err := utils.PostPara(r, "redirectType") + if err != nil { + redirectTypeString = "307" + } + + redirectionStatusCode, err := strconv.Atoi(redirectTypeString) + if err != nil { + utils.SendErrorResponse(w, "invalid status code number") + return + } + + err = redirectTable.EditRedirectRule(originalRedirectUrl, newRedirectUrl, destUrl, forwardChildpath == "true", redirectionStatusCode) + if err != nil { + utils.SendErrorResponse(w, err.Error()) + return + } + + utils.SendOK(w) +} + // Toggle redirection regex support. Note that this cost another O(n) time complexity to each page load func handleToggleRedirectRegexpSupport(w http.ResponseWriter, r *http.Request) { enabled, err := utils.PostPara(r, "enable") diff --git a/src/web/components/redirection.html b/src/web/components/redirection.html index 98088e0..9b7c4f8 100644 --- a/src/web/components/redirection.html +++ b/src/web/components/redirection.html @@ -13,7 +13,7 @@ Destination URL Copy Pathname Status Code - Remove + Actions @@ -163,13 +163,21 @@ $("#redirectionRuleList").html(""); $.get("/api/redirect/list", function(data){ data.forEach(function(entry){ - $("#redirectionRuleList").append(` - ${entry.RedirectURL} - ${entry.TargetURL} - ${entry.ForwardChildpath?"":""} - ${entry.StatusCode==307?"Temporary Redirect (307)":"Moved Permanently (301)"} - - `); + let encodedEntry = encodeURIComponent(JSON.stringify(entry)); + let hrefURL = entry.RedirectURL; + if (!hrefURL.startsWith("http")){ + hrefURL = "https://" + hrefURL; + } + $("#redirectionRuleList").append(` + ${entry.RedirectURL} + ${entry.TargetURL} + ${entry.ForwardChildpath?"":""} + ${entry.StatusCode==307?"Temporary Redirect (307)":"Moved Permanently (301)"} + + + + + `); }); if (data.length == 0){ @@ -180,6 +188,68 @@ } initRedirectionRuleList(); + function editRule(obj){ + $(".redirectEditBtn").addClass("disabled"); + let payload = JSON.parse(decodeURIComponent($(obj).attr("payload"))); + let row = $(obj).closest("tr"); + let redirectUrl = payload.RedirectURL; + let destUrl = payload.TargetURL; + let forwardChildpath = payload.ForwardChildpath; + let statusCode = payload.StatusCode; + + row.html(` + +
+ +
+ + +
+ +
+ +
+ +

+
+ + + + + + `); + + $(".checkbox").checkbox(); + } + + function saveEditRule(obj){ + let payload = JSON.parse(decodeURIComponent($(obj).attr("payload"))); + let redirectUrl = $("#editRedirectUrl").val(); + let destUrl = $("#editDestUrl").val(); + let forwardChildpath = $("#editForwardChildpath").is(":checked"); + let statusCode = parseInt($("input[name='editStatusCode']:checked").val()); + + $.cjax({ + url: "/api/redirect/edit", + method: "POST", + data: { + originalRedirectUrl: payload.RedirectURL, + newRedirectUrl: redirectUrl, + destUrl: destUrl, + forwardChildpath: forwardChildpath, + redirectType: statusCode, + }, + success: function(data){ + if (data.error != undefined){ + msgbox(data.error, false); + }else{ + msgbox("Redirection rule updated", true); + initRedirectionRuleList(); + } + } + }); + } + function initRegexpSupportToggle(){ $.get("/api/redirect/regex", function(data){ //Set the checkbox initial state