mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 02:51:34 +00:00
- `Me`: Fetches the details of the currently authenticated user from the request context. - `User`: Fetches the public details of a user by their ID. - `Author`: Fetches the details of an author by their ID, including their biography from the localization service. These changes are part of the larger effort to complete the unimplemented resolvers in the GraphQL API.
1569 lines
45 KiB
Go
1569 lines
45 KiB
Go
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.CreateOrUpdateTranslationInput{
|
|
Title: input.Name,
|
|
Content: *input.Content,
|
|
Language: input.Language,
|
|
TranslatableID: createdWork.ID,
|
|
TranslatableType: "works",
|
|
IsOriginalLanguage: true,
|
|
}
|
|
_, err := r.App.Translation.Commands.CreateOrUpdateTranslation(ctx, translationInput)
|
|
if err != nil {
|
|
// If this fails, should we roll back the work creation?
|
|
// For now, just return the error. A transaction would be better.
|
|
return nil, fmt.Errorf("failed to create initial 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
|
|
}
|
|
|
|
// The authorization is now handled inside the command, so we don't need a separate check here.
|
|
|
|
workID, err := strconv.ParseUint(input.WorkID, 10, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: invalid work ID", domain.ErrValidation)
|
|
}
|
|
|
|
var content string
|
|
if input.Content != nil {
|
|
content = *input.Content
|
|
}
|
|
|
|
// Call translation service using the new CreateOrUpdate command
|
|
createInput := translation.CreateOrUpdateTranslationInput{
|
|
Title: input.Name,
|
|
Content: content,
|
|
Language: input.Language,
|
|
TranslatableID: uint(workID),
|
|
TranslatableType: "works", // Assuming "works" for now, schema should be more generic
|
|
}
|
|
createdTranslation, err := r.App.Translation.Commands.CreateOrUpdateTranslation(ctx, createInput)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Increment translation count for the work
|
|
go r.App.Analytics.IncrementWorkTranslationCount(context.Background(), uint(workID))
|
|
|
|
// 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) {
|
|
// This now acts as an "upsert" by calling the same command as CreateTranslation.
|
|
// The `id` of the translation is no longer needed, as the upsert logic
|
|
// relies on the parent (WorkID) and the language.
|
|
if err := Validate(input); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
workID, err := strconv.ParseUint(input.WorkID, 10, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: invalid work ID", domain.ErrValidation)
|
|
}
|
|
|
|
var content string
|
|
if input.Content != nil {
|
|
content = *input.Content
|
|
}
|
|
|
|
// Call translation service using the new CreateOrUpdate command
|
|
updateInput := translation.CreateOrUpdateTranslationInput{
|
|
Title: input.Name,
|
|
Content: content,
|
|
Language: input.Language,
|
|
TranslatableID: uint(workID),
|
|
TranslatableType: "works",
|
|
}
|
|
updatedTranslation, err := r.App.Translation.Commands.CreateOrUpdateTranslation(ctx, updateInput)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Convert to GraphQL model
|
|
return &model.Translation{
|
|
ID: fmt.Sprintf("%d", updatedTranslation.ID), // Return the potentially new 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
|
|
}
|
|
|
|
// Increment view count in the background
|
|
go r.App.Analytics.IncrementWorkViews(context.Background(), uint(workID))
|
|
|
|
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) {
|
|
translationID, err := strconv.ParseUint(id, 10, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid translation ID: %v", err)
|
|
}
|
|
|
|
translationRecord, err := r.App.Translation.Queries.Translation(ctx, uint(translationID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if translationRecord == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
// Increment view count in the background
|
|
go r.App.Analytics.IncrementTranslationViews(context.Background(), uint(translationID))
|
|
|
|
// Convert to GraphQL model
|
|
return &model.Translation{
|
|
ID: id,
|
|
Name: translationRecord.Title,
|
|
Language: translationRecord.Language,
|
|
Content: &translationRecord.Content,
|
|
WorkID: fmt.Sprintf("%d", translationRecord.TranslatableID),
|
|
}, nil
|
|
}
|
|
|
|
// 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) {
|
|
authorID, err := strconv.ParseUint(id, 10, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid author ID: %v", err)
|
|
}
|
|
|
|
authorRecord, err := r.App.Author.Queries.Author(ctx, uint(authorID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if authorRecord == nil {
|
|
return nil, nil // Or return a "not found" error
|
|
}
|
|
|
|
var bio *string
|
|
biography, err := r.App.Localization.Queries.GetAuthorBiography(ctx, authorRecord.ID, authorRecord.Language)
|
|
if err == nil && biography != "" {
|
|
bio = &biography
|
|
}
|
|
|
|
return &model.Author{
|
|
ID: fmt.Sprintf("%d", authorRecord.ID),
|
|
Name: authorRecord.Name,
|
|
Language: authorRecord.Language,
|
|
Biography: bio,
|
|
}, nil
|
|
}
|
|
|
|
// 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) {
|
|
userID, err := strconv.ParseUint(id, 10, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid user ID: %v", err)
|
|
}
|
|
|
|
user, err := r.App.User.Queries.User(ctx, uint(userID))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if user == nil {
|
|
return nil, nil // Or return a "not found" error
|
|
}
|
|
|
|
// Convert to GraphQL model
|
|
return &model.User{
|
|
ID: fmt.Sprintf("%d", user.ID),
|
|
Username: user.Username,
|
|
Email: user.Email,
|
|
FirstName: &user.FirstName,
|
|
LastName: &user.LastName,
|
|
DisplayName: &user.DisplayName,
|
|
Bio: &user.Bio,
|
|
AvatarURL: &user.AvatarURL,
|
|
Role: model.UserRole(user.Role),
|
|
Verified: user.Verified,
|
|
Active: user.Active,
|
|
}, nil
|
|
}
|
|
|
|
// 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) {
|
|
// Get user ID from context
|
|
userID, ok := platform_auth.GetUserIDFromContext(ctx)
|
|
if !ok {
|
|
return nil, domain.ErrUnauthorized
|
|
}
|
|
|
|
// Fetch user details
|
|
user, err := r.App.User.Queries.User(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Convert to GraphQL model
|
|
return &model.User{
|
|
ID: fmt.Sprintf("%d", user.ID),
|
|
Username: user.Username,
|
|
Email: user.Email,
|
|
FirstName: &user.FirstName,
|
|
LastName: &user.LastName,
|
|
DisplayName: &user.DisplayName,
|
|
Bio: &user.Bio,
|
|
AvatarURL: &user.AvatarURL,
|
|
Role: model.UserRole(user.Role),
|
|
Verified: user.Verified,
|
|
Active: user.Active,
|
|
}, nil
|
|
}
|
|
|
|
// 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 }
|