commit f960eab641546eb85d660f2b837bec4839089863 Author: Steve Date: Sun Mar 29 18:16:01 2020 -0400 initial api work diff --git a/backend/addViews.go b/backend/addViews.go new file mode 100644 index 0000000..9883c05 --- /dev/null +++ b/backend/addViews.go @@ -0,0 +1,63 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "strconv" + + "github.com/gorilla/mux" +) + +func addMovie(w http.ResponseWriter, r *http.Request) { + var newmov Movie + reqBody, err := ioutil.ReadAll(r.Body) + if err != nil { + fmt.Fprintf(w, "Please enter a movie") + } + json.Unmarshal(reqBody, &newmov) + fmt.Println(newmov) + mov, err := db.CreateMovie(newmov.Title, newmov.Imdb) + if err != nil || mov.ID == 0 { + fmt.Fprintf(w, "Error creating movie") + return + } + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(mov) +} + +func addTaggedMovie(w http.ResponseWriter, r *http.Request) { + movieIDstr := mux.Vars(r)["mid"] + tagIDstr := mux.Vars(r)["tid"] + movieID, err := strconv.Atoi(movieIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid movie ID passed") + return + } + tagID, err := strconv.Atoi(tagIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid tag ID passed") + return + } + err = db.TagMovie(tagID, movieID) + if err != nil { + fmt.Fprintf(w, "Error tagging movie") + } + json.NewEncoder(w).Encode("tagged") +} + +func addTag(w http.ResponseWriter, r *http.Request) { + var newtag Tag + reqBody, err := ioutil.ReadAll(r.Body) + if err != nil { + fmt.Fprintf(w, "Please enter a tag") + } + json.Unmarshal(reqBody, &newtag) + + tag, _ := db.CreateTag(newtag.Name) + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(tag) +} diff --git a/backend/delViews.go b/backend/delViews.go new file mode 100644 index 0000000..e3e0631 --- /dev/null +++ b/backend/delViews.go @@ -0,0 +1,60 @@ +package main + +import ( + "fmt" + "net/http" + "strconv" + + "github.com/gorilla/mux" +) + +func delOneMovie(w http.ResponseWriter, r *http.Request) { + movieIDstr := mux.Vars(r)["id"] + movieID, err := strconv.Atoi(movieIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid movie ID passed") + return + } + err = db.DeleteMovie(movieID) + if err != nil { + fmt.Fprintf(w, "Error deleting movie") + return + } + fmt.Fprintf(w, "Movie deleted succesfully") +} + +func delOneTag(w http.ResponseWriter, r *http.Request) { + tagIDstr := mux.Vars(r)["id"] + tagID, err := strconv.Atoi(tagIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid tag ID passed") + return + } + err = db.DeleteTag(tagID) + if err != nil { + fmt.Fprintf(w, "Error deleting tag") + return + } + fmt.Fprintf(w, "Tag deleted succesfully") +} + +func delTaggedMovie(w http.ResponseWriter, r *http.Request) { + movieIDstr := mux.Vars(r)["mid"] + tagIDstr := mux.Vars(r)["tid"] + movieID, err := strconv.Atoi(movieIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid movie ID passed") + return + } + tagID, err := strconv.Atoi(tagIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid tag ID passed") + return + } + err = db.UnTagMovie(tagID, movieID) + if err != nil { + fmt.Fprintf(w, "Error untagging movie") + return + } + fmt.Fprintf(w, "Untagged movie") +} diff --git a/backend/getViews.go b/backend/getViews.go new file mode 100644 index 0000000..f3c48cc --- /dev/null +++ b/backend/getViews.go @@ -0,0 +1,78 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "strconv" + + "github.com/gorilla/mux" +) + +func homeLink(w http.ResponseWriter, r *http.Request) { + movies, err := db.GetMovies() + if err != nil { + log.Fatal("Error showing homepage (all movies)") + } + json.NewEncoder(w).Encode(movies) +} + +func getMovies(w http.ResponseWriter, r *http.Request) { + movies, err := db.GetMovies() + if err != nil { + log.Fatal("Error getting all movies") + } + json.NewEncoder(w).Encode(movies) +} + +func getOneMovie(w http.ResponseWriter, r *http.Request) { + movieIDstr := mux.Vars(r)["id"] + movieID, err := strconv.Atoi(movieIDstr) + if err != nil { + log.Println("Error: invalid movie ID passed") + return + } + mov, err := db.GetMovieById(movieID) + if err != nil { + log.Fatal("Error getting one movie") + } + json.NewEncoder(w).Encode(mov) +} + +func getTaggedMovies(w http.ResponseWriter, r *http.Request) { + tagIDstr := mux.Vars(r)["id"] + tagID, err := strconv.Atoi(tagIDstr) + if err != nil { + fmt.Fprintf(w, "Error: invalid tag ID passed") + return + } + movies, err := db.GetMoviesByTag(tagID) + if err != nil { + fmt.Fprintf(w, "Error fetching movies by tag") + return + } + json.NewEncoder(w).Encode(movies) +} + +func getTags(w http.ResponseWriter, r *http.Request) { + tags, err := db.GetTags() + if err != nil { + log.Fatal("Error getting all tags") + } + json.NewEncoder(w).Encode(tags) +} + +func getOneTag(w http.ResponseWriter, r *http.Request) { + tagIDstr := mux.Vars(r)["id"] + tagID, err := strconv.Atoi(tagIDstr) + if err != nil { + log.Println("Error: invalid tag ID passed") + return + } + tag, err := db.GetTagById(tagID) + if err != nil { + log.Fatal("Error getting one tag") + } + json.NewEncoder(w).Encode(tag) +} diff --git a/backend/main.go b/backend/main.go new file mode 100644 index 0000000..7fec126 --- /dev/null +++ b/backend/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "log" + "net/http" + + "github.com/gorilla/mux" +) + +var db MovieDB + +func main() { + setupDB() + router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/", homeLink) + router.HandleFunc("/movie", getMovies).Methods("GET") + router.HandleFunc("/movie", addMovie).Methods("POST") + router.HandleFunc("/movie/{id}", getOneMovie).Methods("GET") + router.HandleFunc("/movie/{id}", delOneMovie).Methods("DELETE") + + router.HandleFunc("/movie/tag/{id}", getTaggedMovies).Methods("GET") + router.HandleFunc("/movie/{mid}/tag/{tid}", addTaggedMovie).Methods("POST") + router.HandleFunc("/movie/{mid}/tag/{tid}", delTaggedMovie).Methods("DELETE") + + router.HandleFunc("/tag", getTags).Methods("GET") + router.HandleFunc("/tag", addTag).Methods("POST") + router.HandleFunc("/tag/{id}", getOneTag).Methods("GET") + router.HandleFunc("/tag/{id}", delOneTag).Methods("DELETE") + + log.Fatal(http.ListenAndServe(":8080", router)) +} + +func setupDB() { + db = CreateMemDB() + id1, _ := db.CreateMovie("Murder By Death", "tt0074937") + id2, _ := db.CreateMovie("Satanic Panic", "tt8510350") + id3, _ := db.CreateMovie("Event Horizon", "tt0119081") + id4, _ := db.CreateMovie("Shrek", "tt0126029") + fmt.Printf("Created %v %v %v %v\n", id1, id2, id3, id4) + t1, _ := db.CreateTag("deea") + t2, _ := db.CreateTag("steve") + t3, _ := db.CreateTag("bad") + fmt.Printf("Created tags %v %v %v\n", t1, t2, t3) + db.TagMovie(t1.ID, id1.ID) + db.TagMovie(t2.ID, id2.ID) + db.TagMovie(t3.ID, id3.ID) + db.TagMovie(t3.ID, id4.ID) +} diff --git a/backend/mem.go b/backend/mem.go new file mode 100644 index 0000000..0d4af71 --- /dev/null +++ b/backend/mem.go @@ -0,0 +1,146 @@ +package main + +import ( + "errors" +) + +type MemDB struct { + MovieList map[int]*Movie + TagList map[int]*Tag + TagToMovie map[string][]int + mId int + tId int +} + +func CreateMemDB() *MemDB { + return &MemDB{make(map[int]*Movie), make(map[int]*Tag), make(map[string][]int), 1, 1} +} + +func (m *MemDB) CreateMovie(title, imdb string) (Movie, error) { + mov := Movie{m.mId, title, imdb, []*Tag{}} + m.MovieList[m.mId] = &mov + m.mId = m.mId + 1 + return mov, nil +} + +func (m *MemDB) UpdateMovie(id int, title string, imdb string) error { + m.MovieList[id].Title = title + m.MovieList[id].Imdb = imdb + return nil +} +func (m *MemDB) GetMovies(limit ...int) ([]Movie, error) { + lim := -1 + var res []Movie + if len(limit) > 0 { + lim = limit[0] + } + count := 0 + for _, mov := range m.MovieList { + if count == lim { + break + } + res = append(res, *mov) + } + return res, nil +} + +func (m *MemDB) GetMovieById(id int) (Movie, error) { + mov := m.MovieList[id] + if mov.ID == 0 { + return *mov, errors.New("No movie found!") + } else { + return *mov, nil + } +} + +func (m *MemDB) GetMoviesByTag(id int) ([]Movie, error) { + tag := m.TagList[id] + if tag.Name == "" { + return []Movie{}, nil //nonexistent tag is a valid option + } + var res []Movie + movies := m.TagToMovie[tag.Name] + for _, movID := range movies { + res = append(res, *m.MovieList[movID]) + } + return res, nil +} + +func (m *MemDB) DeleteMovie(id int) error { + delete(m.MovieList, id) + return nil +} + +func (m *MemDB) CreateTag(name string) (Tag, error) { + tag := Tag{m.tId, name} + m.TagList[m.tId] = &tag + m.tId = m.tId + 1 + return tag, nil +} + +func (m *MemDB) DeleteTag(id int) error { + tag := m.TagList[id] + delete(m.TagList, id) + delete(m.TagToMovie, tag.Name) + return nil +} + +func (m *MemDB) GetTags(limit ...int) ([]Tag, error) { + lim := -1 + var res []Tag + if len(limit) > 0 { + lim = limit[0] + } + count := 0 + for _, tag := range m.TagList { + if count == lim { + break + } + res = append(res, *tag) + } + return res, nil +} + +func (m *MemDB) GetTagById(id int) (Tag, error) { + tag := m.TagList[id] + if tag.ID == 0 { + return *tag, errors.New("No tag found!") + } else { + return *tag, nil + } +} + +func (m *MemDB) TagMovie(tagId int, movieId int) error { + mov := m.MovieList[movieId] + tag := m.TagList[tagId] + if mov.ID == 0 { + return errors.New("No movie found for tagging!") + } + if tag.ID == 0 { + return errors.New("No tag found for tagging!") + } + m.TagToMovie[tag.Name] = append(m.TagToMovie[tag.Name], movieId) + mov.Tags = append(mov.Tags, tag) + + return nil +} + +func (m *MemDB) UnTagMovie(tagId int, movieId int) error { + mov := m.MovieList[movieId] + tag := m.TagList[tagId] + if mov.ID == 0 { + return errors.New("No movie found for untagging!") + } + if tag.ID == 0 { + return errors.New("No tag found for untagging!") + } + for i, v := range m.TagToMovie[tag.Name] { + if v == movieId { + m.TagToMovie[tag.Name][i] = m.TagToMovie[tag.Name][len(m.TagToMovie[tag.Name])-1] + m.TagToMovie[tag.Name] = m.TagToMovie[tag.Name][:len(m.TagToMovie[tag.Name])-1] + break + } + } + + return nil +} diff --git a/backend/types.go b/backend/types.go new file mode 100644 index 0000000..d424470 --- /dev/null +++ b/backend/types.go @@ -0,0 +1,28 @@ +package main + +type Movie struct { + ID int `json:"id"` + Title string `json:"title"` + Imdb string `json:"imdb"` + Tags []*Tag `json:"tags"` +} + +type Tag struct { + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` +} + +type MovieDB interface { + CreateMovie(title string, imdb string) (Movie, error) + UpdateMovie(id int, title string, imbd string) error + GetMovies(limit ...int) ([]Movie, error) + GetMovieById(id int) (Movie, error) + GetMoviesByTag(id int) ([]Movie, error) + DeleteMovie(id int) error + CreateTag(name string) (Tag, error) + DeleteTag(id int) error + GetTags(limit ...int) ([]Tag, error) + GetTagById(id int) (Tag, error) + TagMovie(tagId int, movieId int) error + UnTagMovie(tagId int, movieId int) error +}