// HandlerTest handles test GET request. func HandlerTest(ctx context.Context, w http.ResponseWriter, r *http.Request) ErrHandler { c, err := conf.FromContext(ctx) if err != nil { return ErrHandler{err, http.StatusInternalServerError} } coll, err := db.C(ctx, "tests") if err != nil { return ErrHandler{err, http.StatusInternalServerError} } command := r.FormValue("write") switch { case c.Debug && command == "add": err = coll.Insert(bson.M{"ts": time.Now()}) case c.Debug && command == "del": err = coll.Remove(nil) } if err != nil && err != mgo.ErrNotFound { return ErrHandler{err, http.StatusInternalServerError} } n, err := coll.Count() if err != nil { return ErrHandler{err, http.StatusInternalServerError} } u, err := auth.ExtractUser(ctx) if err != nil { return ErrHandler{err, http.StatusInternalServerError} } c.L.Debug.Printf("user=%v", u) fmt.Fprintf(w, "found %v items", n) return ErrHandler{nil, http.StatusOK} }
// HandlerInfo returns main API info. func HandlerInfo(ctx context.Context, w http.ResponseWriter, r *http.Request) core.ErrHandler { c, err := conf.FromContext(ctx) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } user, err := auth.ExtractUser(ctx) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } result := &infoResponse{ Err: 0, Msg: "ok", Result: []infoResponseItem{ infoResponseItem{ Version: Version, AuthOk: !user.IsAnonymous(), PackSize: c.Settings.MaxPack, }, }, } b, err := json.Marshal(result) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", b) return core.ErrHandler{Err: nil, Status: http.StatusOK} }
// 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 }
// HandlerUserAdd creates new user. func HandlerUserAdd(ctx context.Context, w http.ResponseWriter, r *http.Request) core.ErrHandler { var uar []userAddRequest user, err := auth.ExtractUser(ctx) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } if !user.HasRole("admin") { return core.ErrHandler{Err: errors.New("permissions error"), Status: http.StatusForbidden} } defer r.Body.Close() decoder := json.NewDecoder(r.Body) err = decoder.Decode(&uar) if (err != nil) && (err != io.EOF) { return core.ErrHandler{Err: err, Status: http.StatusBadRequest} } if len(uar) == 0 { return core.ErrHandler{Err: ErrEmptyRequest, Status: http.StatusNoContent} } names := make([]string, len(uar)) for i, v := range uar { names[i] = v.Name } usersResult, err := auth.CreateUsers(ctx, names) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } items := make([]userAddResponseItem, len(usersResult)) for i, ur := range usersResult { if ur.Err != "" { items[i] = userAddResponseItem{ Name: ur.Name, Token: "", Err: ur.Err, } } else { items[i] = userAddResponseItem{ Name: ur.U.Name, Token: ur.T, Err: "", } } } result := &userAddResponse{ Err: 0, Msg: "ok", Result: items, } b, err := json.Marshal(result) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", b) return core.ErrHandler{Err: nil, Status: http.StatusOK} }
// 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 }
// HandlerExport exports URLs data. func HandlerExport(ctx context.Context, w http.ResponseWriter, r *http.Request) core.ErrHandler { const ( layout = "2006-01-02" pageSize = 1000 ) c, err := conf.FromContext(ctx) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } user, err := auth.ExtractUser(ctx) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } if !user.HasRole("admin") { return core.ErrHandler{Err: errors.New("permissions error"), Status: http.StatusForbidden} } defer r.Body.Close() exp := &exportRequest{} decoder := json.NewDecoder(r.Body) err = decoder.Decode(exp) if (err != nil) && (err != io.EOF) { return core.ErrHandler{Err: err, Status: http.StatusBadRequest} } period, err := exp.parsePeriod() if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } filter := trim.Filter{ Group: exp.Group, Tag: exp.Tag, Period: period, Active: exp.Active, Page: exp.Page, PageSize: pageSize, } cus, pages, err := trim.Export(ctx, filter) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } items := make([]exportResponseItem, len(cus)) for i, cu := range cus { id := cu.String() items[i] = exportResponseItem{ ID: id, Short: c.Address(id), Original: cu.Original, Group: cu.Group, Tag: cu.Tag, Created: cu.Created.UTC().Format(layout), } } result := &exportResponse{ Err: 0, Msg: "ok", Pages: pages, Result: items, } b, err := json.Marshal(result) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", b) return core.ErrHandler{Err: nil, Status: http.StatusOK} }
// HandlerImport imports predefined short URLs. func HandlerImport(ctx context.Context, w http.ResponseWriter, r *http.Request) core.ErrHandler { var imprs []importRequestItem user, err := auth.ExtractUser(ctx) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } if !user.HasRole("admin") { return core.ErrHandler{Err: errors.New("permissions error"), Status: http.StatusForbidden} } defer r.Body.Close() decoder := json.NewDecoder(r.Body) err = decoder.Decode(&imprs) if (err != nil) && (err != io.EOF) { return core.ErrHandler{Err: err, Status: http.StatusBadRequest} } n := len(imprs) if n == 0 { return core.ErrHandler{Err: ErrEmptyRequest, Status: http.StatusNoContent} } links := make(map[string]*trim.ReqParams, n) for _, impr := range imprs { params := &trim.ReqParams{ Original: impr.Original, Tag: "", NotDirect: false, IsAPI: true, TTL: nil, Group: "", Cb: trim.CallBack{}, } err = params.Valid() if err != nil { return core.ErrHandler{Err: err, Status: http.StatusBadRequest} } links[impr.Short] = params } cus, err := trim.Import(ctx, links) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } items := make([]importResponseItem, len(cus)) for i, cu := range cus { if cu.Err != "" { items[i] = importResponseItem{Err: cu.Err} } else { items[i] = importResponseItem{Short: cu.Cu.String()} } } result := &importResponse{ Err: 0, Msg: "ok", Result: items, } b, err := json.Marshal(result) if err != nil { return core.ErrHandler{Err: err, Status: http.StatusInternalServerError} } w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, "%s", b) return core.ErrHandler{Err: nil, Status: http.StatusOK} }