working notely

This commit is contained in:
wagslane
2023-05-30 21:42:09 -06:00
parent 80ec635705
commit e2c8b1bcd9
5 changed files with 63 additions and 132 deletions

View File

@@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/bootdotdev/learn-cicd-starter/internal/database" "github.com/bootdotdev/learn-cicd-starter/internal/database"
"github.com/go-chi/chi"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -20,67 +19,6 @@ func (cfg *apiConfig) handlerNotesGet(w http.ResponseWriter, r *http.Request, us
respondWithJSON(w, http.StatusOK, databasePostsToPosts(posts)) 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) { func (cfg *apiConfig) handlerNotesCreate(w http.ResponseWriter, r *http.Request, user database.User) {
type parameters struct { type parameters struct {
Note string `json:"note"` Note string `json:"note"`

View File

@@ -34,16 +34,6 @@ func (q *Queries) CreateNote(ctx context.Context, arg CreateNoteParams) error {
return err return err
} }
const deleteNote = `-- name: DeleteNote :exec
DELETE FROM notes WHERE id = ?
`
func (q *Queries) DeleteNote(ctx context.Context, id string) error {
_, err := q.db.ExecContext(ctx, deleteNote, id)
return err
}
const getNote = `-- name: GetNote :one const getNote = `-- name: GetNote :one
SELECT id, created_at, updated_at, note, user_id FROM notes WHERE id = ? SELECT id, created_at, updated_at, note, user_id FROM notes WHERE id = ?
@@ -95,19 +85,3 @@ func (q *Queries) GetNotesForUser(ctx context.Context, userID string) ([]Note, e
} }
return items, nil return items, nil
} }
const updateNote = `-- name: UpdateNote :exec
UPDATE notes SET updated_at = ?, note = ? WHERE id = ?
`
type UpdateNoteParams struct {
UpdatedAt time.Time
Note string
ID string
}
func (q *Queries) UpdateNote(ctx context.Context, arg UpdateNoteParams) error {
_, err := q.db.ExecContext(ctx, updateNote, arg.UpdatedAt, arg.Note, arg.ID)
return err
}

View File

@@ -53,6 +53,7 @@ func main() {
} }
dbQueries := database.New(db) dbQueries := database.New(db)
apiCfg.DB = dbQueries apiCfg.DB = dbQueries
log.Println("Connected to database!")
} }
router := chi.NewRouter() router := chi.NewRouter()
@@ -85,8 +86,6 @@ func main() {
v1Router.Get("/users", apiCfg.middlewareAuth(apiCfg.handlerUsersGet)) v1Router.Get("/users", apiCfg.middlewareAuth(apiCfg.handlerUsersGet))
v1Router.Get("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesGet)) v1Router.Get("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesGet))
v1Router.Post("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesCreate)) v1Router.Post("/notes", apiCfg.middlewareAuth(apiCfg.handlerNotesCreate))
v1Router.Delete("/notes/{noteID}", apiCfg.middlewareAuth(apiCfg.handlerNotesDelete))
v1Router.Put("/notes/{noteID}", apiCfg.middlewareAuth(apiCfg.handlerNotesUpdate))
} }
v1Router.Get("/healthz", handlerReadiness) v1Router.Get("/healthz", handlerReadiness)

View File

@@ -10,11 +10,3 @@ SELECT * FROM notes WHERE id = ?;
-- name: GetNotesForUser :many -- name: GetNotesForUser :many
SELECT * FROM notes WHERE user_id = ?; SELECT * FROM notes WHERE user_id = ?;
-- --
-- name: UpdateNote :exec
UPDATE notes SET updated_at = ?, note = ? WHERE id = ?;
--
-- name: DeleteNote :exec
DELETE FROM notes WHERE id = ?;
--

View File

