From 79ff687eef6d99388c9fe31fd35342df95ecd5e2 Mon Sep 17 00:00:00 2001 From: rawdaGastan Date: Wed, 5 Mar 2025 13:31:30 +0200 Subject: [PATCH 1/6] add welcome notification --- server/app/user_handler.go | 9 +++++++++ server/internal/templates/welcome.html | 10 +++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/server/app/user_handler.go b/server/app/user_handler.go index d0282cbb..2ec18a6c 100644 --- a/server/app/user_handler.go +++ b/server/app/user_handler.go @@ -250,6 +250,15 @@ func (a *App) VerifySignUpCodeHandler(req *http.Request) (interface{}, Response) return nil, InternalServerError(errors.New(internalServerErrorMsg)) } + notification := models.Notification{UserID: user.ID.String(), + Msg: "Welcome! Your account has been created successfully", + } + err = a.db.CreateNotification(¬ification) + if err != nil { + log.Error().Err(err).Send() + return nil, InternalServerError(errors.New(internalServerErrorMsg)) + } + return ResponseMsg{ Message: "Account is created successfully.", }, Created() diff --git a/server/internal/templates/welcome.html b/server/internal/templates/welcome.html index 0b36af11..936a6c52 100644 --- a/server/internal/templates/welcome.html +++ b/server/internal/templates/welcome.html @@ -198,13 +198,9 @@ Welcome, -name-!

- Your account has been created successfully. We are so glad to - have you here. You will receive a voucher to give you access - to your needed resources as requested. -

-

-

- The request will be processed within 12 hours. + Your account has been created successfully, + and you're now ready to explore deployments on our platform. We are so glad to + have you here.

