This commit is contained in:
2025-05-01 14:42:12 -06:00
parent 693d11c506
commit bd59f428ba
13 changed files with 288 additions and 124 deletions
+1
View File
@@ -4,5 +4,6 @@ go 1.24.2
require (
github.com/gorilla/mux v1.8.1 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/neo4j/neo4j-go-driver/v5 v5.28.0 // indirect
)
+2
View File
@@ -1,4 +1,6 @@
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/neo4j/neo4j-go-driver/v5 v5.28.0 h1:chDT68PHNa8JZRmjSkGzAbk1weLWo4rMtDvccvpobg0=
github.com/neo4j/neo4j-go-driver/v5 v5.28.0/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k=
+13 -5
View File
@@ -14,6 +14,7 @@ import (
"time"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)
@@ -34,7 +35,7 @@ func serve() {
var wg sync.WaitGroup
driver_ctx := context.Background()
driver, err := neo4j.NewDriverWithContext("bolt://localhost:7687", neo4j.BasicAuth("neo4j", "jzLbsy2C23WHzQ-", ""))
driver, err := neo4j.NewDriverWithContext(os.Getenv("NEO4J_BOLT"), neo4j.BasicAuth("neo4j", os.Getenv("NEO4J_PASSWORD"), ""))
if err != nil {
panic(err)
}
@@ -43,18 +44,19 @@ func serve() {
err = driver.VerifyConnectivity(driver_ctx)
if err != nil {
log.Println("Error connecting to neo4j.")
panic(err)
}
fmt.Println("neo4j connection established.")
rsrc_endpoints := []string{
"/auth",
"/users",
"/users",
"/users/{user_id}",
"/users/{user_id}",
"/users/{user_id}",
"/users/{user_id}",
"/users/{user_id}/posts",
"/users/{user_id}/spaces",
"/spaces",
@@ -74,9 +76,9 @@ func serve() {
methods := []string{
http.MethodPost,
http.MethodGet,
http.MethodGet,
http.MethodPost,
http.MethodGet,
http.MethodGet,
http.MethodPatch,
http.MethodDelete,
http.MethodGet,
@@ -97,10 +99,10 @@ func serve() {
}
functions := []func(http.ResponseWriter, *http.Request){
auth_user(driver, driver_ctx),
create_new_user(driver, driver_ctx),
retrieve_all_users(driver, driver_ctx),
retrieve_user(driver, driver_ctx),
auth_user(driver, driver_ctx),
update_user(driver, driver_ctx),
delete_user(driver, driver_ctx),
retrieve_users_posts(driver, driver_ctx),
@@ -168,5 +170,11 @@ func serve() {
}
func main() {
err := godotenv.Load("../.env")
if err != nil {
log.Println("Error loading .env.")
return
}
serve()
}
+121 -21
View File
@@ -3,24 +3,112 @@ package main
import (
"context"
"encoding/json"
// "fmt"
"fmt"
"io"
"os"
"strconv"
//"io"
// "log"
"log"
"net/http"
// "os"
// "os/signal"
// "reflect"
"math/rand"
"strings"
// "sync"
// "time"
"github.com/gorilla/mux"
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)
func id_exists(id int, driver neo4j.DriverWithContext, driver_ctx context.Context) bool {
result, _ := neo4j.ExecuteQuery(driver_ctx, driver,
"MATCH (u:User) WHERE id(u) = $id RETURN count(u)",
map[string]any{
"id": id,
}, neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
if len(result.Records) > 0 {
return true
} else {
return false
}
}
func create_new_user(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
return
w.Header().Set("Access-Control-Allow-Origin", "http://localhost:2025")
err := r.ParseMultipartForm(10 << 20) // Limit to 10MB
if err != nil {
log.Println("Unable to parse form.")
}
username := r.FormValue("username")
email := r.FormValue("email")
password_hash := r.FormValue("password_hash")
id := rand.Intn(999999999999) + 1
for id_exists(id, driver, driver_ctx) {
id = rand.Intn(999999999999) + 1
}
profile_picture_file, header, err := r.FormFile("profile_picture")
if err != nil {
log.Println("Error retrieving file from form.")
}
defer profile_picture_file.Close()
filename_parts := strings.Split(header.Filename, ".")
ext := filename_parts[len(filename_parts)-1]
dst, err := os.Create(os.Getenv("PROFILE_IMAGES_FQ_PATH") + strconv.Itoa(id) + ext)
if err != nil {
log.Println("Error saving profile picture.")
}
defer dst.Close()
_, err = io.Copy(dst, profile_picture_file)
if err != nil {
log.Println("Error writing file to filesystem.")
}
result, _ := neo4j.ExecuteQuery(driver_ctx, driver,
"CREATE (u:User {id: $id, username: $username, email: $email, password_hash: $password_hash, profile_picture: $profile_picture, created_at: datetime()})-[:USER_TYPE]->(:Role {name: 'User'}) RETURN elementId(u) AS id",
map[string]any{
"id": id,
"username": username,
"email": email,
"password_hash": password_hash,
"profile_picture": strconv.Itoa(id) + ext,
}, neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
if len(result.Records) > 0 {
ret := struct {
Auth bool `json:"auth"`
Id string `json:"id"`
}{
Auth: true,
Id: strconv.Itoa(id),
}
json, err := json.Marshal(ret)
if err != nil {
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, string(json))
log.Println("User ID:", id, "Action: Signup")
} else {
return
}
}
}
@@ -32,38 +120,47 @@ func retrieve_all_users(driver neo4j.DriverWithContext, driver_ctx context.Conte
func retrieve_user(driver neo4j.DriverWithContext, driver_ctx context.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user_id, _ := strconv.Atoi(mux.Vars(r)["user_id"])
id, _ := strconv.Atoi(mux.Vars(r)["user_id"])
result, _ := neo4j.ExecuteQuery(driver_ctx, driver,
"MATCH (u:User) WHERE id(u) = $user_id RETURN u.username AS username, u.email AS email, u.profile_picture AS profile_picture",
map[string]any{
"user_id": user_id,
"user_id": id,
}, neo4j.EagerResultTransformer,
neo4j.ExecuteQueryWithDatabase("neo4j"))
record := result.Records[0]
vals := record.AsMap()
user := struct {
Username string `json:"username"`
Email string `json:"email"`
ProfilePicture string `json:"profile_picture"`
}{
Username: vals["username"].(string),
Email: vals["email"].(string),
ProfilePicture: vals["profile_picture"].(string),
}
if len(result.Records) > 0 {
record := result.Records[0]
vals := record.AsMap()
user := struct {
Username string `json:"username"`
Email string `json:"email"`
ProfilePicture string `json:"profile_picture"`
}{
Username: vals["username"].(string),
Email: vals["email"].(string),
ProfilePicture: vals["profile_picture"].(string),
}
json, err := json.Marshal(user)
if err != nil {
json, err := json.Marshal(user)
if err != nil {
return
}
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, string(json))
log.Println("User ID:", id, "Action: Retrieval")
} else {
return
}
send_response(w, json)
}
}
func auth_user(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")
username := r.FormValue("username")
password_hash := r.FormValue("password_hash")
@@ -96,7 +193,10 @@ func auth_user(driver neo4j.DriverWithContext, driver_ctx context.Context) http.
return
}
send_response(w, json)
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, string(json))
log.Println("User ID:", id, "Action: Login")
} else {
return
}