@@ -6,38 +6,31 @@
<title>Notely</title> <title>Notely</title>
</head> </head>
<body> <body class="section">
<h1>Notely</h1> <h1>Notely</h1>
<button id="createUserButton">Create User</button>
<h2>Create Note</h2> <div id="userCreationContainer" class="section">
<input id="nameField" type="text" placeholder="Enter your name">
<button id="createUserButton" onclick="createUser()">Create User</button>
</div>
<div id="noteSection" class="section" style="display: none;">
<p id="greetingMessage"></p>
<textarea id="newNoteContent"></textarea> <textarea id="newNoteContent"></textarea>
<button id="createNoteButton">Create Note</button> <button id="createNoteButton" onclick="createNote()">Create Note</button>
<h2>Your Notes</h2> <h2>Your Notes</h2>
<div id="notes"></div> <div id="notes"></div>
<button onclick="logout()">Logout</button>
</div>
<script> <script>
const API_BASE = '/v1'; const API_BASE = '/v1';
let currentUserAPIKey = localStorage.getItem('currentUserAPIKey') let currentUserAPIKey = null;
let currentUser = null; let currentUser = null;
document.getElementById('createUserButton').addEventListener('click', createUser);
document.getElementById('createNoteButton').addEventListener('click', createNote);
async function createUser() {
const response = await fetch(`${API_BASE}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Test User' })
});
const user = await response.json();
localStorage.setItem('currentUserAPIKey', user.api_key);
currentUserAPIKey = user.api_key;
currentUser = user;
alert(`User Created: ${user.name}`);
}
async function createNote() { async function createNote() {
if (!currentUser) { if (!currentUser) {
alert('Please create a user first'); alert('Please create a user first');
@@ -51,7 +44,6 @@
}); });
const note = await response.json(); const note = await response.json();
displayNote(note); displayNote(note);
} }
async function getUser() { async function getUser() {
@@ -59,11 +51,6 @@
return await response.json(); return await response.json();
} }
function logout() {
localStorage.removeItem('currentUserAPIKey');
currentUser = null;
}
async function loadNotes() { async function loadNotes() {
if (!currentUser) { if (!currentUser) {
return; return;
@@ -82,14 +69,48 @@
document.getElementById('notes').appendChild(noteElement); document.getElementById('notes').appendChild(noteElement);
} }
async function createUser() {
const nameField = document.getElementById('nameField');
const response = await fetch(`${API_BASE}/users`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: nameField.value }) // using the value from nameField
});
const user = await response.json();
localStorage.setItem('currentUserAPIKey', user.api_key);
login()
alert(`User Created: ${user.name}`);
// Once a user is created, hide the user creation section and show the note section
document.getElementById('userCreationContainer').style.display = 'none';
document.getElementById('noteSection').style.display = 'flex';
}
function logout() {
localStorage.removeItem('currentUserAPIKey');
currentUser = null;
// When a user logs out, show the user creation section and hide the note section
document.getElementById('userCreationContainer').style.display = 'block';
document.getElementById('noteSection').style.display = 'none';
}
async function login() { async function login() {
currentUserAPIKey = localStorage.getItem('currentUserAPIKey')
if (!currentUserAPIKey) { if (!currentUserAPIKey) {
return return;
} }
const user = await getUser(); const user = await getUser();
currentUser = user; currentUser = user;
currentUserAPIKey = user.api_key; currentUserAPIKey = user.api_key;
await loadNotes(); await loadNotes();
// When a user logs in, hide the user creation section and show the note section
document.getElementById('userCreationContainer').style.display = 'none';
document.getElementById('noteSection').style.display = 'flex';
// Display a greeting message
document.getElementById('greetingMessage').textContent = `Hello ${user.name}!`;
} }
login(); login();
@@ -110,21 +131,27 @@
color: var(--light); color: var(--light);
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100vh;
}
.section {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
height: 100vh;
justify-content: center; justify-content: center;
} }
textarea { textarea {
width: 300px; width: 300px;
height: 100px; height: 100px;
margin-bottom: 10px; margin-bottom: 10px;
} }
input {
display: block;
padding: 1rem;
}
button { button {
background-color: var(--primary); background-color: var(--primary);
color: var(--light); color: var(--light);
@@ -151,6 +178,7 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
</style> </style>
<!-- your existing CSS code... -->
</body> </body>
</html> </html>