modified: serv_nginx/api_bb/internal/handlers/avatar.go

add loggs into all methods
This commit is contained in:
2025-10-16 12:42:19 +05:00
parent 4afc8c2cfd
commit 1704ceb91b
+108 -6
View File
@@ -29,6 +29,12 @@ func NewAvatarHandler(avatarService service.AvatarService) *AvatarHandler {
func (h *AvatarHandler) Routes() chi.Router { func (h *AvatarHandler) Routes() chi.Router {
r := chi.NewRouter() r := chi.NewRouter()
h.logger.Debug("Registering avatar routes",
zap.String("POST", "/upload"),
zap.String("DELETE", "/delete"),
zap.String("GET", "/{filename}"),
)
// r.Get("/avatar/{filename}", h.ServeAvatar) // r.Get("/avatar/{filename}", h.ServeAvatar)
r.Post("/upload", h.UploadAvatar) r.Post("/upload", h.UploadAvatar)
r.Delete("/delete", h.DeleteAvatar) r.Delete("/delete", h.DeleteAvatar)
@@ -38,25 +44,54 @@ func (h *AvatarHandler) Routes() chi.Router {
} }
func (h *AvatarHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) { func (h *AvatarHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) {
h.logger.Debug("UploadAvatar START",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
defer func() {
h.logger.Debug("UploadAvatar END",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
)
}()
user, ok := middleware.GetUserFromContext(r.Context()) user, ok := middleware.GetUserFromContext(r.Context())
if !ok { if !ok {
h.logger.Warn("UploadAvatar: authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required") utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return return
} }
h.logger.Debug("UploadAvatar: user authenticated",
zap.Int64("user_id", int64(user.ID)),
zap.String("username", user.FirstName+user.LastName),
)
// Парсим multipart форму // Парсим multipart форму
h.logger.Debug("UploadAvatar: parsing multipart form")
if err := r.ParseMultipartForm(10 << 20); err != nil { // 10MB limit if err := r.ParseMultipartForm(10 << 20); err != nil { // 10MB limit
h.logger.Error("UploadAvatar: failed to parse form", zap.Error(err))
utils.RespondWithError(w, http.StatusBadRequest, "Failed to parse form: "+err.Error()) utils.RespondWithError(w, http.StatusBadRequest, "Failed to parse form: "+err.Error())
return return
} }
h.logger.Debug("UploadAvatar: getting file from form")
file, header, err := r.FormFile("avatar") file, header, err := r.FormFile("avatar")
if err != nil { if err != nil {
h.logger.Error("UploadAvatar: failed to get file from form", zap.Error(err))
utils.RespondWithError(w, http.StatusBadRequest, "Failed to get file: "+err.Error()) utils.RespondWithError(w, http.StatusBadRequest, "Failed to get file: "+err.Error())
return return
} }
defer file.Close() defer file.Close()
h.logger.Debug("UploadAvatar: file received",
zap.String("filename", header.Filename),
zap.Int64("size", header.Size),
zap.String("content_type", header.Header.Get("Content-Type")),
)
// Проверяем тип файла // Проверяем тип файла
allowedTypes := map[string]bool{ allowedTypes := map[string]bool{
"image/jpeg": true, "image/jpeg": true,
@@ -64,19 +99,34 @@ func (h *AvatarHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) {
"image/png": true, "image/png": true,
"image/gif": true, "image/gif": true,
} }
if !allowedTypes[header.Header.Get("Content-Type")] { contentType := header.Header.Get("Content-Type")
if !allowedTypes[contentType] {
h.logger.Warn("UploadAvatar: invalid file type",
zap.String("content_type", contentType),
zap.String("filename", header.Filename),
)
utils.RespondWithError(w, http.StatusBadRequest, "Only JPEG, PNG and GIF images are allowed") utils.RespondWithError(w, http.StatusBadRequest, "Only JPEG, PNG and GIF images are allowed")
return return
} }
h.logger.Debug("UploadAvatar: file type validated successfully")
// Загружаем аватар // Загружаем аватар
h.logger.Debug("UploadAvatar: calling avatarService.UploadAvatar",
zap.Int64("user_id", int64(user.ID)),
)
avatarPath, err := h.avatarService.UploadAvatar(user.ID, file, header) avatarPath, err := h.avatarService.UploadAvatar(user.ID, file, header)
if err != nil { if err != nil {
h.logger.Error("Failed to upload avatar", zap.Error(err)) h.logger.Error("UploadAvatar: failed to upload avatar", zap.Error(err))
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to upload avatar: "+err.Error()) utils.RespondWithError(w, http.StatusInternalServerError, "Failed to upload avatar: "+err.Error())
return return
} }
h.logger.Info("UploadAvatar: avatar uploaded successfully",
zap.Int64("user_id", int64(user.ID)),
zap.String("avatar_path", avatarPath),
)
// Возвращаем ответ с полем success // Возвращаем ответ с полем success
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{ utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
"success": true, "success": true,
@@ -86,18 +136,44 @@ func (h *AvatarHandler) UploadAvatar(w http.ResponseWriter, r *http.Request) {
} }
func (h *AvatarHandler) DeleteAvatar(w http.ResponseWriter, r *http.Request) { func (h *AvatarHandler) DeleteAvatar(w http.ResponseWriter, r *http.Request) {
h.logger.Debug("DeleteAvatar START",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.String("remote_addr", r.RemoteAddr),
)
defer func() {
h.logger.Debug("DeleteAvatar END",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
)
}()
user, ok := middleware.GetUserFromContext(r.Context()) user, ok := middleware.GetUserFromContext(r.Context())
if !ok { if !ok {
h.logger.Warn("DeleteAvatar: authentication required")
utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required") utils.RespondWithError(w, http.StatusUnauthorized, "Authentication required")
return return
} }
h.logger.Debug("DeleteAvatar: user authenticated",
zap.Int64("user_id", int64(user.ID)),
zap.String("username", user.FirstName+user.LastName),
)
h.logger.Debug("DeleteAvatar: calling avatarService.DeleteAvatar",
zap.Int64("user_id", int64(user.ID)),
)
if err := h.avatarService.DeleteAvatar(user.ID); err != nil { if err := h.avatarService.DeleteAvatar(user.ID); err != nil {
h.logger.Error("Failed to delete avatar", zap.Error(err)) h.logger.Error("DeleteAvatar: failed to delete avatar", zap.Error(err))
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete avatar: "+err.Error()) utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete avatar: "+err.Error())
return return
} }
h.logger.Info("DeleteAvatar: avatar deleted successfully",
zap.Int64("user_id", int64(user.ID)),
)
// Возвращаем ответ с полем success // Возвращаем ответ с полем success
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{ utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
"success": true, "success": true,
@@ -109,37 +185,63 @@ func (h *AvatarHandler) DeleteAvatar(w http.ResponseWriter, r *http.Request) {
func (h *AvatarHandler) GetAvatar(w http.ResponseWriter, r *http.Request) { func (h *AvatarHandler) GetAvatar(w http.ResponseWriter, r *http.Request) {
filename := chi.URLParam(r, "filename") filename := chi.URLParam(r, "filename")
h.logger.Info("handling get avatar request", h.logger.Debug("GetAvatar START",
zap.String("method", r.Method),
zap.String("filename", filename),
zap.String("remote_addr", r.RemoteAddr),
zap.String("url", r.URL.String()),
)
defer func() {
h.logger.Debug("GetAvatar END",
zap.String("method", r.Method),
zap.String("filename", filename),
)
}()
h.logger.Info("GetAvatar: handling get avatar request",
zap.String("method", r.Method), zap.String("method", r.Method),
zap.String("filename", filename), zap.String("filename", filename),
zap.String("remote_addr", r.RemoteAddr), zap.String("remote_addr", r.RemoteAddr),
) )
// Вариант 1: Используем ServeAvatarFile (более эффективно для больших файлов) // Вариант 1: Используем ServeAvatarFile (более эффективно для больших файлов)
h.logger.Debug("GetAvatar: calling avatarService.ServeAvatarFile",
zap.String("filename", filename),
)
contentType, err := h.avatarService.ServeAvatarFile(w, filename) contentType, err := h.avatarService.ServeAvatarFile(w, filename)
if err != nil { if err != nil {
h.logger.Warn("failed to serve avatar file", h.logger.Warn("GetAvatar: failed to serve avatar file",
zap.String("filename", filename), zap.String("filename", filename),
zap.Error(err), zap.Error(err),
) )
switch { switch {
case err.Error() == "avatar file not found": case err.Error() == "avatar file not found":
h.logger.Warn("GetAvatar: avatar file not found", zap.String("filename", filename))
utils.RespondWithError(w, http.StatusNotFound, "Avatar not found") utils.RespondWithError(w, http.StatusNotFound, "Avatar not found")
case err.Error() == "invalid filename" || err.Error() == "unsupported file format": case err.Error() == "invalid filename" || err.Error() == "unsupported file format":
h.logger.Warn("GetAvatar: invalid filename or format",
zap.String("filename", filename),
zap.Error(err),
)
utils.RespondWithError(w, http.StatusBadRequest, err.Error()) utils.RespondWithError(w, http.StatusBadRequest, err.Error())
default: default:
h.logger.Error("GetAvatar: internal server error", zap.Error(err))
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to serve avatar") utils.RespondWithError(w, http.StatusInternalServerError, "Failed to serve avatar")
} }
return return
} }
// Устанавливаем заголовки // Устанавливаем заголовки
h.logger.Debug("GetAvatar: setting response headers",
zap.String("content_type", contentType),
)
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
w.Header().Set("Cache-Control", "public, max-age=31536000") // Кэш на 1 год w.Header().Set("Cache-Control", "public, max-age=31536000") // Кэш на 1 год
w.Header().Set("Expires", time.Now().Add(365*24*time.Hour).Format(http.TimeFormat)) w.Header().Set("Expires", time.Now().Add(365*24*time.Hour).Format(http.TimeFormat))
h.logger.Info("avatar served successfully", h.logger.Info("GetAvatar: avatar served successfully",
zap.String("filename", filename), zap.String("filename", filename),
zap.String("content_type", contentType), zap.String("content_type", contentType),
) )