// GET: /node // To do: // - Iterate node queries func (cr *NodeController) ReadMany(ctx context.Context) error { u, err := request.Authenticate(ctx.HttpRequest()) if err != nil && err.Error() != e.NoAuth { return request.AuthError(err, ctx) } // Gather query params query := ctx.HttpRequest().URL.Query() // Setup query and nodes objects q := bson.M{} nodes := node.Nodes{} if u != nil { // Admin sees all if !u.Admin { q["$or"] = []bson.M{bson.M{"acl.read": []string{}}, bson.M{"acl.read": u.Uuid}, bson.M{"acl.owner": u.Uuid}} } } else { if conf.Bool(conf.Conf["anon-read"]) { // select on only nodes with no read rights set q["acl.read"] = []string{} } else { return responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth) } } // Gather params to make db query. Do not include the // following list. paramlist := map[string]int{"limit": 1, "offset": 1, "query": 1, "querynode": 1, "owner": 1, "read": 1, "write": 1, "delete": 1, "public_owner": 1, "public_read": 1, "public_write": 1, "public_delete": 1} if _, ok := query["query"]; ok { for key := range query { if _, found := paramlist[key]; !found { keyStr := fmt.Sprintf("attributes.%s", key) value := query.Get(key) if value != "" { if numValue, err := strconv.Atoi(value); err == nil { q["$or"] = ListOfMaps{{keyStr: value}, {keyStr: numValue}} } else if value == "null" { q["$or"] = ListOfMaps{{keyStr: value}, {keyStr: nil}} } else { q[keyStr] = value } } else { existsMap := map[string]bool{ "$exists": true, } q[keyStr] = existsMap } } } } else if _, ok := query["querynode"]; ok { for key := range query { if _, found := paramlist[key]; !found { value := query.Get(key) if value != "" { if numValue, err := strconv.Atoi(value); err == nil { q["$or"] = ListOfMaps{{key: value}, {key: numValue}} } else if value == "null" { q["$or"] = ListOfMaps{{key: value}, {key: nil}} } else { q[key] = value } } else { existsMap := map[string]bool{ "$exists": true, } q[key] = existsMap } } } } // defaults limit := 25 offset := 0 if _, ok := query["limit"]; ok { limit = util.ToInt(query.Get("limit")) } if _, ok := query["offset"]; ok { offset = util.ToInt(query.Get("offset")) } // Allowing user to query based on ACL's with a comma-separated list of users. // Users can be written as a username or a UUID. for _, atype := range []string{"owner", "read", "write", "delete"} { if _, ok := query[atype]; ok { users := strings.Split(query.Get(atype), ",") for _, v := range users { if uuid.Parse(v) != nil { q["acl."+atype] = v } else { u := user.User{Username: v} if err := u.SetMongoInfo(); err != nil { err_msg := "err " + err.Error() logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } q["acl."+atype] = u.Uuid } } } } if _, ok := query["public_owner"]; ok { // If search is for public_owner AND owner = non-empty string then return zero nodes, no nodes can match this query. if _, exists := q["acl.owner"]; exists { return responder.RespondWithPaginatedData(ctx, nodes, limit, offset, 0) } q["acl.owner"] = "" } // Allowing users to query based on whether ACL is public for _, atype := range []string{"read", "write", "delete"} { if _, ok := query["public_"+atype]; ok { sizeMap := map[string]int{ "$size": 0, } // Currently a node cannot be public and have an ACL at the same time, so this returns zero nodes. if _, exists := q["acl."+atype]; exists { return responder.RespondWithPaginatedData(ctx, nodes, limit, offset, 0) } else { q["acl."+atype] = sizeMap } } } // Get nodes from db count, err := nodes.GetPaginated(q, limit, offset) if err != nil { err_msg := "err " + err.Error() logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } return responder.RespondWithPaginatedData(ctx, nodes, limit, offset, count) }
// GET: /node // To do: // - Iterate node queries func (cr *NodeController) ReadMany(ctx context.Context) error { u, err := request.Authenticate(ctx.HttpRequest()) if err != nil && err.Error() != e.NoAuth { return request.AuthError(err, ctx) } // Gather query params query := ctx.HttpRequest().URL.Query() // Setup query and nodes objects q := bson.M{} nodes := node.Nodes{} if u != nil { // Admin sees all if !u.Admin { q["$or"] = []bson.M{bson.M{"acl.read": []string{}}, bson.M{"acl.read": u.Uuid}, bson.M{"acl.owner": u.Uuid}} } } else { if conf.Bool(conf.Conf["anon-read"]) { // select on only nodes with no read rights set q["acl.read"] = []string{} } else { return responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth) } } // Gather params to make db query. Do not include the // following list. paramlist := map[string]int{"limit": 1, "offset": 1, "query": 1, "querynode": 1} if _, ok := query["query"]; ok { for key := range query { if _, found := paramlist[key]; !found { q[fmt.Sprintf("attributes.%s", key)] = query.Get(key) } } } else if _, ok := query["querynode"]; ok { for key := range query { if key == "type" { querytypes := strings.Split(query.Get(key), ",") q["type"] = bson.M{"$all": querytypes} } else { if _, found := paramlist[key]; !found { q[key] = query.Get(key) } } } } // defaults limit := 25 offset := 0 if _, ok := query["limit"]; ok { limit = util.ToInt(query.Get("limit")) } if _, ok := query["offset"]; ok { offset = util.ToInt(query.Get("offset")) } // Get nodes from db count, err := nodes.GetPaginated(q, limit, offset) if err != nil { err_msg := "err " + err.Error() logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } return responder.RespondWithPaginatedData(ctx, nodes, limit, offset, count) }
// GET: /node // To do: // - Iterate node queries func (cr *NodeController) ReadMany(ctx context.Context) error { u, err := request.Authenticate(ctx.HttpRequest()) if err != nil && err.Error() != e.NoAuth { return request.AuthError(err, ctx) } // Gather query params query := ctx.HttpRequest().URL.Query() // Setup query and nodes objects // Note: query is composed of 3 sub-query objects: // 1) qPerm - user permissions (system-defined) // 2) qOpts - query options (user-defined) // 3) qAcls - ACL queries (user-defined) q := bson.M{} qPerm := bson.M{} qOpts := bson.M{} qAcls := bson.M{} nodes := node.Nodes{} if u != nil { // Skip this part if user is an admin if !u.Admin { qPerm["$or"] = []bson.M{bson.M{"acl.read": "public"}, bson.M{"acl.read": u.Uuid}, bson.M{"acl.owner": u.Uuid}} } } else { // User is anonymous if conf.ANON_READ { // select on only nodes that are publicly readable qPerm["acl.read"] = "public" } else { return responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth) } } // bson.M is a convenient alias for a map[string]interface{} map, useful for dealing with BSON in a native way. var OptsMArray []bson.M // Gather params to make db query. Do not include the following list. if _, ok := query["query"]; ok { paramlist := map[string]int{"query": 1, "limit": 1, "offset": 1, "order": 1, "direction": 1, "distinct": 1} for key := range query { if _, found := paramlist[key]; !found { keyStr := fmt.Sprintf("attributes.%s", key) for _, value := range query[key] { if value != "" { OptsMArray = append(OptsMArray, parseOption(keyStr, value)) } else { OptsMArray = append(OptsMArray, bson.M{keyStr: map[string]bool{"$exists": true}}) } } } } } else if _, ok := query["querynode"]; ok { paramlist := map[string]int{"querynode": 1, "limit": 1, "offset": 1, "order": 1, "direction": 1, "distinct": 1, "owner": 1, "read": 1, "write": 1, "delete": 1, "public_owner": 1, "public_read": 1, "public_write": 1, "public_delete": 1} for key := range query { if _, found := paramlist[key]; !found { for _, value := range query[key] { if value != "" { OptsMArray = append(OptsMArray, parseOption(key, value)) } else { OptsMArray = append(OptsMArray, bson.M{key: map[string]bool{"$exists": true}}) } } } } } if len(OptsMArray) > 0 { qOpts["$and"] = OptsMArray } // bson.M is a convenient alias for a map[string]interface{} map, useful for dealing with BSON in a native way. var AclsMArray []bson.M // Allowing user to query based on ACL's with a comma-separated list of users. // Restricting ACL queries to just the querynode operation. // Users can be written as a username or a UUID. if _, qok := query["querynode"]; qok { for _, atype := range []string{"owner", "read", "write", "delete"} { if _, ok := query[atype]; ok { users := strings.Split(query.Get(atype), ",") for _, v := range users { if uuid.Parse(v) != nil { AclsMArray = append(AclsMArray, bson.M{"acl." + atype: v}) } else { u := user.User{Username: v} if err := u.SetMongoInfo(); err != nil { err_msg := "err " + err.Error() logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } AclsMArray = append(AclsMArray, bson.M{"acl." + atype: u.Uuid}) } } } } // Allowing users to query based on whether ACL is public for _, atype := range []string{"owner", "read", "write", "delete"} { if _, ok := query["public_"+atype]; ok { AclsMArray = append(AclsMArray, bson.M{"acl." + atype: "public"}) } } } if len(AclsMArray) > 0 { qAcls["$and"] = AclsMArray } // Combine permissions query with query parameters and ACL query into one AND clause q["$and"] = []bson.M{qPerm, qOpts, qAcls} // process distinct query if _, ok := query["distinct"]; ok { dField := query.Get("distinct") if !node.HasAttributeField(dField) { err_msg := "err unable to run distinct query on non-indexed attributes field: " + dField logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } results, err := node.DbFindDistinct(q, dField) if err != nil { err_msg := "err " + err.Error() logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } return responder.RespondWithData(ctx, results) } // defaults order := "created_on" direction := "-" limit := 25 offset := 0 // get from query if _, ok := query["query"]; ok { if _, ok := query["order"]; ok { order = fmt.Sprintf("attributes.%s", query.Get("order")) } } else { if _, ok := query["order"]; ok { order = query.Get("order") } } if _, ok := query["direction"]; ok { if query.Get("direction") == "asc" { direction = "" } } if _, ok := query["limit"]; ok { limit = util.ToInt(query.Get("limit")) } if _, ok := query["offset"]; ok { offset = util.ToInt(query.Get("offset")) } // Get nodes from db order = direction + order count, err := nodes.GetPaginated(q, limit, offset, order) if err != nil { err_msg := "err " + err.Error() logger.Error(err_msg) return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg) } return responder.RespondWithPaginatedData(ctx, nodes, limit, offset, count) }