diff --git a/app/app.go b/app/app.go index a19e1f6..ec6eb9a 100644 --- a/app/app.go +++ b/app/app.go @@ -55,6 +55,13 @@ func (app *App) setRouters() { app.Get("/api/subjects/{name}", app.handleRequest(handler.GetSubject)) app.Put("/api/subjects/{name}", app.handleRequest(handler.UpdateSubject)) app.Delete("/api/subjects/{name}", app.handleRequest(handler.DeleteSubject)) + + // Routing for problems + app.Get("/api/problems", app.handleRequest(handler.GetProblems)) + app.Get("/api/problems/{name}", app.handleRequest(handler.GetProblem)) + app.Post("/api/problems", app.handleRequest(handler.CreateProblem)) + app.Put("/api/problems/{name}", app.handleRequest(handler.UpdateProblem)) + app.Delete("/api/problems/{name}", app.handleRequest(handler.DeleteProblem)) } // Get wraps the router for GET method diff --git a/app/dbOperations/problems.go b/app/dbOperations/problems.go new file mode 100644 index 0000000..3c34223 --- /dev/null +++ b/app/dbOperations/problems.go @@ -0,0 +1,154 @@ +package dbOperations + +import ( + "errors" + "fmt" + + gremcos "github.com/supplyon/gremcos" + "github.com/supplyon/gremcos/api" + "github.com/supplyon/gremcos/interfaces" + + modelStorage "github.com/imeplusplus/dont-panic-api/app/modelStorage" +) + +func CreateProblem(cosmos gremcos.Cosmos, problem modelStorage.Problem) (modelStorage.Problem, error) { + _, err := GetProblemByName(cosmos, problem.Name) + + if err == nil { + return modelStorage.Problem{}, fmt.Errorf("there is already a problem with name %v", problem.Name) + } + + g := api.NewGraph("g") + + query := g.AddV("problem").Property("partitionKey", "problem") + query = addProblemVertexProperties(query, problem) + + res, err := cosmos.ExecuteQuery(query) + if err != nil { + fmt.Println("Failed to execute a gremlin command", query.String()) + return problem, err + } + + problems, err := getProblemsFromResponse(res) + if len(problems) == 0 { + return modelStorage.Problem{}, err + } + + return problems[0], err +} + +func GetProblems(cosmos gremcos.Cosmos) ([]modelStorage.Problem, error) { + g := api.NewGraph("g") + + query := g.V().HasLabel("problem") + res, err := cosmos.ExecuteQuery(query) + if err != nil { + fmt.Println("Failed to execute a gremlin command", query.String()) + return nil, err + } + + return getProblemsFromResponse(res) +} + +func GetProblemByName(cosmos gremcos.Cosmos, name string) (modelStorage.Problem, error) { + var problem modelStorage.Problem + g := api.NewGraph("g") + query := g.V().HasLabel("problem").Has("name", name) + + res, err := cosmos.ExecuteQuery(query) + if err != nil { + fmt.Println("Failed to execute a gremlin command", query.String()) + return problem, err + } + + problems, err := getProblemsFromResponse(res) + if len(problems) == 0 { + return modelStorage.Problem{}, err + } + + return problems[0], err +} + +func UpdateProblem(cosmos gremcos.Cosmos, problem modelStorage.Problem, name string) (modelStorage.Problem, error) { + if problem.Name != name { + _, err := GetProblemByName(cosmos, problem.Name) + if err == nil { + return modelStorage.Problem{}, fmt.Errorf("there is already a problem with name %v. can't rename in this case", problem.Name) + } + } + + oldProblem, err := GetProblemByName(cosmos, name) + if err != nil { + return oldProblem, fmt.Errorf("there is no problem with name '%v' to update in the database", name) + } + + g := api.NewGraph("g") + query := addProblemVertexProperties(g.VByStr(oldProblem.Id), problem) + + res, err := cosmos.ExecuteQuery(query) + if err != nil { + fmt.Println("Failed to execute a gremlin command", query.String()) + return problem, err + } + + problems, err := getProblemsFromResponse(res) + if len(problems) == 0 { + return modelStorage.Problem{}, err + } + + return problems[0], err +} + +func DeleteProblem(cosmos gremcos.Cosmos, name string) error { + _, err := GetProblemByName(cosmos, name) + + if err != nil { + return fmt.Errorf("there is no problem with name '%v' to delete in the database", name) + } + + g := api.NewGraph("g") + query := g.V().HasLabel("problem").Has("name", name).Drop() + + _, err = cosmos.ExecuteQuery(query) + + return err +} + +func addProblemVertexProperties(vertex interfaces.Vertex, problem modelStorage.Problem) interfaces.Vertex { + vertex = vertex. + Property("name", problem.Name). + Property("difficulty", problem.Difficulty). + Property("link", problem.Link) + + return vertex +} + +func getProblemsFromResponse(res []interfaces.Response) ([]modelStorage.Problem, error) { + var problems []modelStorage.Problem + response := api.ResponseArray(res) + vertices, _ := response.ToVertices() + + if len(vertices) == 0 { + return problems, errors.New("there is no data with type 'api.vertex' in the response. the graph query didn't return any vertex") + } + + for _, v := range vertices { + problems = append(problems, vertexToProblem(v)) + } + + return problems, nil +} + +func vertexToProblem(vertex api.Vertex) modelStorage.Problem { + var problem modelStorage.Problem + + problem.Id = vertex.ID + + properties := vertex.Properties + problem.Name = properties["name"][0].Value.AsString() + problem.Difficulty = int(properties["difficulty"][0].Value.AsInt32()) + problem.Link = properties["link"][0].Value.AsString() + problem.PartitionKey = properties["partitionKey"][0].Value.AsString() + + return problem +} diff --git a/app/dbOperations/subjects.go b/app/dbOperations/subjects.go index 5b71962..7e5fa83 100644 --- a/app/dbOperations/subjects.go +++ b/app/dbOperations/subjects.go @@ -8,10 +8,10 @@ import ( "github.com/supplyon/gremcos/api" "github.com/supplyon/gremcos/interfaces" - "github.com/imeplusplus/dont-panic-api/app/model" + modelStorage "github.com/imeplusplus/dont-panic-api/app/modelStorage" ) -func GetSubjects(cosmos gremcos.Cosmos) ([]model.Subject, error) { +func GetSubjects(cosmos gremcos.Cosmos) ([]modelStorage.Subject, error) { g := api.NewGraph("g") query := g.V().HasLabel("subject") @@ -34,32 +34,32 @@ func GetSubjects(cosmos gremcos.Cosmos) ([]model.Subject, error) { return subjects, nil } -func GetSubjectByName(cosmos gremcos.Cosmos, name string) (model.Subject, error) { - var subject model.Subject +func GetSubjectByName(cosmos gremcos.Cosmos, name string) (modelStorage.Subject, error) { + var subject modelStorage.Subject g := api.NewGraph("g") query := g.V().HasLabel("subject").Has("name", name) res, err := cosmos.ExecuteQuery(query) if err != nil { fmt.Println("Failed to execute a gremlin command " + query.String()) - //logger.Error().Err(err).Msg("Failed to execute a gremlin command") + // logger.Error().Err(err).Msg("Failed to execute a gremlin command") return subject, err } return getSubjectFromResponse(res) } -func CreateSubject(cosmos gremcos.Cosmos, subject model.Subject) (model.Subject, error) { +func CreateSubject(cosmos gremcos.Cosmos, subject modelStorage.Subject) (modelStorage.Subject, error) { _, err := GetSubjectByName(cosmos, subject.Name) if err == nil { - return model.Subject{}, errors.New("There is already a subject with name " + subject.Name) + return modelStorage.Subject{}, errors.New("There is already a subject with name " + subject.Name) } g := api.NewGraph("g") query := g.AddV("subject").Property("partitionKey", "subject") - query = addVertexProperties(query, subject) + query = addSubjectVertexProperties(query, subject) res, err := cosmos.ExecuteQuery(query) if err != nil { @@ -71,15 +71,15 @@ func CreateSubject(cosmos gremcos.Cosmos, subject model.Subject) (model.Subject, return getSubjectFromResponse(res) } -func UpdateSubject(cosmos gremcos.Cosmos, subject model.Subject, name string) (model.Subject, error) { +func UpdateSubject(cosmos gremcos.Cosmos, subject modelStorage.Subject, name string) (modelStorage.Subject, error) { oldSubject, err := GetSubjectByName(cosmos, name) if err != nil { - return model.Subject{}, errors.New("There is no subject with name " + oldSubject.Name) + return modelStorage.Subject{}, errors.New("There is no subject with name " + oldSubject.Name) } g := api.NewGraph("g") - query := addVertexProperties(g.VByStr(oldSubject.Id), subject) + query := addSubjectVertexProperties(g.VByStr(oldSubject.Id), subject) res, err := cosmos.ExecuteQuery(query) if err != nil { @@ -100,7 +100,7 @@ func DeleteSubject(cosmos gremcos.Cosmos, name string) error { return err } -func addVertexProperties(vertex interfaces.Vertex, subject model.Subject) interfaces.Vertex { +func addSubjectVertexProperties(vertex interfaces.Vertex, subject modelStorage.Subject) interfaces.Vertex { vertex = vertex. Property("name", subject.Name). Property("difficulty", subject.Difficulty). @@ -117,16 +117,16 @@ func addVertexProperties(vertex interfaces.Vertex, subject model.Subject) interf return vertex } -func getSubjectFromResponse(res []interfaces.Response) (model.Subject, error) { - var subject model.Subject +func getSubjectFromResponse(res []interfaces.Response) (modelStorage.Subject, error) { + var subject modelStorage.Subject response := api.ResponseArray(res) - vertices, err := response.ToVertices() + vertices, _ := response.ToVertices() if len(vertices) == 0 { - return subject, errors.New("There is no vertex in the response") + return subject, errors.New("there is no vertex in the response") } - subject, err = vertexToSubject(vertices[0]) + subject, err := vertexToSubject(vertices[0]) if err != nil { return subject, err } @@ -134,8 +134,8 @@ func getSubjectFromResponse(res []interfaces.Response) (model.Subject, error) { return subject, nil } -func verticesToSubjects(vertices []api.Vertex) []model.Subject { - subjects := []model.Subject{} +func verticesToSubjects(vertices []api.Vertex) []modelStorage.Subject { + subjects := []modelStorage.Subject{} for _, v := range vertices { subject, err := vertexToSubject(v) @@ -147,8 +147,8 @@ func verticesToSubjects(vertices []api.Vertex) []model.Subject { return subjects } -func vertexToSubject(vertex api.Vertex) (model.Subject, error) { - var subject model.Subject +func vertexToSubject(vertex api.Vertex) (modelStorage.Subject, error) { + var subject modelStorage.Subject subject.Id = vertex.ID diff --git a/app/handler/problems.go b/app/handler/problems.go new file mode 100644 index 0000000..992d97b --- /dev/null +++ b/app/handler/problems.go @@ -0,0 +1,117 @@ +package handler + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/gorilla/mux" + gremcos "github.com/supplyon/gremcos" + + "github.com/imeplusplus/dont-panic-api/app/dbOperations" + modelStorage "github.com/imeplusplus/dont-panic-api/app/modelStorage" +) + +func CreateProblem(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { + problem := modelStorage.Problem{} + if err := json.NewDecoder(r.Body).Decode(&problem); err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + problem, err := dbOperations.CreateProblem(cosmos, problem) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(problem) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + } +} + +func GetProblems(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { + problems, err := dbOperations.GetProblems(cosmos) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + err = json.NewEncoder(w).Encode(problems) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + } +} + +func GetProblem(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + problem, err := dbOperations.GetProblemByName(cosmos, vars["name"]) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("Content-Type", "application/json") + err = json.NewEncoder(w).Encode(problem) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + } +} + +func UpdateProblem(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + problem := modelStorage.Problem{} + if err := json.NewDecoder(r.Body).Decode(&problem); err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + problem, err := dbOperations.UpdateProblem(cosmos, problem, vars["name"]) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("Content-Type", "application/json") + err = json.NewEncoder(w).Encode(problem) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + } +} + +func DeleteProblem(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + err := dbOperations.DeleteProblem(cosmos, vars["name"]) + + if err != nil { + fmt.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(http.StatusAccepted) +} diff --git a/app/handler/subjects.go b/app/handler/subjects.go index 042645e..7b9faa2 100644 --- a/app/handler/subjects.go +++ b/app/handler/subjects.go @@ -9,7 +9,7 @@ import ( gremcos "github.com/supplyon/gremcos" "github.com/imeplusplus/dont-panic-api/app/dbOperations" - "github.com/imeplusplus/dont-panic-api/app/model" + modelStorage "github.com/imeplusplus/dont-panic-api/app/modelStorage" ) func GetSubjects(cosmos gremcos.Cosmos, w http.ResponseWriter, _ *http.Request) { @@ -53,7 +53,7 @@ func GetSubject(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { func UpdateSubject(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) - subject := model.Subject{} + subject := modelStorage.Subject{} err := json.NewDecoder(r.Body).Decode(&subject) if err != nil { @@ -95,7 +95,7 @@ func DeleteSubject(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request } func CreateSubject(cosmos gremcos.Cosmos, w http.ResponseWriter, r *http.Request) { - subject := model.Subject{} + subject := modelStorage.Subject{} var err error if err = json.NewDecoder(r.Body).Decode(&subject); err != nil { w.WriteHeader(http.StatusBadRequest) diff --git a/app/modelStorage/problem.go b/app/modelStorage/problem.go new file mode 100644 index 0000000..7e19ae8 --- /dev/null +++ b/app/modelStorage/problem.go @@ -0,0 +1,9 @@ +package modelStorage + +type Problem struct { + Id string `json:"id"` + Name string `json:"name"` + Difficulty int `json:"difficulty"` + Link string `json:"link"` + PartitionKey string `json:"partitionKey"` +} diff --git a/app/model/subject.go b/app/modelStorage/subject.go similarity index 92% rename from app/model/subject.go rename to app/modelStorage/subject.go index a635432..85e376b 100644 --- a/app/model/subject.go +++ b/app/modelStorage/subject.go @@ -1,4 +1,4 @@ -package model +package modelStorage type Subject struct { Id string `json:"id"`