diff --git a/controllers/network.go b/controllers/network.go index f340e836..d822b539 100644 --- a/controllers/network.go +++ b/controllers/network.go @@ -24,6 +24,8 @@ import ( func networkHandlers(r *mux.Router) { r.HandleFunc("/api/networks", logic.SecurityCheck(true, http.HandlerFunc(getNetworks))). Methods(http.MethodGet) + r.HandleFunc("/api/v1/networks/stats", logic.SecurityCheck(true, http.HandlerFunc(getNetworksStats))). + Methods(http.MethodGet) r.HandleFunc("/api/networks", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceNetworks, http.HandlerFunc(createNetwork)))). Methods(http.MethodPost) r.HandleFunc("/api/networks/{networkname}", logic.SecurityCheck(true, http.HandlerFunc(getNetwork))). @@ -74,6 +76,48 @@ func getNetworks(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(allnetworks) } +// @Summary Lists all networks with stats +// @Router /api/v1/networks/stats [get] +// @Tags Networks +// @Security oauth +// @Produce json +// @Success 200 {object} models.SuccessResponse +// @Failure 500 {object} models.ErrorResponse +func getNetworksStats(w http.ResponseWriter, r *http.Request) { + + var err error + allnetworks, err := logic.GetNetworks() + if err != nil && !database.IsEmptyRecord(err) { + slog.Error("failed to fetch networks", "error", err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + if r.Header.Get("ismaster") != "yes" { + username := r.Header.Get("user") + user, err := logic.GetUser(username) + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + allnetworks = logic.FilterNetworksByRole(allnetworks, *user) + } + allNodes, err := logic.GetAllNodes() + if err != nil { + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) + return + } + netstats := []models.NetworkStatResp{} + logic.SortNetworks(allnetworks[:]) + for _, network := range allnetworks { + netstats = append(netstats, models.NetworkStatResp{ + Network: network, + Hosts: len(logic.GetNetworkNodesMemory(allNodes, network.NetID)), + }) + } + logger.Log(2, r.Header.Get("user"), "fetched networks.") + logic.ReturnSuccessResponseWithJson(w, r, netstats, "fetched networks with stats") +} + // @Summary Get a network // @Router /api/networks/{networkname} [get] // @Tags Networks diff --git a/migrate/migrate.go b/migrate/migrate.go index 1675f4ee..a2d9b65d 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -319,6 +319,7 @@ func syncUsers() { nodes, err := logic.GetAllNodes() if err == nil { for _, netI := range networks { + logic.CreateDefaultNetworkRolesAndGroups(models.NetworkID(netI.NetID)) networkNodes := logic.GetNetworkNodesMemory(nodes, netI.NetID) for _, networkNodeI := range networkNodes { if networkNodeI.IsIngressGateway { diff --git a/models/network.go b/models/network.go index c29b45d7..32d95f86 100644 --- a/models/network.go +++ b/models/network.go @@ -97,3 +97,8 @@ func (network *Network) GetNetworkNetworkCIDR6() *net.IPNet { _, netCidr, _ := net.ParseCIDR(network.AddressRange6) return netCidr } + +type NetworkStatResp struct { + Network + Hosts int `json:"hosts"` +} diff --git a/pro/email/invite.go b/pro/email/invite.go index c2b39bd2..86018462 100644 --- a/pro/email/invite.go +++ b/pro/email/invite.go @@ -2,6 +2,7 @@ package email import ( "fmt" + "github.com/gravitl/netmaker/servercfg" ) // UserInvitedMail - mail for users that are invited to a tenant @@ -12,16 +13,54 @@ type UserInvitedMail struct { // GetSubject - gets the subject of the email func (UserInvitedMail) GetSubject(info Notification) string { - return "Netmaker: Pending Invitation" + return "You're invited to join Netmaker" } // GetBody - gets the body of the email func (invite UserInvitedMail) GetBody(info Notification) string { + if servercfg.DeployedByOperator() { + return invite.BodyBuilder. + WithParagraph("Hi there,"). + WithParagraph("
"). + WithParagraph("Great news! Your colleague has invited you to join their Netmaker SaaS Tenant."). + WithParagraph("Click the button to accept your invitation:"). + WithParagraph("
"). + WithParagraph(fmt.Sprintf("Accept Invitation", invite.InviteURL)). + WithParagraph("
"). + WithParagraph("Why you'll love Netmaker:"). + WithParagraph(""). + WithParagraph("Got questions? Our team is here to help you every step of the way."). + WithParagraph("
"). + WithParagraph("Welcome aboard,"). + WithParagraph("

The Netmaker Team

"). + WithParagraph("P.S. Curious to learn more before accepting? Check out our quick start tutorial at netmaker.io/tutorials"). + Build() + } return invite.BodyBuilder. - WithHeadline("Join Netmaker from this invite!"). - WithParagraph("Hello from Netmaker,"). - WithParagraph("You have been invited to join Netmaker."). - WithParagraph(fmt.Sprintf("Join Using This Invite Link Netmaker", invite.InviteURL)). + WithParagraph("Hi there,"). + WithParagraph("
"). + WithParagraph("Great news! Your colleague has invited you to join their Netmaker network."). + WithParagraph("Click the button to accept your invitation:"). + WithParagraph("
"). + WithParagraph(fmt.Sprintf("Accept Invitation", invite.InviteURL)). + WithParagraph("
"). + WithParagraph("Why you'll love Netmaker:"). + WithParagraph(""). + WithParagraph("Got questions? Our team is here to help you every step of the way."). + WithParagraph("
"). + WithParagraph("Welcome aboard,"). + WithParagraph("

The Netmaker Team

"). + WithParagraph("P.S. Curious to learn more before accepting? Check out our quick start tutorial at netmaker.io/tutorials"). Build() } diff --git a/pro/email/utils.go b/pro/email/utils.go index 69a58fe0..b689a8be 100644 --- a/pro/email/utils.go +++ b/pro/email/utils.go @@ -73,7 +73,7 @@ func (b *EmailBodyBuilderWithH1HeadlineAndImage) Build() string {