diff --git a/databaseutil/databaseutil.go b/databaseutil/databaseutil.go index 8f2afc9..864d991 100644 --- a/databaseutil/databaseutil.go +++ b/databaseutil/databaseutil.go @@ -8,6 +8,7 @@ package databaseutil import ( "database/sql" "errors" + "strconv" "time" "github.com/lib/pq" @@ -306,6 +307,76 @@ func StoreNoteCategoryRelationship(noteId int64, category string) error { return nil } +func StoreNewPublication(authorId int64, creationTime time.Time) (int64, error) { + sqlQuery := ` + INSERT INTO publication (author_id, creation_time) + VALUES ($1, $2) + RETURNING id` + + rows, err := db.Query(sqlQuery, authorId, creationTime) + if err != nil { + return -1, convertPostgresError(err) + } + defer rows.Close() + + var lastInsertId int64 + for rows.Next() { + + if lastInsertId != 0 { + return -1, QueryResultContainedMultipleRowsError + } + + if err := rows.Scan(&lastInsertId); err != nil { + return -1, convertPostgresError(err) + } + } + + if lastInsertId == 0 { + return -1, QueryResultContainedNoRowsError + } + + if err := rows.Err(); err != nil { + return -1, convertPostgresError(err) + } + + return lastInsertId, nil + +} + +func StorePublicationNoteRelationship(publication_id int64, noteIds []int64) error { + sqlQuery := ` + INSERT INTO note_to_publication_relationship (publication_id, note_id) + VALUES ($1, $2)` + + values := make([]interface{}, len(noteIds)*2, len(noteIds)*2) + values[0] = publication_id + values[1] = noteIds[0] + + for index, noteId := range noteIds { + if index == 0 { + continue + } + sqlQuery += ", ($" + strconv.Itoa(2*index+1) + ", $" + strconv.Itoa((2*index)+2) + ")" + values[2*index] = publication_id + values[(2*index)+1] = noteId + } + + rows, err := db.Query(sqlQuery, values...) + if err != nil { + return convertPostgresError(err) + } + defer rows.Close() + + if err := rows.Err(); err != nil { + return convertPostgresError(err) + } + + return nil + +} + +// ----------------------------------------------------------------------- + // PRIVATE func returnNotes(rows *sql.Rows) ([]*NoteData, error) { var notes []*NoteData = make([]*NoteData, 0, 10) diff --git a/handlers/handlers.go b/handlers/handlers.go index 9acbfe3..cdfab3e 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -12,6 +12,7 @@ import ( "github.com/atmiguel/cerealnotes/models" "github.com/atmiguel/cerealnotes/paths" "github.com/atmiguel/cerealnotes/services/noteservice" + "github.com/atmiguel/cerealnotes/services/publicationservice" "github.com/atmiguel/cerealnotes/services/userservice" "github.com/dgrijalva/jwt-go" ) @@ -214,6 +215,36 @@ func HandleSessionApiRequest( } } +func HandlePublicationApiRequest( + responseWriter http.ResponseWriter, + request *http.Request, + userId models.UserId, +) { + switch request.Method { + case http.MethodPost: + myUnpublishedNotes, err := noteservice.GetMyUnpublishedNotes(userId) + if err != nil { + http.Error(responseWriter, err.Error(), http.StatusInternalServerError) + return + } + + if len(myUnpublishedNotes) == 0 { + http.Error(responseWriter, "Can't publish if you have no unpublished notes", http.StatusBadRequest) + return + } + + if err := publicationservice.CreateAndPublishNotes(userId, myUnpublishedNotes); err != nil { + http.Error(responseWriter, err.Error(), http.StatusInternalServerError) + return + } + + responseWriter.WriteHeader(http.StatusCreated) + + default: + respondWithMethodNotAllowed(responseWriter, http.MethodPost) + } +} + func HandleNoteApiRequest( responseWriter http.ResponseWriter, request *http.Request, @@ -232,6 +263,10 @@ func HandleNoteApiRequest( fmt.Println(len(publishedNotes)) myUnpublishedNotes, err := noteservice.GetMyUnpublishedNotes(userId) + if err != nil { + http.Error(responseWriter, err.Error(), http.StatusInternalServerError) + return + } fmt.Println("number of unpublished notes") fmt.Println(len(myUnpublishedNotes)) @@ -318,6 +353,8 @@ func HandleNoteApiRequest( return } + responseWriter.WriteHeader(http.StatusOK) + default: respondWithMethodNotAllowed(responseWriter, http.MethodGet, http.MethodPost, http.MethodDelete) } diff --git a/models/publication.go b/models/publication.go index 6091325..6065fe5 100644 --- a/models/publication.go +++ b/models/publication.go @@ -5,6 +5,15 @@ import "time" type PublicationId int64 type Publication struct { + Id int64 `json:"id"` AuthorId UserId `json:"authorId"` CreationTime time.Time `json:"creationTime"` } + +func CreateNewPublication(userId UserId) *Publication { + return &Publication{ + Id: -1, + AuthorId: userId, + CreationTime: time.Now().UTC(), + } +} diff --git a/paths/paths.go b/paths/paths.go index 8db612c..9156156 100644 --- a/paths/paths.go +++ b/paths/paths.go @@ -8,7 +8,8 @@ const ( HomePage = "/home" NotesPage = "/notes" - UserApi = "/api/user" - SessionApi = "/api/session" - NoteApi = "/api/note" + UserApi = "/api/user" + SessionApi = "/api/session" + NoteApi = "/api/note" + PublicationApi = "/api/publication" ) diff --git a/routers/routers.go b/routers/routers.go index 6bcd2b5..5f1bc71 100644 --- a/routers/routers.go +++ b/routers/routers.go @@ -41,6 +41,7 @@ func DefineRoutes() http.Handler { mux.HandleFunc(paths.SessionApi, handlers.HandleSessionApiRequest) handleAuthenticated(mux, paths.NoteApi, handlers.HandleNoteApiRequest) + handleAuthenticated(mux, paths.PublicationApi, handlers.HandlePublicationApiRequest) return mux } diff --git a/services/publicationservice/publicationservice.go b/services/publicationservice/publicationservice.go new file mode 100644 index 0000000..9e59d70 --- /dev/null +++ b/services/publicationservice/publicationservice.go @@ -0,0 +1,65 @@ +/* +Package noteservice handles interactions with database layer. +*/ +package publicationservice + +import ( + "errors" + + "github.com/atmiguel/cerealnotes/databaseutil" + "github.com/atmiguel/cerealnotes/models" +) + +var PublicationIdNotSet error = errors.New("The PublicationId was not set") +var PublicationAuthorDiffersFromUserAuthor error = errors.New("A note under this publication has a different author than the publication") + +func CreateAndPublishNotes(userId models.UserId, notes []*models.Note) error { + publication := models.CreateNewPublication(userId) + if err := StoreNewPublication(publication); err != nil { + return err + } + + if err := PublishNotes(publication, notes); err != nil { + return err + } + + return nil +} + +func StoreNewPublication(publication *models.Publication) error { + id, err := databaseutil.StoreNewPublication(int64(publication.AuthorId), publication.CreationTime) + if err != nil { + return err + } + + publication.Id = id + + if publication.Id < 0 { + return PublicationIdNotSet + } + + return nil +} + +func PublishNotes(publication *models.Publication, notes []*models.Note) error { + if publication.Id < 0 { + return PublicationIdNotSet + } + + noteIds := make([]int64, 0, 10) + + for _, note := range notes { + + if publication.AuthorId != note.AuthorId { + return PublicationAuthorDiffersFromUserAuthor + } + + noteIds = append(noteIds, note.Id) + } + + if err := databaseutil.StorePublicationNoteRelationship(publication.Id, noteIds); err != nil { + return err + } + + return nil +}