From 807aada0430a9d1cb8c9789ccea7c0a6d87807ce Mon Sep 17 00:00:00 2001 From: rawdaGastan Date: Wed, 5 Mar 2025 13:37:40 +0200 Subject: [PATCH 2/6] add notification time --- server/models/notification.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/models/notification.go b/server/models/notification.go index 1bf0f4ae..dd9f4d6b 100644 --- a/server/models/notification.go +++ b/server/models/notification.go @@ -1,6 +1,8 @@ // Package models for database models package models +import "time" + const ( // VMsType deployment VMsType = "vms" @@ -15,7 +17,8 @@ type Notification struct { Msg string `json:"msg" binding:"required"` Seen bool `json:"seen" binding:"required"` // to allow redirecting from notifications to the right pages - Type string `json:"type" binding:"required"` + Type string `json:"type" binding:"required"` + CreatedAt time.Time `json:"created_at"` } // ListNotifications returns a list of notifications for a user. From 064a459aabdefb12123945c6659b1420debd3627 Mon Sep 17 00:00:00 2001 From: rawdaGastan Date: Wed, 5 Mar 2025 13:46:52 +0200 Subject: [PATCH 3/6] send email after account deletion --- server/app/user_handler.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/server/app/user_handler.go b/server/app/user_handler.go index 2ec18a6c..a45ba445 100644 --- a/server/app/user_handler.go +++ b/server/app/user_handler.go @@ -1068,6 +1068,19 @@ func (a *App) DeleteUserHandler(req *http.Request) (interface{}, Response) { return nil, InternalServerError(errors.New(internalServerErrorMsg)) } + subject, body := internal.AdminMailContent( + "Your account has been deleted", + "We are writing to confirm that your account has been successfully deleted as per your request.\n\n"+ + "All your personal data, account information, and associated content have been permanently removed from our system", + a.config.Server.Host, user.Name(), + ) + + err = internal.SendMail(a.config.MailSender.Email, a.config.MailSender.SendGridKey, user.Email, subject, body) + if err != nil { + log.Error().Err(err).Send() + return nil, InternalServerError(errors.New(internalServerErrorMsg)) + } + return ResponseMsg{ Message: "User is deleted successfully", }, Ok() From db40ea460bd0ab8c6e18a4cd05a07928057f758d Mon Sep 17 00:00:00 2001 From: rawdaGastan Date: Wed, 5 Mar 2025 14:38:22 +0200 Subject: [PATCH 4/6] round tft balance --- server/app/admin_handler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/app/admin_handler.go b/server/app/admin_handler.go index ac94d145..1e228fd8 100644 --- a/server/app/admin_handler.go +++ b/server/app/admin_handler.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "fmt" + "math" "net/http" "strconv" "strings" @@ -266,7 +267,7 @@ func (a *App) GetBalanceHandler(req *http.Request) (interface{}, Response) { return ResponseMsg{ Message: "Balance is found", - Data: balance, + Data: math.Round(balance*100) / 100, }, Ok() } From 09bb9b46f9cee63b4d58c1928ae1675a90c1984f Mon Sep 17 00:00:00 2001 From: rawdaGastan Date: Wed, 5 Mar 2025 14:41:27 +0200 Subject: [PATCH 5/6] add endpoint to get prices of vms and public ips --- server/app/admin_handler.go | 20 +++++++++++++ server/app/app.go | 2 ++ server/docs/docs.go | 60 +++++++++++++++++++++++++++++++++++++ server/docs/swagger.yaml | 39 ++++++++++++++++++++++++ 4 files changed, 121 insertions(+) diff --git a/server/app/admin_handler.go b/server/app/admin_handler.go index 1e228fd8..fcaeae23 100644 --- a/server/app/admin_handler.go +++ b/server/app/admin_handler.go @@ -245,6 +245,26 @@ func (a *App) GetDlsCountHandler(req *http.Request) (interface{}, Response) { }, Ok() } +// GetPricesHandler return vms and public ip prices +// Example endpoint: Get vms and public ip prices +// @Summary Get vms and public ip prices +// @Description Get vms and public ip prices +// @Tags Admin +// @Accept json +// @Produce json +// @Security BearerAuth +// @Success 200 {object} internal.Prices +// @Failure 400 {object} Response +// @Failure 401 {object} Response +// @Failure 500 {object} Response +// @Router /prices [get] +func (a *App) GetPricesHandler(req *http.Request) (interface{}, Response) { + return ResponseMsg{ + Message: "Prices are found", + Data: a.config.PricesPerMonth, + }, Ok() +} + // GetBalanceHandler return account balance information // Example endpoint: Get main TF account balance // @Summary Get main TF account balance diff --git a/server/app/app.go b/server/app/app.go index 2d455988..fd2028c3 100644 --- a/server/app/app.go +++ b/server/app/app.go @@ -130,6 +130,7 @@ func (a *App) registerHandlers() { voucherRouter := adminRouter.PathPrefix("/voucher").Subrouter() maintenanceRouter := adminRouter.PathPrefix("/maintenance").Subrouter() balanceRouter := adminRouter.PathPrefix("/balance").Subrouter() + pricesRouter := adminRouter.PathPrefix("/prices").Subrouter() deploymentsRouter := adminRouter.PathPrefix("/deployments").Subrouter() nextLaunchRouter := adminRouter.PathPrefix("/nextlaunch").Subrouter() @@ -188,6 +189,7 @@ func (a *App) registerHandlers() { adminRouter.HandleFunc("/set_admin", WrapFunc(a.SetAdminHandler)).Methods("PUT", "OPTIONS") adminRouter.HandleFunc("/set_prices", WrapFunc(a.SetPricesHandler)).Methods("PUT", "OPTIONS") balanceRouter.HandleFunc("", WrapFunc(a.GetBalanceHandler)).Methods("GET", "OPTIONS") + pricesRouter.HandleFunc("", WrapFunc(a.GetPricesHandler)).Methods("GET", "OPTIONS") maintenanceRouter.HandleFunc("", WrapFunc(a.UpdateMaintenanceHandler)).Methods("PUT", "OPTIONS") deploymentsRouter.HandleFunc("", WrapFunc(a.DeleteAllDeploymentsHandler)).Methods("DELETE", "OPTIONS") deploymentsRouter.HandleFunc("/vm/{id}", WrapFunc(a.DeleteVMDeploymentHandler)).Methods("DELETE", "OPTIONS") diff --git a/server/docs/docs.go b/server/docs/docs.go index 6ec7941d..2d8766cc 100644 --- a/server/docs/docs.go +++ b/server/docs/docs.go @@ -1117,6 +1117,46 @@ const docTemplate = `{ } } }, + "/prices": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Get vms and public ip prices", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin" + ], + "summary": "Get vms and public ip prices", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/internal.Prices" + } + }, + "400": { + "description": "Bad Request", + "schema": {} + }, + "401": { + "description": "Unauthorized", + "schema": {} + }, + "500": { + "description": "Internal Server Error", + "schema": {} + } + } + } + }, "/region": { "get": { "security": [ @@ -3154,6 +3194,23 @@ const docTemplate = `{ "voucherAndBalanceAndCard" ] }, + "internal.Prices": { + "type": "object", + "properties": { + "large_vm": { + "type": "number" + }, + "medium_vm": { + "type": "number" + }, + "public_ip": { + "type": "number" + }, + "small_vm": { + "type": "number" + } + } + }, "models.Card": { "type": "object", "required": [ @@ -3394,6 +3451,9 @@ const docTemplate = `{ "user_id" ], "properties": { + "created_at": { + "type": "string" + }, "id": { "type": "integer" }, diff --git a/server/docs/swagger.yaml b/server/docs/swagger.yaml index 1cb21fca..87199e43 100644 --- a/server/docs/swagger.yaml +++ b/server/docs/swagger.yaml @@ -336,6 +336,17 @@ definitions: - voucherAndCard - balanceAndCard - voucherAndBalanceAndCard + internal.Prices: + properties: + large_vm: + type: number + medium_vm: + type: number + public_ip: + type: number + small_vm: + type: number + type: object models.Card: properties: brand: @@ -491,6 +502,8 @@ definitions: type: object models.Notification: properties: + created_at: + type: string id: type: integer msg: @@ -1401,6 +1414,32 @@ paths: summary: Set user's notifications as seen tags: - Notification + /prices: + get: + consumes: + - application/json + description: Get vms and public ip prices + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/internal.Prices' + "400": + description: Bad Request + schema: {} + "401": + description: Unauthorized + schema: {} + "500": + description: Internal Server Error + schema: {} + security: + - BearerAuth: [] + summary: Get vms and public ip prices + tags: + - Admin /region: get: consumes: From 3bb78106551f72e2d5771fe5cab3e04d755157a7 Mon Sep 17 00:00:00 2001 From: rawdaGastan Date: Wed, 5 Mar 2025 14:43:19 +0200 Subject: [PATCH 6/6] delete user vouchers when account is deleted --- server/app/user_handler.go | 11 +++++++++-- server/models/voucher.go | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/server/app/user_handler.go b/server/app/user_handler.go index a45ba445..c620e9d8 100644 --- a/server/app/user_handler.go +++ b/server/app/user_handler.go @@ -1050,15 +1050,22 @@ func (a *App) DeleteUserHandler(req *http.Request) (interface{}, Response) { } } + // 6. Delete vouchers + err = a.db.DeleteUserVouchers(userID) + if err != nil && err != gorm.ErrRecordNotFound { + log.Error().Err(err).Send() + return nil, InternalServerError(errors.New(internalServerErrorMsg)) + } + + // 7. Remove cards err = a.db.DeleteAllCards(userID) if err != nil && err != gorm.ErrRecordNotFound { log.Error().Err(err).Send() return nil, InternalServerError(errors.New(internalServerErrorMsg)) } - // 6. TODO: should invoices be deleted? + // 8. TODO: should invoices be deleted? - // 7. Remove cards err = a.db.DeleteUser(userID) if err == gorm.ErrRecordNotFound { return nil, NotFound(errors.New("user is not found")) diff --git a/server/models/voucher.go b/server/models/voucher.go index 01f20f2c..466968f8 100644 --- a/server/models/voucher.go +++ b/server/models/voucher.go @@ -71,3 +71,8 @@ func (d *DB) GetNotUsedVoucherByUserID(id string) (Voucher, error) { var res Voucher return res, d.db.Last(&res, "user_id = ? AND used = false", id).Error } + +func (d *DB) DeleteUserVouchers(userID string) error { + var vouchers []Voucher + return d.db.Clauses(clause.Returning{}).Where("user_id = ?", userID).Delete(&vouchers).Error +}