// FriendshipIndex takes in query params through // gin.Context and is restricted to the currentUser // @returns an array of friendship JSON objects func FriendshipIndex(c *gin.Context) { friendships := []models.Friendship{} var curUser models.User database.DBCon.First(&curUser, c.Keys["CurrentUserID"]) database.DBCon.Model(&curUser).Related(&friendships, "Friendships") // Get user and friend and friendshipData // TODO: n + 1 query problem here, so we'll figure this out later for i := range friendships { var fd models.FriendshipData database.DBCon.First(&friendships[i].Friend, friendships[i].FriendID) database.DBCon.First(&fd, friendships[i].FriendshipDataID) if curUser.ID == fd.PositiveUserID { friendships[i].Balance = fd.Balance } else { friendships[i].Balance = -fd.Balance } friendships[i].User = curUser } data, err := jsonapi.Marshal(friendships) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// FriendshipShow takes a given ID from gin.Context // @returns a specific friendship JSON object func FriendshipShow(c *gin.Context) { friendship := models.Friendship{} if database.DBCon.First(&friendship, c.Param("id")).RecordNotFound() { c.AbortWithError(http.StatusNotFound, appError.RecordNotFound). SetMeta(appError.RecordNotFound) return } var fd models.FriendshipData database.DBCon.First(&friendship.User, friendship.UserID) database.DBCon.First(&friendship.Friend, friendship.FriendID) database.DBCon.First(&fd, friendship.FriendshipDataID) if friendship.UserID == fd.PositiveUserID { friendship.Balance = fd.Balance } else { friendship.Balance = -fd.Balance } data, err := jsonapi.Marshal(friendship) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// UserShow is used to show one specific user // @returns a user struct func UserShow(c *gin.Context) { var user models.User database.DBCon.First(&user, c.Param("id")) data, err := jsonapi.Marshal(jsonapi.MarshalIncludedRelations(user)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "couldn't marshal to json"}) } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// UserIndex is used when the user's index is routed to // this handler will run. Generally, it will // come with some query parameters like limit and offset // @returns an array of users func UserIndex(c *gin.Context) { var users []models.User number, err := strconv.Atoi(c.Param("limit")) database.DBCon.Limit(number).Find(&users) data, err := jsonapi.Marshal(users) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "couldn't marshal to json"}) } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// MarshalJSON returns as as the JSON encoding of as. func (as AppSet) MarshalJSON() ([]byte, error) { var ( app []byte appJSON map[string]map[string]interface{} container []byte containerJSON map[string]map[string]interface{} marshaled []byte err error ) if app, err = jsonapi.Marshal(as.App); err != nil { return nil, err } if err = json.Unmarshal(app, &appJSON); err != nil { return nil, err } if container, err = jsonapi.Marshal(as.Container); err != nil { return nil, err } if err = json.Unmarshal(container, &containerJSON); err != nil { return nil, err } data := map[string][]map[string]interface{}{ "data": []map[string]interface{}{ appJSON["data"], containerJSON["data"], }, } if marshaled, err = json.Marshal(data); err != nil { return nil, err } return marshaled, nil }
func JSON(c *echo.Context, code int, i interface{}) error { b, err := jsonapi.Marshal(i) if err != nil { return err } r := c.Response() r.Header().Set("Content-Type", "application/vnd.api+json") r.WriteHeader(code) r.Write(b) return nil }
// TransactionIndex outputs a certain number of transactions // will always be scoped to the current user func TransactionIndex(c *gin.Context) { relatedObjectID := c.Query("relatedObjectId") relatedObjectType := c.Query("relatedObjectType") isSettledQuery := c.Query("isSettled") statusQuery := c.Query("status") curUserID := c.Keys["CurrentUserID"] var transactions []models.Transaction query := database.DBCon isSettled, err := strconv.ParseBool(isSettledQuery) if isSettledQuery != "" && err == nil { query = query.Where("is_settled = ?", isSettled) } // TODO: Check that statusQuery is a valid status if statusQuery != "" { query = query.Where("status = ?", statusQuery) } if relatedObjectID != "" && relatedObjectType != "" { query. Where("related_object_id = ? AND related_object_type = ?", relatedObjectID, relatedObjectType). Order("created_at desc"). Find(&transactions) } else { query. Where("creator_id = ?", curUserID). Find(&transactions) } // Get creator and relatedUser // TODO: n + 1 query problem here, so we'll figure this out later for i := range transactions { database.DBCon.First(&transactions[i].Recipient, transactions[i].RecipientID) database.DBCon.First(&transactions[i].Sender, transactions[i].SenderID) database.DBCon.First(&transactions[i].Creator, transactions[i].CreatorID) } data, err := jsonapi.Marshal(transactions) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// DeviceTokenCreate will create a deviceToken for a specified user // @parameters // @requires deviceType // @requires token // @returns the newly created deviceToken func DeviceTokenCreate(c *gin.Context) { var dt models.DeviceToken buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &dt) if err2 != nil { parseFail := appError.JSONParseFailure parseFail.Detail = err2.Error() c.AbortWithError(http.StatusMethodNotAllowed, err2). SetMeta(parseFail) return } dt.UserID = c.Keys["CurrentUserID"].(uint) // Validate our new deviceToken isValid, errApp := dt.Validate() if isValid == false { c.AbortWithError(errApp.Status, errApp). SetMeta(errApp) return } var existingDeviceToken models.DeviceToken // If deviceToken is not found, then create the token // else update the existing device token with the new one if database.DBCon.Where("user_id = ?", dt.UserID).First(&existingDeviceToken).RecordNotFound() { database.DBCon.Create(&dt) } else { database.DBCon.Model(&existingDeviceToken).Update("token", dt.Token) dt = existingDeviceToken } data, err := jsonapi.Marshal(&dt) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusCreated, "application/vnd.api+json", data) }
// GroupIndex When the group's index is routed to // this handler will run. Generally, it will // come with some query parameters like limit and offset // @returns an array of group structs func GroupIndex(c *gin.Context) { groups := []models.Group{} var curUser models.User database.DBCon.First(&curUser, c.Keys["CurrentUserID"]) database.DBCon.Model(&curUser).Preload("Users").Related(&groups, "Groups") data, err := jsonapi.Marshal(groups) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// TransactionCreate will create a transaction that occurs // between two users in a group // @parameters // @requires type // @requires amount // @requires relatedObjectId // @requires relatedObjectType // @requires recipientId // @requires senderid // @optional memo // @returns the newly created transaction func TransactionCreate(c *gin.Context) { var t models.Transaction buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &t) if err2 != nil { parseFail := appError.JSONParseFailure parseFail.Detail = err2.Error() c.AbortWithError(http.StatusMethodNotAllowed, err2). SetMeta(parseFail) return } t.CreatorID = c.Keys["CurrentUserID"].(uint) // Validate our new transaction isValid, errApp := t.Validate() if isValid == false { c.AbortWithError(errApp.Status, errApp). SetMeta(errApp) return } database.DBCon.Create(&t) database.DBCon.First(&t.Recipient, t.RecipientID) database.DBCon.First(&t.Sender, t.SenderID) database.DBCon.First(&t.Creator, t.CreatorID) data, err := jsonapi.Marshal(&t) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusCreated, "application/vnd.api+json", data) }
// GroupShow is used to show one specific group, returns a group struct // @returns a group struct func GroupShow(c *gin.Context) { var group models.Group var users []models.User if database.DBCon.First(&group, c.Param("id")).RecordNotFound() { c.AbortWithError(http.StatusNotFound, appError.RecordNotFound). SetMeta(appError.RecordNotFound) return } database.DBCon.Model(&group).Related(&users, "Users") group.Users = users data, err := jsonapi.Marshal(group) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// GroupUpdate is used to update a specific group, it'll also come with some form data' // @returns a group struct func GroupUpdate(c *gin.Context) { var group models.Group buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &group) if err2 != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } // Little hack-ish // Remove all current relations database.DBCon.Exec("DELETE FROM group_users WHERE group_id = ?", group.ID) // Add all the given relations for _, c := range group.UserIDs { database.DBCon. Exec("INSERT INTO group_users (group_id, user_id) VALUES (?, ?)", group.ID, c) } database.DBCon.First(&group, group.ID) database.DBCon.Model(&group).Related(&group.Users, "Users") data, err := jsonapi.Marshal(group) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }
// GroupCreate is used to create one specific group, it'll come with some form data // @returns a group struct func GroupCreate(c *gin.Context) { var group models.Group buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &group) if err2 != nil { parseFail := appError.JSONParseFailure parseFail.Detail = err2.Error() c.AbortWithError(http.StatusMethodNotAllowed, err2). SetMeta(parseFail) return } database.DBCon.Create(&group) // Add current user to the group database.DBCon. Exec("INSERT INTO group_users (group_id, user_id) VALUES (?, ?)", group.ID, c.Keys["CurrentUserID"].(uint)) database.DBCon.Model(&group).Related(&group.Users, "Users") data, err3 := jsonapi.Marshal(&group) if err3 != nil { c.AbortWithError(http.StatusInternalServerError, err3). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusCreated, "application/vnd.api+json", data) }
func Get(c *echo.Context) error { filepath := c.Query("path") showHidden := c.Query("show_hidden") == "true" create := c.Query("create") == "true" if len(filepath) < 1 { return c.JSON( http.StatusBadRequest, hash{ "error": "Path not specified", }, ) } s, err := os.Stat(filepath) if err != nil { log.Error(err.(*os.PathError).Err.Error()) m := err.(*os.PathError).Err.Error() if m == "no such file or directory" || m == "The system cannot find the file specified." { if create { err := os.MkdirAll(filepath, 0777) if err != nil { return err } s, err = os.Stat(filepath) if err != nil { return err } } else { return c.JSON( http.StatusNotFound, hash{ "error": "no such file or directory", }, ) } } else { return err } } if s.Mode().IsDir() { f, err := os.Open(filepath) if err != nil { return err } defer f.Close() files, err := f.Readdir(-1) if err != nil { return err } rt := make([]*file, 0) for _, fi := range files { name := fi.Name() if !showHidden && isFileHidden(fi) { continue } fullpath := path.Join(filepath, name) id, err := loadFileId(fullpath) if err != nil { log.Errorf("Cannot retrieve file id for file: %s: %s", fullpath, err.Error()) continue } f := &file{ Id: id, ModTime: fi.ModTime().Unix(), Name: name, Size: fi.Size(), } if fi.IsDir() { f.Type = "directory" } else { f.Type = "regular file" } rt = append(rt, f) } /* * The Content-Length is not set is the buffer length is more than 2048 */ b, err := jsonapi.Marshal(rt) if err != nil { log.Error(err) return err } r := c.Response() r.Header().Set("Content-Length", strconv.Itoa(len(b))) r.Header().Set("Content-Type", "application/json; charset=utf-8") r.Write(b) return nil } return c.File( filepath, s.Name(), true, ) }
// TransactionUpdate will update an existing transaction // between two users in a group // @parameters // @requires id // @optional type // @optional recipientId // @optional senderId // @optional amount // @optional memo // @returns the updated transaction func TransactionUpdate(c *gin.Context) { var t models.Transaction var newT models.Transaction if database.DBCon.First(&t, c.Param("id")).RecordNotFound() { c.AbortWithError(http.StatusNotFound, appError.RecordNotFound). SetMeta(appError.RecordNotFound) return } // Ensure current user is creator of transaction if t.CreatorID != c.Keys["CurrentUserID"].(uint) { c.AbortWithError(appError.InsufficientPermission.Status, appError.InsufficientPermission). SetMeta(appError.InsufficientPermission) return } buffer, err := ioutil.ReadAll(c.Request.Body) if err != nil { c.AbortWithError(http.StatusNotAcceptable, err) } err2 := jsonapi.Unmarshal(buffer, &newT) if err2 != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } t.Type = newT.Type t.Amount = newT.Amount t.Memo = newT.Memo t.RecipientID = newT.RecipientID t.SenderID = newT.SenderID // Validate our new transaction isValid, errApp := t.Validate() if isValid == false { c.AbortWithError(errApp.Status, errApp). SetMeta(errApp) return } database.DBCon.Save(&t) database.DBCon.First(&t.Recipient, t.RecipientID) database.DBCon.First(&t.Sender, t.SenderID) database.DBCon.First(&t.Creator, t.CreatorID) data, err := jsonapi.Marshal(&t) if err != nil { c.AbortWithError(http.StatusInternalServerError, err). SetMeta(appError.JSONParseFailure) return } c.Data(http.StatusOK, "application/vnd.api+json", data) }