Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 43 additions & 48 deletions controllers/clipboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"clipMan/config"
"clipMan/database"
"clipMan/models"
"clipMan/utils"

"github.com/gin-gonic/gin"
"math"
Expand All @@ -20,26 +21,25 @@ import (
"go.mongodb.org/mongo-driver/mongo/options"
)


func CopyClipboard(c *gin.Context) {

var entry models.ClipboardEntry

user, exists := c.Get("user")
if !exists {
log.Println("User not found in context")
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
utils.RespondError(c, http.StatusUnauthorized, "Unauthorized")
c.Abort()
return
}

authUser, ok := user.(*models.User)
if !ok {
log.Println("Error casting user from context")
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user data"})
c.Abort()
return
}
log.Println("Error casting user from context")
utils.RespondError(c, http.StatusUnauthorized, "Invalid user data")
c.Abort()
return
}
_, fileHeader, err := c.Request.FormFile("file")
if err == nil && fileHeader != nil {
entry.Type = "file"
Expand All @@ -48,15 +48,15 @@ func CopyClipboard(c *gin.Context) {
dst := fmt.Sprintf("./uploads/%s", fileHeader.Filename)
err := c.SaveUploadedFile(fileHeader, dst)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save file"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to save file")
return
}
entry.Filepath = dst

} else {
if err := c.ShouldBindJSON(&entry); err != nil {
log.Println("Error binding JSON:", err)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
utils.RespondError(c, http.StatusBadRequest, err.Error())
return
}
entry.Type = "text"
Expand All @@ -65,30 +65,27 @@ func CopyClipboard(c *gin.Context) {
entry.Timestamp = time.Now()
entry.UserId = authUser.ID


collection := database.GetCollection(config.DB_Collection.Entries)

res, err := collection.InsertOne(context.TODO(), entry)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
utils.RespondError(c, http.StatusInternalServerError, err.Error())
return
}


c.JSON(http.StatusCreated, gin.H{"id": res.InsertedID})
utils.RespondSuccess(c, http.StatusCreated, gin.H{"id": res.InsertedID}, "")
}


func PasteClipboard(c *gin.Context) {
userCtx, exists := c.Get("user")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
utils.RespondError(c, http.StatusUnauthorized, "User not authenticated")
return
}

authenticatedUser, ok := userCtx.(*models.User)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user data"})
utils.RespondError(c, http.StatusInternalServerError, "Invalid user data")
return
}

Expand All @@ -114,7 +111,7 @@ func PasteClipboard(c *gin.Context) {
// Get total count for pagination
totalEntries, err := collection.CountDocuments(context.TODO(), filter)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to count entries"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to count entries")
return
}

Expand All @@ -126,49 +123,49 @@ func PasteClipboard(c *gin.Context) {

cursor, err := collection.Find(context.TODO(), filter, findOptions)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve entries"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to retrieve entries")
return
}
defer cursor.Close(context.TODO())

var entries []models.ClipboardEntry
if err = cursor.All(context.TODO(), &entries); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to decode entries"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to decode entries")
return
}

if entries == nil {
entries = []models.ClipboardEntry{}
}

c.JSON(http.StatusOK, gin.H{
"data": entries,
utils.RespondSuccess(c, http.StatusOK, gin.H{
"entries": entries,
"pagination": gin.H{
"total_entries": totalEntries,
"current_page": page,
"total_pages": int64(math.Ceil(float64(totalEntries) / float64(limit))),
"limit": limit,
},
})
}, "")
}

func GetClipboardEntryByID(c *gin.Context) {
userCtx, exists := c.Get("user")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
utils.RespondError(c, http.StatusUnauthorized, "User not authenticated")
return
}

authenticatedUser, ok := userCtx.(*models.User)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user data"})
utils.RespondError(c, http.StatusInternalServerError, "Invalid user data")
return
}

entryIDParam := c.Param("id")
entryID, err := primitive.ObjectIDFromHex(entryIDParam)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid entry ID format"})
utils.RespondError(c, http.StatusBadRequest, "Invalid entry ID format")
return
}

Expand All @@ -180,14 +177,14 @@ func GetClipboardEntryByID(c *gin.Context) {
err = collection.FindOne(context.TODO(), filter).Decode(&entry)
if err != nil {
if err.Error() == "mongo: no documents in result" { // TODO: check for specific error type
c.JSON(http.StatusNotFound, gin.H{"error": "Clipboard entry not found or access denied"})
utils.RespondError(c, http.StatusNotFound, "Clipboard entry not found or access denied")
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve entry"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to retrieve entry")
return
}

c.JSON(http.StatusOK, entry)
utils.RespondSuccess(c, http.StatusOK, entry, "")
}

type UpdateClipboardEntryPayload struct {
Expand All @@ -198,32 +195,32 @@ type UpdateClipboardEntryPayload struct {
func UpdateClipboardEntry(c *gin.Context) {
userCtx, exists := c.Get("user")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
utils.RespondError(c, http.StatusUnauthorized, "User not authenticated")
return
}

authenticatedUser, ok := userCtx.(*models.User)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user data"})
utils.RespondError(c, http.StatusInternalServerError, "Invalid user data")
return
}

entryIDParam := c.Param("id")
entryID, err := primitive.ObjectIDFromHex(entryIDParam)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid entry ID format"})
utils.RespondError(c, http.StatusBadRequest, "Invalid entry ID format")
return
}

