Conversation
internal/pkg/jobs/cleanUp.go
Outdated
| func PermanentDeleteJob(db *sqlx.DB) { | ||
| slog.Info("entering into the cleanup job") | ||
| c := cron.New() | ||
| _, err := c.AddFunc("36 00 * * *", func() { | ||
| slog.Info("Job scheduled for user cleanup from database") | ||
| ur := repository.NewUserRepository(db) // pass in *sql.DB or whatever is needed | ||
| err := ur.DeleteUser(nil) | ||
| if err != nil { | ||
| slog.Error("Cleanup job error", "error", err) | ||
| } else { | ||
| slog.Info("User cleanup Job completed.") | ||
| } | ||
| }) | ||
|
|
||
| if err != nil { | ||
| slog.Error("failed to start user delete job ", "error", err) | ||
| } | ||
|
|
||
| c.Start() | ||
| } |
There was a problem hiding this comment.
Could we explore different patterns for structure Jobs in Golang, maybe look for things using struct and struct embedding with a Common struct.
internal/app/auth/service.go
Outdated
| err = s.userService.RecoverAccountInGracePeriod(ctx, userData.Id) | ||
| if err != nil { | ||
| slog.Error("error in recovering account in grace period during login", "error", err) | ||
| return "", apperrors.ErrInternalServer | ||
| } |
There was a problem hiding this comment.
Only call recover if userData.IsDeleted is true
internal/app/router.go
Outdated
|
|
||
| router.HandleFunc("PATCH /api/v1/user/email", middleware.Authentication(deps.UserHandler.UpdateUserEmail, deps.AppCfg)) | ||
|
|
||
| router.HandleFunc("DELETE /api/user/delete", middleware.Authentication(deps.UserHandler.DeleteUser, deps.AppCfg)) |
There was a problem hiding this comment.
Generally in HTTP routes, we keep id in both token and path, and in handler we check if both are equal. So the path would be DELETE /api/user/delete/{user_id}
internal/app/user/handler.go
Outdated
| val := ctx.Value(middleware.UserIdKey) | ||
|
|
||
| userID := val.(int) |
There was a problem hiding this comment.
We could extract this logic into a util function, so it can be reused in other handlers
internal/repository/user.go
Outdated
| executer := ur.BaseRepository.initiateQueryExecuter(tx) | ||
| _, err := executer.ExecContext(ctx, `UPDATE users SET is_deleted = false, deleted_at = NULL WHERE id = $1`, userID) | ||
| slog.Error("unable to reverse the soft delete ", "error", err) | ||
| return apperrors.ErrInternalServer |
There was a problem hiding this comment.
missing err check
internal/repository/user.go
Outdated
| return user, nil | ||
| } | ||
|
|
||
| func (ur *userRepository) AccountScheduledForDelete(ctx context.Context, tx *sqlx.Tx, userID int) error { |
There was a problem hiding this comment.
Logic seems correct, but such logic should be in service layer instead of repo
internal/repository/user.go
Outdated
| return nil | ||
| } | ||
|
|
||
| func (ur *userRepository) DeleteUser(tx *sqlx.Tx) error { |
There was a problem hiding this comment.
rename function
internal/repository/user.go
Outdated
| return User{}, apperrors.ErrInternalServer | ||
| } | ||
| var user User | ||
| err = executer.QueryRowContext(ctx, getUserByIdQuery, userID).Scan( |
There was a problem hiding this comment.
We could use GetUserById instead
Improve/migrate.go
issue resolved is #6
Approach :-
--extract the user_id from the the JWT token.
--update the database set is_deleted= true, deleted_at= current_time
--this marks the account as "soft-deleted".
2.User tries to login again within 90 days.
--during login, after verifying Github OAuth check if the user is soft deleted.
--if deleted_at + 90 days > now then user is within grace period.
--reverse the deletion by deleted = false, deleted_at = NULL.
3.Background Job runs daily.
--run a scheduled Job once a day using cron package.
--it runs the query and permanently deletes the user whose deleted_at timestamp is older than 90 days.