Skip to content

Commit 838f16c

Browse files
committed
feat: init app
1 parent 975556b commit 838f16c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2137
-1
lines changed

.tool-versions

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
golang 1.18.10

Dockerfile

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM golang:1.19.2-alpine as build
2+
3+
COPY . .
4+
5+
# Set CGO_ENABLED to 0 to turn off dynamic linking to libc/libmusl
6+
RUN GOPATH=/ CGO_ENABLED=0 go build -o /snippetbox ./cmd/web
7+
8+
FROM scratch
9+
10+
ENV DB_HOST="127.0.0.1:3306"
11+
12+
COPY --from=build /snippetbox /snippetbox
13+
COPY --from=build /go/tls /tls
14+
15+
EXPOSE 4000/tcp
16+
17+
CMD [ "/snippetbox" ]

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
# snippetbox-k8s
2-
# snippetbox-k8s

cmd/.DS_Store

6 KB
Binary file not shown.

cmd/web/context.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package main
2+
3+
type contextKey string
4+
5+
const isAuthenticatedContextKey = contextKey("isAuthenticated")

cmd/web/handlers.go

+242
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"net/http"
7+
"strconv"
8+
9+
"snippetbox.thejeremyharrington.net/internal/models"
10+
"snippetbox.thejeremyharrington.net/internal/validator"
11+
12+
"github.com/julienschmidt/httprouter"
13+
)
14+
15+
func (app *application) home(w http.ResponseWriter, r *http.Request) {
16+
snippets, err := app.snippets.Latest()
17+
if err != nil {
18+
app.serverError(w, err)
19+
return
20+
}
21+
22+
data := app.newTemplateData(r)
23+
data.Snippets = snippets
24+
25+
app.render(w, http.StatusOK, "home.tmpl", data)
26+
}
27+
28+
func (app *application) snippetView(w http.ResponseWriter, r *http.Request) {
29+
params := httprouter.ParamsFromContext(r.Context())
30+
31+
id, err := strconv.Atoi(params.ByName("id"))
32+
if err != nil || id < 1 {
33+
app.notFound(w)
34+
return
35+
}
36+
37+
snippet, err := app.snippets.Get(id)
38+
if err != nil {
39+
if errors.Is(err, models.ErrNoRecord) {
40+
app.notFound(w)
41+
} else {
42+
app.serverError(w, err)
43+
}
44+
return
45+
}
46+
47+
data := app.newTemplateData(r)
48+
data.Snippet = snippet
49+
50+
app.render(w, http.StatusOK, "view.tmpl", data)
51+
}
52+
53+
func (app *application) snippetCreate(w http.ResponseWriter, r *http.Request) {
54+
data := app.newTemplateData(r)
55+
56+
data.Form = snippetCreateForm{
57+
Expires: 365,
58+
}
59+
60+
app.render(w, http.StatusOK, "create.tmpl", data)
61+
}
62+
63+
type snippetCreateForm struct {
64+
Title string `form:"title"`
65+
Content string `form:"content"`
66+
Expires int `form:"expires"`
67+
validator.Validator `form:"-"`
68+
}
69+
70+
func (app *application) snippetCreatePost(w http.ResponseWriter, r *http.Request) {
71+
var form snippetCreateForm
72+
73+
err := app.decodePostForm(r, &form)
74+
if err != nil {
75+
app.clientError(w, http.StatusBadRequest)
76+
return
77+
}
78+
79+
form.CheckField(validator.NotBlank(form.Title), "title", "This field cannot be blank")
80+
form.CheckField(validator.MaxChars(form.Title, 100), "title", "This field cannot be more than 100 characters long")
81+
form.CheckField(validator.NotBlank(form.Content), "content", "This field cannot be blank")
82+
83+
form.CheckField(validator.PermittedValue(form.Expires, 1, 7, 365), "expires", "This field must equal 1, 7 or 365")
84+
85+
if !form.Valid() {
86+
data := app.newTemplateData(r)
87+
data.Form = form
88+
89+
app.render(w, http.StatusUnprocessableEntity, "create.tmpl", data)
90+
return
91+
}
92+
93+
id, err := app.snippets.Insert(form.Title, form.Content, form.Expires)
94+
if err != nil {
95+
app.serverError(w, err)
96+
return
97+
}
98+
99+
app.sessionManager.Put(r.Context(), "flash", "Snippet successfully created!")
100+
101+
http.Redirect(w, r, fmt.Sprintf("/snippet/view/%d", id), http.StatusSeeOther)
102+
}
103+
104+
type userSignupForm struct {
105+
Name string `form:"name"`
106+
Email string `form:"email"`
107+
Password string `form:"password"`
108+
validator.Validator `form:"-"`
109+
}
110+
111+
func (app *application) userSignup(w http.ResponseWriter, r *http.Request) {
112+
data := app.newTemplateData(r)
113+
data.Form = userSignupForm{}
114+
app.render(w, http.StatusOK, "signup.tmpl", data)
115+
}
116+
117+
func (app *application) userSignupPost(w http.ResponseWriter, r *http.Request) {
118+
var form userSignupForm
119+
120+
err := app.decodePostForm(r, &form)
121+
if err != nil {
122+
app.clientError(w, http.StatusBadRequest)
123+
return
124+
}
125+
126+
form.CheckField(validator.NotBlank(form.Name), "name", "This field cannot be blank")
127+
form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
128+
form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
129+
form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
130+
form.CheckField(validator.MinChars(form.Password, 8), "password", "This field must be at least 8 characters long")
131+
132+
if !form.Valid() {
133+
data := app.newTemplateData(r)
134+
data.Form = form
135+
app.render(w, http.StatusUnprocessableEntity, "signup.tmpl", data)
136+
return
137+
}
138+
139+
err = app.users.Insert(form.Name, form.Email, form.Password)
140+
if err != nil {
141+
if errors.Is(err, models.ErrDuplicateEmail) {
142+
form.AddFieldError("email", "Email address is already in use")
143+
144+
data := app.newTemplateData(r)
145+
data.Form = form
146+
app.render(w, http.StatusUnprocessableEntity, "signup.tmpl", data)
147+
} else {
148+
app.serverError(w, err)
149+
}
150+
151+
return
152+
}
153+
154+
app.sessionManager.Put(r.Context(), "flash", "Your signup was successful. Please log in.")
155+
156+
http.Redirect(w, r, "/user/login", http.StatusSeeOther)
157+
}
158+
159+
type userLoginForm struct {
160+
Email string `form:"email"`
161+
Password string `form:"password"`
162+
validator.Validator `form:"-"`
163+
}
164+
165+
func (app *application) userLogin(w http.ResponseWriter, r *http.Request) {
166+
data := app.newTemplateData(r)
167+
data.Form = userLoginForm{}
168+
app.render(w, http.StatusOK, "login.tmpl", data)
169+
}
170+
171+
func (app *application) userLoginPost(w http.ResponseWriter, r *http.Request) {
172+
var form userLoginForm
173+
174+
err := app.decodePostForm(r, &form)
175+
if err != nil {
176+
app.clientError(w, http.StatusBadRequest)
177+
return
178+
}
179+
180+
form.CheckField(validator.NotBlank(form.Email), "email", "This field cannot be blank")
181+
form.CheckField(validator.Matches(form.Email, validator.EmailRX), "email", "This field must be a valid email address")
182+
form.CheckField(validator.NotBlank(form.Password), "password", "This field cannot be blank")
183+
184+
if !form.Valid() {
185+
data := app.newTemplateData(r)
186+
data.Form = form
187+
app.render(w, http.StatusUnprocessableEntity, "login.tmpl", data)
188+
return
189+
}
190+
191+
id, err := app.users.Authenticate(form.Email, form.Password)
192+
if err != nil {
193+
if errors.Is(err, models.ErrInvalidCredentials) {
194+
form.AddNonFieldError("Email or password is incorrect")
195+
196+
data := app.newTemplateData(r)
197+
data.Form = form
198+
app.render(w, http.StatusUnprocessableEntity, "login.tmpl", data)
199+
} else {
200+
app.serverError(w, err)
201+
}
202+
return
203+
}
204+
205+
err = app.sessionManager.RenewToken(r.Context())
206+
if err != nil {
207+
app.serverError(w, err)
208+
return
209+
}
210+
211+
app.sessionManager.Put(r.Context(), "authenticatedUserID", id)
212+
213+
http.Redirect(w, r, "/snippet/create", http.StatusSeeOther)
214+
}
215+
216+
func (app *application) userLogoutPost(w http.ResponseWriter, r *http.Request) {
217+
err := app.sessionManager.RenewToken(r.Context())
218+
if err != nil {
219+
app.serverError(w, err)
220+
return
221+
}
222+
223+
app.sessionManager.Remove(r.Context(), "authenticatedUserID")
224+
225+
app.sessionManager.Put(r.Context(), "flash", "You've been logged out successfully!")
226+
227+
http.Redirect(w, r, "/", http.StatusSeeOther)
228+
}
229+
230+
func ping(w http.ResponseWriter, r *http.Request) {
231+
w.Write([]byte("OK"))
232+
}
233+
234+
type searchForm struct {
235+
Text string `form:"text"`
236+
}
237+
238+
func (app *application) Search(w http.ResponseWriter, r *http.Request) {
239+
data := app.newTemplateData(r)
240+
data.Form = searchForm{}
241+
// app.render(w, http.StatusOK, "login.tmpl", data)
242+
}

0 commit comments

Comments
 (0)