Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moshe - Gohort 1.5 #14

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 96 additions & 45 deletions controllers/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,80 +6,131 @@ import (
"fmt"
"net/http"
"strconv"
"strings"

"cloud.google.com/go/datastore"
"github.com/go-martini/martini"
"google.golang.org/api/iterator"

"acme-books/models"
)

type LibraryController struct{}

func (lc LibraryController) GetByKey(params martini.Params, w http.ResponseWriter) {
ctx := context.Background()
client, _ := datastore.NewClient(ctx, "acme-books")
type LibraryController struct {
bi *models.BookInt
}

defer client.Close()
func NewLibrary(client *datastore.Client, ctx context.Context, books []models.Book) (*LibraryController, error) {
bi := models.NewBookInt(client, ctx)
lc := LibraryController{bi}
if err := lc.bootstrapBooks(books); err != nil {
fmt.Println("Problem bootstrapping library: ", err)
return nil, err
}
return &lc, nil
}

id, err := strconv.Atoi(params["id"])
func (lc LibraryController) bootstrapBooks(books []models.Book) error {
return lc.bi.PutBooks(books)
}

if err != nil {
fmt.Println(err)
func (lc LibraryController) Get(w http.ResponseWriter, params martini.Params) {
if id, err := strconv.Atoi(params["id"]); err != nil {
fmt.Println("Bad id: ", err)
w.WriteHeader(http.StatusBadRequest)
return
} else if book, err := lc.bi.GetBookByKey(int64(id)); err != nil {
fmt.Println("Error getting book: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else if jsonStr, err := json.MarshalIndent(book, "", " "); err != nil {
fmt.Println("Error serializing: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else {
w.WriteHeader(http.StatusOK)
w.Write(jsonStr)
}
}

func (lc LibraryController) List(w http.ResponseWriter, r *http.Request) {
var output []models.Book
var err error

var book models.Book
key := datastore.IDKey("Book", int64(id), nil)
r.ParseForm()

err = client.Get(ctx, key, &book)
title := r.Form.Get("title")
author := r.Form.Get("author")
borrowed := r.Form.Get("borrowed")

if err != nil {
fmt.Println(err)
w.WriteHeader(http.StatusInternalServerError)
switch sortBy := r.Form.Get("sort"); sortBy {
case "author", "title", "id", "":
output, err = lc.bi.GetBooks(title, author, borrowed, strings.Title(sortBy))
default:
fmt.Println("Unknown sorting field: ", sortBy)
w.WriteHeader(http.StatusBadRequest)
return
}

jsonStr, err := json.MarshalIndent(book, "", " ")

if err != nil {
fmt.Println(err)
fmt.Println("Error getting books: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else if jsonStr, err := json.MarshalIndent(output, "", " "); err != nil {
fmt.Println("Error serializing: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else {
w.WriteHeader(http.StatusOK)
w.Write(jsonStr)
}

w.WriteHeader(http.StatusOK)
w.Write(jsonStr)
}

func (lc LibraryController) ListAll(r *http.Request, w http.ResponseWriter) {
ctx := context.Background()
client, _ := datastore.NewClient(ctx, "acme-books")

defer client.Close()

var output []models.Book
// Return a handler to borrow or return a book. TODO: sanitize inputs
func (lc LibraryController) BorrowOrReturn(borrow bool) martini.Handler {
return func(w http.ResponseWriter, params martini.Params) {
var book models.Book

it := client.Run(ctx, datastore.NewQuery("Book"))
for {
var b models.Book
_, err := it.Next(&b)
if err == iterator.Done {
fmt.Println(err)
break
state := "return"
if borrow {
state = "borrow"
}
output = append(output, b)
if id, err := strconv.Atoi(params["id"]); err != nil {
fmt.Println("Bad id: ", err)
w.WriteHeader(http.StatusBadRequest)
return
} else if book, err = lc.bi.GetBookByKey(int64(id)); err == datastore.ErrNoSuchEntity {
fmt.Println("Book not found: ", id)
w.WriteHeader(http.StatusBadRequest)
return
} else if err != nil {
fmt.Println("Error getting book: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else if book.Borrowed == borrow {
fmt.Printf("Book already %sed: %d\n", state, id)
w.WriteHeader(http.StatusBadRequest)
return
}
book.Borrowed = borrow
if err := lc.bi.PutBook(book); err != nil {
fmt.Printf("Error %sing book: %s\n", state, err)
w.WriteHeader(http.StatusInternalServerError)
return
}
fmt.Printf("Book %sed: %d\n", state, book.Id)
w.WriteHeader(http.StatusNoContent)
}
}

jsonStr, err := json.MarshalIndent(output, "", " ")

if err != nil {
fmt.Println(err)
func (lc LibraryController) AddBook(w http.ResponseWriter, book models.Book) {
if newbook, err := lc.bi.NewBook(book); err != nil {
fmt.Println("Error adding book: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else if jsonStr, err := json.MarshalIndent(newbook, "", " "); err != nil {
fmt.Println("Error serializing: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
} else {
w.WriteHeader(http.StatusOK)
w.Write(jsonStr)
}

w.WriteHeader(http.StatusOK)
w.Write(jsonStr)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ require (
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab
github.com/joho/godotenv v1.4.0
github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf // indirect
google.golang.org/api v0.60.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf h1:6YSkbjZVghliN7zwJC/U3QQG+OVXOrij3qQ8sxfPIMg=
github.com/martini-contrib/binding v0.0.0-20160701174519-05d3e151b6cf/go.mod h1:aCggxkm1kuifLw/LEQUbz91N1ZM6PhV7dz03xPQduZA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
Expand Down
35 changes: 3 additions & 32 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
package main

import (
"context"
"fmt"
"log"
"os"

"cloud.google.com/go/datastore"

"acme-books/models"
"acme-books/server"

"github.com/joho/godotenv"
)

func main() {
func init() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file! Did you forget to run `gcloud beta emulators datastore env-init > .env`")
}
}

bootstrapBooks()

func main() {
host := getEnvWithDefault("HOST", "localhost")
port := getEnvWithDefault("PORT", "3030")

Expand All @@ -34,27 +29,3 @@ func getEnvWithDefault(key, fallback string) string {
}
return fallback
}

func bootstrapBooks() {
ctx := context.Background()
client, _ := datastore.NewClient(ctx, "acme-books")

defer client.Close()

books := []models.Book{
{Id: 1, Author: "George Orwell", Title: "1984", Borrowed: false},
{Id: 2, Author: "George Orwell", Title: "Animal Farm", Borrowed: false},
{Id: 3, Author: "Robert Jordan", Title: "Eye of the world", Borrowed: false},
{Id: 4, Author: "Various", Title: "Collins Dictionary", Borrowed: false},
}

var keys []*datastore.Key

for _, book := range books {
keys = append(keys, datastore.IDKey("Book", book.Id, nil))
}

if _, err := client.PutMulti(ctx, keys, books); err != nil {
fmt.Println(err)
}
}
86 changes: 84 additions & 2 deletions models/book.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,90 @@
package models

import (
"context"
"strconv"

"cloud.google.com/go/datastore"
)

type Book struct {
Id int64
Title string `json:"title"`
Author string `json:"writer"`
Title string `json:"title" binding:"required"`
Author string `json:"writer" binding:"required"`
Borrowed bool `json:"borrowed"`
}

type BookInt struct {
client *datastore.Client
ctx context.Context
}

func NewBookInt(client *datastore.Client, ctx context.Context) *BookInt {
return &BookInt{client, ctx}
}

func (bi BookInt) GetBookByKey(id int64) (book Book, err error) {
key := datastore.IDKey("Book", id, nil)
err = bi.client.Get(bi.ctx, key, &book)
return book, err
}

func (bi BookInt) GetBooks(title, author, borrowed, sort string) ([]Book, error) {
var books []Book
query := datastore.NewQuery("Book")

if title != "" {
query = query.Filter("Title =", title)
}

if author != "" {
query = query.Filter("Author =", author)
}

if borrowed != "" {
if b, err := strconv.ParseBool(borrowed); err != nil {
return books, err

} else {
query = query.Filter("Borrowed =", b)
}
}

if sort == "" {
sort = "Id"
}

query = query.Order(sort)

_, err := bi.client.GetAll(bi.ctx, query, &books)
return books, err
}

func (bi BookInt) PutBooks(books []Book) error {
var keys []*datastore.Key

for _, book := range books {
keys = append(keys, datastore.IDKey("Book", book.Id, nil))
}

_, err := bi.client.PutMulti(bi.ctx, keys, books)
return err
}

func (bi BookInt) PutBook(book Book) error {
return bi.PutBooks([]Book{book})
}

func (bi BookInt) NewBook(book Book) (Book, error) {
q := datastore.NewQuery("Book")
if n, err := bi.client.Count(bi.ctx, q); err != nil {
return Book{}, err
} else {
book.Id = int64(n) + 1
}
if err := bi.PutBook(book); err != nil {
return Book{}, err
} else {
return book, nil
}
}
13 changes: 8 additions & 5 deletions server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ package server

import (
"github.com/go-martini/martini"
"github.com/martini-contrib/binding"

"acme-books/controllers"
"acme-books/models"
)

func NewRouter() *martini.ClassicMartini {
libraryController := new(controllers.LibraryController)

func NewRouter(library *controllers.LibraryController) *martini.ClassicMartini {
router := martini.Classic()

router.Get("/books", libraryController.ListAll)
router.Get("/books/:id", libraryController.GetByKey)
router.Get("/books", library.List)
router.Get("/books/:id", library.Get)
router.Put("/:id/borrow", library.BorrowOrReturn(true))
router.Put("/:id/return", library.BorrowOrReturn(false))
router.Post("/book", binding.Bind(models.Book{}), library.AddBook)

return router
}
Loading