all repos

onasty @ 39d6b8ed38db7cc38f0cf0ea3f297ad7265f40cb

a one-time notes service

onasty/internal/transport/http/apiv1/note.go (view raw)

Smirnov Olexandr Smirnov Olexandr
ss2316544@gmail.com
fix(api): get note with password (#151)..., 11 months ago
1
package apiv1
2
3
import (
4
	"net/http"
5
	"time"
6
7
	"github.com/gin-gonic/gin"
8
	"github.com/olexsmir/onasty/internal/dtos"
9
	"github.com/olexsmir/onasty/internal/service/notesrv"
10
)
11
12
type createNoteRequest struct {
13
	Content              string    `json:"content"`
14
	Slug                 string    `json:"slug"`
15
	Password             string    `json:"password"`
16
	BurnBeforeExpiration bool      `json:"burn_before_expiration"`
17
	ExpiresAt            time.Time `json:"expires_at"`
18
}
19
20
type createNoteResponse struct {
21
	Slug string `json:"slug"`
22
}
23
24
func (a *APIV1) createNoteHandler(c *gin.Context) {
25
	var req createNoteRequest
26
	if err := c.ShouldBindJSON(&req); err != nil {
27
		newError(c, http.StatusBadRequest, "invalid request")
28
		return
29
	}
30
31
	// TODO: burn_before_expiration shouldn't be set if user has not set or specified expires_at
32
33
	slug, err := a.notesrv.Create(c.Request.Context(), dtos.CreateNote{
34
		Content:              req.Content,
35
		UserID:               a.getUserID(c),
36
		Slug:                 req.Slug,
37
		Password:             req.Password,
38
		BurnBeforeExpiration: req.BurnBeforeExpiration,
39
		CreatedAt:            time.Now(),
40
		ExpiresAt:            req.ExpiresAt,
41
	}, a.getUserID(c))
42
	if err != nil {
43
		errorResponse(c, err)
44
		return
45
	}
46
47
	c.JSON(http.StatusCreated, createNoteResponse{slug})
48
}
49
50
type getNoteBySlugResponse struct {
51
	Content              string    `json:"content"`
52
	ReadAt               time.Time `json:"read_at,omitzero"`
53
	BurnBeforeExpiration bool      `json:"burn_before_expiration"`
54
	CreatedAt            time.Time `json:"created_at"`
55
	ExpiresAt            time.Time `json:"expires_at,omitzero"`
56
}
57
58
func (a *APIV1) getNoteBySlugHandler(c *gin.Context) {
59
	note, err := a.notesrv.GetBySlugAndRemoveIfNeeded(
60
		c.Request.Context(),
61
		notesrv.GetNoteBySlugInput{
62
			Slug:     c.Param("slug"),
63
			Password: c.Query("password"),
64
		},
65
	)
66
	if err != nil {
67
		errorResponse(c, err)
68
		return
69
	}
70
71
	status := http.StatusOK
72
	if !note.ReadAt.IsZero() {
73
		status = http.StatusNotFound
74
	}
75
76
	c.JSON(status, getNoteBySlugResponse{
77
		Content:              note.Content,
78
		ReadAt:               note.ReadAt,
79
		CreatedAt:            note.CreatedAt,
80
		ExpiresAt:            note.ExpiresAt,
81
		BurnBeforeExpiration: note.BurnBeforeExpiration,
82
	})
83
}
84
85
type getNoteMetadataBySlugResponse struct {
86
	CreatedAt   time.Time `json:"created_at"`
87
	HasPassword bool      `json:"has_password"`
88
}
89
90
func (a *APIV1) getNoteMetadataByIDHandler(c *gin.Context) {
91
	meta, err := a.notesrv.GetNoteMetadataBySlug(c.Request.Context(), c.Param("slug"))
92
	if err != nil {
93
		errorResponse(c, err)
94
		return
95
	}
96
97
	c.JSON(http.StatusOK, getNoteMetadataBySlugResponse{
98
		CreatedAt:   meta.CreatedAt,
99
		HasPassword: meta.HasPassword,
100
	})
101
}
102
103
type getNotesResponse struct {
104
	Content              string    `json:"content"`
105
	Slug                 string    `json:"slug"`
106
	BurnBeforeExpiration bool      `json:"burn_before_expiration"`
107
	HasPassword          bool      `json:"has_password"`
108
	CreatedAt            time.Time `json:"created_at"`
109
	ExpiresAt            time.Time `json:"expires_at,omitzero"`
110
	ReadAt               time.Time `json:"read_at,omitzero"`
111
}
112
113
func (a *APIV1) getNotesHandler(c *gin.Context) {
114
	notes, err := a.notesrv.GetAllByAuthorID(c.Request.Context(), a.getUserID(c))
115
	if err != nil {
116
		errorResponse(c, err)
117
		return
118
	}
119
120
	var response []getNotesResponse
121
	for _, note := range notes {
122
		response = append(response, getNotesResponse{
123
			Content:              note.Content,
124
			Slug:                 note.Slug,
125
			BurnBeforeExpiration: note.BurnBeforeExpiration,
126
			HasPassword:          note.HasPassword,
127
			CreatedAt:            note.CreatedAt,
128
			ExpiresAt:            note.ExpiresAt,
129
			ReadAt:               note.ReadAt,
130
		})
131
	}
132
133
	c.JSON(http.StatusOK, response)
134
}
135
136
type updateNoteRequest struct {
137
	ExpiresAt            *time.Time `json:"expires_at,omitempty"`
138
	BurnBeforeExpiration *bool      `json:"burn_before_expiration,omitempty"`
139
}
140
141
func (a *APIV1) updateNoteHandler(c *gin.Context) {
142
	var req updateNoteRequest
143
	if err := c.ShouldBindJSON(&req); err != nil {
144
		newError(c, http.StatusBadRequest, "invalid request")
145
		return
146
	}
147
148
	// TODO: burn_before_expiration shouldn't be set if user has not set or specified expires_at
149
150
	if err := a.notesrv.UpdateExpirationTimeSettings(
151
		c.Request.Context(),
152
		dtos.PatchNote{
153
			BurnBeforeExpiration: req.BurnBeforeExpiration,
154
			ExpiresAt:            req.ExpiresAt,
155
		},
156
		c.Param("slug"),
157
		a.getUserID(c),
158
	); err != nil {
159
		errorResponse(c, err)
160
		return
161
	}
162
163
	c.Status(http.StatusOK)
164
}
165
166
func (a *APIV1) deleteNoteHandler(c *gin.Context) {
167
	if err := a.notesrv.DeleteBySlug(
168
		c.Request.Context(),
169
		c.Param("slug"),
170
		a.getUserID(c),
171
	); err != nil {
172
		errorResponse(c, err)
173
		return
174
	}
175
176
	c.Status(http.StatusNoContent)
177
}
178
179
type setNotePasswordRequest struct {
180
	Password string `json:"password"`
181
}
182
183
func (a *APIV1) setNotePasswordHandler(c *gin.Context) {
184
	var req setNotePasswordRequest
185
	if err := c.ShouldBindJSON(&req); err != nil {
186
		newError(c, http.StatusBadRequest, "invalid request")
187
		return
188
	}
189
190
	if err := a.notesrv.UpdatePassword(
191
		c.Request.Context(),
192
		c.Param("slug"),
193
		req.Password,
194
		a.getUserID(c),
195
	); err != nil {
196
		errorResponse(c, err)
197
		return
198
	}
199
200
	c.Status(http.StatusOK)
201
}