Example #1
0
File: auth.go Project: z0rr0/luss
// 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
}
Example #2
0
File: trim.go Project: z0rr0/luss
// 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
}
Example #3
0
File: trim.go Project: z0rr0/luss
// 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
}
Example #4
0
File: auth.go Project: z0rr0/luss
// 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
}
Example #5
0
File: auth.go Project: z0rr0/luss
// 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
}
Example #6
0
File: trim.go Project: z0rr0/luss
// 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
}
Example #7
0
File: trim.go Project: z0rr0/luss
// 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
}