package main import ( "context" "encoding/json" // "fmt" //"io" "log" "net/http" // "os" // "os/signal" "strconv" //"strings" // "sync" // "time" "github.com/gorilla/mux" "github.com/neo4j/neo4j-go-driver/v5/neo4j" ) // TODO: Need to test. func create_new_space(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "http://localhost:2025") // Must be a user to create a space. user_id, ok := user_id_from_context(r.Context()) if !ok { log.Println("Invalid user ID") http.Error(w, "Invalid user ID", http.StatusBadRequest) return } err := r.ParseMultipartForm(10 << 20) // Limit to 10MB if err != nil { log.Println("Unable to parse form:", err) http.Error(w, "Unable to parse form", http.StatusBadRequest) return } var space map[string]any err = json.NewDecoder(r.Body).Decode(&space) if space["id"] != -1 { log.Println("Attempt to create a space with a defined ID") http.Error(w, "Space ID cannot be provided.", http.StatusBadRequest) return } stmt := ` MATCH (owner:User) WHERE id(owner) = $user_id CREATE (s:Space { created_at: datetime(), name: $name, description: $description }) CREATE (owner)-[:SPACE_MEMBER {role: "Owner"}]->(s) UNWIND $members as member MATCH (m:User) WHERE id(m) = member.id CREATE (m)-[:SPACE_MEMBER {role: member.role}]->(s) RETURN id(s) AS id, s.name AS name ` stmt_args := map[string]any{ "user_id": user_id, "name": space["name"], "description": space["description"], "members": space["members"], } result, err := neo4j.ExecuteQuery(driver_ctx, driver, stmt, stmt_args, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j")) if err != nil || len(result.Records) != 2 { log.Println("Error creating Space:", err) http.Error(w, "Failed to create Space", http.StatusInternalServerError) return } record := result.Records[0] space_id, _ := record.Get("id") space_name, _ := record.Get("name") record_obj := map[string]any{ "space_id": space_id, "space_name": space_name, } obj, err := json.Marshal(record_obj) if err != nil { http.Error(w, "Failed to marshal JSON.", http.StatusInternalServerError) return } w.WriteHeader(http.StatusCreated) w.Write(obj) return } } // TODO: Need to implement for ADMIN ONLY func retrieve_all_spaces(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { return } } func retrieve_space(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { return } } // TODO: Implement access for Public and Open Spaces func auth_user_in_space(driver neo4j.DriverWithContext, driver_ctx context.Context, user_id int, space_id int) bool { stmt := ` MATCH (u:User), (s:Space) WHERE id(u) = $user_id AND id(s) = $space_id RETURN EXISTS((u)-[:SPACE_MEMBER]->(s)) ` stmt_args := map[string]any{ "user_id": user_id, "space_id": space_id, } result, err := neo4j.ExecuteQuery(driver_ctx, driver, stmt, stmt_args, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j")) if err != nil { log.Println("Something went wrong authorizing the user to a space.") return false } if len(result.Records) > 0 { return result.Records[0].Values[0].(bool) } else { return false } } // TODO: Implement func update_space(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { return } } // TODO: Implement func delete_space(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { return } } // TODO: Need to handle multiple topics. func retrieve_spaces_posts(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "http://localhost:2025") // Must be a user to create a space. user_id, ok := user_id_from_context(r.Context()) if !ok { log.Println("Invalid user ID") http.Error(w, "Invalid user ID", http.StatusBadRequest) return } space_id, _ := strconv.Atoi(mux.Vars(r)["space_id"]) if !auth_user_in_space(driver, driver_ctx, user_id, space_id) { log.Println("User", user_id, "attempted access to space", space_id, ", which is not allowed.") http.Error(w, "You are not a member of that space.", http.StatusUnauthorized) return } stmt := ` MATCH (p:Post)-[:IN_SPACE]->(s:Space) MATCH (s)-[:SPACE_TYPE]->(st:SpaceType) MATCH (p)-[:POST_TYPE]->(pt:PostType) MATCH (p)-[:STATUS]->(ps:PostStatus) MATCH (p)-[:TAGGED_WITH]->(t:Topic) MATCH (a:User)-[:CREATED]->(p) WHERE id(s) = $space_id AND ps.name = "Published" RETURN id(a) AS author_id, a.username AS author_username, a.profile_picture AS author_picture, p.title AS title, p.excerpt AS excerpt, p.location AS location, p.content AS content, pt.name AS post_type, id(t) AS topic_id, t.name AS topic_name, s.name AS space_name, ` stmt_args := map[string]any{ "space_id": space_id, } result, err := neo4j.ExecuteQuery(driver_ctx, driver, stmt, stmt_args, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j")) if !(len(result.Records) >= 2) { log.Println("Failed to retrieve Posts for Space", space_id, ". Error:", err) http.Error(w, "Error retrieving Posts from Space.", http.StatusInternalServerError) return } posts_obj := map[int]any{} for index, record := range result.Records { author_id, _ := record.Get("author_id") author_username, _ := record.Get("author_username") author_picture, _ := record.Get("author_picture") title, _ := record.Get("title") excerpt, _ := record.Get("excerpt") location, _ := record.Get("location") content, _ := record.Get("content") post_type, _ := record.Get("post_type") topic_id, _ := record.Get("topic_id") topic_name, _ := record.Get("topic_name") space_name, _ := record.Get("space_name") record_obj := map[string]any{ "author_id": author_id, "author_username": author_username, "author_picture": author_picture, "title": title, "excerpt": excerpt, "location": location, "content": content, "post_type": post_type, "topic_id": topic_id, "topic_name": topic_name, "space_name": space_name, } posts_obj[index] = record_obj } obj, err := json.Marshal(posts_obj) if err != nil { http.Error(w, "Failed to parse into JSON", http.StatusInternalServerError) log.Println("error marshalling json") return } w.WriteHeader(http.StatusOK) w.Write(obj) return } } // TODO: Implement for Space Member role == Administrator OR role == Owner func retrieve_spaces_users(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { return } }