all repos

onasty @ bc92b8268dc567b48d4d567ffdfefb0442152335

a one-time notes service
5 files changed, 326 insertions(+), 55 deletions(-)
feat: get all read and unread notes (#188)

* refactor: some moving of code around

* feat: implement get all read notes

* test(e2e): add missing test for "get all notes"

* feat: implement get all unread notes

* refactor: remove duplications for type conversions
Author: Olexandr Smirnov ss2316544@gmail.com
Committed by: GitHub noreply@github.com
Committed at: 2025-08-13 15:12:37 +0300
Parent: efd9704
M e2e/apiv1_notes_authorized_test.go
···
        2
        2
         

      
        3
        3
         import (

      
        4
        4
         	"net/http"

      
        
        5
        +	"slices"

      
        5
        6
         	"time"

      
        6
        7
         )

      
        7
        8
         

      ···
        199
        200
         

      
        200
        201
         	e.Equal(httpResp.Code, http.StatusBadRequest)

      
        201
        202
         }

      
        
        203
        +

      
        
        204
        +type apiv1NoteGetAllResponse struct {

      
        
        205
        +	Content              string    `json:"content"`

      
        
        206
        +	Slug                 string    `json:"slug"`

      
        
        207
        +	BurnBeforeExpiration bool      `json:"burn_before_expiration"`

      
        
        208
        +	HasPassword          bool      `json:"has_password"`

      
        
        209
        +	CreatedAt            time.Time `json:"created_at"`

      
        
        210
        +	ExpiresAt            time.Time `json:"expires_at"`

      
        
        211
        +	ReadAt               time.Time `json:"read_at"`

      
        
        212
        +}

      
        
        213
        +

      
        
        214
        +func (e *AppTestSuite) TestNoteV1_GetAll() {

      
        
        215
        +	notesInfo := []struct {

      
        
        216
        +		slug    string

      
        
        217
        +		content string

      
        
        218
        +		read    bool

      
        
        219
        +	}{

      
        
        220
        +		{slug: e.uuid(), content: e.uuid(), read: true},

      
        
        221
        +		{slug: e.uuid(), content: e.uuid(), read: true},

      
        
        222
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        223
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        224
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        225
        +	}

      
        
        226
        +

      
        
        227
        +	_, toks := e.createAndSingIn(e.uuid()+"@test.com", "password")

      
        
        228
        +

      
        
        229
        +	// create notes

      
        
        230
        +	for _, ni := range notesInfo {

      
        
        231
        +		httpResp := e.httpRequest(

      
        
        232
        +			http.MethodPost,

      
        
        233
        +			"/api/v1/note",

      
        
        234
        +			e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct

      
        
        235
        +				Content: ni.content,

      
        
        236
        +				Slug:    ni.slug,

      
        
        237
        +			}),

      
        
        238
        +			toks.AccessToken)

      
        
        239
        +

      
        
        240
        +		e.Equal(http.StatusCreated, httpResp.Code)

      
        
        241
        +	}

      
        
        242
        +

      
        
        243
        +	// read notes

      
        
        244
        +	for _, ni := range notesInfo {

      
        
        245
        +		if ni.read {

      
        
        246
        +			httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+ni.slug, nil)

      
        
        247
        +			e.Equal(http.StatusOK, httpResp.Code)

      
        
        248
        +		}

      
        
        249
        +	}

      
        
        250
        +

      
        
        251
        +	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note", nil, toks.AccessToken)

      
        
        252
        +

      
        
        253
        +	var body []apiv1NoteGetAllResponse

      
        
        254
        +	e.readBodyAndUnjsonify(httpResp.Body, &body)

      
        
        255
        +

      
        
        256
        +	e.Equal(http.StatusOK, httpResp.Code)

      
        
        257
        +	e.Len(body, len(notesInfo))

      
        
        258
        +}

      
        
        259
        +

      
        
        260
        +func (e *AppTestSuite) TestNoteV1_GetAllRead_inaccesibleForAnUnauthorized() {

      
        
        261
        +	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/read", nil)

      
        
        262
        +	e.Equal(httpResp.Code, http.StatusUnauthorized)

      
        
        263
        +}

      
        
        264
        +

      
        
        265
        +func (e *AppTestSuite) TestNoteV1_GetAllRead() {

      
        
        266
        +	notesInfo := []struct {

      
        
        267
        +		slug    string

      
        
        268
        +		content string

      
        
        269
        +	}{

      
        
        270
        +		{slug: e.uuid(), content: e.uuid()},

      
        
        271
        +		{slug: e.uuid(), content: e.uuid()},

      
        
        272
        +		{slug: e.uuid(), content: e.uuid()},

      
        
        273
        +		{slug: e.uuid(), content: e.uuid()},

      
        
        274
        +	}

      
        
        275
        +

      
        
        276
        +	_, toks := e.createAndSingIn(e.uuid()+"@test.com", "password")

      
        
        277
        +

      
        
        278
        +	// create few notes

      
        
        279
        +	for _, ni := range notesInfo {

      
        
        280
        +		httpResp := e.httpRequest(

      
        
        281
        +			http.MethodPost,

      
        
        282
        +			"/api/v1/note",

      
        
        283
        +			e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct

      
        
        284
        +				Content: ni.content,

      
        
        285
        +				Slug:    ni.slug,

      
        
        286
        +			}),

      
        
        287
        +			toks.AccessToken)

      
        
        288
        +

      
        
        289
        +		e.Equal(http.StatusCreated, httpResp.Code)

      
        
        290
        +	}

      
        
        291
        +

      
        
        292
        +	// read those notes

      
        
        293
        +	for _, ni := range notesInfo {

      
        
        294
        +		httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+ni.slug, nil)

      
        
        295
        +		e.Equal(http.StatusOK, httpResp.Code)

      
        
        296
        +	}

      
        
        297
        +

      
        
        298
        +	// check if all notes are returned

      
        
        299
        +	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/read", nil, toks.AccessToken)

      
        
        300
        +

      
        
        301
        +	var body []apiv1NoteGetAllResponse

      
        
        302
        +	e.readBodyAndUnjsonify(httpResp.Body, &body)

      
        
        303
        +

      
        
        304
        +	e.Equal(http.StatusOK, httpResp.Code)

      
        
        305
        +	e.require.Len(body, len(notesInfo))

      
        
        306
        +}

      
        
        307
        +

      
        
        308
        +func (e *AppTestSuite) TestNoteV1_GetAllUnread_inaccesibleForAnUnauthorized() {

      
        
        309
        +	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/unread", nil)

      
        
        310
        +	e.Equal(httpResp.Code, http.StatusUnauthorized)

      
        
        311
        +}

      
        
        312
        +

      
        
        313
        +func (e *AppTestSuite) TestNoteV1_GetAllUnread() {

      
        
        314
        +	type notesTestData struct {

      
        
        315
        +		slug    string

      
        
        316
        +		content string

      
        
        317
        +		read    bool

      
        
        318
        +	}

      
        
        319
        +

      
        
        320
        +	notesInfo := []notesTestData{

      
        
        321
        +		{slug: e.uuid(), content: e.uuid(), read: true},

      
        
        322
        +		{slug: e.uuid(), content: e.uuid(), read: true},

      
        
        323
        +		{slug: e.uuid(), content: e.uuid(), read: true},

      
        
        324
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        325
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        326
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        327
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        328
        +		{slug: e.uuid(), content: e.uuid(), read: false},

      
        
        329
        +	}

      
        
        330
        +	unreadNotesTotal := len(

      
        
        331
        +		slices.DeleteFunc(

      
        
        332
        +			slices.Clone(notesInfo),

      
        
        333
        +			func(n notesTestData) bool { return n.read }),

      
        
        334
        +	)

      
        
        335
        +

      
        
        336
        +	_, toks := e.createAndSingIn(e.uuid()+"@test.com", "password")

      
        
        337
        +

      
        
        338
        +	// create notes

      
        
        339
        +	for _, ni := range notesInfo {

      
        
        340
        +		httpResp := e.httpRequest(

      
        
        341
        +			http.MethodPost,

      
        
        342
        +			"/api/v1/note",

      
        
        343
        +			e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct

      
        
        344
        +				Content: ni.content,

      
        
        345
        +				Slug:    ni.slug,

      
        
        346
        +			}),

      
        
        347
        +			toks.AccessToken)

      
        
        348
        +

      
        
        349
        +		e.Equal(http.StatusCreated, httpResp.Code)

      
        
        350
        +	}

      
        
        351
        +

      
        
        352
        +	// read notes

      
        
        353
        +	for _, ni := range notesInfo {

      
        
        354
        +		if ni.read {

      
        
        355
        +			httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+ni.slug, nil)

      
        
        356
        +			e.Equal(http.StatusOK, httpResp.Code)

      
        
        357
        +		}

      
        
        358
        +	}

      
        
        359
        +

      
        
        360
        +	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/unread", nil, toks.AccessToken)

      
        
        361
        +

      
        
        362
        +	var body []apiv1NoteGetAllResponse

      
        
        363
        +	e.readBodyAndUnjsonify(httpResp.Body, &body)

      
        
        364
        +

      
        
        365
        +	e.Equal(http.StatusOK, httpResp.Code)

      
        
        366
        +	e.Len(body, unreadNotesTotal)

      
        
        367
        +}

      
