diff --git a/internal/dtos/note.go b/internal/dtos/note.go index 3a2a3863..adab5d58 100644 --- a/internal/dtos/note.go +++ b/internal/dtos/note.go @@ -12,7 +12,6 @@ func (n NoteSlugDTO) String() string { return string(n) } type NoteDTO struct { Content string - UserID uuid.UUID Slug string BurnBeforeExpiration bool CreatedAt time.Time diff --git a/internal/service/notesrv/notesrv.go b/internal/service/notesrv/notesrv.go index c941728b..129777db 100644 --- a/internal/service/notesrv/notesrv.go +++ b/internal/service/notesrv/notesrv.go @@ -3,14 +3,17 @@ package notesrv import ( "context" - "github.com/google/uuid" + "github.com/gofrs/uuid/v5" "github.com/olexsmir/onasty/internal/dtos" "github.com/olexsmir/onasty/internal/models" "github.com/olexsmir/onasty/internal/store/psql/noterepo" ) type NoteServicer interface { - Create(ctx context.Context, note dtos.CreateNoteDTO) (dtos.NoteSlugDTO, error) + // Create create note + // if slug is empty it will be generated, otherwise used as is + // if userID is empty it means user isn't authorized so it will be used + Create(ctx context.Context, note dtos.CreateNoteDTO, userID uuid.UUID) (dtos.NoteSlugDTO, error) GetBySlugAndRemoveIfNeeded(ctx context.Context, slug dtos.NoteSlugDTO) (dtos.NoteDTO, error) } @@ -26,13 +29,27 @@ func New(noterepo noterepo.NoteStorer) NoteServicer { } } -func (n *NoteSrv) Create(ctx context.Context, inp dtos.CreateNoteDTO) (dtos.NoteSlugDTO, error) { +func (n *NoteSrv) Create( + ctx context.Context, + inp dtos.CreateNoteDTO, + userID uuid.UUID, +) (dtos.NoteSlugDTO, error) { if inp.Slug == "" { - inp.Slug = uuid.New().String() + inp.Slug = uuid.Must(uuid.NewV4()).String() } err := n.noterepo.Create(ctx, inp) - return dtos.NoteSlugDTO(inp.Slug), err + if err != nil { + return "", err + } + + if !userID.IsNil() { + if err := n.noterepo.SetAuthorIDBySlug(ctx, dtos.NoteSlugDTO(inp.Slug), userID); err != nil { + return "", err + } + } + + return dtos.NoteSlugDTO(inp.Slug), nil } func (n *NoteSrv) GetBySlugAndRemoveIfNeeded( diff --git a/internal/store/psql/noterepo/noterepo.go b/internal/store/psql/noterepo/noterepo.go index a8030b62..5f08e08a 100644 --- a/internal/store/psql/noterepo/noterepo.go +++ b/internal/store/psql/noterepo/noterepo.go @@ -4,6 +4,7 @@ import ( "context" "errors" + "github.com/gofrs/uuid/v5" "github.com/henvic/pgq" "github.com/jackc/pgx/v5" "github.com/olexsmir/onasty/internal/dtos" @@ -15,6 +16,8 @@ type NoteStorer interface { Create(ctx context.Context, inp dtos.CreateNoteDTO) error GetBySlug(ctx context.Context, slug dtos.NoteSlugDTO) (dtos.NoteDTO, error) DeleteBySlug(ctx context.Context, slug dtos.NoteSlugDTO) error + + SetAuthorIDBySlug(ctx context.Context, slug dtos.NoteSlugDTO, authorID uuid.UUID) error } var _ NoteStorer = (*NoteRepo)(nil) @@ -30,8 +33,8 @@ func New(db *psqlutil.DB) NoteStorer { func (s *NoteRepo) Create(ctx context.Context, inp dtos.CreateNoteDTO) error { query, args, err := pgq. Insert("notes"). - Columns("content", "user_id", "slug", "burn_before_expiration ", "created_at", "expires_at"). - Values(inp.Content, inp.UserID, inp.Slug, inp.BurnBeforeExpiration, inp.CreatedAt, inp.ExpiresAt). + Columns("content", "slug", "burn_before_expiration ", "created_at", "expires_at"). + Values(inp.Content, inp.Slug, inp.BurnBeforeExpiration, inp.CreatedAt, inp.ExpiresAt). SQL() if err != nil { return err @@ -82,3 +85,36 @@ func (s *NoteRepo) DeleteBySlug(ctx context.Context, slug dtos.NoteSlugDTO) erro return err } + +func (s *NoteRepo) SetAuthorIDBySlug( + ctx context.Context, + slug dtos.NoteSlugDTO, + authorID uuid.UUID, +) error { + tx, err := s.db.Begin(ctx) + if err != nil { + return err + } + defer tx.Rollback(ctx) //nolint:errcheck + + var noteID uuid.UUID + err = tx.QueryRow(ctx, "select id from notes where slug = $1", slug.String()).Scan(¬eID) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return models.ErrNoteNotFound + } + return err + } + + _, err = tx.Exec( + ctx, + "insert into notes_authors (note_id, user_id) values ($1, $2)", + noteID, + authorID, + ) + if err != nil { + return err + } + + return tx.Commit(ctx) +} diff --git a/internal/transport/http/apiv1/note.go b/internal/transport/http/apiv1/note.go index f25831d9..0b9921dd 100644 --- a/internal/transport/http/apiv1/note.go +++ b/internal/transport/http/apiv1/note.go @@ -1,6 +1,7 @@ package apiv1 import ( + "log/slog" "net/http" "time" @@ -38,8 +39,11 @@ func (a *APIV1) createNoteHandler(c *gin.Context) { if err := note.Validate(); err != nil { newErrorStatus(c, http.StatusBadRequest, err.Error()) return + } + slog.Debug("userid", "a", a.getUserID(c)) + slug, err := a.notesrv.Create(c.Request.Context(), dtos.CreateNoteDTO{ Content: note.Content, UserID: a.getUserID(c), @@ -47,7 +51,7 @@ func (a *APIV1) createNoteHandler(c *gin.Context) { BurnBeforeExpiration: note.BurnBeforeExpiration, CreatedAt: note.CreatedAt, ExpiresAt: note.ExpiresAt, - }) + }, a.getUserID(c)) if err != nil { errorResponse(c, err) return