Пример #1
0
func parseAclRequestTyped(cx *goweb.Context) (ids []string, err error) {
	var users []string
	query := util.Q(cx.Request.URL.Query())
	params, _, err := request.ParseMultipartForm(cx.Request)
	if err != nil && err.Error() == "request Content-Type isn't multipart/form-data" && query.Has("users") {
		users = strings.Split(query.Value("users"), ",")
	} else if params["users"] != "" {
		users = strings.Split(params["users"], ",")
	} else {
		return nil, errors.New("Action requires list of comma seperated email address in 'users' parameter")
	}
	for _, v := range users {
		if isEmail(v) {
			u := user.User{Username: v, Email: v}
			if err := u.SetUuid(); err != nil {
				return nil, err
			}
			ids = append(ids, u.Uuid)
		} else if isUuid(v) {
			ids = append(ids, v)
		} else {
			return nil, errors.New("Unknown user id. Must be uuid or email address")
		}
	}
	return ids, nil
}
Пример #2
0
// POST: /node
func (cr *Controller) Create(cx *goweb.Context) {
	// Log Request and check for Auth
	request.Log(cx.Request)
	u, err := request.Authenticate(cx.Request)
	if err != nil && err.Error() != e.NoAuth {
		request.AuthError(err, cx)
		return
	}

	// Fake public user
	if u == nil {
		if conf.Bool(conf.Conf["anon-write"]) {
			u = &user.User{Uuid: ""}
		} else {
			cx.RespondWithErrorMessage(e.NoAuth, http.StatusUnauthorized)
			return
		}
	}

	// Parse uploaded form
	params, files, err := request.ParseMultipartForm(cx.Request)
	if err != nil {
		// If not multipart/form-data it will create an empty node.
		// TODO: create another request parser for non-multipart request
		// to handle this cleaner.
		if err.Error() == "request Content-Type isn't multipart/form-data" {
			n, err := node.CreateNodeUpload(u, params, files)
			if err != nil {
				logger.Error("Error at create empty: " + err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
			if n == nil {
				// Not sure how you could get an empty node with no error
				// Assume it's the user's fault
				cx.RespondWithError(http.StatusBadRequest)
				return
			} else {
				cx.RespondWithData(n)
				return
			}
		} else {
			// Some error other than request encoding. Theoretically
			// could be a lost db connection between user lookup and parsing.
			// Blame the user, Its probaby their fault anyway.
			logger.Error("Error parsing form: " + err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	}
	// Create node
	n, err := node.CreateNodeUpload(u, params, files)
	if err != nil {
		logger.Error("err@node_CreateNodeUpload: " + err.Error())
		cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
		return
	}
	cx.RespondWithData(n)
	return
}
Пример #3
0
func parseAclRequest(cx *goweb.Context) (ids map[string][]string, err error) {
	ids = map[string][]string{}
	users := map[string][]string{}
	query := util.Q(cx.Request.URL.Query())
	params, _, err := request.ParseMultipartForm(cx.Request)
	if err != nil && err.Error() == "request Content-Type isn't multipart/form-data" && (query.Has("all") || query.Has("read") || query.Has("write") || query.Has("delete")) {
		if query.Has("all") {
			users["all"] = strings.Split(query.Value("all"), ",")
		}
		if query.Has("read") {
			users["read"] = strings.Split(query.Value("read"), ",")
		}
		if query.Has("write") {
			users["write"] = strings.Split(query.Value("write"), ",")
		}
		if query.Has("delete") {
			users["delete"] = strings.Split(query.Value("delete"), ",")
		}
	} else if params["all"] != "" || params["read"] != "" || params["write"] != "" || params["delete"] != "" {
		users["all"] = strings.Split(params["all"], ",")
		users["read"] = strings.Split(params["read"], ",")
		users["write"] = strings.Split(params["write"], ",")
		users["delete"] = strings.Split(params["delete"], ",")
	} else {
		return nil, errors.New("Action requires list of comma seperated email address in 'all', 'read', 'write', and/or 'delete' parameter")
	}
	for k, _ := range users {
		for _, v := range users[k] {
			if v != "" {
				if isEmail(v) {
					u := user.User{Username: v, Email: v}
					if err := u.SetUuid(); err != nil {
						return nil, err
					}
					ids[k] = append(ids[k], u.Uuid)
				} else if isUuid(v) {
					ids[k] = append(ids[k], v)
				} else {
					return nil, errors.New("Unknown user id. Must be uuid or email address")
				}
			}
		}
	}
	if len(ids["all"]) > 0 {
		ids["read"] = append(ids["read"], ids["all"]...)
		ids["write"] = append(ids["write"], ids["all"]...)
		ids["delete"] = append(ids["delete"], ids["all"]...)
	}
	delete(ids, "all")
	return ids, nil
}
Пример #4
0
func parseAclRequestTyped(ctx context.Context) (ids []string, err error) {
	var users []string
	query := ctx.HttpRequest().URL.Query()
	params, _, err := request.ParseMultipartForm(ctx.HttpRequest())
	if _, ok := query["users"]; ok && err != nil && err.Error() == "request Content-Type isn't multipart/form-data" {
		users = strings.Split(query.Get("users"), ",")
	} else if params["users"] != "" {
		users = strings.Split(params["users"], ",")
	} else {
		return nil, errors.New("Action requires list of comma separated usernames in 'users' parameter")
	}
	for _, v := range users {
		if uuid.Parse(v) != nil {
			ids = append(ids, v)
		} else {
			u := user.User{Username: v}
			if err := u.SetMongoInfo(); err != nil {
				return nil, err
			}
			ids = append(ids, u.Uuid)
		}
	}
	return ids, nil
}
Пример #5
0
// POST: /node
func (cr *NodeController) Create(ctx context.Context) error {
	u, err := request.Authenticate(ctx.HttpRequest())
	if err != nil && err.Error() != e.NoAuth {
		return request.AuthError(err, ctx)
	}

	// Fake public user
	if u == nil {
		if conf.Bool(conf.Conf["anon-write"]) {
			u = &user.User{Uuid: ""}
		} else {
			return responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth)
		}
	}

	// Parse uploaded form
	params, files, err := request.ParseMultipartForm(ctx.HttpRequest())
	if err != nil {
		if err.Error() == "request Content-Type isn't multipart/form-data" {
			// If not multipart/form-data it will try to read the Body of the
			// request. If the Body is not empty it will create a file from
			// the Body contents. If the Body is empty it will create an empty
			// node.
			if ctx.HttpRequest().ContentLength != 0 {
				params, files, err = request.DataUpload(ctx.HttpRequest())
				if err != nil {
					err_msg := "Error uploading data from request body:" + err.Error()
					logger.Error(err_msg)
					return responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
				}
			}

			n, cn_err := node.CreateNodeUpload(u, params, files)

			if cn_err != nil {
				err_msg := "Error at create empty node: " + cn_err.Error()
				logger.Error(err_msg)
				return responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
			}
			if n == nil {
				// Not sure how you could get an empty node with no error
				// Assume it's the user's fault
				return responder.RespondWithError(ctx, http.StatusBadRequest, "Error, could not create node.")
			} else {
				return responder.RespondWithData(ctx, n)
			}
		} else {
			// Some error other than request encoding. Theoretically
			// could be a lost db connection between user lookup and parsing.
			// Blame the user, Its probaby their fault anyway.
			err_msg := "Error parsing form: " + err.Error()
			logger.Error(err_msg)
			return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
		}
	}

	// Create node
	n, err := node.CreateNodeUpload(u, params, files)
	if err != nil {
		err_msg := "err@node_CreateNodeUpload: " + err.Error()
		logger.Error(err_msg)
		return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
	}
	return responder.RespondWithData(ctx, n)
}
Пример #6
0
// GET, POST, PUT, DELETE: /node/{nid}/acl/
// GET is the only action implemented here.
func AclRequest(ctx context.Context) {
	nid := ctx.PathValue("nid")

	u, err := request.Authenticate(ctx.HttpRequest())
	if err != nil && err.Error() != e.NoAuth {
		request.AuthError(err, ctx)
		return
	}

	// acl require auth even for public data
	if u == nil {
		responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth)
		return
	}

	// Load node and handle user unauthorized
	n, err := node.LoadUnauth(nid)
	if err != nil {
		if err.Error() == e.MongoDocNotFound {
			responder.RespondWithError(ctx, http.StatusNotFound, "Node not found")
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			err_msg := "Err@node_Read:LoadNode: " + err.Error()
			logger.Error(err_msg)
			responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
			return
		}
	}

	// only the owner can view/edit acl's unless owner="" or owner=nil
	// note: owner can only be empty when anonymous node creation is enabled in shock config.
	if n.Acl.Owner != u.Uuid && n.Acl.Owner != "" {
		err_msg := "Only the node owner can edit/view node ACL's"
		logger.Error(err_msg)
		responder.RespondWithError(ctx, http.StatusUnauthorized, err_msg)
		return
	}

	if ctx.HttpRequest().Method == "GET" {
	    if u.Uuid == n.Acl.Owner || rights["read"] {
		// this is pretty clumsy and I could have done it with a lot less code and cleaner
		// in perl or js, but I am not so familiar with GO yet (it always hurts the first time)
		// the return structure should probably not be a concatenated string, but rather a hash
		// for each entry containing Username, Fullname and Uuid
		
		// owner
		cu, err := user.FindByUuid(n.Acl.Owner)
		if err != nil {
		    responder.RespondWithError(ctx, http.StatusInternalServerError, "Err@Uuid_Resolve: "+err.Error())
		    return
		} else {
		    n.Acl.Owner = cu.Username + "|" + cu.Uuid
		}

		// read
		p1 := []string{}
		for _, v := range n.Acl.Read {
		    cu, err := user.FindByUuid(v)
		    if err != nil {
			responder.RespondWithError(ctx, http.StatusInternalServerError, "Err@Uuid_Resolve: "+err.Error())
			return
		    } else {
			p1 = append(p1, cu.Username + "|" + cu.Uuid)
		    }
		}
		n.Acl.Read = p1

		// write
		p2 := []string{}
		for _, v := range n.Acl.Write {
		    cu, err := user.FindByUuid(v)
		    if err != nil {
			responder.RespondWithError(ctx, http.StatusInternalServerError, "Err@Uuid_Resolve: "+err.Error())
			return
		    } else {
			p2 = append(p2, cu.Username + "|" + cu.Uuid)
		    }
		}
		n.Acl.Write = p2

		// delete
		p3 := []string{}
		for _, v := range n.Acl.Delete {
		    cu, err := user.FindByUuid(v)
		    if err != nil {
			responder.RespondWithError(ctx, http.StatusInternalServerError, "Err@Uuid_Resolve: "+err.Error())
			return
		    } else {
			p3 = append(p3, cu.Username + "|" + cu.Uuid)
		    }
		}
		n.Acl.Delete = p3

		responder.RespondWithData(ctx, n.Acl)
	} else {
		responder.RespondWithError(ctx, http.StatusNotImplemented, "This request type is not implemented.")
	}
	return
}

// GET, POST, PUT, DELETE: /node/{nid}/acl/{type}
func AclTypedRequest(ctx context.Context) {
	nid := ctx.PathValue("nid")
	rtype := ctx.PathValue("type")

	u, err := request.Authenticate(ctx.HttpRequest())
	if err != nil && err.Error() != e.NoAuth {
		request.AuthError(err, ctx)
		return
	}

	if !validAclTypes[rtype] {
		responder.RespondWithError(ctx, http.StatusBadRequest, "Invalid acl type")
		return
	}

	// acl require auth even for public data
	if u == nil {
		responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth)
		return
	}

	// Load node and handle user unauthorized
	n, err := node.LoadUnauth(nid)
	if err != nil {
		if err.Error() == e.MongoDocNotFound {
			responder.RespondWithError(ctx, http.StatusNotFound, "Node not found")
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			err_msg := "Err@node_Read:LoadNode: " + err.Error()
			logger.Error(err_msg)
			responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
			return
		}
	}

	// only the owner can view/edit acl's unless owner="" or owner=nil
	// note: owner can only be empty when anonymous node creation is enabled in shock config.
	if n.Acl.Owner != u.Uuid && n.Acl.Owner != "" {
		err_msg := "Only the node owner can edit/view node ACL's"
		logger.Error(err_msg)
		responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
		return
	}

	requestMethod := ctx.HttpRequest().Method
	if requestMethod != "GET" {
		ids, err := parseAclRequestTyped(ctx)
		if err != nil {
			responder.RespondWithError(ctx, http.StatusBadRequest, err.Error())
			return
		}
		if requestMethod == "POST" || requestMethod == "PUT" {
			if rtype == "owner" {
				if len(ids) == 1 {
					n.Acl.SetOwner(ids[0])
				} else {
					responder.RespondWithError(ctx, http.StatusBadRequest, "Too many users. Nodes may have only one owner.")
					return
				}
			} else if rtype == "all" {
				for _, atype := range []string{"read", "write", "delete"} {
					for _, i := range ids {
						n.Acl.Set(i, map[string]bool{atype: true})
					}
				}
			} else {
				for _, i := range ids {
					n.Acl.Set(i, map[string]bool{rtype: true})
				}
			}
			n.Save()
		} else if requestMethod == "DELETE" {
			if rtype == "owner" {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Deleting ownership is not a supported request type.")
				return
			} else if rtype == "all" {
				for _, atype := range []string{"read", "write", "delete"} {
					for _, i := range ids {
						n.Acl.UnSet(i, map[string]bool{atype: true})
					}
				}
			} else {
				for _, i := range ids {
					n.Acl.UnSet(i, map[string]bool{rtype: true})
				}
			}
			n.Save()
		} else {
			responder.RespondWithError(ctx, http.StatusNotImplemented, "This request type is not implemented.")
			return
		}
	}

	switch rtype {
	default:
		responder.RespondWithError(ctx, http.StatusNotImplemented, "This request type is not implemented.")
	case "read":
		responder.RespondWithData(ctx, map[string][]string{"read": n.Acl.Read})
	case "write":
		responder.RespondWithData(ctx, map[string][]string{"write": n.Acl.Write})
	case "delete":
		responder.RespondWithData(ctx, map[string][]string{"delete": n.Acl.Delete})
	case "owner":
		responder.RespondWithData(ctx, map[string]string{"owner": n.Acl.Owner})
	case "all":
		responder.RespondWithData(ctx, n.Acl)
	}

	return
}

func parseAclRequestTyped(ctx context.Context) (ids []string, err error) {
	var users []string
	query := ctx.HttpRequest().URL.Query()
	params, _, err := request.ParseMultipartForm(ctx.HttpRequest())
	if _, ok := query["users"]; ok && err != nil && err.Error() == "request Content-Type isn't multipart/form-data" {
		users = strings.Split(query.Get("users"), ",")
	} else if params["users"] != "" {
		users = strings.Split(params["users"], ",")
	} else {
		return nil, errors.New("Action requires list of comma separated usernames in 'users' parameter")
	}
	for _, v := range users {
		if uuid.Parse(v) != nil {
			ids = append(ids, v)
		} else {
			u := user.User{Username: v}
			if err := u.SetMongoInfo(); err != nil {
				return nil, err
			}
			ids = append(ids, u.Uuid)
		}
	}
	return ids, nil
}
Пример #7
0
// GET, PUT, DELETE: /node/{nid}/index/{idxType}
func IndexTypedRequest(ctx context.Context) {
	nid := ctx.PathValue("nid")
	idxType := ctx.PathValue("idxType")

	u, err := request.Authenticate(ctx.HttpRequest())
	if err != nil && err.Error() != e.NoAuth {
		request.AuthError(err, ctx)
		return
	}

	// Fake public user
	if u == nil {
		u = &user.User{Uuid: ""}
	}

	// Load node and handle user unauthorized
	n, err := node.Load(nid, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
			return
		} else if err.Error() == e.MongoDocNotFound {
			responder.RespondWithError(ctx, http.StatusNotFound, "Node not found.")
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			err_msg := "Err@index:LoadNode: " + err.Error()
			logger.Error(err_msg)
			responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
			return
		}
	}

	switch ctx.HttpRequest().Method {
	case "DELETE":
		rights := n.Acl.Check(u.Uuid)
		if !rights["write"] {
			responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
			return
		}

		if _, has := n.Indexes[idxType]; has {
			if err := n.DeleteIndex(idxType); err != nil {
				err_msg := err.Error()
				logger.Error(err_msg)
				responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
			}
			responder.RespondOK(ctx)
		} else {
			responder.RespondWithError(ctx, http.StatusBadRequest, fmt.Sprintf("Node %s does not have index of type %s.", n.Id, idxType))
		}

	case "GET":
		if v, has := n.Indexes[idxType]; has {
			responder.RespondWithData(ctx, map[string]interface{}{idxType: v})
		} else {
			responder.RespondWithError(ctx, http.StatusBadRequest, fmt.Sprintf("Node %s does not have index of type %s.", n.Id, idxType))
		}

	case "PUT":
		rights := n.Acl.Check(u.Uuid)
		if !rights["write"] {
			responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
			return
		}

		// Gather query params
		query := ctx.HttpRequest().URL.Query()
		_, forceRebuild := query["force_rebuild"]

		if _, has := n.Indexes[idxType]; has {
			if idxType == "size" {
				responder.RespondOK(ctx)
				return
			} else if !forceRebuild {
				responder.RespondWithError(ctx, http.StatusBadRequest, "This index already exists, please add the parameter 'force_rebuild=1' to force a rebuild of the existing index.")
				return
			}
		}

		if !n.HasFile() {
			responder.RespondWithError(ctx, http.StatusBadRequest, "Node has no file.")
			return
		} else if idxType == "" {
			responder.RespondWithError(ctx, http.StatusBadRequest, "Index create requires type.")
			return
		}
		if _, ok := index.Indexers[idxType]; !ok && idxType != "bai" && idxType != "subset" && idxType != "column" {
			responder.RespondWithError(ctx, http.StatusBadRequest, fmt.Sprintf("Index type %s unavailable.", idxType))
			return
		}
		if idxType == "size" {
			responder.RespondWithError(ctx, http.StatusBadRequest, fmt.Sprintf("Index type size is a virtual index and does not require index building."))
			return
		}

		if conf.Bool(conf.Conf["perf-log"]) {
			logger.Perf("START indexing: " + nid)
		}

		if idxType == "bai" {
			//bam index is created by the command-line tool samtools
			if n.Type == "subset" {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Shock does not support bam index creation on subset nodes.")
				return
			}

			if ext := n.FileExt(); ext == ".bam" {
				if err := index.CreateBamIndex(n.FilePath()); err != nil {
					responder.RespondWithError(ctx, http.StatusInternalServerError, "Error while creating bam index.")
					return
				}
				responder.RespondOK(ctx)
				return
			} else {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Index type bai requires .bam file.")
				return
			}
		}

		subsetSize := int64(0)
		count := int64(0)
		indexFormat := ""
		subsetName := ""
		if idxType == "subset" {
			// Utilizing the multipart form parser since we need to upload a file.
			params, files, err := request.ParseMultipartForm(ctx.HttpRequest())
			if err != nil {
				responder.RespondWithError(ctx, http.StatusBadRequest, err.Error())
				return
			}

			parentIndex, hasParent := params["parent_index"]
			if !hasParent {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Index type subset requires parent_index param.")
				return
			} else if _, has := n.Indexes[parentIndex]; !has {
				responder.RespondWithError(ctx, http.StatusBadRequest, fmt.Sprintf("Node %s does not have index of type %s.", n.Id, parentIndex))
				return
			}

			newIndex, hasName := params["index_name"]
			if !hasName {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Index type subset requires index_name param.")
				return
			} else if _, reservedName := index.Indexers[newIndex]; reservedName || newIndex == "bai" {
				responder.RespondWithError(ctx, http.StatusBadRequest, fmt.Sprintf("%s is a reserved index name and cannot be used to create a custom subset index.", newIndex))
				return
			}
			subsetName = newIndex

			subsetIndices, hasFile := files["subset_indices"]
			if !hasFile {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Index type subset requires subset_indices file.")
				return
			}

			f, _ := os.Open(subsetIndices.Path)
			defer f.Close()
			idxer := index.NewSubsetIndexer(f)

			// we default to "array" index format for backwards compatibility
			indexFormat = "array"
			if n.Indexes[parentIndex].Format == "array" || n.Indexes[parentIndex].Format == "matrix" {
				indexFormat = n.Indexes[parentIndex].Format
			}
			count, subsetSize, err = index.CreateSubsetIndex(&idxer, n.IndexPath()+"/"+newIndex+".idx", n.IndexPath()+"/"+parentIndex+".idx", indexFormat, n.Indexes[parentIndex].TotalUnits)
			if err != nil {
				logger.Error("err " + err.Error())
				responder.RespondWithError(ctx, http.StatusBadRequest, err.Error())
				return
			}

		} else if idxType == "column" {
			// Gather query params
			query := ctx.HttpRequest().URL.Query()

			if n.Type == "subset" {
				responder.RespondWithError(ctx, http.StatusBadRequest, "Shock does not support column index creation on subset nodes.")
				return
			}

			if _, exists := query["number"]; !exists {
				err_msg := "Index type column requires a number parameter in the url."
				logger.Error(err_msg)
				responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
				return
			}

			num_str := query.Get("number")
			idxType = idxType + num_str
			num, err := strconv.Atoi(num_str)
			if err != nil || num < 1 {
				err_msg := "Index type column requires a number parameter in the url of an integer greater than zero."
				logger.Error(err_msg)
				responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
				return
			}

			f, _ := os.Open(n.FilePath())
			defer f.Close()
			idxer := index.NewColumnIndexer(f)
			count, indexFormat, err = index.CreateColumnIndex(&idxer, num, n.IndexPath()+"/"+idxType+".idx")
			if err != nil {
				logger.Error("err " + err.Error())
				responder.RespondWithError(ctx, http.StatusBadRequest, err.Error())
				return
			}
		} else {
			if n.Type == "subset" && (idxType != "chunkrecord" || n.Subset.Parent.IndexName != "record") {
				responder.RespondWithError(ctx, http.StatusBadRequest, "For subset nodes, Shock currently only supports subset and chunkrecord indexes. Also, for a chunkrecord index, the subset node must have been generated from a record index.")
				return
			}

			newIndexer := index.Indexers[idxType]
			f, _ := os.Open(n.FilePath())
			defer f.Close()
			var idxer index.Indexer
			if n.Type == "subset" {
				idxer = newIndexer(f, n.Type, n.Subset.Index.Format, n.IndexPath()+"/"+n.Subset.Parent.IndexName+".idx")
			} else {
				idxer = newIndexer(f, n.Type, "", "")
			}
			count, indexFormat, err = idxer.Create(n.IndexPath() + "/" + idxType + ".idx")
			if err != nil {
				logger.Error("err " + err.Error())
				responder.RespondWithError(ctx, http.StatusBadRequest, err.Error())
				return
			}
		}

		if count == 0 {
			responder.RespondWithError(ctx, http.StatusBadRequest, "Index empty.")
			return
		}

		idxInfo := node.IdxInfo{
			Type:        idxType,
			TotalUnits:  count,
			AvgUnitSize: n.File.Size / count,
			Format:      indexFormat,
		}

		//if idxType == "chunkrecord" {
		//	idxInfo.AvgUnitSize = conf.CHUNK_SIZE
		//}

		if idxType == "subset" {
			idxType = subsetName
			idxInfo.AvgUnitSize = subsetSize / count
		}

		if err := n.SetIndexInfo(idxType, idxInfo); err != nil {
			logger.Error("[email protected]: " + err.Error())
		}

		if conf.Bool(conf.Conf["perf-log"]) {
			logger.Perf("END indexing: " + nid)
		}

		responder.RespondOK(ctx)
		return

	default:
		responder.RespondWithError(ctx, http.StatusNotImplemented, "This request type is not implemented.")
	}
	return
}
Пример #8
0
// PUT: /node/{id} -> multipart-form
func (cr *NodeController) Replace(id string, ctx context.Context) error {
	u, err := request.Authenticate(ctx.HttpRequest())
	if err != nil && err.Error() != e.NoAuth {
		return request.AuthError(err, ctx)
	}

	// public user (no auth) can be used in some cases
	if u == nil {
		if conf.ANON_WRITE {
			u = &user.User{Uuid: "public"}
		} else {
			return responder.RespondWithError(ctx, http.StatusUnauthorized, e.NoAuth)
		}
	}

	// Load node by id
	n, err := node.Load(id)
	if err != nil {
		if err == mgo.ErrNotFound {
			return responder.RespondWithError(ctx, http.StatusNotFound, e.NodeNotFound)
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			err_msg := "Err@node_Update:LoadNode: " + id + ":" + err.Error()
			logger.Error(err_msg)
			return responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
		}
	}

	rights := n.Acl.Check(u.Uuid)
	prights := n.Acl.Check("public")
	if rights["write"] == false && u.Admin == false && n.Acl.Owner != u.Uuid && prights["write"] == false {
		return responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
	}

	if conf.LOG_PERF {
		logger.Perf("START PUT data: " + id)
	}
	params, files, err := request.ParseMultipartForm(ctx.HttpRequest())
	// clean up temp dir !!
	defer node.RemoveAllFormFiles(files)
	if err != nil {
		err_msg := "err@node_ParseMultipartForm: " + err.Error()
		logger.Error(err_msg)
		return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
	}

	// need delete rights to set expiration
	if _, hasExpiration := params["expiration"]; hasExpiration {
		if rights["delete"] == false && u.Admin == false && n.Acl.Owner != u.Uuid && prights["delete"] == false {
			return responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
		}
	}

	if _, hasCopyData := params["copy_data"]; hasCopyData {
		_, err = node.Load(params["copy_data"])
		if err != nil {
			return request.AuthError(err, ctx)
		}
	}

	if _, hasParentNode := params["parent_node"]; hasParentNode {
		_, err = node.Load(params["parent_node"])
		if err != nil {
			return request.AuthError(err, ctx)
		}
	}

	err = n.Update(params, files)
	if err != nil {
		err_msg := "err@node_Update: " + id + ": " + err.Error()
		logger.Error(err_msg)
		return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
	}
	responder.RespondWithData(ctx, n)
	if conf.LOG_PERF {
		logger.Perf("END PUT data: " + id)
	}
	return nil
}
Пример #9
0
// PUT: /node/{id} -> multipart-form
func (cr *Controller) Update(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	request.Log(cx.Request)
	u, err := request.Authenticate(cx.Request)
	if err != nil && err.Error() != e.NoAuth {
		request.AuthError(err, cx)
		return
	}

	// Gather query params
	query := util.Q(cx.Request.URL.Query())

	// Fake public user
	if u == nil {
		u = &user.User{Uuid: ""}
	}

	n, err := node.Load(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			cx.RespondWithError(http.StatusUnauthorized)
			return
		} else if err.Error() == e.MongoDocNotFound {
			cx.RespondWithNotFound()
			return
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			logger.Error("Err@node_Update:LoadNode: " + err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	if query.Has("index") {
		if conf.Bool(conf.Conf["perf-log"]) {
			logger.Perf("START indexing: " + id)
		}

		if !n.HasFile() {
			cx.RespondWithErrorMessage("node file empty", http.StatusBadRequest)
			return
		}

		if query.Value("index") == "bai" {
			//bam index is created by the command-line tool samtools
			if ext := n.FileExt(); ext == ".bam" {
				if err := index.CreateBamIndex(n.FilePath()); err != nil {
					cx.RespondWithErrorMessage("Error while creating bam index", http.StatusBadRequest)
					return
				}
				return
			} else {
				cx.RespondWithErrorMessage("Index type bai requires .bam file", http.StatusBadRequest)
				return
			}
		}

		idxtype := query.Value("index")
		if _, ok := index.Indexers[idxtype]; !ok {
			cx.RespondWithErrorMessage("invalid index type", http.StatusBadRequest)
			return
		}

		newIndexer := index.Indexers[idxtype]
		f, _ := os.Open(n.FilePath())
		defer f.Close()
		idxer := newIndexer(f)
		count, err := idxer.Create()
		if err != nil {
			logger.Error("err " + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}

		if err := idxer.Dump(n.IndexPath() + "/" + query.Value("index") + ".idx"); err != nil {
			logger.Error("err " + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}

		idxInfo := node.IdxInfo{
			Type:        query.Value("index"),
			TotalUnits:  count,
			AvgUnitSize: n.File.Size / count,
		}

		if idxtype == "chunkrecord" {
			idxInfo.AvgUnitSize = conf.CHUNK_SIZE
		}

		if err := n.SetIndexInfo(query.Value("index"), idxInfo); err != nil {
			logger.Error("[email protected]: " + err.Error())
		}

		if conf.Bool(conf.Conf["perf-log"]) {
			logger.Perf("END indexing: " + id)
		}

		cx.RespondWithOK()
		return

	} else {
		if conf.Bool(conf.Conf["perf-log"]) {
			logger.Perf("START PUT data: " + id)
		}
		params, files, err := request.ParseMultipartForm(cx.Request)
		if err != nil {
			logger.Error("err@node_ParseMultipartForm: " + err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}

		err = n.Update(params, files)
		if err != nil {
			errors := []string{e.FileImut, e.AttrImut, "parts cannot be less than 1"}
			for e := range errors {
				if err.Error() == errors[e] {
					cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
					return
				}
			}
			logger.Error("err@node_Update: " + id + ":" + err.Error())
			cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
			return
		}
		cx.RespondWithData(n)
		if conf.Bool(conf.Conf["perf-log"]) {
			logger.Perf("END PUT data: " + id)
		}
	}
	return
}
Пример #10
0
// PUT: /node/{id} -> multipart-form
func (cr *NodeController) Replace(id string, ctx context.Context) error {
	u, err := request.Authenticate(ctx.HttpRequest())
	if err != nil && err.Error() != e.NoAuth {
		return request.AuthError(err, ctx)
	}

	// Fake public user
	if u == nil {
		u = &user.User{Uuid: ""}
	}

	n, err := node.Load(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			return responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
		} else if err.Error() == e.MongoDocNotFound {
			return responder.RespondWithError(ctx, http.StatusNotFound, "Node not found")
		} else {
			// In theory the db connection could be lost between
			// checking user and load but seems unlikely.
			err_msg := "Err@node_Update:LoadNode: " + err.Error()
			logger.Error(err_msg)
			return responder.RespondWithError(ctx, http.StatusInternalServerError, err_msg)
		}
	}

	rights := n.Acl.Check(u.Uuid)
	if !rights["write"] {
		return responder.RespondWithError(ctx, http.StatusUnauthorized, e.UnAuth)
	}

	if conf.Bool(conf.Conf["perf-log"]) {
		logger.Perf("START PUT data: " + id)
	}
	params, files, err := request.ParseMultipartForm(ctx.HttpRequest())
	if err != nil {
		err_msg := "err@node_ParseMultipartForm: " + err.Error()
		logger.Error(err_msg)
		return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
	}

	if _, hasCopyData := params["copy_data"]; hasCopyData {
		_, err = node.Load(params["copy_data"], u.Uuid)
		if err != nil {
			return request.AuthError(err, ctx)
		}
	}

	if _, hasParentNode := params["parent_node"]; hasParentNode {
		_, err = node.Load(params["parent_node"], u.Uuid)
		if err != nil {
			return request.AuthError(err, ctx)
		}
	}

	err = n.Update(params, files)
	if err != nil {
		err_msg := "err@node_Update: " + id + ": " + err.Error()
		logger.Error(err_msg)
		return responder.RespondWithError(ctx, http.StatusBadRequest, err_msg)
	}
	responder.RespondWithData(ctx, n)
	if conf.Bool(conf.Conf["perf-log"]) {
		logger.Perf("END PUT data: " + id)
	}
	return nil
}