M internal/service/notesrv/notesrv.go
···
        34
        34
         	GetNoteMetadataBySlug(ctx context.Context, slug dtos.NoteSlug) (dtos.NoteMetadata, error)

      
        35
        35
         

      
        36
        36
         	// GetAllByAuthorID returns all notes by author id.

      
        37
        
        -	GetAllByAuthorID(

      
        38
        
        -		ctx context.Context,

      
        39
        
        -		authorID uuid.UUID,

      
        40
        
        -	) ([]dtos.NoteDetailed, error)

      
        
        37
        +	GetAllByAuthorID(ctx context.Context, authorID uuid.UUID) ([]dtos.NoteDetailed, error)

      
        
        38
        +

      
        
        39
        +	// GetAllReadByAuthorID returns all notes that ARE READ and authored by author id.

      
        
        40
        +	GetAllReadByAuthorID(ctx context.Context, authorID uuid.UUID) ([]dtos.NoteDetailed, error)

      
        
        41
        +

      
        
        42
        +	// GetAllUnreadByAuthorID returns all notes that ARE UNREAD and authored by author id.

      
        
        43
        +	GetAllUnreadByAuthorID(ctx context.Context, authorID uuid.UUID) ([]dtos.NoteDetailed, error)

      
        41
        44
         

      
        42
        45
         	// UpdateExpirationTimeSettings updates expiresAt and burnBeforeExpiration.

      
        43
        46
         	// If notes is not found returns [models.ErrNoteNotFound].

      ···
        164
        167
         		return nil, err

      
        165
        168
         	}

      
        166
        169
         

      
        167
        
        -	var resNotes []dtos.NoteDetailed

      
        168
        
        -	for _, note := range notes {

      
        169
        
        -		resNotes = append(resNotes, dtos.NoteDetailed{

      
        170
        
        -			Content:              note.Content,

      
        171
        
        -			Slug:                 note.Slug,

      
        172
        
        -			BurnBeforeExpiration: note.BurnBeforeExpiration,

      
        173
        
        -			HasPassword:          note.Password != "",

      
        174
        
        -			CreatedAt:            note.CreatedAt,

      
        175
        
        -			ExpiresAt:            note.ExpiresAt,

      
        176
        
        -			ReadAt:               note.ReadAt,

      
        177
        
        -		})

      
        
        170
        +	return n.mapNoteModelToDto(notes), nil

      
        
        171
        +}

      
        
        172
        +

      
        
        173
        +func (n *NoteSrv) GetAllReadByAuthorID(

      
        
        174
        +	ctx context.Context,

      
        
        175
        +	authorID uuid.UUID,

      
        
        176
        +) ([]dtos.NoteDetailed, error) {

      
        
        177
        +	notes, err := n.noterepo.GetAllReadByAuthorID(ctx, authorID)

      
        
        178
        +	if err != nil {

      
        
        179
        +		return nil, err

      
        
        180
        +	}

      
        
        181
        +

      
        
        182
        +	return n.mapNoteModelToDto(notes), nil

      
        
        183
        +}

      
        
        184
        +

      
        
        185
        +func (n *NoteSrv) GetAllUnreadByAuthorID(

      
        
        186
        +	ctx context.Context,

      
        
        187
        +	authorID uuid.UUID,

      
        
        188
        +) ([]dtos.NoteDetailed, error) {

      
        
        189
        +	notes, err := n.noterepo.GetAllUnreadByAuthorID(ctx, authorID)

      
        
        190
        +	if err != nil {

      
        
        191
        +		return nil, err

      
        178
        192
         	}

      
        179
        193
         

      
        180
        
        -	return resNotes, nil

      
        
        194
        +	return n.mapNoteModelToDto(notes), nil

      
        181
        195
         }

      
        182
        196
         

      
        183
        197
         func (n *NoteSrv) UpdateExpirationTimeSettings(

      ···
        248
        262
         	}

      
        249
        263
         	return n.noterepo.GetBySlug(ctx, inp.Slug)

      
        250
        264
         }

      
        
        265
        +

      
        
        266
        +func (n *NoteSrv) mapNoteModelToDto(notes []models.Note) []dtos.NoteDetailed {

      
        
        267
        +	var resNotes []dtos.NoteDetailed

      
        
        268
        +	for _, note := range notes {

      
        
        269
        +		resNotes = append(resNotes, dtos.NoteDetailed{

      
        
        270
        +			Content:              note.Content,

      
        
        271
        +			Slug:                 note.Slug,

      
        
        272
        +			BurnBeforeExpiration: note.BurnBeforeExpiration,

      
        
        273
        +			HasPassword:          note.Password != "",

      
        
        274
        +			CreatedAt:            note.CreatedAt,

      
        
        275
        +			ExpiresAt:            note.ExpiresAt,

      
        
        276
        +			ReadAt:               note.ReadAt,

      
        
        277
        +		})

      
        
        278
        +	}

      
        
        279
        +

      
        
        280
        +	return resNotes

      
        
        281
        +}

      
