package graphql // This file will be automatically regenerated based on the schema, any resolver implementations // will be copied through when generating and any unknown code will be moved to the end. // Code generated by github.com/99designs/gqlgen version v0.17.78 import ( "context" "fmt" "strconv" "tercul/internal/adapters/graphql/model" "tercul/internal/app/auth" "tercul/internal/app/author" "tercul/internal/app/book" "tercul/internal/app/bookmark" "tercul/internal/app/collection" "tercul/internal/app/comment" "tercul/internal/app/like" "tercul/internal/app/translation" "tercul/internal/app/user" "tercul/internal/domain" "tercul/internal/domain/work" platform_auth "tercul/internal/platform/auth" ) // Register is the resolver for the register field. func (r *mutationResolver) Register(ctx context.Context, input model.RegisterInput) (*model.AuthPayload, error) { // Convert GraphQL input to service input registerInput := auth.RegisterInput{ Username: input.Username, Email: input.Email, Password: input.Password, FirstName: input.FirstName, LastName: input.LastName, } // Call auth service authResponse, err := r.App.Auth.Commands.Register(ctx, registerInput) if err != nil { return nil, err } // Convert service response to GraphQL response return &model.AuthPayload{ Token: authResponse.Token, User: &model.User{ ID: fmt.Sprintf("%d", authResponse.User.ID), Username: authResponse.User.Username, Email: authResponse.User.Email, FirstName: &authResponse.User.FirstName, LastName: &authResponse.User.LastName, DisplayName: &authResponse.User.DisplayName, Role: model.UserRole(authResponse.User.Role), Verified: authResponse.User.Verified, Active: authResponse.User.Active, }, }, nil } // Login is the resolver for the login field. func (r *mutationResolver) Login(ctx context.Context, input model.LoginInput) (*model.AuthPayload, error) { // Convert GraphQL input to service input loginInput := auth.LoginInput{ Email: input.Email, Password: input.Password, } // Call auth service authResponse, err := r.App.Auth.Commands.Login(ctx, loginInput) if err != nil { return nil, err } // Convert service response to GraphQL response return &model.AuthPayload{ Token: authResponse.Token, User: &model.User{ ID: fmt.Sprintf("%d", authResponse.User.ID), Username: authResponse.User.Username, Email: authResponse.User.Email, FirstName: &authResponse.User.FirstName, LastName: &authResponse.User.LastName, DisplayName: &authResponse.User.DisplayName, Role: model.UserRole(authResponse.User.Role), Verified: authResponse.User.Verified, Active: authResponse.User.Active, }, }, nil } // CreateWork is the resolver for the createWork field. func (r *mutationResolver) CreateWork(ctx context.Context, input model.WorkInput) (*model.Work, error) { if err := Validate(input); err != nil { return nil, err } // Create domain model workModel := &work.Work{ Title: input.Name, TranslatableModel: domain.TranslatableModel{Language: input.Language}, // Description: *input.Description, // Other fields can be set here } // Call work service createdWork, err := r.App.Work.Commands.CreateWork(ctx, workModel) if err != nil { return nil, err } if input.Content != nil && *input.Content != "" { translationInput := translation.CreateTranslationInput{ Title: input.Name, Content: *input.Content, Language: input.Language, TranslatableID: createdWork.ID, TranslatableType: "works", IsOriginalLanguage: true, } _, err := r.App.Translation.Commands.CreateTranslation(ctx, translationInput) if err != nil { return nil, fmt.Errorf("failed to create translation: %w", err) } } // Convert to GraphQL model return &model.Work{ ID: fmt.Sprintf("%d", createdWork.ID), Name: createdWork.Title, Language: createdWork.Language, Content: input.Content, }, nil } // UpdateWork is the resolver for the updateWork field. func (r *mutationResolver) UpdateWork(ctx context.Context, id string, input model.WorkInput) (*model.Work, error) { if err := Validate(input); err != nil { return nil, err } workID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("%w: invalid work ID", domain.ErrValidation) } // Create domain model workModel := &work.Work{ TranslatableModel: domain.TranslatableModel{ BaseModel: domain.BaseModel{ID: uint(workID)}, Language: input.Language, }, Title: input.Name, } // Call work service err = r.App.Work.Commands.UpdateWork(ctx, workModel) if err != nil { return nil, err } // Convert to GraphQL model return &model.Work{ ID: id, Name: workModel.Title, Language: workModel.Language, Content: input.Content, }, nil } // DeleteWork is the resolver for the deleteWork field. func (r *mutationResolver) DeleteWork(ctx context.Context, id string) (bool, error) { workID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("%w: invalid work ID", domain.ErrValidation) } err = r.App.Work.Commands.DeleteWork(ctx, uint(workID)) if err != nil { return false, err } return true, nil } // CreateTranslation is the resolver for the createTranslation field. func (r *mutationResolver) CreateTranslation(ctx context.Context, input model.TranslationInput) (*model.Translation, error) { if err := Validate(input); err != nil { return nil, err } can, err := r.App.Authz.CanCreateTranslation(ctx) if err != nil { return nil, err } if !can { return nil, domain.ErrForbidden } workID, err := strconv.ParseUint(input.WorkID, 10, 32) if err != nil { return nil, fmt.Errorf("%w: invalid work ID", domain.ErrValidation) } // Create domain model translationModel := &domain.Translation{ Title: input.Name, Language: input.Language, TranslatableID: uint(workID), TranslatableType: "Work", } if input.Content != nil { translationModel.Content = *input.Content } // Call translation service createInput := translation.CreateTranslationInput{ Title: translationModel.Title, Content: translationModel.Content, Description: translationModel.Description, Language: translationModel.Language, Status: translationModel.Status, TranslatableID: translationModel.TranslatableID, TranslatableType: translationModel.TranslatableType, TranslatorID: translationModel.TranslatorID, } createdTranslation, err := r.App.Translation.Commands.CreateTranslation(ctx, createInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Translation{ ID: fmt.Sprintf("%d", createdTranslation.ID), Name: createdTranslation.Title, Language: createdTranslation.Language, Content: &createdTranslation.Content, WorkID: input.WorkID, }, nil } // UpdateTranslation is the resolver for the updateTranslation field. func (r *mutationResolver) UpdateTranslation(ctx context.Context, id string, input model.TranslationInput) (*model.Translation, error) { if err := Validate(input); err != nil { return nil, err } translationID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid translation ID: %v", err) } // Call translation service updateInput := translation.UpdateTranslationInput{ ID: uint(translationID), Title: input.Name, Language: input.Language, } if input.Content != nil { updateInput.Content = *input.Content } updatedTranslation, err := r.App.Translation.Commands.UpdateTranslation(ctx, updateInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Translation{ ID: id, Name: updatedTranslation.Title, Language: updatedTranslation.Language, Content: &updatedTranslation.Content, WorkID: input.WorkID, }, nil } // DeleteTranslation is the resolver for the deleteTranslation field. func (r *mutationResolver) DeleteTranslation(ctx context.Context, id string) (bool, error) { translationID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("invalid translation ID: %v", err) } err = r.App.Translation.Commands.DeleteTranslation(ctx, uint(translationID)) if err != nil { return false, err } return true, nil } // CreateBook is the resolver for the createBook field. func (r *mutationResolver) CreateBook(ctx context.Context, input model.BookInput) (*model.Book, error) { if err := Validate(input); err != nil { return nil, err } createInput := book.CreateBookInput{ Title: input.Name, Description: *input.Description, Language: input.Language, ISBN: input.Isbn, } createdBook, err := r.App.Book.Commands.CreateBook(ctx, createInput) if err != nil { return nil, err } return &model.Book{ ID: fmt.Sprintf("%d", createdBook.ID), Name: createdBook.Title, Language: createdBook.Language, Description: &createdBook.Description, Isbn: &createdBook.ISBN, }, nil } // UpdateBook is the resolver for the updateBook field. func (r *mutationResolver) UpdateBook(ctx context.Context, id string, input model.BookInput) (*model.Book, error) { if err := Validate(input); err != nil { return nil, err } bookID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("%w: invalid book ID", domain.ErrValidation) } updateInput := book.UpdateBookInput{ ID: uint(bookID), Title: &input.Name, Description: input.Description, Language: &input.Language, ISBN: input.Isbn, } updatedBook, err := r.App.Book.Commands.UpdateBook(ctx, updateInput) if err != nil { return nil, err } return &model.Book{ ID: id, Name: updatedBook.Title, Language: updatedBook.Language, Description: &updatedBook.Description, Isbn: &updatedBook.ISBN, }, nil } // DeleteBook is the resolver for the deleteBook field. func (r *mutationResolver) DeleteBook(ctx context.Context, id string) (bool, error) { bookID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("%w: invalid book ID", domain.ErrValidation) } err = r.App.Book.Commands.DeleteBook(ctx, uint(bookID)) if err != nil { return false, err } return true, nil } // CreateAuthor is the resolver for the createAuthor field. func (r *mutationResolver) CreateAuthor(ctx context.Context, input model.AuthorInput) (*model.Author, error) { if err := Validate(input); err != nil { return nil, err } // Call author service createInput := author.CreateAuthorInput{ Name: input.Name, } createdAuthor, err := r.App.Author.Commands.CreateAuthor(ctx, createInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Author{ ID: fmt.Sprintf("%d", createdAuthor.ID), Name: createdAuthor.Name, Language: createdAuthor.Language, }, nil } // UpdateAuthor is the resolver for the updateAuthor field. func (r *mutationResolver) UpdateAuthor(ctx context.Context, id string, input model.AuthorInput) (*model.Author, error) { if err := Validate(input); err != nil { return nil, err } authorID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid author ID: %v", err) } // Call author service updateInput := author.UpdateAuthorInput{ ID: uint(authorID), Name: input.Name, } updatedAuthor, err := r.App.Author.Commands.UpdateAuthor(ctx, updateInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Author{ ID: id, Name: updatedAuthor.Name, Language: updatedAuthor.Language, }, nil } // DeleteAuthor is the resolver for the deleteAuthor field. func (r *mutationResolver) DeleteAuthor(ctx context.Context, id string) (bool, error) { authorID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("invalid author ID: %v", err) } err = r.App.Author.Commands.DeleteAuthor(ctx, uint(authorID)) if err != nil { return false, err } return true, nil } // UpdateUser is the resolver for the updateUser field. func (r *mutationResolver) UpdateUser(ctx context.Context, id string, input model.UserInput) (*model.User, error) { if err := Validate(input); err != nil { return nil, err } userID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid user ID: %v", err) } updateInput := user.UpdateUserInput{ ID: uint(userID), Username: input.Username, Email: input.Email, Password: input.Password, FirstName: input.FirstName, LastName: input.LastName, DisplayName: input.DisplayName, Bio: input.Bio, AvatarURL: input.AvatarURL, Verified: input.Verified, Active: input.Active, } if input.Role != nil { role := domain.UserRole(input.Role.String()) updateInput.Role = &role } if input.CountryID != nil { countryID, err := strconv.ParseUint(*input.CountryID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid country ID: %v", err) } uid := uint(countryID) updateInput.CountryID = &uid } if input.CityID != nil { cityID, err := strconv.ParseUint(*input.CityID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid city ID: %v", err) } uid := uint(cityID) updateInput.CityID = &uid } if input.AddressID != nil { addressID, err := strconv.ParseUint(*input.AddressID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid address ID: %v", err) } uid := uint(addressID) updateInput.AddressID = &uid } updatedUser, err := r.App.User.Commands.UpdateUser(ctx, updateInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.User{ ID: fmt.Sprintf("%d", updatedUser.ID), Username: updatedUser.Username, Email: updatedUser.Email, FirstName: &updatedUser.FirstName, LastName: &updatedUser.LastName, DisplayName: &updatedUser.DisplayName, Bio: &updatedUser.Bio, AvatarURL: &updatedUser.AvatarURL, Role: model.UserRole(updatedUser.Role), Verified: updatedUser.Verified, Active: updatedUser.Active, }, nil } // DeleteUser is the resolver for the deleteUser field. func (r *mutationResolver) DeleteUser(ctx context.Context, id string) (bool, error) { panic(fmt.Errorf("not implemented: DeleteUser - deleteUser")) } // CreateCollection is the resolver for the createCollection field. func (r *mutationResolver) CreateCollection(ctx context.Context, input model.CollectionInput) (*model.Collection, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Call collection service createInput := collection.CreateCollectionInput{ Name: input.Name, UserID: userID, } if input.Description != nil { createInput.Description = *input.Description } createdCollection, err := r.App.Collection.Commands.CreateCollection(ctx, createInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Collection{ ID: fmt.Sprintf("%d", createdCollection.ID), Name: createdCollection.Name, Description: &createdCollection.Description, User: &model.User{ ID: fmt.Sprintf("%d", userID), }, }, nil } // UpdateCollection is the resolver for the updateCollection field. func (r *mutationResolver) UpdateCollection(ctx context.Context, id string, input model.CollectionInput) (*model.Collection, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Parse collection ID collectionID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid collection ID: %v", err) } // Call collection service updateInput := collection.UpdateCollectionInput{ ID: uint(collectionID), Name: input.Name, UserID: userID, } if input.Description != nil { updateInput.Description = *input.Description } updatedCollection, err := r.App.Collection.Commands.UpdateCollection(ctx, updateInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Collection{ ID: id, Name: updatedCollection.Name, Description: &updatedCollection.Description, User: &model.User{ ID: fmt.Sprintf("%d", userID), }, }, nil } // DeleteCollection is the resolver for the deleteCollection field. func (r *mutationResolver) DeleteCollection(ctx context.Context, id string) (bool, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return false, fmt.Errorf("unauthorized") } // Parse collection ID collectionID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("invalid collection ID: %v", err) } // Call collection service err = r.App.Collection.Commands.DeleteCollection(ctx, uint(collectionID), userID) if err != nil { return false, err } return true, nil } // AddWorkToCollection is the resolver for the addWorkToCollection field. func (r *mutationResolver) AddWorkToCollection(ctx context.Context, collectionID string, workID string) (*model.Collection, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Parse IDs collID, err := strconv.ParseUint(collectionID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid collection ID: %v", err) } wID, err := strconv.ParseUint(workID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid work ID: %v", err) } // Add work to collection addInput := collection.AddWorkToCollectionInput{ CollectionID: uint(collID), WorkID: uint(wID), UserID: userID, } err = r.App.Collection.Commands.AddWorkToCollection(ctx, addInput) if err != nil { return nil, err } // Fetch the updated collection to return it updatedCollection, err := r.App.Collection.Queries.Collection(ctx, uint(collID)) if err != nil { return nil, err } // Convert to GraphQL model return &model.Collection{ ID: collectionID, Name: updatedCollection.Name, Description: &updatedCollection.Description, }, nil } // RemoveWorkFromCollection is the resolver for the removeWorkFromCollection field. func (r *mutationResolver) RemoveWorkFromCollection(ctx context.Context, collectionID string, workID string) (*model.Collection, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Parse IDs collID, err := strconv.ParseUint(collectionID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid collection ID: %v", err) } wID, err := strconv.ParseUint(workID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid work ID: %v", err) } // Remove work from collection removeInput := collection.RemoveWorkFromCollectionInput{ CollectionID: uint(collID), WorkID: uint(wID), UserID: userID, } err = r.App.Collection.Commands.RemoveWorkFromCollection(ctx, removeInput) if err != nil { return nil, err } // Fetch the updated collection to return it updatedCollection, err := r.App.Collection.Queries.Collection(ctx, uint(collID)) if err != nil { return nil, err } // Convert to GraphQL model return &model.Collection{ ID: collectionID, Name: updatedCollection.Name, Description: &updatedCollection.Description, }, nil } // CreateComment is the resolver for the createComment field. func (r *mutationResolver) CreateComment(ctx context.Context, input model.CommentInput) (*model.Comment, error) { // Custom validation if (input.WorkID == nil && input.TranslationID == nil) || (input.WorkID != nil && input.TranslationID != nil) { return nil, fmt.Errorf("must provide either workId or translationId, but not both") } // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Create command input createInput := comment.CreateCommentInput{ Text: input.Text, UserID: userID, } if input.WorkID != nil { workID, err := strconv.ParseUint(*input.WorkID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid work ID: %v", err) } wID := uint(workID) createInput.WorkID = &wID } if input.TranslationID != nil { translationID, err := strconv.ParseUint(*input.TranslationID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid translation ID: %v", err) } tID := uint(translationID) createInput.TranslationID = &tID } if input.ParentCommentID != nil { parentCommentID, err := strconv.ParseUint(*input.ParentCommentID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid parent comment ID: %v", err) } pID := uint(parentCommentID) createInput.ParentID = &pID } // Call comment service createdComment, err := r.App.Comment.Commands.CreateComment(ctx, createInput) if err != nil { return nil, err } // Increment analytics if createdComment.WorkID != nil { r.App.Analytics.IncrementWorkComments(ctx, *createdComment.WorkID) } if createdComment.TranslationID != nil { r.App.Analytics.IncrementTranslationComments(ctx, *createdComment.TranslationID) } // Convert to GraphQL model return &model.Comment{ ID: fmt.Sprintf("%d", createdComment.ID), Text: createdComment.Text, User: &model.User{ ID: fmt.Sprintf("%d", userID), }, }, nil } // UpdateComment is the resolver for the updateComment field. func (r *mutationResolver) UpdateComment(ctx context.Context, id string, input model.CommentInput) (*model.Comment, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Parse comment ID commentID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid comment ID: %v", err) } // Fetch the existing comment commentModel, err := r.App.Comment.Queries.Comment(ctx, uint(commentID)) if err != nil { return nil, err } if commentModel == nil { return nil, fmt.Errorf("comment not found") } // Check ownership if commentModel.UserID != userID { return nil, fmt.Errorf("unauthorized") } // Call comment service updateInput := comment.UpdateCommentInput{ ID: uint(commentID), Text: input.Text, } updatedComment, err := r.App.Comment.Commands.UpdateComment(ctx, updateInput) if err != nil { return nil, err } // Convert to GraphQL model return &model.Comment{ ID: id, Text: updatedComment.Text, User: &model.User{ ID: fmt.Sprintf("%d", userID), }, }, nil } // DeleteComment is the resolver for the deleteComment field. func (r *mutationResolver) DeleteComment(ctx context.Context, id string) (bool, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return false, fmt.Errorf("unauthorized") } // Parse comment ID commentID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("invalid comment ID: %v", err) } // Fetch the existing comment comment, err := r.App.Comment.Queries.Comment(ctx, uint(commentID)) if err != nil { return false, err } if comment == nil { return false, fmt.Errorf("comment not found") } // Check ownership if comment.UserID != userID { return false, fmt.Errorf("unauthorized") } // Call comment repository err = r.App.Comment.Commands.DeleteComment(ctx, uint(commentID)) if err != nil { return false, err } return true, nil } // CreateLike is the resolver for the createLike field. func (r *mutationResolver) CreateLike(ctx context.Context, input model.LikeInput) (*model.Like, error) { // Custom validation if (input.WorkID == nil && input.TranslationID == nil && input.CommentID == nil) || (input.WorkID != nil && input.TranslationID != nil) || (input.WorkID != nil && input.CommentID != nil) || (input.TranslationID != nil && input.CommentID != nil) { return nil, fmt.Errorf("must provide exactly one of workId, translationId, or commentId") } // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Create command input createInput := like.CreateLikeInput{ UserID: userID, } if input.WorkID != nil { workID, err := strconv.ParseUint(*input.WorkID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid work ID: %v", err) } wID := uint(workID) createInput.WorkID = &wID } if input.TranslationID != nil { translationID, err := strconv.ParseUint(*input.TranslationID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid translation ID: %v", err) } tID := uint(translationID) createInput.TranslationID = &tID } if input.CommentID != nil { commentID, err := strconv.ParseUint(*input.CommentID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid comment ID: %v", err) } cID := uint(commentID) createInput.CommentID = &cID } // Call like service createdLike, err := r.App.Like.Commands.CreateLike(ctx, createInput) if err != nil { return nil, err } // Increment analytics if createdLike.WorkID != nil { r.App.Analytics.IncrementWorkLikes(ctx, *createdLike.WorkID) } if createdLike.TranslationID != nil { r.App.Analytics.IncrementTranslationLikes(ctx, *createdLike.TranslationID) } // Convert to GraphQL model return &model.Like{ ID: fmt.Sprintf("%d", createdLike.ID), User: &model.User{ID: fmt.Sprintf("%d", userID)}, }, nil } // DeleteLike is the resolver for the deleteLike field. func (r *mutationResolver) DeleteLike(ctx context.Context, id string) (bool, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return false, fmt.Errorf("unauthorized") } // Parse like ID likeID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("invalid like ID: %v", err) } // Fetch the existing like like, err := r.App.Like.Queries.Like(ctx, uint(likeID)) if err != nil { return false, err } if like == nil { return false, fmt.Errorf("like not found") } // Check ownership if like.UserID != userID { return false, fmt.Errorf("unauthorized") } // Call like service err = r.App.Like.Commands.DeleteLike(ctx, uint(likeID)) if err != nil { return false, err } return true, nil } // CreateBookmark is the resolver for the createBookmark field. func (r *mutationResolver) CreateBookmark(ctx context.Context, input model.BookmarkInput) (*model.Bookmark, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return nil, fmt.Errorf("unauthorized") } // Parse work ID workID, err := strconv.ParseUint(input.WorkID, 10, 32) if err != nil { return nil, fmt.Errorf("invalid work ID: %v", err) } // Create command input createInput := bookmark.CreateBookmarkInput{ UserID: userID, WorkID: uint(workID), } if input.Name != nil { createInput.Name = *input.Name } // Call bookmark service createdBookmark, err := r.App.Bookmark.Commands.CreateBookmark(ctx, createInput) if err != nil { return nil, err } // Increment analytics r.App.Analytics.IncrementWorkBookmarks(ctx, uint(workID)) // Convert to GraphQL model return &model.Bookmark{ ID: fmt.Sprintf("%d", createdBookmark.ID), Name: &createdBookmark.Name, User: &model.User{ID: fmt.Sprintf("%d", userID)}, Work: &model.Work{ID: fmt.Sprintf("%d", workID)}, }, nil } // DeleteBookmark is the resolver for the deleteBookmark field. func (r *mutationResolver) DeleteBookmark(ctx context.Context, id string) (bool, error) { // Get user ID from context userID, ok := platform_auth.GetUserIDFromContext(ctx) if !ok { return false, fmt.Errorf("unauthorized") } // Parse bookmark ID bookmarkID, err := strconv.ParseUint(id, 10, 32) if err != nil { return false, fmt.Errorf("invalid bookmark ID: %v", err) } // Fetch the existing bookmark bookmark, err := r.App.Bookmark.Queries.Bookmark(ctx, uint(bookmarkID)) if err != nil { return false, err } if bookmark == nil { return false, fmt.Errorf("bookmark not found") } // Check ownership if bookmark.UserID != userID { return false, fmt.Errorf("unauthorized") } // Call bookmark service err = r.App.Bookmark.Commands.DeleteBookmark(ctx, uint(bookmarkID)) if err != nil { return false, err } return true, nil } // CreateContribution is the resolver for the createContribution field. func (r *mutationResolver) CreateContribution(ctx context.Context, input model.ContributionInput) (*model.Contribution, error) { panic(fmt.Errorf("not implemented: CreateContribution - createContribution")) } // UpdateContribution is the resolver for the updateContribution field. func (r *mutationResolver) UpdateContribution(ctx context.Context, id string, input model.ContributionInput) (*model.Contribution, error) { panic(fmt.Errorf("not implemented: UpdateContribution - updateContribution")) } // DeleteContribution is the resolver for the deleteContribution field. func (r *mutationResolver) DeleteContribution(ctx context.Context, id string) (bool, error) { panic(fmt.Errorf("not implemented: DeleteContribution - deleteContribution")) } // ReviewContribution is the resolver for the reviewContribution field. func (r *mutationResolver) ReviewContribution(ctx context.Context, id string, status model.ContributionStatus, feedback *string) (*model.Contribution, error) { panic(fmt.Errorf("not implemented: ReviewContribution - reviewContribution")) } // Logout is the resolver for the logout field. func (r *mutationResolver) Logout(ctx context.Context) (bool, error) { panic(fmt.Errorf("not implemented: Logout - logout")) } // RefreshToken is the resolver for the refreshToken field. func (r *mutationResolver) RefreshToken(ctx context.Context) (*model.AuthPayload, error) { panic(fmt.Errorf("not implemented: RefreshToken - refreshToken")) } // ForgotPassword is the resolver for the forgotPassword field. func (r *mutationResolver) ForgotPassword(ctx context.Context, email string) (bool, error) { panic(fmt.Errorf("not implemented: ForgotPassword - forgotPassword")) } // ResetPassword is the resolver for the resetPassword field. func (r *mutationResolver) ResetPassword(ctx context.Context, token string, newPassword string) (bool, error) { panic(fmt.Errorf("not implemented: ResetPassword - resetPassword")) } // VerifyEmail is the resolver for the verifyEmail field. func (r *mutationResolver) VerifyEmail(ctx context.Context, token string) (bool, error) { panic(fmt.Errorf("not implemented: VerifyEmail - verifyEmail")) } // ResendVerificationEmail is the resolver for the resendVerificationEmail field. func (r *mutationResolver) ResendVerificationEmail(ctx context.Context, email string) (bool, error) { panic(fmt.Errorf("not implemented: ResendVerificationEmail - resendVerificationEmail")) } // UpdateProfile is the resolver for the updateProfile field. func (r *mutationResolver) UpdateProfile(ctx context.Context, input model.UserInput) (*model.User, error) { panic(fmt.Errorf("not implemented: UpdateProfile - updateProfile")) } // ChangePassword is the resolver for the changePassword field. func (r *mutationResolver) ChangePassword(ctx context.Context, currentPassword string, newPassword string) (bool, error) { panic(fmt.Errorf("not implemented: ChangePassword - changePassword")) } // Work is the resolver for the work field. func (r *queryResolver) Work(ctx context.Context, id string) (*model.Work, error) { workID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid work ID: %v", err) } workRecord, err := r.App.Work.Queries.GetWorkByID(ctx, uint(workID)) if err != nil { return nil, err } if workRecord == nil { return nil, nil } content := r.resolveWorkContent(ctx, workRecord.ID, workRecord.Language) return &model.Work{ ID: id, Name: workRecord.Title, Language: workRecord.Language, Content: content, }, nil } // Works is the resolver for the works field. func (r *queryResolver) Works(ctx context.Context, limit *int32, offset *int32, language *string, authorID *string, categoryID *string, tagID *string, search *string) ([]*model.Work, error) { // This resolver has complex logic that should be moved to the application layer. // For now, I will just call the ListWorks query. // A proper implementation would have specific query methods for each filter. page := 1 pageSize := 20 if limit != nil { pageSize = int(*limit) } if offset != nil { page = int(*offset)/pageSize + 1 } paginatedResult, err := r.App.Work.Queries.ListWorks(ctx, page, pageSize) if err != nil { return nil, err } // Convert to GraphQL model var result []*model.Work for _, w := range paginatedResult.Items { content := r.resolveWorkContent(ctx, w.ID, w.Language) result = append(result, &model.Work{ ID: fmt.Sprintf("%d", w.ID), Name: w.Title, Language: w.Language, Content: content, }) } return result, nil } // Translation is the resolver for the translation field. func (r *queryResolver) Translation(ctx context.Context, id string) (*model.Translation, error) { panic(fmt.Errorf("not implemented: Translation - translation")) } // Translations is the resolver for the translations field. func (r *queryResolver) Translations(ctx context.Context, workID string, language *string, limit *int32, offset *int32) ([]*model.Translation, error) { panic(fmt.Errorf("not implemented: Translations - translations")) } // Book is the resolver for the book field. func (r *queryResolver) Book(ctx context.Context, id string) (*model.Book, error) { bookID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("%w: invalid book ID", domain.ErrValidation) } bookRecord, err := r.App.Book.Queries.Book(ctx, uint(bookID)) if err != nil { return nil, err } if bookRecord == nil { return nil, nil } return &model.Book{ ID: fmt.Sprintf("%d", bookRecord.ID), Name: bookRecord.Title, Language: bookRecord.Language, Description: &bookRecord.Description, Isbn: &bookRecord.ISBN, }, nil } // Books is the resolver for the books field. func (r *queryResolver) Books(ctx context.Context, limit *int32, offset *int32) ([]*model.Book, error) { books, err := r.App.Book.Queries.Books(ctx) if err != nil { return nil, err } var result []*model.Book for _, b := range books { result = append(result, &model.Book{ ID: fmt.Sprintf("%d", b.ID), Name: b.Title, Language: b.Language, Description: &b.Description, Isbn: &b.ISBN, }) } return result, nil } // Author is the resolver for the author field. func (r *queryResolver) Author(ctx context.Context, id string) (*model.Author, error) { panic(fmt.Errorf("not implemented: Author - author")) } // Authors is the resolver for the authors field. func (r *queryResolver) Authors(ctx context.Context, limit *int32, offset *int32, search *string, countryID *string) ([]*model.Author, error) { var authors []*domain.Author var err error var countryIDUint *uint if countryID != nil { parsedID, err := strconv.ParseUint(*countryID, 10, 32) if err != nil { return nil, err } uid := uint(parsedID) countryIDUint = &uid } authors, err = r.App.Author.Queries.Authors(ctx, countryIDUint) if err != nil { return nil, err } // Convert to GraphQL model; resolve biography var result []*model.Author for _, a := range authors { var bio *string authorWithTranslations, err := r.App.Author.Queries.AuthorWithTranslations(ctx, a.ID) if err == nil && authorWithTranslations != nil { biography, err := r.App.Localization.Queries.GetAuthorBiography(ctx, a.ID, a.Language) if err == nil && biography != "" { bio = &biography } } result = append(result, &model.Author{ ID: fmt.Sprintf("%d", a.ID), Name: a.Name, Language: a.Language, Biography: bio, }) } return result, nil } // User is the resolver for the user field. func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) { panic(fmt.Errorf("not implemented: User - user")) } // UserByEmail is the resolver for the userByEmail field. func (r *queryResolver) UserByEmail(ctx context.Context, email string) (*model.User, error) { panic(fmt.Errorf("not implemented: UserByEmail - userByEmail")) } // UserByUsername is the resolver for the userByUsername field. func (r *queryResolver) UserByUsername(ctx context.Context, username string) (*model.User, error) { panic(fmt.Errorf("not implemented: UserByUsername - userByUsername")) } // Users is the resolver for the users field. func (r *queryResolver) Users(ctx context.Context, limit *int32, offset *int32, role *model.UserRole) ([]*model.User, error) { var users []domain.User var err error if role != nil { // Convert GraphQL role to model role var modelRole domain.UserRole switch *role { case model.UserRoleReader: modelRole = domain.UserRoleReader case model.UserRoleContributor: modelRole = domain.UserRoleContributor case model.UserRoleReviewer: modelRole = domain.UserRoleReviewer case model.UserRoleEditor: modelRole = domain.UserRoleEditor case model.UserRoleAdmin: modelRole = domain.UserRoleAdmin default: return nil, fmt.Errorf("invalid user role: %s", *role) } users, err = r.App.User.Queries.UsersByRole(ctx, modelRole) } else { users, err = r.App.User.Queries.Users(ctx) } if err != nil { return nil, err } // Convert to GraphQL model var result []*model.User for _, u := range users { // Convert model role to GraphQL role var graphqlRole model.UserRole switch u.Role { case domain.UserRoleReader: graphqlRole = model.UserRoleReader case domain.UserRoleContributor: graphqlRole = model.UserRoleContributor case domain.UserRoleReviewer: graphqlRole = model.UserRoleReviewer case domain.UserRoleEditor: graphqlRole = model.UserRoleEditor case domain.UserRoleAdmin: graphqlRole = model.UserRoleAdmin default: graphqlRole = model.UserRoleReader } result = append(result, &model.User{ ID: fmt.Sprintf("%d", u.ID), Username: u.Username, Email: u.Email, Role: graphqlRole, }) } return result, nil } // Me is the resolver for the me field. func (r *queryResolver) Me(ctx context.Context) (*model.User, error) { panic(fmt.Errorf("not implemented: Me - me")) } // UserProfile is the resolver for the userProfile field. func (r *queryResolver) UserProfile(ctx context.Context, userID string) (*model.UserProfile, error) { panic(fmt.Errorf("not implemented: UserProfile - userProfile")) } // Collection is the resolver for the collection field. func (r *queryResolver) Collection(ctx context.Context, id string) (*model.Collection, error) { panic(fmt.Errorf("not implemented: Collection - collection")) } // Collections is the resolver for the collections field. func (r *queryResolver) Collections(ctx context.Context, userID *string, limit *int32, offset *int32) ([]*model.Collection, error) { panic(fmt.Errorf("not implemented: Collections - collections")) } // Tag is the resolver for the tag field. func (r *queryResolver) Tag(ctx context.Context, id string) (*model.Tag, error) { tagID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, err } tag, err := r.App.Tag.Queries.Tag(ctx, uint(tagID)) if err != nil { return nil, err } return &model.Tag{ ID: fmt.Sprintf("%d", tag.ID), Name: tag.Name, }, nil } // Tags is the resolver for the tags field. func (r *queryResolver) Tags(ctx context.Context, limit *int32, offset *int32) ([]*model.Tag, error) { tags, err := r.App.Tag.Queries.Tags(ctx) if err != nil { return nil, err } // Convert to GraphQL model var result []*model.Tag for _, t := range tags { result = append(result, &model.Tag{ ID: fmt.Sprintf("%d", t.ID), Name: t.Name, }) } return result, nil } // Category is the resolver for the category field. func (r *queryResolver) Category(ctx context.Context, id string) (*model.Category, error) { categoryID, err := strconv.ParseUint(id, 10, 32) if err != nil { return nil, fmt.Errorf("invalid category ID: %v", err) } category, err := r.App.Category.Queries.Category(ctx, uint(categoryID)) if err != nil { return nil, err } if category == nil { return nil, nil } return &model.Category{ ID: fmt.Sprintf("%d", category.ID), Name: category.Name, }, nil } // Categories is the resolver for the categories field. func (r *queryResolver) Categories(ctx context.Context, limit *int32, offset *int32) ([]*model.Category, error) { categories, err := r.App.Category.Queries.Categories(ctx) if err != nil { return nil, err } // Convert to GraphQL model var result []*model.Category for _, c := range categories { result = append(result, &model.Category{ ID: fmt.Sprintf("%d", c.ID), Name: c.Name, }) } return result, nil } // Comment is the resolver for the comment field. func (r *queryResolver) Comment(ctx context.Context, id string) (*model.Comment, error) { panic(fmt.Errorf("not implemented: Comment - comment")) } // Comments is the resolver for the comments field. func (r *queryResolver) Comments(ctx context.Context, workID *string, translationID *string, userID *string, limit *int32, offset *int32) ([]*model.Comment, error) { panic(fmt.Errorf("not implemented: Comments - comments")) } // Search is the resolver for the search field. func (r *queryResolver) Search(ctx context.Context, query string, limit *int32, offset *int32, filters *model.SearchFilters) (*model.SearchResults, error) { panic(fmt.Errorf("not implemented: Search - search")) } // TrendingWorks is the resolver for the trendingWorks field. func (r *queryResolver) TrendingWorks(ctx context.Context, timePeriod *string, limit *int32) ([]*model.Work, error) { tp := "daily" if timePeriod != nil { tp = *timePeriod } l := 10 if limit != nil { l = int(*limit) } workRecords, err := r.App.Analytics.GetTrendingWorks(ctx, tp, l) if err != nil { return nil, err } var result []*model.Work for _, w := range workRecords { result = append(result, &model.Work{ ID: fmt.Sprintf("%d", w.ID), Name: w.Title, Language: w.Language, }) } return result, nil } // Mutation returns MutationResolver implementation. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } // Query returns QueryResolver implementation. func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } type mutationResolver struct{ *Resolver } type queryResolver struct{ *Resolver }