package v1 import ( "database/sql" "encoding/json" "fmt" "io/ioutil" "net/http" "path/filepath" "strconv" "strings" "github.com/gorilla/mux" ) func RegisterNovelsRoutes(r *mux.Router) { r.HandleFunc("/novels", resolveNovels).Methods("GET", "OPTIONS", "POST") r.HandleFunc("/novels/{novelId:[0-9]+}", resolveNovel).Methods("GET", "OPTIONS", "PUT", "DELETE") r.HandleFunc("/novels/{novelId:[0-9]+}/cover", uploadNovelCover).Methods("POST", "OPTIONS") r.HandleFunc("/novels/{novelId:[0-9]+}/comments", resolveNovelComments).Methods("GET", "OPTIONS", "POST") r.HandleFunc("/novels/{novelId:[0-9]+}/characters", resolveNovelCharacters).Methods("GET", "OPTIONS") r.HandleFunc("/novels/{novelId:[0-9]+}/genres", resolveNovelGenres).Methods("GET", "OPTIONS") } func resolveNovels(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { sortBy, ok := r.URL.Query()["sort"] if !ok || len(sortBy) <= 0 { sortBy = append(sortBy, "rating") } query, ok := r.URL.Query()["q"] if ok { novels, err := SearchNovels(query[0]) Response(w, err, novels) return } novels, err := FetchNovels(sortBy[0]) Response(w, err, &novels) } else if r.Method == http.MethodPost { body, err := ReadBody(r) if err != nil { Error(w, err) return } var novel Novel err = json.Unmarshal(body, &novel) if err != nil { Error(w, err) return } novel, err = CreateNovel(&novel) if err == nil { w.WriteHeader(http.StatusCreated) w.Header().Add("Location", fmt.Sprintf("https://%v%v/%v", r.Host, r.URL, novel.ID)) } Response(w, err, &novel) } } func resolveNovelGenres(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id, _ := strconv.Atoi(vars["novelId"]) genres, err := FetchNovelGenres(int32(id)) Response(w, err, genres) } func resolveNovelCharacters(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) novelId, _ := strconv.Atoi(vars["novelId"]) characters, err := FetchNovelCharacters(novelId) Response(w, err, characters) } func resolveNovel(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) novelId, _ := strconv.Atoi(vars["novelId"]) if r.Method == http.MethodGet { novel, err := FetchNovel(novelId) Response(w, err, novel) } else if r.Method == http.MethodPut { body, err := ReadBody(r) if err != nil { Error(w, err) return } novel, err := FetchNovel(novelId) if err != nil { Response(w, err, nil) return } err = json.Unmarshal(body, novel) if err != nil { Error(w, err) return } novel, err = UpdateNovel(novel) Response(w, err, novel) } else if r.Method == http.MethodDelete { _, err := FetchNovel(novelId) if err == sql.ErrNoRows { NotFound.Ferror(w) return } err = DeleteNovel(novelId) if err != nil { w.WriteHeader(500) Error(w, err) return } w.WriteHeader(http.StatusNoContent) JSON(w, "") } } func uploadNovelCover(w http.ResponseWriter, r *http.Request) { user, err := FetchCurrentUser(r) if err != nil { w.WriteHeader(http.StatusInternalServerError) Error(w, err) return } if !hasPermission(user, "novel") { NoAccess.Ferror(w) return } vars := mux.Vars(r) novelId, _ := strconv.Atoi(vars["novelId"]) err = r.ParseMultipartForm(1024 * 1024 * 2) if err != nil { w.WriteHeader(http.StatusBadRequest) Error(w, err) return } file, handler, err := r.FormFile("cover") if err != nil { w.WriteHeader(http.StatusBadRequest) Error(w, err) return } if !strings.HasPrefix(handler.Header["Content-Type"][0], "image") { w.WriteHeader(http.StatusBadRequest) RawError(w, "Wrong document type!") return } fileBytes, err := ioutil.ReadAll(file) if err != nil { w.WriteHeader(http.StatusInternalServerError) Error(w, err) return } err = file.Close() if err != nil { w.WriteHeader(http.StatusInternalServerError) Error(w, err) return } ext := strings.Split(handler.Header["Content-Type"][0], "/")[1] path := filepath.Join(config.CDNPath, "novels", "logo", fmt.Sprintf("%v.%v", novelId, ext)) err = ioutil.WriteFile(path, fileBytes, 0644) if err != nil { w.WriteHeader(http.StatusInternalServerError) Error(w, err) return } coverPath := fmt.Sprintf("%v/novels/logo/%v.%v", config.CDNUrl, novelId, ext) err = UpdateNovelCover(novelId, coverPath) Response(w, err, coverPath) } func resolveNovelComments(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) novelId, _ := strconv.Atoi(vars["novelId"]) if r.Method == http.MethodGet { offsetParam, ok := r.URL.Query()["offset"] if !ok || len(offsetParam) <= 0 { offsetParam = append(offsetParam, "0") } countParam, ok := r.URL.Query()["count"] if !ok || len(countParam) <= 0 { countParam = append(countParam, "5") } offset, _ := strconv.Atoi(offsetParam[0]) count, _ := strconv.Atoi(countParam[0]) var response = make(map[string]interface{}, 2) comments, err := FetchNovelComments(novelId) response["count"] = len(comments) if offset+count > len(comments) { comments = comments[offset:] } else { comments = comments[offset : offset+count] } response["comments"] = comments Response(w, err, response) } else if r.Method == http.MethodPost { user, err := FetchCurrentUser(r) if err != nil { Error(w, err) return } body, err := ReadBody(r) if err != nil { Error(w, err) return } commentData := CommentNovel{NovelID: int16(novelId), UserID: user.ID} err = json.Unmarshal(body, &commentData) if err != nil { Error(w, err) return } comment, err := AddNovelComment(commentData) Response(w, err, comment) } }