M internal/store/psql/noterepo/noterepo.go
···
        29
        29
         	// GetAllByAuthorID returns all notes with specified author.

      
        30
        30
         	GetAllByAuthorID(ctx context.Context, authorID uuid.UUID) ([]models.Note, error)

      
        31
        31
         

      
        
        32
        +	// GetAllReadByAuthorID returns all notes that are read and authored by specified author.

      
        
        33
        +	GetAllReadByAuthorID(ctx context.Context, authorID uuid.UUID) ([]models.Note, error)

      
        
        34
        +

      
        
        35
        +	// GetAllUnreadByAuthorID returns all notes that are unread and authored by specified author.

      
        
        36
        +	GetAllUnreadByAuthorID(ctx context.Context, authorID uuid.UUID) ([]models.Note, error)

      
        
        37
        +

      
        32
        38
         	// GetCountOfNotesByAuthorID returns count of notes created by specified author.

      
        33
        39
         	GetCountOfNotesByAuthorID(ctx context.Context, authorID uuid.UUID) (int64, error)

      
        34
        40
         

      ···
        129
        135
         	slug dtos.NoteSlug,

      
        130
        136
         ) (dtos.NoteMetadata, error) {

      
        131
        137
         	query := `--sql

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

      
        133
        
        -	from notes n

      
        134
        
        -	where slug = $1

      
        135
        
        -	`

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

      
        
        139
        +from notes n

      
        
        140
        +where slug = $1`

      
        136
        141
         

      
        137
        142
         	var readAt sql.NullTime

      
        138
        143
         	var metadata dtos.NoteMetadata

      ···
        153
        158
         	authorID uuid.UUID,

      
        154
        159
         ) ([]models.Note, error) {

      
        155
        160
         	query := `--sql

      
        156
        
        -	select n.content, n.slug, n.burn_before_expiration, n.password, n.read_at, n.created_at, n.expires_at

      
        157
        
        -	from notes n

      
        158
        
        -	right join notes_authors na on n.id = na.note_id

      
        159
        
        -	where na.user_id = $1`

      
        
        161
        +select n.content, n.slug, n.burn_before_expiration, n.password, n.read_at, n.created_at, n.expires_at

      
        
        162
        +from notes n

      
        
        163
        +inner join notes_authors na on n.id = na.note_id

      
        
        164
        +where na.user_id = $1`

      
        160
        165
         

      
        161
        
        -	rows, err := s.db.Query(ctx, query, authorID.String())

      
        162
        
        -	if err != nil {

      
        163
        
        -		return nil, err

      
        164
        
        -	}

      
        
        166
        +	return s.getAllNotes(ctx, query, authorID)

      
        
        167
        +}

      
        165
        168
         

      
        166
        
        -	defer rows.Close()

      
        
        169
        +func (s *NoteRepo) GetAllReadByAuthorID(

      
        
        170
        +	ctx context.Context,

      
        
        171
        +	authorID uuid.UUID,

      
        
        172
        +) ([]models.Note, error) {

      
        
        173
        +	query := `--sql

      
        
        174
        +select n.content, n.slug, n.burn_before_expiration, n.password, n.read_at, n.created_at, n.expires_at

      
        
        175
        +from notes n

      
        
        176
        +inner join notes_authors na on n.id = na.note_id

      
        
        177
        +where na.user_id = $1

      
        
        178
        +	and n.read_at is not null`

      
        167
        179
         

      
        168
        
        -	var notes []models.Note

      
        169
        
        -	for rows.Next() {

      
        170
        
        -		var note models.Note

      
        171
        
        -		var readAt sql.NullTime

      
        172
        
        -		if err := rows.Scan(&note.Content, &note.Slug, &note.BurnBeforeExpiration, &note.Password,

      
        173
        
        -			&readAt, &note.CreatedAt, &note.ExpiresAt); err != nil {

      
        174
        
        -			return nil, err

      
        175
        
        -		}

      
        
        180
        +	return s.getAllNotes(ctx, query, authorID)

      
        
        181
        +}

      
        176
        182
         

      
        177
        
        -		note.ReadAt = psqlutil.NullTimeToTime(readAt)

      
        178
        
        -		notes = append(notes, note)

      
        179
        
        -	}

      
        
        183
        +func (s *NoteRepo) GetAllUnreadByAuthorID(

      
        
        184
        +	ctx context.Context,

      
        
        185
        +	authorID uuid.UUID,

      
        
        186
        +) ([]models.Note, error) {

      
        
        187
        +	query := `--sql

      
        
        188
        +select n.content, n.slug, n.burn_before_expiration, n.password, n.read_at, n.created_at, n.expires_at

      
        
        189
        +from notes n

      
        
        190
        +inner join notes_authors na on n.id = na.note_id

      
        
        191
        +where na.user_id = $1

      
        
        192
        +	and n.read_at is null`

      
        180
        193
         

      
        181
        
        -	return notes, rows.Err()

      
        
        194
        +	return s.getAllNotes(ctx, query, authorID)

      
        182
        195
         }

      
        183
        196
         

      
        184
        197
         func (s *NoteRepo) GetCountOfNotesByAuthorID(

      ···
        359
        372
         

      
        360
        373
         	return nil

      
        361
        374
         }

      
        
        375
        +

      
        
        376
        +// getAllNotes is a helper function for [NoteRepo.GetAllByAuthorID], [NoteRepo.GetAllReadByAuthorID],

      
        
        377
        +// and [NoteRepo.GetAllUnreadByAuthorID].

      
        
        378
        +// The query's SELECT elements order should be consistent across all function calls.

      
        
        379
        +func (s *NoteRepo) getAllNotes(

      
        
        380
        +	ctx context.Context,

      
        
        381
        +	query string,

      
        
        382
        +	authorID uuid.UUID,

      
        
        383
        +) ([]models.Note, error) {

      
        
        384
        +	rows, err := s.db.Query(ctx, query, authorID.String())

      
        
        385
        +	if err != nil {

      
        
        386
        +		return nil, err

      
        
        387
        +	}

      
        
        388
        +

      
        
        389
        +	defer rows.Close()

      
        
        390
        +

      
        
        391
        +	var notes []models.Note

      
        
        392
        +	for rows.Next() {

      
        
        393
        +		var note models.Note

      
        
        394
        +		var readAt sql.NullTime

      
        
        395
        +		if err := rows.Scan(&note.Content, &note.Slug, &note.BurnBeforeExpiration, &note.Password,

      
        
        396
        +			&readAt, &note.CreatedAt, &note.ExpiresAt); err != nil {

      
        
        397
        +			return nil, err

      
        
        398
        +		}

      
        
        399
        +

      
        
        400
        +		note.ReadAt = psqlutil.NullTimeToTime(readAt)

      
        
        401
        +		notes = append(notes, note)

      
        
        402
        +	}

      
        
        403
        +

      
        
        404
        +	return notes, rows.Err()

      
        
        405
        +}

      
