From e5a80c8ae74ca6e43737a09a5ddcc03e07c12833 Mon Sep 17 00:00:00 2001 From: anxi0uz Date: Fri, 20 Mar 2026 17:28:13 +0500 Subject: [PATCH] delete endpoint --- internal/handler/user.go | 64 ++++++++++++++++++++++++++++++++++++++-- pkg/storage.go | 6 +++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/internal/handler/user.go b/internal/handler/user.go index 883af13..1f8c3b7 100644 --- a/internal/handler/user.go +++ b/internal/handler/user.go @@ -168,14 +168,74 @@ func (s *Server) AuthRegister(w http.ResponseWriter, r *http.Request) { FullName: req.FullName, } - if err := storage.Create[models.User](ctx, "users", user, s.DB); err != nil { + if err := storage.Create(ctx, "users", user, s.DB); err != nil { slog.ErrorContext(ctx, "Error while creating user", slog.String("error", err.Error())) s.JSON(w, r, http.StatusInternalServerError, "Server error", "error") return } s.issueTokens(w, r, &user) } -func (s *Server) DeleteMe(w http.ResponseWriter, r *http.Request) {} +func (s *Server) DeleteMe(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + claimsValue := ctx.Value("user") + claims, ok := claimsValue.(*Claims) + if !ok { + slog.ErrorContext(ctx, "Error while converting claims", slog.Any("claims", claimsValue)) + s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") + return + } + userID := claims.ID + tx, err := s.DB.Begin(ctx) + if err != nil { + slog.ErrorContext(ctx, "Error while begining transaction", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") + return + } + defer tx.Rollback(ctx) + + err = storage.Delete[models.User](ctx, "users", tx, func(sb *sqlbuilder.DeleteBuilder) { + sb.Where(sb.Equal("id", userID)) + }) + if err != nil { + slog.ErrorContext(ctx, "Error while deleting user", slog.String("error", err.Error()), slog.String("id", userID.String())) + s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") + return + } + + jwt := r.Header.Get("Authorization") + tokenKey := "access_token" + jwt + if err := s.Redis.Del(ctx, tokenKey).Err(); err != nil { + slog.ErrorContext(ctx, "Error while deleting access token from redis", slog.String("token", jwt)) + s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") + return + } + cookie, err := r.Cookie("refresh_token") + if err != nil { + s.JSON(w, r, http.StatusUnauthorized, "Missing refresh token", "error") + return + } + refreshStr := cookie.Value + if refreshStr == "" { + s.JSON(w, r, http.StatusUnauthorized, "Empty refresh token", "error") + return + } + key := "refresh_token:" + refreshStr + if err := s.Redis.Del(ctx, key).Err(); err != nil { + slog.ErrorContext(ctx, "Error while deleting refresh token from redis", slog.String("token", refreshStr)) + s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") + return + } + + if err := tx.Commit(ctx); err != nil { + slog.ErrorContext(ctx, "Error while committing transaction", slog.String("error", err.Error())) + s.JSON(w, r, http.StatusInternalServerError, "Internal server error", "error") + return + } + + s.JSON(w, r, http.StatusOK, "deleted", "ok") +} + func (s *Server) GetMe(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/pkg/storage.go b/pkg/storage.go index 742b5cb..7cee172 100644 --- a/pkg/storage.go +++ b/pkg/storage.go @@ -132,12 +132,16 @@ func Update[T any](ctx context.Context, table string, item T, db Querier, opts . return nil } -func Delete[T any](ctx context.Context, table string, db Querier, opts ...func(*sqlbuilder.SelectBuilder)) error { +func Delete[T any](ctx context.Context, table string, db Querier, opts ...func(*sqlbuilder.DeleteBuilder)) error { structs := sqlbuilder.NewStruct(new(T)) sb := structs.WithoutTag("db", "-").DeleteFrom(table) sb.SetFlavor(sqlbuilder.PostgreSQL) + for _, opt := range opts { + opt(sb) + } + query, args := sb.Build() if _, err := db.Exec(ctx, query, args...); err != nil {