// DisableUsers deactivates users' accounts. // Administrator permissions should be checked before this call. func DisableUsers(ctx context.Context, names []string) ([]UserResult, error) { s, err := db.CtxSession(ctx) if err != nil { return nil, err } coll, err := db.Coll(s, "users") if err != nil { return nil, err } now := time.Now().UTC() result := make([]UserResult, len(names)) for i, name := range names { err = coll.Update(bson.M{"_id": name, "off": false}, bson.M{"$set": bson.M{"off": true, "mt": now}}) if err != nil { errMsg := "internal error" if err == mgo.ErrNotFound { errMsg = "not found" } result[i] = UserResult{Name: name, Err: errMsg} continue } result[i] = UserResult{Name: name, Err: ""} } return result, nil }
// Shorten returns new short links. func Shorten(ctx context.Context, params []*ReqParams) ([]*CustomURL, error) { c, err := conf.FromContext(ctx) if err != nil { return nil, err } u, err := auth.ExtractUser(ctx) if err != nil { return nil, err } // check URLs pack size n := len(params) if n > c.Settings.MaxPack { return nil, fmt.Errorf("too big ReqParams pack size [%v]", n) } s, err := db.CtxSession(ctx) if err != nil { return nil, err } // prepare coll, err := db.Coll(s, "urls") if err != nil { return nil, err } now := time.Now().UTC() err = db.LockURL(s) if err != nil { return nil, err } defer db.UnlockURL(s) num, err := getMax(coll) if err != nil { return nil, err } documents := make([]interface{}, n) cus := make([]*CustomURL, n) for i, param := range params { num++ cus[i] = &CustomURL{ ID: num, Group: param.Group, Tag: param.Tag, Original: param.Original, User: u.Name, TTL: param.TTL, NotDirect: param.NotDirect, Created: now, Modified: now, Cb: param.Cb, API: param.IsAPI, } documents[i] = cus[i] } err = coll.Insert(documents...) if err != nil { return nil, err } return cus, nil }
// Export exports URLs data. func Export(ctx context.Context, filter Filter) ([]*CustomURL, [3]int, error) { var result []*CustomURL pages := [3]int{1, 1, filter.PageSize} s, err := db.CtxSession(ctx) if err != nil { return nil, pages, err } coll, err := db.Coll(s, "urls") if err != nil { return nil, pages, err } conditions := bson.M{"group": filter.Group, "tag": filter.Tag} if filter.Active { conditions["off"] = false } switch { case filter.Period[0] != nil && filter.Period[1] != nil: conditions["$and"] = []bson.M{ bson.M{"ts": bson.M{"$gte": *filter.Period[0]}}, bson.M{"ts": bson.M{"$lte": *filter.Period[1]}}, } case filter.Period[0] != nil: conditions["ts"] = bson.M{"$gte": *filter.Period[0]} case filter.Period[1] != nil: conditions["ts"] = bson.M{"$lte": *filter.Period[1]} } // TODO: add skip+limit n, err := coll.Find(conditions).Count() if err != nil { return nil, pages, err } if n == 0 { return result, pages, nil } pages[0] = filter.Page pages[1] = n / pages[2] if n%pages[2] != 0 { pages[1]++ } switch { case pages[0] < 1: pages[0] = 1 case pages[0] > pages[1]: pages[0] = pages[1] } err = coll.Find(conditions).Skip((pages[0] - 1) * pages[2]).Limit(pages[2]).Sort("-id").All(&result) if err != nil { return nil, pages, err } return result, pages, nil }
// ChangeUsers updates user's tokens. // Administrator permissions should be checked before this call. func ChangeUsers(ctx context.Context, names []string) ([]UserResult, error) { c, err := conf.FromContext(ctx) if err != nil { return nil, err } user, err := ExtractUser(ctx) if err != nil { return nil, err } s, err := db.CtxSession(ctx) if err != nil { return nil, err } coll, err := db.Coll(s, "users") if err != nil { return nil, err } now := time.Now().UTC() isAdmin := user.HasRole("admin") result := make([]UserResult, len(names)) for i, name := range names { if !isAdmin && user.Name != name { result[i] = UserResult{Name: name, U: nil, Err: "permissions error"} continue } token, hash, err := genToken(c) if err != nil { result[i] = UserResult{Name: name, U: nil, Err: "internal error"} continue } err = coll.UpdateId(name, bson.M{"$set": bson.M{"token": hash, "mt": now}}) if err != nil { errMsg := "internal error" if err == mgo.ErrNotFound { errMsg = "not found" } result[i] = UserResult{Name: name, U: nil, Err: errMsg} continue } result[i] = UserResult{Name: name, U: nil, T: token + hash, Err: ""} } return result, nil }
// CreateUsers creates new users. func CreateUsers(ctx context.Context, names []string) ([]UserResult, error) { c, err := conf.FromContext(ctx) if err != nil { return nil, err } s, err := db.CtxSession(ctx) if err != nil { return nil, err } coll, err := db.Coll(s, "users") if err != nil { return nil, err } now := time.Now().UTC() result := make([]UserResult, len(names)) for i, name := range names { token, hash, err := genToken(c) if err != nil { result[i] = UserResult{Name: name, U: nil, Err: "internal error"} continue } user := &User{ Name: name, Token: hash, Roles: []string{"user"}, Modified: now, Created: now, } if err := coll.Insert(user); err != nil { if mgo.IsDup(err) { result[i] = UserResult{Name: name, U: nil, Err: "duplicate item"} } else { result[i] = UserResult{Name: name, U: nil, Err: "internal error"} } continue } result[i] = UserResult{Name: name, U: user, T: token + hash, Err: ""} } return result, nil }
// MultiLengthen returns short URLs info for slice of links. func MultiLengthen(ctx context.Context, links []string) ([]ChangeResult, error) { var result []ChangeResult c, err := conf.FromContext(ctx) if err != nil { return nil, err } n := len(links) if n > c.Settings.MaxPack { return nil, fmt.Errorf("too big pack size [%v]", n) } s, err := db.CtxSession(ctx) if err != nil { return nil, err } coll, err := db.Coll(s, "urls") if err != nil { return nil, err } for _, link := range links { id, err := Decode(link) if err != nil { c.L.Error.Printf("decode error [%v]: %v", link, err) result = append(result, ChangeResult{Cu: &CustomURL{ID: id}, Err: "invalid value"}) continue } cu := &CustomURL{} err = coll.FindId(id).One(cu) if err != nil { msg := "internal error" if err == mgo.ErrNotFound { msg = "not found" } result = append(result, ChangeResult{Cu: &CustomURL{ID: id}, Err: msg}) continue } result = append(result, ChangeResult{Cu: cu}) } return result, nil }
// Import imports short URLs. func Import(ctx context.Context, links map[string]*ReqParams) ([]ChangeResult, error) { var result []ChangeResult c, err := conf.FromContext(ctx) if err != nil { return nil, err } u, err := auth.ExtractUser(ctx) if err != nil { return nil, err } n := len(links) if n > c.Settings.MaxPack { return nil, fmt.Errorf("too big pack size [%v]", n) } s, err := db.CtxSession(ctx) if err != nil { return nil, err } // prepare coll, err := db.Coll(s, "urls") if err != nil { return nil, err } now := time.Now().UTC() for short, param := range links { num, err := Decode(short) if err != nil { result = append(result, ChangeResult{Err: "invalid short URL value"}) continue } cu := &CustomURL{ ID: num, Group: param.Group, Tag: param.Tag, Original: param.Original, User: u.Name, TTL: param.TTL, NotDirect: param.NotDirect, Created: now, Modified: now, Cb: param.Cb, API: param.IsAPI, } // a locking of every insert is not fast // but the pack doesn't lock other operations. err = db.LockURL(s) if err != nil { return nil, err } errIns := coll.Insert(cu) err = db.UnlockURL(s) if err != nil { return nil, err } if errIns != nil { msg := "internal error" if mgo.IsDup(errIns) { msg = "duplicate item" } result = append(result, ChangeResult{Err: msg}) continue } result = append(result, ChangeResult{Cu: cu}) } return result, nil }