M internal/transport/http/apiv1/apiv1.go
···
        34
        34
         

      
        35
        35
         func (a *APIV1) Routes(r *gin.RouterGroup) {

      
        36
        36
         	r.Use(a.metricsMiddleware)

      
        
        37
        +

      
        
        38
        +	r.GET("/me", a.authorizedMiddleware, a.getMeHandler)

      
        
        39
        +

      
        37
        40
         	auth := r.Group("/auth")

      
        38
        41
         	{

      
        39
        42
         		auth.POST("/signup", a.signUpHandler)

      ···
        58
        61
         		}

      
        59
        62
         	}

      
        60
        63
         

      
        61
        
        -	r.GET("/me", a.authorizedMiddleware, a.getMeHandler)

      
        62
        
        -

      
        63
        64
         	note := r.Group("/note")

      
        64
        65
         	{

      
        65
        66
         		note.GET("/:slug", a.getNoteBySlugHandler)

      ···
        74
        75
         		authorized := note.Group("", a.authorizedMiddleware)

      
        75
        76
         		{

      
        76
        77
         			authorized.GET("", a.getNotesHandler)

      
        
        78
        +

      
        
        79
        +			// FIXME: those links make slugs `read` and `unread` unavailable

      
        
        80
        +			authorized.GET("/read", a.getReadNotesHandler)

      
        
        81
        +			authorized.GET("/unread", a.getUnReadNotesHandler)

      
        
        82
        +

      
        77
        83
         			authorized.PATCH(":slug/expires", a.updateNoteHandler)

      
        78
        84
         			authorized.PATCH(":slug/password", a.setNotePasswordHandler)

      
        79
        85
         			authorized.DELETE(":slug", a.deleteNoteHandler)

      
M internal/transport/http/apiv1/note.go
···
        154
        154
         		return

      
        155
        155
         	}

      
        156
        156
         

      
        157
        
        -	var response []getNotesResponse

      
        158
        
        -	for _, note := range notes {

      
        159
        
        -		response = append(response, getNotesResponse{

      
        160
        
        -			Content:              note.Content,

      
        161
        
        -			Slug:                 note.Slug,

      
        162
        
        -			BurnBeforeExpiration: note.BurnBeforeExpiration,

      
        163
        
        -			HasPassword:          note.HasPassword,

      
        164
        
        -			CreatedAt:            note.CreatedAt,

      
        165
        
        -			ExpiresAt:            note.ExpiresAt,

      
        166
        
        -			ReadAt:               note.ReadAt,

      
        167
        
        -		})

      
        
        157
        +	c.JSON(http.StatusOK, mapNotesDTOToResponse(notes))

      
        
        158
        +}

      
        
        159
        +

      
        
        160
        +func (a *APIV1) getReadNotesHandler(c *gin.Context) {

      
        
        161
        +	notes, err := a.notesrv.GetAllReadByAuthorID(c.Request.Context(), a.getUserID(c))

      
        
        162
        +	if err != nil {

      
        
        163
        +		errorResponse(c, err)

      
        
        164
        +		return

      
        
        165
        +	}

      
        
        166
        +

      
        
        167
        +	c.JSON(http.StatusOK, mapNotesDTOToResponse(notes))

      
        
        168
        +}

      
        
        169
        +

      
        
        170
        +func (a *APIV1) getUnReadNotesHandler(c *gin.Context) {

      
        
        171
        +	notes, err := a.notesrv.GetAllUnreadByAuthorID(c.Request.Context(), a.getUserID(c))

      
        
        172
        +	if err != nil {

      
        
        173
        +		errorResponse(c, err)

      
        
        174
        +		return

      
        168
        175
         	}

      
        169
        176
         

      
        170
        
        -	c.JSON(http.StatusOK, response)

      
        
        177
        +	c.JSON(http.StatusOK, mapNotesDTOToResponse(notes))

      
        171
        178
         }

      
        172
        179
         

      
        173
        180
         type updateNoteRequest struct {

      ···
        236
        243
         

      
        237
        244
         	c.Status(http.StatusOK)

      
        238
        245
         }

      
        
        246
        +

      
        
        247
        +func mapNotesDTOToResponse(notes []dtos.NoteDetailed) []getNotesResponse {

      
        
        248
        +	var response []getNotesResponse

      
        
        249
        +	for _, note := range notes {

      
        
        250
        +		response = append(response, getNotesResponse{

      
        
        251
        +			Content:              note.Content,

      
        
        252
        +			Slug:                 note.Slug,

      
        
        253
        +			BurnBeforeExpiration: note.BurnBeforeExpiration,

      
        
        254
        +			HasPassword:          note.HasPassword,

      
        
        255
        +			CreatedAt:            note.CreatedAt,

      
        
        256
        +			ExpiresAt:            note.ExpiresAt,

      
        
        257
        +			ReadAt:               note.ReadAt,

      
        
        258
        +		})

      
        
        259
        +	}

      
        
        260
        +

      
        
        261
        +	return response

      
        
        262
        +}