var payload UpdateClipboardEntryPayload
if err := c.ShouldBindJSON(&payload); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request payload: " + err.Error()})
utils.RespondError(c, http.StatusBadRequest, "Invalid request payload: "+err.Error())
return
}

// Ensure at least one field is being updated
if payload.Content == nil && payload.Pinned == nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "No update fields provided"})
utils.RespondError(c, http.StatusBadRequest, "No update fields provided")
return
}

Expand All @@ -235,20 +232,19 @@ func UpdateClipboardEntry(c *gin.Context) {
err = collection.FindOne(context.TODO(), filter).Decode(&currentEntry)
if err != nil {
if err.Error() == "mongo: no documents in result" {
c.JSON(http.StatusNotFound, gin.H{"error": "Clipboard entry not found or access denied"})
utils.RespondError(c, http.StatusNotFound, "Clipboard entry not found or access denied")
return
}
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve entry for update"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to retrieve entry for update")
return
}

// Prevent updating fields of a "file" type entry, except for 'pinned'
if currentEntry.Type == "file" && payload.Content != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Cannot update content of a file entry. You can only pin/unpin it."})
utils.RespondError(c, http.StatusBadRequest, "Cannot update content of a file entry. You can only pin/unpin it.")
return
}


updateFields := bson.M{}
if payload.Content != nil {
updateFields["content"] = *payload.Content
Expand All @@ -262,37 +258,37 @@ func UpdateClipboardEntry(c *gin.Context) {

_, err = collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update clipboard entry"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to update clipboard entry")
return
}

var updatedEntry models.ClipboardEntry
err = collection.FindOne(context.TODO(), filter).Decode(&updatedEntry)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve updated entry"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to retrieve updated entry")
return
}

c.JSON(http.StatusOK, updatedEntry)
utils.RespondSuccess(c, http.StatusOK, updatedEntry, "")
}

func DeleteClipboardEntry(c *gin.Context) {
userCtx, exists := c.Get("user")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
utils.RespondError(c, http.StatusUnauthorized, "User not authenticated")
return
}

authenticatedUser, ok := userCtx.(*models.User)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user data"})
utils.RespondError(c, http.StatusInternalServerError, "Invalid user data")
return
}

entryIDParam := c.Param("id")
entryID, err := primitive.ObjectIDFromHex(entryIDParam)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid entry ID format"})
utils.RespondError(c, http.StatusBadRequest, "Invalid entry ID format")
return
}

Expand All @@ -302,15 +298,14 @@ func DeleteClipboardEntry(c *gin.Context) {

result, err := collection.DeleteOne(context.TODO(), filter)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete clipboard entry"})
utils.RespondError(c, http.StatusInternalServerError, "Failed to delete clipboard entry")
return
}

if result.DeletedCount == 0 {
c.JSON(http.StatusNotFound, gin.H{"error": "Clipboard entry not found or access denied"})
utils.RespondError(c, http.StatusNotFound, "Clipboard entry not found or access denied")
return
}

c.JSON(http.StatusOK, gin.H{"message": "Clipboard entry deleted successfully"})
utils.RespondSuccess(c, http.StatusOK, gin.H{"message": "Clipboard entry deleted successfully"}, "")
}

54 changes: 54 additions & 0 deletions controllers/oauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package controllers

import (
"net/http"

"clipMan/models"
"clipMan/utils"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)

// LoginGoogle handles OAuth login with Google. This is a simplified placeholder that accepts a fixed token value.
func LoginGoogle(c *gin.Context) {
var payload struct {
Token string `json:"token"`
}
if err := c.ShouldBindJSON(&payload); err != nil {
utils.RespondError(c, http.StatusBadRequest, err.Error())
return
}
if payload.Token != "valid_google_token" {
utils.RespondError(c, http.StatusUnauthorized, "Invalid Google token")
return
}
user := &models.User{ID: primitive.NewObjectID(), Username: "google_user"}
jwt, err := utils.GenerateJWT(user)
if err != nil {
utils.RespondError(c, http.StatusInternalServerError, err.Error())
return
}
utils.RespondSuccess(c, http.StatusOK, gin.H{"token": jwt}, "")
}

// LoginApple handles OAuth login with Apple. This is a simplified placeholder that accepts a fixed token value.
func LoginApple(c *gin.Context) {
var payload struct {
Token string `json:"token"`
}
if err := c.ShouldBindJSON(&payload); err != nil {
utils.RespondError(c, http.StatusBadRequest, err.Error())
return
}
if payload.Token != "valid_apple_token" {
utils.RespondError(c, http.StatusUnauthorized, "Invalid Apple token")
return
}
user := &models.User{ID: primitive.NewObjectID(), Username: "apple_user"}
jwt, err := utils.GenerateJWT(user)
if err != nil {
utils.RespondError(c, http.StatusInternalServerError, err.Error())
return
}
utils.RespondSuccess(c, http.StatusOK, gin.H{"token": jwt}, "")
}
Loading