Skip to content

Commit 41625e5

Browse files
committed
Create note
1 parent d0b4e11 commit 41625e5

File tree

12 files changed

+748
-5
lines changed

12 files changed

+748
-5
lines changed

app/db/models.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/db/notes.queries.sql.go

Lines changed: 189 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/forms/notes.forms.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package forms
2+
3+
import (
4+
"net/http"
5+
6+
z "github.com/Oudwins/zog"
7+
"github.com/Oudwins/zog/zhttp"
8+
)
9+
10+
var noteTitleSchema = z.String().Trim().Required().Min(1).Max(255)
11+
12+
type CreateNote struct {
13+
Title string `zog:"title"`
14+
Content string `zog:"content"`
15+
}
16+
17+
var createNoteSchema = z.Struct(z.Shape{
18+
"title": noteTitleSchema,
19+
"content": z.String().Trim().Required(),
20+
})
21+
22+
func ParseCreateNote(r *http.Request) (CreateNote, map[string][]string) {
23+
var form CreateNote
24+
errs := createNoteSchema.Parse(zhttp.Request(r), &form)
25+
if errs == nil {
26+
return form, nil
27+
}
28+
29+
return form, z.Issues.SanitizeMap(errs)
30+
}
31+
32+
type UpdateNote struct {
33+
Title string `zog:"title"`
34+
Content string `zog:"content"`
35+
}
36+
37+
var updateNoteSchema = z.Struct(z.Shape{
38+
"title": noteTitleSchema,
39+
"content": z.String().Trim(),
40+
})
41+
42+
func ParseUpdateNote(r *http.Request) (UpdateNote, map[string][]string) {
43+
var form UpdateNote
44+
errs := updateNoteSchema.Parse(zhttp.Request(r), &form)
45+
if errs == nil {
46+
return form, nil
47+
}
48+
49+
return form, z.Issues.SanitizeMap(errs)
50+
}

app/handlers/notes.handlers.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package handlers
22

33
import (
4+
"database/sql"
5+
"fmt"
46
"log/slog"
57
"net/http"
8+
"time"
69

10+
"github.com/nicolashery/simply-shared-notes/app/db"
11+
"github.com/nicolashery/simply-shared-notes/app/forms"
12+
"github.com/nicolashery/simply-shared-notes/app/publicid"
13+
"github.com/nicolashery/simply-shared-notes/app/rctx"
14+
"github.com/nicolashery/simply-shared-notes/app/session"
715
"github.com/nicolashery/simply-shared-notes/app/views/pages"
816
)
917

@@ -20,3 +28,83 @@ func handleNotesList(logger *slog.Logger) http.HandlerFunc {
2028
}
2129
}
2230
}
31+
32+
func handleNotesNew(logger *slog.Logger) http.HandlerFunc {
33+
return func(w http.ResponseWriter, r *http.Request) {
34+
var form forms.CreateNote
35+
36+
err := pages.NotesNew(&form, forms.EmptyErrors()).Render(r.Context(), w)
37+
if err != nil {
38+
logger.Error(
39+
"failed to render template",
40+
slog.Any("error", err),
41+
slog.String("template", "NotesNew"),
42+
)
43+
http.Error(w, "internal server error", http.StatusInternalServerError)
44+
}
45+
}
46+
}
47+
48+
func handleNotesCreate(logger *slog.Logger, queries *db.Queries) http.HandlerFunc {
49+
return func(w http.ResponseWriter, r *http.Request) {
50+
form, errors := forms.ParseCreateNote(r)
51+
if errors != nil {
52+
w.WriteHeader(http.StatusUnprocessableEntity)
53+
err := pages.NotesNew(&form, errors).Render(r.Context(), w)
54+
if err != nil {
55+
logger.Error(
56+
"failed to render template",
57+
slog.Any("error", err),
58+
slog.String("template", "NotesNew"),
59+
)
60+
http.Error(w, "internal server error", http.StatusInternalServerError)
61+
}
62+
return
63+
}
64+
65+
notePublicID, err := publicid.Generate()
66+
if err != nil {
67+
logger.Error("error generating note public ID", slog.Any("error", err))
68+
http.Error(w, "error creating note", http.StatusInternalServerError)
69+
return
70+
}
71+
identity := rctx.GetIdentity(r.Context())
72+
space := rctx.GetSpace(r.Context())
73+
now := time.Now().UTC()
74+
75+
note, err := queries.CreateNote(
76+
r.Context(),
77+
db.CreateNoteParams{
78+
CreatedAt: now,
79+
UpdatedAt: now,
80+
CreatedBy: sql.NullInt64{Int64: identity.Member.ID, Valid: true},
81+
UpdatedBy: sql.NullInt64{Int64: identity.Member.ID, Valid: true},
82+
SpaceID: space.ID,
83+
PublicID: notePublicID,
84+
Title: form.Title,
85+
Content: form.Content,
86+
},
87+
)
88+
if err != nil {
89+
logger.Error("error creating note in database", slog.Any("error", err))
90+
http.Error(w, "error creating note", http.StatusInternalServerError)
91+
return
92+
}
93+
94+
sess := rctx.GetSession(r.Context())
95+
sess.AddFlash(session.FlashMessage{
96+
Type: session.FlashType_Info,
97+
Content: fmt.Sprintf("Created new note: %s", note.Title),
98+
})
99+
err = sess.Save(r, w)
100+
if err != nil {
101+
logger.Error("failed to save session", slog.Any("error", err))
102+
http.Error(w, "internal server error", http.StatusInternalServerError)
103+
return
104+
}
105+
106+
access := rctx.GetAccess(r.Context())
107+
108+
http.Redirect(w, r, fmt.Sprintf("/s/%s/notes", access.Token), http.StatusSeeOther)
109+
}
110+
}

app/handlers/routes.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ func RegisterRoutes(r chi.Router, cfg *config.Config, logger *slog.Logger, sqlDB
4444
Get("/share", handleTokensShow(logger))
4545

4646
r.Get("/notes", handleNotesList(logger))
47+
r.With(Authorize(access.Action_CreateNote)).Group(func(r chi.Router) {
48+
r.Get("/notes/new", handleNotesNew(logger))
49+
r.Post("/notes/new", handleNotesCreate(logger, queries))
50+
})
4751

4852
r.Get("/members", handleMembersList(logger, queries))
4953
r.With(Authorize(access.Action_CreateMember)).Group(func(r chi.Router) {

0 commit comments

Comments
 (0)