327 lines
9.5 KiB
Go
327 lines
9.5 KiB
Go
// user_resolvers.go
|
||
package graph
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"tailly_back_v2/internal/domain"
|
||
"tailly_back_v2/internal/service"
|
||
"tailly_back_v2/proto"
|
||
"time"
|
||
)
|
||
|
||
type userResolver struct{ *Resolver }
|
||
|
||
// User is the resolver for the user field.
|
||
func (r *queryResolver) User(ctx context.Context, id int) (*domain.User, error) {
|
||
user, err := r.Services.User.GetByID(ctx, id)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get user: %w", err)
|
||
}
|
||
return user, nil
|
||
}
|
||
|
||
// Me is the resolver for the me field.
|
||
func (r *queryResolver) Me(ctx context.Context) (*domain.User, error) {
|
||
|
||
userID, err := getUserIDFromContext(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
user, err := r.Services.User.GetByID(ctx, userID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get current user: %w", err)
|
||
}
|
||
|
||
return user, nil
|
||
}
|
||
|
||
// User returns UserResolver implementation.
|
||
func (r *Resolver) User() UserResolver { return &userResolver{r} }
|
||
|
||
// EmailConfirmedAt is the resolver for the emailConfirmedAt field.
|
||
func (r *userResolver) EmailConfirmedAt(ctx context.Context, obj *domain.User) (*string, error) {
|
||
if obj.EmailConfirmedAt == nil {
|
||
return nil, nil
|
||
}
|
||
formatted := obj.EmailConfirmedAt.Format(time.RFC3339)
|
||
return &formatted, nil
|
||
}
|
||
|
||
// CreatedAt is the resolver for the createdAt field.
|
||
func (r *userResolver) CreatedAt(ctx context.Context, obj *domain.User) (string, error) {
|
||
return obj.CreatedAt.Format(time.RFC3339), nil
|
||
}
|
||
|
||
// UpdatedAt is the resolver for the updatedAt field.
|
||
func (r *userResolver) UpdatedAt(ctx context.Context, obj *domain.User) (string, error) {
|
||
return obj.UpdatedAt.Format(time.RFC3339), nil
|
||
}
|
||
|
||
// UpdateProfile is the resolver for the updateProfile field.
|
||
func (r *mutationResolver) UpdateProfile(ctx context.Context, username string, email string, avatar string) (*domain.User, error) {
|
||
userID, err := getUserIDFromContext(ctx)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
user, err := r.Services.User.UpdateProfile(ctx, userID, username, email, avatar)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to update profile: %w", err)
|
||
}
|
||
return user, nil
|
||
}
|
||
|
||
// ChangePassword is the resolver for the changePassword field.
|
||
func (r *mutationResolver) ChangePassword(ctx context.Context, oldPassword string, newPassword string) (bool, error) {
|
||
userID, err := getUserIDFromContext(ctx)
|
||
if err != nil {
|
||
return false, err
|
||
}
|
||
|
||
if err := r.Services.User.ChangePassword(ctx, userID, oldPassword, newPassword); err != nil {
|
||
return false, fmt.Errorf("failed to change password: %w", err)
|
||
}
|
||
return true, nil
|
||
}
|
||
|
||
// Register is the resolver for the register field.
|
||
func (r *mutationResolver) Register(ctx context.Context, input domain.RegisterInput) (*domain.User, error) {
|
||
user, err := r.Services.Auth.Register(ctx, service.RegisterInput{
|
||
Username: input.Username,
|
||
Email: input.Email,
|
||
Password: input.Password,
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to register: %w", err)
|
||
}
|
||
return user, nil
|
||
}
|
||
|
||
// Login is the resolver for the login field.
|
||
func (r *mutationResolver) Login(ctx context.Context, input domain.LoginInput) (*domain.Tokens, error) {
|
||
|
||
tokens, err := r.Services.Auth.Login(ctx, input.Email, input.Password)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to login: %w", err)
|
||
}
|
||
return tokens, nil
|
||
}
|
||
|
||
// Users is the resolver for the users field.
|
||
func (r *queryResolver) Users(ctx context.Context) ([]*domain.User, error) {
|
||
userID, err := getUserIDFromContext(ctx)
|
||
|
||
users, err := r.Services.User.GetAll(ctx, userID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get users: %w", err)
|
||
}
|
||
return users, nil
|
||
}
|
||
|
||
// FollowersCount is the resolver for the followersCount field.
|
||
func (r *userResolver) FollowersCount(ctx context.Context, obj *domain.User) (int, error) {
|
||
res, err := r.SubscribeClient.GetFollowersCount(ctx, &proto.GetCountRequest{
|
||
UserId: int32(obj.ID),
|
||
})
|
||
if err != nil {
|
||
return 0, fmt.Errorf("failed to get followers count: %w", err)
|
||
}
|
||
return int(res.Count), nil
|
||
}
|
||
|
||
// FollowingCount is the resolver for the followingCount field.
|
||
func (r *userResolver) FollowingCount(ctx context.Context, obj *domain.User) (int, error) {
|
||
res, err := r.SubscribeClient.GetFollowingCount(ctx, &proto.GetCountRequest{
|
||
UserId: int32(obj.ID),
|
||
})
|
||
if err != nil {
|
||
return 0, fmt.Errorf("failed to get following count: %w", err)
|
||
}
|
||
return int(res.Count), nil
|
||
}
|
||
|
||
// IsFollowing is the resolver for the isFollowing field.
|
||
func (r *userResolver) IsFollowing(ctx context.Context, obj *domain.User, userID int) (bool, error) {
|
||
currentUserID, err := getUserIDFromContext(ctx)
|
||
if err != nil {
|
||
return false, fmt.Errorf("authentication required: %w", err)
|
||
}
|
||
|
||
res, err := r.SubscribeClient.IsFollowing(ctx, &proto.IsFollowingRequest{
|
||
FollowerId: int32(currentUserID),
|
||
FollowingId: int32(userID),
|
||
})
|
||
if err != nil {
|
||
return false, fmt.Errorf("failed to check subscription status: %w", err)
|
||
}
|
||
return res.IsFollowing, nil
|
||
}
|
||
|
||
// Followers is the resolver for the followers field.
|
||
func (r *userResolver) Followers(ctx context.Context, obj *domain.User, limit *int, offset *int) (*FollowersResponse, error) {
|
||
limitVal := 20
|
||
if limit != nil {
|
||
limitVal = *limit
|
||
}
|
||
|
||
offsetVal := 0
|
||
if offset != nil {
|
||
offsetVal = *offset
|
||
}
|
||
|
||
res, err := r.SubscribeClient.GetFollowers(ctx, &proto.GetFollowersRequest{
|
||
UserId: int32(obj.ID),
|
||
Limit: int32(limitVal),
|
||
Offset: int32(offsetVal),
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get followers: %w", err)
|
||
}
|
||
|
||
return &FollowersResponse{
|
||
Followers: convertProtoFollowersToGraphQL(res.Followers),
|
||
TotalCount: int(res.TotalCount),
|
||
}, nil
|
||
}
|
||
|
||
// Following is the resolver for the following field.
|
||
func (r *userResolver) Following(ctx context.Context, obj *domain.User, limit *int, offset *int) (*FollowingResponse, error) {
|
||
limitVal := 20
|
||
if limit != nil {
|
||
limitVal = *limit
|
||
}
|
||
|
||
offsetVal := 0
|
||
if offset != nil {
|
||
offsetVal = *offset
|
||
}
|
||
|
||
res, err := r.SubscribeClient.GetFollowing(ctx, &proto.GetFollowingRequest{
|
||
UserId: int32(obj.ID),
|
||
Limit: int32(limitVal),
|
||
Offset: int32(offsetVal),
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get following: %w", err)
|
||
}
|
||
|
||
return &FollowingResponse{
|
||
Following: convertProtoFollowingToGraphQL(res.Following),
|
||
TotalCount: int(res.TotalCount),
|
||
}, nil
|
||
}
|
||
|
||
// SubscriptionNotifications is the resolver for the subscriptionNotifications field.
|
||
func (r *userResolver) SubscriptionNotifications(ctx context.Context, obj *domain.User, unreadOnly *bool, limit *int, offset *int) (*NotificationsResponse, error) {
|
||
currentUserID, err := getUserIDFromContext(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("authentication required: %w", err)
|
||
}
|
||
|
||
// Можно смотреть только свои уведомления
|
||
if obj.ID != currentUserID {
|
||
return nil, fmt.Errorf("access denied: can only view your own notifications")
|
||
}
|
||
|
||
unreadOnlyVal := false
|
||
if unreadOnly != nil {
|
||
unreadOnlyVal = *unreadOnly
|
||
}
|
||
|
||
limitVal := 20
|
||
if limit != nil {
|
||
limitVal = *limit
|
||
}
|
||
|
||
offsetVal := 0
|
||
if offset != nil {
|
||
offsetVal = *offset
|
||
}
|
||
|
||
res, err := r.SubscribeClient.GetSubscriptionNotifications(ctx, &proto.GetNotificationsRequest{
|
||
UserId: int32(obj.ID),
|
||
UnreadOnly: unreadOnlyVal,
|
||
Limit: int32(limitVal),
|
||
Offset: int32(offsetVal),
|
||
})
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get notifications: %w", err)
|
||
}
|
||
|
||
return &NotificationsResponse{
|
||
Notifications: convertProtoNotificationsToGraphQL(res.Notifications),
|
||
TotalCount: int(res.TotalCount),
|
||
UnreadCount: int(res.UnreadCount),
|
||
}, nil
|
||
}
|
||
|
||
// LikeNotifications is the resolver for the likeNotifications field.
|
||
func (r *userResolver) LikeNotifications(ctx context.Context, obj *domain.User, unreadOnly *bool, limit *int, offset *int) (*LikeNotificationsResponse, error) {
|
||
currentUserID, err := getUserIDFromContext(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("authentication required: %w", err)
|
||
}
|
||
|
||
// Можно смотреть только свои уведомления
|
||
if obj.ID != currentUserID {
|
||
return nil, fmt.Errorf("access denied: can only view your own notifications")
|
||
}
|
||
|
||
unreadOnlyVal := false
|
||
if unreadOnly != nil {
|
||
unreadOnlyVal = *unreadOnly
|
||
}
|
||
|
||
limitVal := 20
|
||
if limit != nil {
|
||
limitVal = *limit
|
||
}
|
||
|
||
offsetVal := 0
|
||
if offset != nil {
|
||
offsetVal = *offset
|
||
}
|
||
|
||
notifications, totalCount, unreadCount, err := r.Services.Like.GetLikeNotifications(ctx, obj.ID, unreadOnlyVal, limitVal, offsetVal)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get like notifications: %w", err)
|
||
}
|
||
|
||
// Заполняем дополнительные поля для GraphQL
|
||
for _, notification := range notifications {
|
||
// Получаем информацию о пользователе, который поставил лайк
|
||
likerUser, err := r.Services.User.GetByID(ctx, notification.LikerID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get liker user: %w", err)
|
||
}
|
||
notification.SetLiker(likerUser)
|
||
|
||
// Получаем информацию о посте
|
||
post, err := r.Services.Post.GetByID(ctx, notification.PostID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get post: %w", err)
|
||
}
|
||
|
||
// Получаем автора поста
|
||
postAuthor, err := r.Services.User.GetByID(ctx, post.AuthorID)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to get post author: %w", err)
|
||
}
|
||
|
||
// Устанавливаем автора поста
|
||
post.Author = postAuthor
|
||
notification.SetPost(post)
|
||
|
||
// Форматируем дату
|
||
notification.SetCreatedAtStr()
|
||
}
|
||
|
||
return &LikeNotificationsResponse{
|
||
Notifications: notifications,
|
||
TotalCount: totalCount,
|
||
UnreadCount: unreadCount,
|
||
}, nil
|
||
}
|