package posts import ( "errors" "git.aiterp.net/rpdata/api/models" "github.com/globalsign/mgo/bson" ) // Move the post func Move(post models.Post, toPosition int) ([]models.Post, error) { if toPosition < 1 { return nil, errors.New("Invalid position") } mutex.Lock() defer mutex.Unlock() // To avoid problems, only allow target indices that are allowed. If it's 1, then there is bound to // be a post at the position. if toPosition > 1 { existing := models.Post{} err := collection.Find(bson.M{"logId": post.LogID, "position": toPosition}).One(&existing) if err != nil || existing.Position != toPosition { return nil, errors.New("No post found at the position") } } query := bson.M{"logId": post.LogID} operation := bson.M{"$inc": bson.M{"position": 1}} if toPosition < post.Position { query["$and"] = []bson.M{ bson.M{"position": bson.M{"$gte": toPosition}}, bson.M{"position": bson.M{"$lt": post.Position}}, } } else { query["$and"] = []bson.M{ bson.M{"position": bson.M{"$gt": post.Position}}, bson.M{"position": bson.M{"$lte": toPosition}}, } operation["$inc"] = bson.M{"position": -1} } _, err := collection.UpdateAll(query, operation) if err != nil { return nil, errors.New("Moving others failed: " + err.Error()) } err = collection.UpdateId(post.ID, bson.M{"$set": bson.M{"position": toPosition}}) if err != nil { return nil, errors.New("Moving failed: " + err.Error() + " (If you see this on the page, please let me know ASAP)") } from, to := post.Position, toPosition if to < from { from, to = to, from } posts := make([]models.Post, 0, (to-from)+1) err = collection.Find(bson.M{"logId": post.LogID, "position": bson.M{"$gte": from, "$lte": to}}).Sort("position").All(&posts) if err != nil { return nil, errors.New("The move completed successfully, but finding the moved posts failed: " + err.Error()) } return posts, nil }