From ae5ddc7d79dc8fb431abfc2cf1bec2ee3b645644 Mon Sep 17 00:00:00 2001 From: c7-2know Date: Thu, 29 Aug 2024 16:58:52 +0300 Subject: [PATCH] implement storing profile picture on cloud service --- .../AAiT-backend-group-11/bootstrap/env.go | 27 +++--- .../delivery/controller/auth_controller.go | 20 ++-- .../delivery/controller/profile_controller.go | 68 ++++++++++++-- .../delivery/router/auth_router.go | 2 +- .../delivery/router/profile_router.go | 22 ++++- .../delivery/router/router.go | 3 +- .../domain/dto/profile_dto.go | 15 ++- .../domain/interfaces/auth.go | 2 +- .../domain/interfaces/profile.go | 20 +++- .../domain/interfaces/token.go | 5 +- .../middleware/authorization.go | 7 +- .../repository/profile_repository.go | 71 +++++++++++++- .../repository/token_repository.go | 7 +- .../service/auth_serivce.go | 2 +- .../service/profile_service.go | 92 +++++++++++++++++-- .../service/token_service.go | 44 +++++++-- 16 files changed, 339 insertions(+), 68 deletions(-) diff --git a/backend/AAiT-backend-group-11/bootstrap/env.go b/backend/AAiT-backend-group-11/bootstrap/env.go index 35877483f..865651f56 100644 --- a/backend/AAiT-backend-group-11/bootstrap/env.go +++ b/backend/AAiT-backend-group-11/bootstrap/env.go @@ -11,19 +11,22 @@ import ( // Env is a struct to hold environment variables. type Env struct { - AppEnv string `mapstructure:"APP_ENV"` - ContextTimeout int `mapstructure:"CONTEXT_TIMEOUT"` - DBHost string `mapstructure:"DB_HOST"` - DBPort string `mapstructure:"DB_PORT"` - DBName string `mapstructure:"DB_NAME"` - DBUri string `mapstructure:"MONGODB_URI"` - AccessTokenExpiryHour int `mapstructure:"ACCESS_TOKEN_EXPIRY_HOUR"` - RefreshTokenExpiryHour int `mapstructure:"REFRESH_TOKEN_EXPIRY_HOUR"` - AccessTokenSecret string `mapstructure:"ACCESS_TOKEN_SECRET"` - RefreshTokenSecret string `mapstructure:"REFRESH_TOKEN_SECRET"` - PasswordResetSecret string `mapstructure:"PASSWORD_RESET_SECRET"` - GeminiApiKey string `mapstructure:"GEMINI_API_KEY"` + AppEnv string `mapstructure:"APP_ENV"` + ContextTimeout int `mapstructure:"CONTEXT_TIMEOUT"` + DBHost string `mapstructure:"DB_HOST"` + DBPort string `mapstructure:"DB_PORT"` + DBName string `mapstructure:"DB_NAME"` + DBUri string `mapstructure:"MONGODB_URI"` + AccessTokenExpiryHour int `mapstructure:"ACCESS_TOKEN_EXPIRY_HOUR"` + RefreshTokenExpiryHour int `mapstructure:"REFRESH_TOKEN_EXPIRY_HOUR"` + AccessTokenSecret string `mapstructure:"ACCESS_TOKEN_SECRET"` + RefreshTokenSecret string `mapstructure:"REFRESH_TOKEN_SECRET"` + PasswordResetSecret string `mapstructure:"PASSWORD_RESET_SECRET"` + GeminiApiKey string `mapstructure:"GEMINI_API_KEY"` RedisAddress string `mapstructure:"REDIS_ADDRESS"` + CloudName string `mapstructure:"CLOUD_NAME"` + ApiKey string `mapstructure:"CLOUD_API_KEY"` + ApiSecret string `mapstructure:"CLOUD_API_SECRET"` } // NewEnv initializes and returns a new instance of the Env struct. diff --git a/backend/AAiT-backend-group-11/delivery/controller/auth_controller.go b/backend/AAiT-backend-group-11/delivery/controller/auth_controller.go index e2ef59efc..1fecdb6df 100644 --- a/backend/AAiT-backend-group-11/delivery/controller/auth_controller.go +++ b/backend/AAiT-backend-group-11/delivery/controller/auth_controller.go @@ -73,27 +73,35 @@ func (controller *AuthController) Login(c *gin.Context) { } c.Header("Authorization", "Bearer "+accessToken) + c.SetCookie("refresh_token", refreshToken.Token, int(refreshToken.ExpiresAt.Unix()), "/", "localhost", false, true) + c.Set("userId", refreshToken.UserID) + + c.JSON(200, gin.H{"access_token": accessToken}) c.JSON(200, gin.H{"refresh_token": refreshToken.Token}) c.JSON(200, gin.H{"message": "login successful"}) - c.Set("userId", refreshToken.UserID) - c.SetCookie("refresh_token", refreshToken.Token, int(refreshToken.ExpiresAt.Unix()), "/", "localhost", false, true) } func (controller *AuthController) Logout(c *gin.Context) { userId := c.GetString("userId") - controller.authService.Logout(userId) + err:=controller.authService.Logout(userId) + if err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + c.SetCookie("refresh_token", "", -1, "/", "localhost", false, true) + c.Header("Authorization", "") c.JSON(200, gin.H{"message": "succesfully logged out"}) } func (controller *AuthController) RefreshAccessToken(c *gin.Context) { - var token entities.RefreshToken - err := c.ShouldBindJSON(&token) + refresh,err:=c.Cookie("refresh_token") + if err != nil { c.JSON(400, gin.H{"error": err.Error()}) return } - controller.authService.RefreshAccessToken(&token) + controller.authService.RefreshAccessToken(refresh) } func (controller *AuthController) VerifyEmail(c *gin.Context) { diff --git a/backend/AAiT-backend-group-11/delivery/controller/profile_controller.go b/backend/AAiT-backend-group-11/delivery/controller/profile_controller.go index aee4e9cce..536e475d4 100644 --- a/backend/AAiT-backend-group-11/delivery/controller/profile_controller.go +++ b/backend/AAiT-backend-group-11/delivery/controller/profile_controller.go @@ -14,6 +14,14 @@ type ProfileController struct { func NewProfileController(service interfaces.ProfileService) ProfileController { return ProfileController{ProfileService: service} } +func (controller *ProfileController) GetAllProfiles(ctx *gin.Context) { + profiles, err := controller.ProfileService.GetAllProfiles() + if err != nil { + ctx.JSON(400, gin.H{"error": err.Error()}) + return + } + ctx.JSON(200, profiles) +} func (controller *ProfileController) CreateUserProfile(ctx *gin.Context) { var profile dto.CreateProfileDto @@ -28,18 +36,17 @@ func (controller *ProfileController) CreateUserProfile(ctx *gin.Context) { return } profile.UserID = userID - + profile_, err := controller.ProfileService.CreateUserProfile(&profile) - if err!=nil{ + if err != nil { ctx.JSON(400, gin.H{"error": err.Error()}) return } ctx.JSON(200, gin.H{"message": "Profile created successfully", "profile": profile_}) } - func (controller *ProfileController) GetUserProfile(ctx *gin.Context) { - userId:=ctx.Param("userId") + userId := ctx.Param("userId") profile, err := controller.ProfileService.GetUserProfile(userId) if err != nil { ctx.JSON(400, gin.H{"error": err.Error()}) @@ -56,10 +63,10 @@ func (controller *ProfileController) UpdateUserProfile(ctx *gin.Context) { ctx.JSON(400, gin.H{"error": err.Error()}) return } - updUserId:=ctx.Param("userId") + updUserId := ctx.Param("userId") UserID := ctx.GetString("userId") - if UserID!=updUserId { + if UserID != updUserId { ctx.JSON(400, gin.H{"error": "You are only authorized to update your own profile"}) return } @@ -73,10 +80,11 @@ func (controller *ProfileController) UpdateUserProfile(ctx *gin.Context) { } func (controller *ProfileController) DeleteUserProfile(ctx *gin.Context) { - delId:=ctx.Param("userId") + delId := ctx.Param("userId") userId := ctx.GetString("userId") - if userId!=delId { - ctx.JSON(400, gin.H{"error": "You are only authorized to delete your own profile"}) + if userId != delId { + + ctx.JSON(400, gin.H{"error": "You are only authorized to delete your own profile", "userId": userId, "delId": delId}) return } err := controller.ProfileService.DeleteUserProfile(userId) @@ -86,3 +94,45 @@ func (controller *ProfileController) DeleteUserProfile(ctx *gin.Context) { } ctx.JSON(200, gin.H{"message": "Profile deleted successfully"}) } + +func (controller *ProfileController) UpdateOrCreateProfilePicture(ctx *gin.Context) { + userId := ctx.GetString("userId") + image, err := ctx.FormFile("image") + if err != nil { + ctx.JSON(400, gin.H{"error": err.Error()}) + return + } + + url, err := controller.ProfileService.UpdateProfilePicture(userId, image) + if err != nil { + ctx.JSON(400, gin.H{"error": err.Error()}) + return + } + ctx.JSON(200, gin.H{"message": "Profile picture updated successfully", "url": url}) + +} + +func (controller *ProfileController) GetProfilePicture(ctx *gin.Context) { + userId := ctx.Param("userId") + url, err := controller.ProfileService.GetProfilePicture(userId) + if err != nil { + ctx.JSON(400, gin.H{"error": err.Error()}) + return + } + ctx.JSON(200, gin.H{"url": url}) +} + +func (controller *ProfileController) DeleteProfilePicture(ctx *gin.Context) { + userId := ctx.GetString("userId") + user_id := ctx.Param("userId") + if userId != user_id { + ctx.JSON(400, gin.H{"error": "You cann't delete others profile picture", "userId": userId, "user_id": user_id}) + return + } + err := controller.ProfileService.DeleteProfilePicture(userId) + if err != nil { + ctx.JSON(400, gin.H{"error": err.Error()}) + return + } + ctx.JSON(200, gin.H{"message": "Profile picture deleted successfully"}) +} diff --git a/backend/AAiT-backend-group-11/delivery/router/auth_router.go b/backend/AAiT-backend-group-11/delivery/router/auth_router.go index 1186cc848..9d3942fb6 100644 --- a/backend/AAiT-backend-group-11/delivery/router/auth_router.go +++ b/backend/AAiT-backend-group-11/delivery/router/auth_router.go @@ -33,7 +33,7 @@ func NewAuthRouter(env *bootstrap.Env, db *mongo.Database, group *gin.RouterGrou group.POST("login", auth_controller.Login) group.POST("logout", auth_controller.Logout) - group.POST("refresh", auth_controller.RefreshAccessToken) + group.GET("refresh", auth_controller.RefreshAccessToken) group.POST("register", auth_controller.RegisterUser) group.POST("/verify-email", auth_controller.VerifyEmail) group.POST("/forgot-password", auth_controller.RequestPasswordReset) diff --git a/backend/AAiT-backend-group-11/delivery/router/profile_router.go b/backend/AAiT-backend-group-11/delivery/router/profile_router.go index d5005a738..fa2bc7e4c 100644 --- a/backend/AAiT-backend-group-11/delivery/router/profile_router.go +++ b/backend/AAiT-backend-group-11/delivery/router/profile_router.go @@ -1,7 +1,9 @@ package route import ( + "backend-starter-project/bootstrap" "backend-starter-project/delivery/controller" + "backend-starter-project/infrastructure" "backend-starter-project/repository" "backend-starter-project/service" "context" @@ -10,14 +12,28 @@ import ( "go.mongodb.org/mongo-driver/mongo" ) -func NewProfileRouter(db *mongo.Database, group *gin.RouterGroup) { +func NewProfileRouter(env *bootstrap.Env,db *mongo.Database, group *gin.RouterGroup) { + cloudName := env.CloudName + apiKey := env.ApiKey + apiSecret := env.ApiSecret + + imageService,err:= infrastructure.NewImageService(cloudName,apiKey,apiSecret) + if err != nil { + panic(err) + } + + profile_repo := repository.NewProfileRepository(context.TODO(), db) - profile_service := service.NewProfileService(profile_repo) + profile_service := service.NewProfileService(profile_repo,imageService) profile_controller := controller.NewProfileController(profile_service) group.GET("/profile/:userId", profile_controller.GetUserProfile) group.POST("/profile", profile_controller.CreateUserProfile) group.PUT("/profile/:userId", profile_controller.UpdateUserProfile) group.DELETE("/profile/:userId", profile_controller.DeleteUserProfile) - + group.POST("/profile/profilePicture", profile_controller.UpdateOrCreateProfilePicture) + group.PUT("/profile/profilePicture", profile_controller.UpdateOrCreateProfilePicture) + group.GET("/profile/profilePicture/:userId", profile_controller.GetProfilePicture) + group.DELETE("/profile/profilePicture/:userId", profile_controller.DeleteProfilePicture) + group.GET("/profile", profile_controller.GetAllProfiles) } diff --git a/backend/AAiT-backend-group-11/delivery/router/router.go b/backend/AAiT-backend-group-11/delivery/router/router.go index 280ae983c..b22120f99 100644 --- a/backend/AAiT-backend-group-11/delivery/router/router.go +++ b/backend/AAiT-backend-group-11/delivery/router/router.go @@ -24,8 +24,7 @@ func Setup(env *bootstrap.Env, db *mongo.Database, gin *gin.Engine, auth middlew NewBlogRouter(db, privateRouter.Group("/blogs"), model, redis) NewCommmentRouter(db, privateRouter.Group("/comments")) NewAuthRouter(env,db, publicRouter.Group("/auth")) - NewProfileRouter(db, privateRouter.Group("/user")) - NewUserRouter(db, adminRouter.Group("/user")) + NewProfileRouter(env,db, privateRouter.Group("/user")) gin.Run(":8080") } \ No newline at end of file diff --git a/backend/AAiT-backend-group-11/domain/dto/profile_dto.go b/backend/AAiT-backend-group-11/domain/dto/profile_dto.go index 10e0c9a8d..6efff5440 100644 --- a/backend/AAiT-backend-group-11/domain/dto/profile_dto.go +++ b/backend/AAiT-backend-group-11/domain/dto/profile_dto.go @@ -1,5 +1,7 @@ package dto +import "backend-starter-project/domain/entities" + type CreateProfileDto struct { UserID string `json:"-"` Bio string `json:"bio"` @@ -13,5 +15,14 @@ type UpdateProfileDto struct { UserID string `json:"-"` Bio string `json:"bio"` ProfilePicture string `json:"profilePicture"` - Address string `json:"address"` -} \ No newline at end of file + Address string `json:"address"` +} + +type ProfileResponse struct { + ID string `json:"id"` + UserID string `json:"userId"` + Bio string `json:"bio"` + ProfilePicture string `json:"profilePicture"` + ContactInfo entities.ContactInfo `json:"contactInfo"` +} + diff --git a/backend/AAiT-backend-group-11/domain/interfaces/auth.go b/backend/AAiT-backend-group-11/domain/interfaces/auth.go index 3ba4a3509..3fc18eca6 100644 --- a/backend/AAiT-backend-group-11/domain/interfaces/auth.go +++ b/backend/AAiT-backend-group-11/domain/interfaces/auth.go @@ -6,7 +6,7 @@ type AuthenticationService interface { RegisterUser(user *entities.User) (*entities.User, error) Login(emailOrUsername, password string) (*entities.RefreshToken,string, error) Logout(userId string) error - RefreshAccessToken(token *entities.RefreshToken) (string,error) + RefreshAccessToken(token string) (string,error) VerifyEmail(email string, code string) error ResendOtp(request entities.ResendOTPRequest) error } diff --git a/backend/AAiT-backend-group-11/domain/interfaces/profile.go b/backend/AAiT-backend-group-11/domain/interfaces/profile.go index 65a9b67de..5466ef617 100644 --- a/backend/AAiT-backend-group-11/domain/interfaces/profile.go +++ b/backend/AAiT-backend-group-11/domain/interfaces/profile.go @@ -3,18 +3,32 @@ package interfaces import ( "backend-starter-project/domain/dto" "backend-starter-project/domain/entities" + "mime/multipart" ) type ProfileRepository interface { + GetAllProfiles() ([]*entities.Profile, error) GetUserProfile(userId string) (*entities.Profile, error) UpdateUserProfile(profile *entities.Profile) (*entities.Profile, error) CreateUserProfile(profile *entities.Profile) (*entities.Profile, error) DeleteUserProfile(user_id string) error + UpdateProfilePicture(user_id,path string) error + GetProfilePicture(user_id string) (string,error) + DeleteProfilePicture(user_id string) error } type ProfileService interface { - GetUserProfile(userId string) (*entities.Profile, error) - UpdateUserProfile(profile *dto.UpdateProfileDto) (*entities.Profile, error) - CreateUserProfile(profile *dto.CreateProfileDto) (*entities.Profile, error) + GetAllProfiles() ([]*entities.Profile, error) + GetUserProfile(userId string) (*dto.ProfileResponse, error) + UpdateUserProfile(profile *dto.UpdateProfileDto) (*dto.ProfileResponse, error) + CreateUserProfile(profile *dto.CreateProfileDto) (*dto.ProfileResponse, error) DeleteUserProfile(user_id string) error + UpdateProfilePicture(user_id string,file *multipart.FileHeader) (string,error) + GetProfilePicture(user_id string) (string,error) + DeleteProfilePicture(user_id string) error } + +type ImageService interface { + UploadImage(file *multipart.FileHeader) (string, error) + DeleteImage(path string) error +} \ No newline at end of file diff --git a/backend/AAiT-backend-group-11/domain/interfaces/token.go b/backend/AAiT-backend-group-11/domain/interfaces/token.go index f40781245..0184b9cfe 100644 --- a/backend/AAiT-backend-group-11/domain/interfaces/token.go +++ b/backend/AAiT-backend-group-11/domain/interfaces/token.go @@ -16,8 +16,9 @@ type TokenService interface { VerifyRefreshToken(token string) error InvalidateAccessToken(token string) (string, error) InvalidateRefreshToken(token string) (string, error) - GetClaimsFromToken(token string) map[string]string - RefreshAccessToken(token *entities.RefreshToken) (string,error) + GetClaimsFromAccessToken(token string) map[string]string + GetClaimsFromRefreshToken(token string) map[string]string + RefreshAccessToken(accToken string) (string,error) CreateRefreshToken(refreshToken *entities.RefreshToken) (*entities.RefreshToken, error) DeleteRefreshTokenByUserId(userId string) error FindRefreshTokenByUserId(userId string) (*entities.RefreshToken, error) diff --git a/backend/AAiT-backend-group-11/infrastructure/middleware/authorization.go b/backend/AAiT-backend-group-11/infrastructure/middleware/authorization.go index a8acdb4df..72cc901d9 100644 --- a/backend/AAiT-backend-group-11/infrastructure/middleware/authorization.go +++ b/backend/AAiT-backend-group-11/infrastructure/middleware/authorization.go @@ -3,6 +3,7 @@ package middleware import ( "backend-starter-project/domain/interfaces" "errors" + "fmt" "log" "net/http" "strings" @@ -27,8 +28,10 @@ func (middleware *authMiddleware) AuthMiddleware(role string) gin.HandlerFunc { header := c.GetHeader("Authorization") refresh, err := c.Cookie("refresh_token") if err != nil { + fmt.Println("error from auth middleware: second err", err) err := middleware.TokenService.VerifyRefreshToken(refresh) if err != nil { + fmt.Println("error from auth middleware: first err", err) c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"}) c.Abort() return @@ -58,12 +61,12 @@ func (middleware *authMiddleware) AuthMiddleware(role string) gin.HandlerFunc { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"}) c.Abort() } - + fmt.Println("Error from auth middleware: ", err) c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"}) c.Abort() return } - claims := middleware.TokenService.GetClaimsFromToken(authParts[1]) + claims := middleware.TokenService.GetClaimsFromAccessToken(authParts[1]) if role != "" { if claims["role"] != role { c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient permissions"}) diff --git a/backend/AAiT-backend-group-11/repository/profile_repository.go b/backend/AAiT-backend-group-11/repository/profile_repository.go index c5af8bfc3..3f9b0a467 100644 --- a/backend/AAiT-backend-group-11/repository/profile_repository.go +++ b/backend/AAiT-backend-group-11/repository/profile_repository.go @@ -18,9 +18,21 @@ type profileRepository struct { } func NewProfileRepository(ctx context.Context, db *mongo.Database) interfaces.ProfileRepository { - return profileRepository{db: db, collection: db.Collection("profile"), context: ctx} + return &profileRepository{db: db, collection: db.Collection("profile"), context: ctx} } -func (repo profileRepository) GetUserProfile(user_id string) (*entities.Profile, error) { + +func (repo *profileRepository) GetAllProfiles() ([]*entities.Profile, error) { + var profiles []*entities.Profile + cursor, err := repo.collection.Find(repo.context, bson.D{}) + if err != nil { + return nil, err + } + cursor.All(repo.context, &profiles) + return profiles, nil + +} + +func (repo *profileRepository) GetUserProfile(user_id string) (*entities.Profile, error) { userID, err := primitive.ObjectIDFromHex(user_id) if err != nil { return nil, err @@ -42,7 +54,7 @@ func (repo profileRepository) GetUserProfile(user_id string) (*entities.Profile, } -func (repo profileRepository) CreateUserProfile(profile *entities.Profile) (*entities.Profile, error) { +func (repo *profileRepository) CreateUserProfile(profile *entities.Profile) (*entities.Profile, error) { if profile.UserID == primitive.NilObjectID { return nil, errors.New("user id is required") } @@ -56,7 +68,7 @@ func (repo profileRepository) CreateUserProfile(profile *entities.Profile) (*ent return profile, nil } -func (repo profileRepository) UpdateUserProfile(profile *entities.Profile) (*entities.Profile, error) { +func (repo *profileRepository) UpdateUserProfile(profile *entities.Profile) (*entities.Profile, error) { user_id := profile.UserID if user_id == primitive.NilObjectID { return nil, errors.New("user id is required") @@ -79,7 +91,7 @@ func (repo profileRepository) UpdateUserProfile(profile *entities.Profile) (*ent return profile, nil } -func (repo profileRepository) DeleteUserProfile(user_id string) error { +func (repo *profileRepository) DeleteUserProfile(user_id string) error { userID, err := primitive.ObjectIDFromHex(user_id) filter := bson.D{{"userId", userID}} _, err = repo.collection.DeleteOne(repo.context, filter) @@ -89,3 +101,52 @@ func (repo profileRepository) DeleteUserProfile(user_id string) error { return nil } + +func (repo *profileRepository) UpdateProfilePicture(user_id, path string) error { + userId, err := primitive.ObjectIDFromHex(user_id) + if err != nil { + return err + } + filter := bson.D{{"userId", userId}} + data := bson.D{{"$set", bson.D{{"profilePicture", path}}}} + var profile entities.Profile + res := repo.collection.FindOne(repo.context, filter) + err = res.Decode(&profile) + if err != nil { + return err + } + _, err = repo.collection.UpdateOne(repo.context, filter, data) + if err != nil { + return err + } + return nil + +} + +func (repo *profileRepository) GetProfilePicture(user_id string) (string, error) { + userId, err := primitive.ObjectIDFromHex(user_id) + if err != nil { + return "", err + } + var profile entities.Profile + prof := repo.collection.FindOne(repo.context, bson.D{{"userId", userId}}) + err = prof.Decode(&profile) + if err != nil { + return "", err + } + return profile.ProfilePicture, nil +} + +func (repo *profileRepository) DeleteProfilePicture(user_id string) error { + userId, err := primitive.ObjectIDFromHex(user_id) + if err != nil { + return err + } + filter := bson.D{{"userId", userId}} + data := bson.D{{"$set", bson.D{{"profilePicture", ""}}}} + _, err = repo.collection.UpdateOne(repo.context, filter, data) + if err != nil { + return err + } + return nil +} diff --git a/backend/AAiT-backend-group-11/repository/token_repository.go b/backend/AAiT-backend-group-11/repository/token_repository.go index 2edc9b531..8aedca16c 100644 --- a/backend/AAiT-backend-group-11/repository/token_repository.go +++ b/backend/AAiT-backend-group-11/repository/token_repository.go @@ -22,9 +22,9 @@ func NewTokenRepository(db *mongo.Database) interfaces.RefreshTokenRepository { func (tr *tokenRepository) CreateRefreshToken(token *entities.RefreshToken) (*entities.RefreshToken, error) { userID := token.UserID - + filter := bson.D{{"userId", userID}} - + existed := tr.Collection.FindOne(context.TODO(), filter) if existed.Err() != nil { _, err := tr.Collection.InsertOne(context.TODO(), token) @@ -40,12 +40,11 @@ func (tr *tokenRepository) FindRefreshTokenByUserId(user_id string) (*entities.R userID, err := primitive.ObjectIDFromHex(user_id) if err != nil { - return nil,err + return nil, err } filter := bson.D{{"userId", userID}} - result := tr.Collection.FindOne(context.TODO(), filter) if result.Err() != nil { return nil, result.Err() diff --git a/backend/AAiT-backend-group-11/service/auth_serivce.go b/backend/AAiT-backend-group-11/service/auth_serivce.go index 556600b85..a46350163 100644 --- a/backend/AAiT-backend-group-11/service/auth_serivce.go +++ b/backend/AAiT-backend-group-11/service/auth_serivce.go @@ -176,7 +176,7 @@ func (service *authService) Logout(userId string) error { } -func (service *authService) RefreshAccessToken(token *entities.RefreshToken) (string, error) { +func (service *authService) RefreshAccessToken(token string) (string, error) { refreshed, err := service.tokenService.RefreshAccessToken(token) if err != nil { return "", err diff --git a/backend/AAiT-backend-group-11/service/profile_service.go b/backend/AAiT-backend-group-11/service/profile_service.go index 45c3a8e8f..260b0e473 100644 --- a/backend/AAiT-backend-group-11/service/profile_service.go +++ b/backend/AAiT-backend-group-11/service/profile_service.go @@ -4,43 +4,65 @@ import ( "backend-starter-project/domain/dto" "backend-starter-project/domain/entities" "backend-starter-project/domain/interfaces" + "mime/multipart" "go.mongodb.org/mongo-driver/bson/primitive" ) type profileService struct { Profile_repo interfaces.ProfileRepository + imageService interfaces.ImageService } -func NewProfileService(repo interfaces.ProfileRepository) interfaces.ProfileService { - return &profileService{Profile_repo: repo} +func NewProfileService(repo interfaces.ProfileRepository,imageS interfaces.ImageService) interfaces.ProfileService { + return &profileService{Profile_repo: repo,imageService: imageS} } +func (profileService *profileService) GetAllProfiles() ([]*entities.Profile, error) { + profiles,err:=profileService.Profile_repo.GetAllProfiles() + if err!=nil{ + return nil,err + } + return profiles,nil +} -func (profileService *profileService) GetUserProfile(userId string) (*entities.Profile, error) { +func (profileService *profileService) GetUserProfile(userId string) (*dto.ProfileResponse, error) { profile, err := profileService.Profile_repo.GetUserProfile(userId) if err != nil { return nil, err } - return profile, nil + res := &dto.ProfileResponse{ + UserID: profile.UserID.Hex(), + Bio: profile.Bio, + ProfilePicture: profile.ProfilePicture, + ContactInfo: profile.ContactInfo, + } + return res, nil } -func (profileService *profileService) UpdateUserProfile(profile_dto *dto.UpdateProfileDto) (*entities.Profile, error) { +func (profileService *profileService) UpdateUserProfile(profile_dto *dto.UpdateProfileDto) (*dto.ProfileResponse, error) { userID, err := primitive.ObjectIDFromHex(profile_dto.UserID) profile := &entities.Profile{ UserID: userID, Bio: profile_dto.Bio, ProfilePicture: profile_dto.ProfilePicture, ContactInfo: entities.ContactInfo{ - Address: profile_dto.Address, + Address: profile_dto.Address, }, } updated, err := profileService.Profile_repo.UpdateUserProfile(profile) if err != nil { return nil, err } - return updated, nil + + res := &dto.ProfileResponse{ + UserID: updated.UserID.Hex(), + Bio: updated.Bio, + ProfilePicture: updated.ProfilePicture, + ContactInfo: updated.ContactInfo, + } + return res, nil } -func (profileService *profileService) CreateUserProfile(profile_dto *dto.CreateProfileDto) (*entities.Profile, error) { +func (profileService *profileService) CreateUserProfile(profile_dto *dto.CreateProfileDto) (*dto.ProfileResponse, error) { userID, err := primitive.ObjectIDFromHex(profile_dto.UserID) if err != nil { return nil, err @@ -60,7 +82,13 @@ func (profileService *profileService) CreateUserProfile(profile_dto *dto.CreateP if err != nil { return nil, err } - return result, nil + response := &dto.ProfileResponse{ + UserID: result.UserID.Hex(), + Bio: result.Bio, + ProfilePicture: result.ProfilePicture, + ContactInfo: result.ContactInfo, + } + return response, nil } func (profileService *profileService) DeleteUserProfile(user_id string) error { err := profileService.Profile_repo.DeleteUserProfile(user_id) @@ -69,3 +97,49 @@ func (profileService *profileService) DeleteUserProfile(user_id string) error { } return nil } + +func (profileService *profileService) UpdateProfilePicture(user_id string, file *multipart.FileHeader) (string, error) { + url, _ := profileService.GetProfilePicture(user_id) + if url != "" { + err := profileService.Profile_repo.UpdateProfilePicture(user_id, url) + if err != nil { + return "", err + } + } + url, err := profileService.imageService.UploadImage(file) + if err != nil { + return "", err + } + + err = profileService.Profile_repo.UpdateProfilePicture(user_id, url) + if err != nil { + return "", err + } + + return url, nil + +} + +func (profileService *profileService) GetProfilePicture(user_id string) (string, error) { + url, err := profileService.Profile_repo.GetProfilePicture(user_id) + if err != nil { + return "", err + } + return url, nil +} + +func (profileService *profileService) DeleteProfilePicture(user_id string) error { + url, err := profileService.Profile_repo.GetProfilePicture(user_id) + if err != nil { + return err + } + err = profileService.Profile_repo.DeleteProfilePicture(user_id) + if err != nil { + return err + } + err = profileService.imageService.DeleteImage(url) + if err != nil { + return err + } + return nil +} \ No newline at end of file diff --git a/backend/AAiT-backend-group-11/service/token_service.go b/backend/AAiT-backend-group-11/service/token_service.go index 1ee06ca43..0d8d67033 100644 --- a/backend/AAiT-backend-group-11/service/token_service.go +++ b/backend/AAiT-backend-group-11/service/token_service.go @@ -82,6 +82,7 @@ func (service *tokenService) GenerateAccessToken(user *entities.User) (string, e } func (service *tokenService) GenerateRefreshToken(user *entities.User) (*entities.RefreshToken, error) { + err:=service.tokenRepository.DeleteRefreshTokenByUserId(user.ID.Hex()) token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "userName": user.Username, @@ -133,6 +134,7 @@ func (service *tokenService) VerifyAccessToken(token string) error { } func (service *tokenService) VerifyRefreshToken(token string) error { + fmt.Println("from token service",token) refreshToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) @@ -140,6 +142,7 @@ func (service *tokenService) VerifyRefreshToken(token string) error { return []byte(service.refreshTokenSecret), nil }) if err != nil { + fmt.Println("from token service 1st",err) return err } @@ -147,13 +150,17 @@ func (service *tokenService) VerifyRefreshToken(token string) error { userId:=claims["userId"].(string) storedToken,err:=service.tokenRepository.FindRefreshTokenByUserId(userId) if err!=nil{ + fmt.Println("from token service",err) + return err } if storedToken.Token!=token{ + fmt.Println("from token service","token is not e") return errors.New("token is not valid") } // if token is expired if float64(time.Now().Unix()) > claims["exp"].(float64) { + service.tokenRepository.DeleteRefreshTokenByUserId(userId) return errors.New("token is expired login again") } @@ -162,14 +169,13 @@ func (service *tokenService) VerifyRefreshToken(token string) error { return nil } -func (service *tokenService) GetClaimsFromToken(token string) map[string]string { +func (service *tokenService) GetClaimsFromAccessToken(token string) map[string]string { Token, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return []byte(service.accessTokenSecret), nil - return []byte(service.accessTokenSecret), nil }) if err != nil { @@ -188,15 +194,41 @@ func (service *tokenService) GetClaimsFromToken(token string) map[string]string return map[string]string{} } +func (service *tokenService) GetClaimsFromRefreshToken(token string) map[string]string { + + Token, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + return []byte(service.refreshTokenSecret), nil + }) + if err != nil { + return map[string]string{} + } + if claims, ok := Token.Claims.(jwt.MapClaims); ok && Token.Valid { + resp := make(map[string]string) + for key, value := range claims { + resp[key] = fmt.Sprintf("%v", value) + } + return resp + } + + return map[string]string{} +} + + +func (service *tokenService) RefreshAccessToken(refreshToken string) (string, error) { + err:=service.VerifyRefreshToken(refreshToken) -func (service *tokenService) RefreshAccessToken(refresh *entities.RefreshToken) (string, error) { - err:=service.VerifyRefreshToken(refresh.Token) if err!=nil{ - service.tokenRepository.DeleteRefreshTokenByUserId(refresh.UserID) return "",err } - userId:=refresh.UserID + claims:=service.GetClaimsFromRefreshToken(refreshToken) + if len(claims)==0{ + return "",errors.New("no claims found,invalid token") + } + userId:=claims["userId"] user, err := service.userRepo.FindUserById(userId) if err != nil { return "", err