Skip to content

Commit

Permalink
kinda working
Browse files Browse the repository at this point in the history
  • Loading branch information
wagslane committed May 31, 2023
1 parent 7d1852d commit 80ec635
Show file tree
Hide file tree
Showing 91 changed files with 13,103 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
out
.env
learn-cicd-starter
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# learn-cicd-starter
The starter code for the "Learn CICD" course on Boot.dev
# learn-cicd-starter (Notely)

The starter code for the "Notely" application for the "Learn CICD" course on [Boot.dev](https://boot.dev).
12 changes: 12 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module github.com/bootdotdev/learn-cicd-starter

go 1.20

require (
github.com/go-chi/chi v1.5.4
github.com/go-chi/cors v1.2.1
github.com/google/uuid v1.3.0
github.com/joho/godotenv v1.5.1
)

require github.com/go-sql-driver/mysql v1.7.1
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
115 changes: 115 additions & 0 deletions handler_notes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package main

import (
"encoding/json"
"net/http"
"time"

"github.com/bootdotdev/learn-cicd-starter/internal/database"
"github.com/go-chi/chi"
"github.com/google/uuid"
)

func (cfg *apiConfig) handlerNotesGet(w http.ResponseWriter, r *http.Request, user database.User) {
posts, err := cfg.DB.GetNotesForUser(r.Context(), user.ID)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't get posts for user")
return
}

respondWithJSON(w, http.StatusOK, databasePostsToPosts(posts))
}

func (cfg *apiConfig) handlerNotesUpdate(w http.ResponseWriter, r *http.Request, user database.User) {
type parameters struct {
Note string `json:"note"`
}
decoder := json.NewDecoder(r.Body)
params := parameters{}
err := decoder.Decode(&params)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't decode parameters")
return
}

noteID := chi.URLParam(r, "noteID")
note, err := cfg.DB.GetNote(r.Context(), noteID)
if err != nil {
respondWithError(w, http.StatusNotFound, "Couldn't get note")
return
}
if note.UserID != user.ID {
respondWithError(w, http.StatusForbidden, "Can't update another user's note")
return
}

err = cfg.DB.UpdateNote(r.Context(), database.UpdateNoteParams{
UpdatedAt: time.Now().UTC(),
Note: params.Note,
ID: noteID,
})
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't update note")
return
}

note, err = cfg.DB.GetNote(r.Context(), noteID)
if err != nil {
respondWithError(w, http.StatusNotFound, "Couldn't get note")
return
}
respondWithJSON(w, http.StatusOK, databaseNoteToNote(note))
}

func (cfg *apiConfig) handlerNotesDelete(w http.ResponseWriter, r *http.Request, user database.User) {
noteID := chi.URLParam(r, "noteID")
note, err := cfg.DB.GetNote(r.Context(), noteID)
if err != nil {
respondWithError(w, http.StatusNotFound, "Couldn't get note")
return
}
if note.UserID != user.ID {
respondWithError(w, http.StatusForbidden, "Can't update another user's note")
return
}

err = cfg.DB.DeleteNote(r.Context(), noteID)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't delete note")
return
}
respondWithJSON(w, http.StatusOK, struct{}{})
}

func (cfg *apiConfig) handlerNotesCreate(w http.ResponseWriter, r *http.Request, user database.User) {
type parameters struct {
Note string `json:"note"`
}
decoder := json.NewDecoder(r.Body)
params := parameters{}
err := decoder.Decode(&params)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't decode parameters")
return
}

id := uuid.New().String()
err = cfg.DB.CreateNote(r.Context(), database.CreateNoteParams{
ID: id,
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
Note: params.Note,
UserID: user.ID,
})
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't create note")
return
}

note, err := cfg.DB.GetNote(r.Context(), id)
if err != nil {
respondWithError(w, http.StatusNotFound, "Couldn't get note")
return
}
respondWithJSON(w, http.StatusOK, databaseNoteToNote(note))
}
7 changes: 7 additions & 0 deletions handler_ready.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "net/http"

func handlerReadiness(w http.ResponseWriter, r *http.Request) {
respondWithJSON(w, http.StatusOK, map[string]string{"status": "ok"})
}
70 changes: 70 additions & 0 deletions handler_user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"log"
"net/http"
"time"

"github.com/bootdotdev/learn-cicd-starter/internal/database"
"github.com/google/uuid"
)

func (cfg *apiConfig) handlerUsersCreate(w http.ResponseWriter, r *http.Request) {
type parameters struct {
Name string `json:"name"`
}
decoder := json.NewDecoder(r.Body)
params := parameters{}
err := decoder.Decode(&params)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't decode parameters")
return
}

apiKey, err := generateRandomSHA256Hash()
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't gen apikey")
return
}

err = cfg.DB.CreateUser(r.Context(), database.CreateUserParams{
ID: uuid.New().String(),
CreatedAt: time.Now().UTC(),
UpdatedAt: time.Now().UTC(),
Name: params.Name,
ApiKey: apiKey,
})
if err != nil {
log.Println(err)
respondWithError(w, http.StatusInternalServerError, "Couldn't create user")
return
}

user, err := cfg.DB.GetUserByAPIKey(r.Context(), apiKey)
if err != nil {
log.Println(err)
respondWithError(w, http.StatusInternalServerError, "Couldn't get user")
return
}

respondWithJSON(w, http.StatusOK, databaseUserToUser(user))
}

func generateRandomSHA256Hash() (string, error) {
randomBytes := make([]byte, 32)
_, err := rand.Read(randomBytes)
if err != nil {
return "", err
}
hash := sha256.Sum256(randomBytes)
hashString := hex.EncodeToString(hash[:])
return hashString, nil
}

func (cfg *apiConfig) handlerUsersGet(w http.ResponseWriter, r *http.Request, user database.User) {
respondWithJSON(w, http.StatusOK, databaseUserToUser(user))
}
23 changes: 23 additions & 0 deletions internal/auth/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package auth

import (
"errors"
"net/http"
"strings"
)

var ErrNoAuthHeaderIncluded = errors.New("no authorization header included")

// GetAPIKey -
func GetAPIKey(headers http.Header) (string, error) {
authHeader := headers.Get("Authorization")
if authHeader == "" {
return "", ErrNoAuthHeaderIncluded
}
splitAuth := strings.Split(authHeader, " ")
if len(splitAuth) < 2 || splitAuth[0] != "ApiKey" {
return "", errors.New("malformed authorization header")
}

return splitAuth[1], nil
}
31 changes: 31 additions & 0 deletions internal/database/db.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions internal/database/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 80ec635

Please sign in to comment.