Jade/main.go
2024-04-21 14:32:32 +02:00

177 lines
4.7 KiB
Go

package main
import (
"context"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/template/django/v3"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var mongoClient *mongo.Client
type Message struct {
ID primitive.ObjectID `bson:"_id"`
Content string `bson:"message"`
Role string `bson:"role"`
Date time.Time `bson:"date"`
}
type Conversation struct {
ID string
Messages []Message
}
func connectToMongoDB(uri string) {
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI(uri).SetServerAPIOptions(serverAPI)
client, err := mongo.Connect(context.TODO(), opts)
if err != nil {
panic(err)
}
mongoClient = client
if err := mongoClient.Ping(context.TODO(), nil); err != nil {
panic(err)
}
}
func main() {
// Import HTML using django engine/template
engine := django.New("./views", ".html")
if engine == nil {
panic("Failed to create django engine")
}
// Create new Fiber instance. Can use any framework. I use fiber for speed and simplicity
app := fiber.New(fiber.Config{
Views: engine,
AppName: "JADE 2.0",
EnablePrintRoutes: true,
})
// Initialize
go connectToMongoDB("mongodb://localhost:27017")
// Add default logger
app.Use(logger.New())
// Add static files
app.Static("/", "./static")
// Add routes
app.Get("/", indexHandler)
app.Get("/isMongoDBConnected", isMongoDBConnectedHandler)
app.Get("/chat", chatPageHandler) // Complete chat page
app.Put("/chat", addMessageHandler) // Add message
app.Delete("/chat", deleteMessageHandler) // Delete message
// Start server
app.Listen(":3000")
}
func indexHandler(c *fiber.Ctx) error {
return c.Render("welcome", fiber.Map{}, "layouts/main")
}
func chatPageHandler(c *fiber.Ctx) error {
return c.Render("chat", fiber.Map{
"Messages": []Message{},
}, "layouts/main")
}
func addMessageHandler(c *fiber.Ctx) error {
message := c.FormValue("message")
collection := mongoClient.Database("chat").Collection("messages")
collection.InsertOne(context.Background(), bson.M{"message": message, "role": "user", "date": time.Now()})
collection.InsertOne(context.Background(), bson.M{"message": "I did something!", "role": "bot", "date": time.Now()})
return generateChatHTML(c)
}
func deleteMessageHandler(c *fiber.Ctx) error {
messageId := c.FormValue("messageId")
// Convert the string ID to a MongoDB ObjectID
objID, err := primitive.ObjectIDFromHex(messageId)
if err != nil {
// If the conversion fails, return an error response
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid message ID format",
})
}
// Delete messages in the database. This one and all the following ones
collection := mongoClient.Database("chat").Collection("messages")
// Get the date of the message
var message Message
err = collection.FindOne(context.TODO(), bson.M{"_id": objID}).Decode(&message)
if err != nil {
if err == mongo.ErrNoDocuments {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"error": "Message not found",
})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Failed to find message",
})
}
// Delete the message and all messages with a date after the specified date
filter := bson.M{
"$or": []bson.M{
{"_id": objID},
{"date": bson.M{"$gt": message.Date}},
},
}
_, err = collection.DeleteMany(context.TODO(), filter)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Failed to delete messages",
})
}
return generateChatHTML(c)
}
func generateChatHTML(c *fiber.Ctx) error {
// Get the messages from the database
collection := mongoClient.Database("chat").Collection("messages")
// Get all messages
cursor, err := collection.Find(context.TODO(), bson.D{})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Failed to find messages",
})
}
// Convert the cursor to an array of messages
var messages []Message
if err = cursor.All(context.TODO(), &messages); err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Failed to convert cursor to array",
})
}
// Render the HTML template with the messages
return c.Render("chat", fiber.Map{
"messages": messages,
})
}
func isMongoDBConnectedHandler(c *fiber.Ctx) error {
if mongoClient != nil {
return c.SendString("<h1>Connected</h1>")
}
return c.SendString("<h1 id='isMongoDBConnected' hx-get='/isMongoDBConnected' hx-trigger='every 1s' hx-swap='outerHTM'>Not connected</h1>")
}