diff --git a/databaseutil/databaseutil.go b/databaseutil/databaseutil.go index 210f4e1..f430a72 100644 --- a/databaseutil/databaseutil.go +++ b/databaseutil/databaseutil.go @@ -94,6 +94,76 @@ func GetPasswordForUserWithEmailAddress(emailAddress string) ([]byte, error) { return password, nil } +type NoteData struct { + Id int64 + AuthorId int64 + Content string + CreationTime time.Time +} + +func returnNotes(rows *sql.Rows) ([]*NoteData, error) { + var notes []*NoteData = make([]*NoteData, 0, 10) + + for rows.Next() { + note := &NoteData{} + if err := rows.Scan(¬e.Id, ¬e.AuthorId, ¬e.Content, ¬e.CreationTime); err != nil { + return nil, err + } + + notes = append(notes, note) + } + + return notes, nil +} + +func GetNote(id int64) (*NoteData, error) { + + sqlQuery := ` + SELECT id, author_id, content, creation_time FROM note + WHERE id = $1` + + rows, err := db.Query(sqlQuery, id) + if err != nil { + return nil, convertPostgresError(err) + } + + defer rows.Close() + + notes, err := returnNotes(rows) + if err != nil { + return nil, err + } + + if len(notes) > 1 { + + return nil, QueryResultContainedMultipleRowsError + } + + if len(notes) < 1 { + return nil, QueryResultContainedNoRowsError + } + + return notes[0], nil +} + +func DeleteNote(id int64) error { + sqlQuery := ` + DELETE FROM note + WHERE id = $1` + + rows, err := db.Query(sqlQuery, id) + if err != nil { + return convertPostgresError(err) + } + defer rows.Close() + + if err := rows.Err(); err != nil { + return convertPostgresError(err) + } + + return nil +} + func StoreNewNote(authorId int64, content string, creationTime time.Time) (int64, error) { sqlQuery := ` INSERT INTO note (author_id, content, creation_time) diff --git a/handlers/handlers.go b/handlers/handlers.go index d853a63..523efc4 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -5,6 +5,7 @@ import ( "fmt" "html/template" "net/http" + "strconv" "strings" "time" @@ -292,8 +293,34 @@ func HandleNoteApiRequest( responseWriter.WriteHeader(http.StatusCreated) + case http.MethodDelete: + + id, err := strconv.ParseInt(request.URL.Query().Get("id"), 10, 64) + if err != nil { + http.Error(responseWriter, err.Error(), http.StatusBadRequest) + return + } + + note, err := noteservice.GetNoteById(id) + if err != nil { + http.Error(responseWriter, err.Error(), http.StatusInternalServerError) + return + } + + if note.AuthorId != userId { + errorString := "You are not the author of this note. you are only allowed to delete your own notes" + http.Error(responseWriter, errorString, http.StatusUnauthorized) + return + } + + err = noteservice.DeleteNoteById(note.Id) + if err != nil { + http.Error(responseWriter, err.Error(), http.StatusInternalServerError) + return + } + default: - respondWithMethodNotAllowed(responseWriter, http.MethodGet, http.MethodPost) + respondWithMethodNotAllowed(responseWriter, http.MethodGet, http.MethodPost, http.MethodDelete) } } diff --git a/migrations/0000_createDbs.sql b/migrations/0000_createDbs.sql index 8f12770..336bc33 100644 --- a/migrations/0000_createDbs.sql +++ b/migrations/0000_createDbs.sql @@ -19,17 +19,17 @@ CREATE TABLE IF NOT EXISTS publication ( CREATE TABLE IF NOT EXISTS note ( id bigserial PRIMARY KEY, - author_id bigint references app_user(id) NOT NULL, + author_id bigint references app_user(id) ON DELETE CASCADE NOT NULL, content text NOT NULL, creation_time timestamp NOT NULL ); CREATE TABLE IF NOT EXISTS note_to_publication_relationship ( - note_id bigint PRIMARY KEY references note(id), - publication_id bigint references publication(id) NOT NULL + note_id bigint PRIMARY KEY references note(id) ON DELETE CASCADE, + publication_id bigint references publication(id) ON DELETE CASCADE NOT NULL ); CREATE TABLE IF NOT EXISTS note_to_category_relationship ( - note_id bigint PRIMARY KEY references note(id), + note_id bigint PRIMARY KEY references note(id) ON DELETE CASCADE, type category NOT NULL ); \ No newline at end of file diff --git a/migrations/tools/drop_everything.sql b/migrations/tools/drop_everything.sql index b7b2cb1..fdb9d26 100644 --- a/migrations/tools/drop_everything.sql +++ b/migrations/tools/drop_everything.sql @@ -6,6 +6,6 @@ DROP TABLE publication CASCADE; DROP TABLE note CASCADE; -DROP TABLE note_to_type_relationship CASCADE; +DROP TABLE note_to_category_relationship CASCADE; DROP TABLE note_to_publication_relationship CASCADE; \ No newline at end of file diff --git a/services/noteservice/noteservice.go b/services/noteservice/noteservice.go index 8278f7a..12df5b2 100644 --- a/services/noteservice/noteservice.go +++ b/services/noteservice/noteservice.go @@ -30,6 +30,26 @@ func StoreNewNote( return nil } +func GetNoteById(id int64) (*models.Note, error) { + noteData, err := databaseutil.GetNote(id) + + if err != nil { + return nil, err + } + + return &models.Note{ + Id: noteData.Id, + AuthorId: models.UserId(noteData.AuthorId), + Content: noteData.Content, + CreationTime: noteData.CreationTime, + }, + nil +} + +func DeleteNoteById(id int64) error { + return databaseutil.DeleteNote(id) +} + func StoreNoteCategoryRelationship( note *models.Note, category models.Category, diff --git a/static/js/base.js b/static/js/base.js new file mode 100644 index 0000000..2143555 --- /dev/null +++ b/static/js/base.js @@ -0,0 +1,32 @@ +$(function() { + // http://stepansuvorov.com/blog/2014/04/jquery-put-and-delete/ + jQuery.each( [ "put", "delete" ], function( i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + if ( jQuery.isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + return jQuery.ajax({ + url: url, + type: method, + dataType: type, + data: data, + success: callback + }); + }; + }); + + jQuery.prototype.getDOM = function() { + if (this.length === 1) { + return this[0]; + } + + if (this.length === 0) { + throw "jQuery object is empty" + } + throw "jQuery Object contains more than 1 object"; + }; + +}); \ No newline at end of file diff --git a/templates/base.tmpl b/templates/base.tmpl index 02de033..443b271 100644 --- a/templates/base.tmpl +++ b/templates/base.tmpl @@ -20,6 +20,7 @@ + {{ block "js" . }} {{ end }}