all repos

onasty @ 450a6a93f5f70a4a975b11d8e232fa4f2ce294fc

a one-time notes service
3 files changed, 31 insertions(+), 5 deletions(-)
fix: get note metadata (#150)

* fix: return 404 if note is read

* fixup! fix: return 404 if note is read

* fix(notesrv): cache only read notes

* test(e2e): test get metadata when note is read
Author: Smirnov Olexandr ss2316544@gmail.com
Committed by: GitHub noreply@github.com
Committed at: 2025-06-30 16:13:48 +0300
Parent: b59aa76
M e2e/apiv1_notes_test.go
···
        268
        268
         

      
        269
        269
         	// get metadata

      
        270
        270
         	metaResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+bodyCreated.Slug+"/meta", []byte{})

      
        271
        
        -	e.Equal(metaResp.Code, http.StatusOK)

      
        
        271
        +	e.Equal(http.StatusOK, metaResp.Code)

      
        272
        272
         

      
        273
        273
         	var metadata apiv1NoteMetadataResponse

      
        274
        274
         	e.readBodyAndUnjsonify(metaResp.Body, &metadata)

      ···
        281
        281
         	metaResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+e.uuid()+"/meta", []byte{})

      
        282
        282
         	e.Equal(http.StatusNotFound, metaResp.Code)

      
        283
        283
         }

      
        
        284
        +

      
        
        285
        +func (e *AppTestSuite) TestNoteV1_GetMetadata_readNote() {

      
        
        286
        +	// create note

      
        
        287
        +	createdResp := e.httpRequest(

      
        
        288
        +		http.MethodPost,

      
        
        289
        +		"/api/v1/note",

      
        
        290
        +		e.jsonify(apiv1NoteCreateRequest{Content: "content"}), //nolint:exhaustruct

      
        
        291
        +	)

      
        
        292
        +	e.Equal(http.StatusCreated, createdResp.Code)

      
        
        293
        +

      
        
        294
        +	var bodyCreated apiv1NoteCreateResponse

      
        
        295
        +	e.readBodyAndUnjsonify(createdResp.Body, &bodyCreated)

      
        
        296
        +

      
        
        297
        +	// read note

      
        
        298
        +	readResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+bodyCreated.Slug, nil)

      
        
        299
        +	e.Equal(http.StatusOK, readResp.Code)

      
        
        300
        +

      
        
        301
        +	// get metadata

      
        
        302
        +	metaResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+e.uuid()+"/meta", nil)

      
        
        303
        +	e.Equal(http.StatusNotFound, metaResp.Code)

      
        
        304
        +}

      
M internal/service/notesrv/notesrv.go
···
        225
        225
         		return models.Note{}, err

      
        226
        226
         	}

      
        227
        227
         

      
        228
        
        -	if !note.IsRead() {

      
        
        228
        +	if note.IsRead() {

      
        229
        229
         		if err = n.cache.SetNote(ctx, inp.Slug, note); err != nil {

      
        230
        230
         			slog.ErrorContext(ctx, "notecache", "err", err)

      
        231
        231
         		}

      
M internal/store/psql/noterepo/noterepo.go
···
        22
        22
         	GetBySlug(ctx context.Context, slug dtos.NoteSlug) (models.Note, error)

      
        23
        23
         

      
        24
        24
         	// GetMetadataBySlug gets note's metadata by its slug.

      
        25
        
        -	// Returns [models.ErrNoteNotFound] if note is not found.

      
        
        25
        +	// Returns [models.ErrNoteNotFound] if note is not found OR read.

      
        26
        26
         	GetMetadataBySlug(ctx context.Context, slug dtos.NoteSlug) (dtos.NoteMetadata, error)

      
        27
        27
         

      
        28
        28
         	// GetAllByAuthorID returns all notes with specified author.

      ···
        123
        123
         	slug dtos.NoteSlug,

      
        124
        124
         ) (dtos.NoteMetadata, error) {

      
        125
        125
         	query := `--sql

      
        126
        
        -	select n.created_at, (n.password is not null and n.password <> '') has_password

      
        
        126
        +	select n.created_at, (n.password is not null and n.password <> '') has_password, n.read_at

      
        127
        127
         	from notes n

      
        128
        128
         	where slug = $1

      
        129
        129
         	`

      
        130
        130
         

      
        
        131
        +	var readAt time.Time

      
        131
        132
         	var metadata dtos.NoteMetadata

      
        132
        
        -	err := s.db.QueryRow(ctx, query, slug).Scan(&metadata.CreatedAt, &metadata.HasPassword)

      
        
        133
        +	err := s.db.QueryRow(ctx, query, slug).Scan(&metadata.CreatedAt, &metadata.HasPassword, &readAt)

      
        133
        134
         	if errors.Is(err, pgx.ErrNoRows) {

      
        
        135
        +		return dtos.NoteMetadata{}, models.ErrNoteNotFound

      
        
        136
        +	}

      
        
        137
        +

      
        
        138
        +	if !readAt.IsZero() {

      
        134
        139
         		return dtos.NoteMetadata{}, models.ErrNoteNotFound

      
        135
        140
         	}

      
        136
        141