From a8c94ca0aabb8e5e38ae5aac90e810bd89e8b2e2 Mon Sep 17 00:00:00 2001 From: Christian Ditaputratama Date: Mon, 4 Nov 2024 23:53:09 +0700 Subject: [PATCH] feat!: Added Add node form and action --- internal/handler/response.go | 25 +++++++ internal/handler/routes.go | 3 +- internal/handler/views/add_node.templ | 56 +++++++++++++++- internal/handler/views/add_node_templ.go | 2 +- internal/handler/views/home.templ | 2 +- internal/handler/views/home_templ.go | 2 +- internal/handler/views/layout.templ | 11 ++++ internal/handler/views/layout_templ.go | 83 +++++++++++++++++++++++- 8 files changed, 178 insertions(+), 6 deletions(-) diff --git a/internal/handler/response.go b/internal/handler/response.go index d4cd8f9..228bb27 100644 --- a/internal/handler/response.go +++ b/internal/handler/response.go @@ -33,6 +33,29 @@ func (s *fiberServer) homeHandler(c *fiber.Ctx) error { // Render Add Node Page func (s *fiberServer) addNodeHandler(c *fiber.Ctx) error { + switch c.Method() { + case fiber.MethodPut: + type formData struct { + Protocol string `form:"protocol"` + Hostname string `form:"hostname"` + Port int `form:"port"` + } + var f formData + + if err := c.BodyParser(&f); err != nil { + handler := adaptor.HTTPHandler(templ.Handler(views.Alert("error", "Cannot parse the request body"))) + return handler(c) + } + + moneroRepo := monero.New() + if err := moneroRepo.Add(f.Protocol, f.Hostname, uint(f.Port)); err != nil { + handler := adaptor.HTTPHandler(templ.Handler(views.Alert("error", err.Error()))) + return handler(c) + } + + handler := adaptor.HTTPHandler(templ.Handler(views.Alert("success", "Node added successfully"))) + return handler(c) + } p := views.Meta{ Title: "Add Monero Node", Description: "You can use this page to add known remote node to the system so my bots can monitor it.", @@ -256,6 +279,8 @@ func ProbeLogs(c *fiber.Ctx) error { } // Handles `POST /nodes` request to add a new node +// +// Deprecated: AddNode is deprecated, use s.addNodeHandler with put method instead func AddNode(c *fiber.Ctx) error { formPort := c.FormValue("port") port, err := strconv.Atoi(formPort) diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 9f8f7c8..5038b09 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -5,13 +5,14 @@ func (s *fiberServer) Routes() { s.App.Get("/remote-nodes", s.remoteNodesHandler) s.App.Get("/remote-nodes/id/:id", s.nodeHandler) s.App.Get("/add-node", s.addNodeHandler) + s.App.Put("/add-node", s.addNodeHandler) // V1 API routes v1 := s.App.Group("/api/v1") // these routes are public, they don't require a prober api key v1.Get("/nodes", Nodes) - v1.Post("/nodes", AddNode) + v1.Post("/nodes", AddNode) // old add node form action endpoint. Deprecated: Use PUT /add-node instead v1.Get("/nodes/id/:id", Node) v1.Get("/nodes/logs", ProbeLogs) v1.Get("/fees", NetFees) diff --git a/internal/handler/views/add_node.templ b/internal/handler/views/add_node.templ index f38396b..208d892 100644 --- a/internal/handler/views/add_node.templ +++ b/internal/handler/views/add_node.templ @@ -15,7 +15,61 @@ templ AddNode() {

You can use this page to add known remote node to the system so my bots can monitor it.

-
+ +
+
+ +
+
+

+ Enter your Monero node information below (IPv6 host check is experimental): +

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+
+
+

+ Existing remote nodes can be found in /remote-nodes page. +

+
+
diff --git a/internal/handler/views/add_node_templ.go b/internal/handler/views/add_node_templ.go index b0dd376..439942a 100644 --- a/internal/handler/views/add_node_templ.go +++ b/internal/handler/views/add_node_templ.go @@ -37,7 +37,7 @@ func AddNode() templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Add Monero Node

You can use this page to add known remote node to the system so my bots can monitor it.


") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("

Add Monero Node

You can use this page to add known remote node to the system so my bots can monitor it.


Important Note

  • As an administrator of this instance, I have full rights to delete, and blacklist any submitted node with or without providing any reason.

Enter your Monero node information below (IPv6 host check is experimental):

Existing remote nodes can be found in /remote-nodes page.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/handler/views/home.templ b/internal/handler/views/home.templ index 2da6b86..245fc2d 100644 --- a/internal/handler/views/home.templ +++ b/internal/handler/views/home.templ @@ -61,7 +61,7 @@ templ Home() { - +

Add Node

diff --git a/internal/handler/views/home_templ.go b/internal/handler/views/home_templ.go index df2c594..3073544 100644 --- a/internal/handler/views/home_templ.go +++ b/internal/handler/views/home_templ.go @@ -82,7 +82,7 @@ func Home() templ.Component { return templ_7745c5c3_Err } } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("etc; can be an other good reference for you.

You can find few resources I provide related to Monero below:

My Stagenet Public Node

Stagenet is what you need to learn Monero safely. Stagenet is technically equivalent to mainnet, both in terms of features and consensus rules.

P2P
RPC
RPC SSL

My Testnet Public Node

Testnet is the \"experimental\" network and blockchain where things get released long before mainnet. As a normal user, use mainnet instead.

P2P
RPC
RPC SSL

Since we desire privacy, we must ensure that each party to a transaction have knowledge only of that which is directly necessary for that transaction.

Eric Hughes in A Cypherpunk's Manifesto.


If you find this project useful, please consider making a donation to help cover the ongoing expenses. Your contribution will go towards ensuring the continued availability of this website, my stagenet and testnet public nodes.

\"ditatompel's

Thank you so much! It means a lot to me. 🥰

") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("etc; can be an other good reference for you.

You can find few resources I provide related to Monero below:

My Stagenet Public Node

Stagenet is what you need to learn Monero safely. Stagenet is technically equivalent to mainnet, both in terms of features and consensus rules.

P2P
RPC
RPC SSL

My Testnet Public Node

Testnet is the \"experimental\" network and blockchain where things get released long before mainnet. As a normal user, use mainnet instead.

P2P
RPC
RPC SSL

Since we desire privacy, we must ensure that each party to a transaction have knowledge only of that which is directly necessary for that transaction.

Eric Hughes in A Cypherpunk's Manifesto.


If you find this project useful, please consider making a donation to help cover the ongoing expenses. Your contribution will go towards ensuring the continued availability of this website, my stagenet and testnet public nodes.

\"ditatompel's

Thank you so much! It means a lot to me. 🥰

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/handler/views/layout.templ b/internal/handler/views/layout.templ index 9ad2814..d30413e 100644 --- a/internal/handler/views/layout.templ +++ b/internal/handler/views/layout.templ @@ -96,3 +96,14 @@ templ heroGradient() {
} + +templ Alert(status, message string) { + switch status { + case "success": +
Success: { message }
+ case "error": +
Error: { message }
+ default: +
{ message }
+ } +} diff --git a/internal/handler/views/layout_templ.go b/internal/handler/views/layout_templ.go index b1edcab..59c8c49 100644 --- a/internal/handler/views/layout_templ.go +++ b/internal/handler/views/layout_templ.go @@ -231,7 +231,7 @@ func base(m Meta) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(", source code licensed under BSD-3-Clause license.

") + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(", source code licensed under BSD-3-Clause license.

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -394,4 +394,85 @@ func heroGradient() templ.Component { }) } +func Alert(status, message string) templ.Component { + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { + return templ_7745c5c3_CtxErr + } + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) + if !templ_7745c5c3_IsBuffer { + defer func() { + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) + if templ_7745c5c3_Err == nil { + templ_7745c5c3_Err = templ_7745c5c3_BufErr + } + }() + } + ctx = templ.InitializeContext(ctx) + templ_7745c5c3_Var21 := templ.GetChildren(ctx) + if templ_7745c5c3_Var21 == nil { + templ_7745c5c3_Var21 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) + switch status { + case "success": + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
Success: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var22 string + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(message) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/handler/views/layout.templ`, Line: 103, Col: 95} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + case "error": + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
Error: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(message) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/handler/views/layout.templ`, Line: 105, Col: 91} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + default: + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var24 string + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(message) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/handler/views/layout.templ`, Line: 107, Col: 68} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + return templ_7745c5c3_Err + }) +} + var _ = templruntime.GeneratedTemplate