<commit_before>package main

import (
	"fmt"
	ds "github.com/MG-RAST/Shock/datastore"
	e "github.com/MG-RAST/Shock/errors"
	"github.com/MG-RAST/Shock/goweb"
	"github.com/MG-RAST/Shock/user"
	"io"
	"launchpad.net/mgo/bson"
	"net/http"
	"os"
	"strconv"
)

type NodeController struct{}

// POST: /node
func (cr *NodeController) Create(cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

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

	// Parse uploaded form
	params, files, err := 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" {
			node, err := ds.CreateNodeUpload(u, params, files)
			if err != nil {
				fmt.Println("Error at create empty:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
			if node == 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(node)
				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.
			fmt.Println("Error at empty create:", err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	}
	// Create node
	node, err := ds.CreateNodeUpload(u, params, files)
	if err != nil {
		fmt.Println("err", err.Error())
		cx.RespondWithError(http.StatusBadRequest)
		return
	}
	cx.RespondWithData(node)
	return
}

// DELETE: /node/{id}
func (cr *NodeController) Delete(id string, cx *goweb.Context) {
	LogRequest(cx.Request)
	cx.RespondWithError(http.StatusNotImplemented)
}

// DELETE: /node
func (cr *NodeController) DeleteMany(cx *goweb.Context) {
	LogRequest(cx.Request)
	cx.RespondWithError(http.StatusNotImplemented)
}

// GET: /node/{id}
func (cr *NodeController) Read(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

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

	// Gather query params and setup flags
	query := cx.Request.URL.Query()
	_, download := query["download"]
	_, pipe := query["pipe"]
	_, list := query["list"]

	// Load node and handle user unauthorized
	node, err := ds.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			fmt.Println("Unauthorized")
			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.
			fmt.Println("Err@node_Read:LoadNode:", err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	// Switch though param flags
	if download {
		if node.File.Empty() {
			cx.RespondWithErrorMessage("node file not found", http.StatusBadRequest)
			return
		}
		_, index := query["index"]
		_, part := query["part"]
		_, chunksize := query["chunksize"]
		if index {
			if query["index"][0] == "size" {
				if part {
					var csize int64 = 1048576
					if chunksize {
						csize, err = strconv.ParseInt(query["chunksize"][0], 10, 64)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid chunksize", http.StatusBadRequest)
							return
						}
					}
					var size int64 = 0
					s := &partStreamer{rs: []*io.SectionReader{}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id}
					r, err := os.Open(node.DataPath())
					if err != nil {
						fmt.Println("Err@node_Read:Open:", err.Error())
						cx.RespondWithError(http.StatusInternalServerError)
						return
					}
					defer r.Close()
					for _, p := range query["part"] {
						pInt, err := strconv.ParseInt(p, 10, 64)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
							return
						}
						pos, length, err := node.File.SizeOffset(pInt, csize)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
							return
						}
						size += length
						s.rs = append(s.rs, io.NewSectionReader(r, pos, length))
					}
					s.size = size
					err = s.stream()
					if err != nil {
						// fix
						fmt.Println("err", err.Error())
					}
				} else {
					cx.RespondWithErrorMessage("Index parameter requires part parameter", http.StatusBadRequest)
					return
				}
			} else {
				if node.HasIndex(query["index"][0]) {
					idx := ds.NewIndex()
					err = idx.Load(fmt.Sprintf("%s/%s", node.IndexPath(), query["index"][0]))
					if err != nil {
						fmt.Println(err.Error())
						cx.RespondWithErrorMessage("Error loading index", http.StatusBadRequest)
						return
					}
					var size int64 = 0
					s := &partStreamer{rs: []*io.SectionReader{}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id}
					r, err := os.Open(node.DataPath())
					if err != nil {
						fmt.Println("Err@node_Read:Open:", err.Error())
						cx.RespondWithError(http.StatusInternalServerError)
						return
					}
					defer r.Close()
					for _, p := range query["part"] {
						pInt, err := strconv.ParseInt(p, 10, 64)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
							return
						}
						p, ok1 := idx.Idx[(pInt - 1)][0].(float64)
						l, ok2 := idx.Idx[(pInt - 1)][1].(float64)
						if !ok1 || !ok2 {
							cx.RespondWithErrorMessage("Malformed index", http.StatusBadRequest)
							return
						}
						pos := int64(p)
						length := int64(l)
						size += length
						s.rs = append(s.rs, io.NewSectionReader(r, pos, length))
					}
					s.size = size
					err = s.stream()
					if err != nil {
						fmt.Println("err", err.Error())
					}
				} else {
					cx.RespondWithErrorMessage("Index not found", http.StatusBadRequest)
					return
				}
			}
		} else {
			nf, err := os.Open(node.DataPath())
			if err != nil {
				// File not found or some sort of file read error.
				// Probably deserves more checking
				fmt.Println("err", err.Error())
				cx.RespondWithError(http.StatusBadRequest)
				return
			}
			s := &streamer{rs: nf, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, size: node.File.Size}
			err = s.stream()
			if err != nil {
				// fix
				fmt.Println("err", err.Error())
			}
		}
		return
	} else if pipe {
		cx.RespondWithError(http.StatusNotImplemented)
	} else if list {
		cx.RespondWithError(http.StatusNotImplemented)
	} else {
		// Base case respond with node in json
		cx.RespondWithData(node)
	}
}

// GET: /node
// To do:
// - Iterate node queries
func (cr *NodeController) ReadMany(cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

	// Gather query params and setup flags
	query := cx.Request.URL.Query()
	l, hasLimit := query["limit"]
	o, hasOffset := query["skip"]
	_, hasQuery := query["query"]

	// Setup query and nodes objects
	q := bson.M{}
	nodes := new(ds.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}}
		}
	} else {
		// select on only nodes with no read rights set
		q["acl.read"] = []string{}
	}

	// Gather params to make db query. Do not include the
	// following list.
	skip := map[string]int{"limit": 1, "skip": 1, "query": 1}
	if hasQuery {
		for key, val := range query {
			_, s := skip[key]
			if !s {
				q[fmt.Sprintf("attributes.%s", key)] = val[0]
			}
		}
	}

	// Limit and skip. Set default if both are not specified
	if hasLimit || hasOffset {
		var lim, off int
		if !hasLimit {
			lim = 100
		} else {
			lim, _ = strconv.Atoi(l[0])
		}
		if !hasOffset {
			off = 0
		} else {
			off, _ = strconv.Atoi(o[0])
		}
		// Get nodes from db
		err := nodes.GetAllLimitOffset(q, lim, off)
		if err != nil {
			fmt.Println("err", err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	} else {
		// Get nodes from db
		err := nodes.GetAll(q)
		if err != nil {
			fmt.Println("err", err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	}

	cx.RespondWithData(nodes)
	return
}

// PUT: /node/{id} -> multipart-form
func (cr *NodeController) Update(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

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

	node, err := ds.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			fmt.Println("Unauthorized")
			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.
			fmt.Println("Err@node_Update:LoadNode:", err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	params, files, err := ParseMultipartForm(cx.Request)
	if err != nil {
		fmt.Println("err", err.Error())
		cx.RespondWithError(http.StatusBadRequest)
		return
	}

	err = node.Update(params, files)
	if err != nil {
		errors := []string{"node file already set and is immutable", "node file immutable", "node attributes immutable", "node part already exists and is immutable"}
		for e := range errors {
			if err.Error() == errors[e] {
				cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
				return
			}
		}
		fmt.Println("err", err.Error())
		cx.RespondWithError(http.StatusBadRequest)
		return
	}
	cx.RespondWithData(node)
	return
}

// PUT: /node
func (cr *NodeController) UpdateMany(cx *goweb.Context) {
	LogRequest(cx.Request)
	cx.RespondWithError(http.StatusNotImplemented)
}
<commit_msg>added filter support<commit_after>package main

import (
	"fmt"
	ds "github.com/MG-RAST/Shock/datastore"
	e "github.com/MG-RAST/Shock/errors"
	"github.com/MG-RAST/Shock/filters/anonymize"
	"github.com/MG-RAST/Shock/goweb"
	"github.com/MG-RAST/Shock/user"
	"io"
	"launchpad.net/mgo/bson"
	"net/http"
	"os"
	"strconv"
)

type NodeController struct{}

// POST: /node
func (cr *NodeController) Create(cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

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

	// Parse uploaded form
	params, files, err := 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" {
			node, err := ds.CreateNodeUpload(u, params, files)
			if err != nil {
				fmt.Println("Error at create empty:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
			if node == 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(node)
				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.
			fmt.Println("Error at empty create:", err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	}
	// Create node
	node, err := ds.CreateNodeUpload(u, params, files)
	if err != nil {
		fmt.Println("err", err.Error())
		cx.RespondWithError(http.StatusBadRequest)
		return
	}
	cx.RespondWithData(node)
	return
}

// DELETE: /node/{id}
func (cr *NodeController) Delete(id string, cx *goweb.Context) {
	LogRequest(cx.Request)
	cx.RespondWithError(http.StatusNotImplemented)
}

// DELETE: /node
func (cr *NodeController) DeleteMany(cx *goweb.Context) {
	LogRequest(cx.Request)
	cx.RespondWithError(http.StatusNotImplemented)
}

// GET: /node/{id}'
// ToDo: clean up this function. About to get unmanagable
func (cr *NodeController) Read(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

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

	// Gather query params and setup flags
	query := cx.Request.URL.Query()
	_, download := query["download"]
	_, pipe := query["pipe"]
	_, list := query["list"]
	_, filter := query["filter"]

	var filterFunc func(io.ReadCloser) io.ReadCloser = nil
	if filter {
		if query["filter"][0] == "anonymize" {
			filterFunc = anonymize.NewReader
		}
	}

	// Load node and handle user unauthorized
	node, err := ds.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			fmt.Println("Unauthorized")
			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.
			fmt.Println("Err@node_Read:LoadNode:", err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	// Switch though param flags
	if download {
		if node.File.Empty() {
			cx.RespondWithErrorMessage("node file not found", http.StatusBadRequest)
			return
		}
		_, index := query["index"]
		_, part := query["part"]
		_, chunksize := query["chunksize"]
		if index {
			if query["index"][0] == "size" {
				if part {
					var csize int64 = 1048576
					if chunksize {
						csize, err = strconv.ParseInt(query["chunksize"][0], 10, 64)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid chunksize", http.StatusBadRequest)
							return
						}
					}
					var size int64 = 0
					s := &streamer{rs: []io.ReadCloser{}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, filter: filterFunc}
					r, err := os.Open(node.DataPath())
					if err != nil {
						fmt.Println("Err@node_Read:Open:", err.Error())
						cx.RespondWithError(http.StatusInternalServerError)
						return
					}
					defer r.Close()
					for _, p := range query["part"] {
						pInt, err := strconv.ParseInt(p, 10, 64)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
							return
						}
						pos, length, err := node.File.SizeOffset(pInt, csize)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
							return
						}
						size += length
						s.rs = append(s.rs, NewSectionReaderCloser(r, pos, length))
					}
					s.size = size
					err = s.stream()
					if err != nil {
						// fix
						fmt.Println("err", err.Error())
					}
				} else {
					cx.RespondWithErrorMessage("Index parameter requires part parameter", http.StatusBadRequest)
					return
				}
			} else {
				if node.HasIndex(query["index"][0]) {
					idx := ds.NewIndex()
					err = idx.Load(fmt.Sprintf("%s/%s", node.IndexPath(), query["index"][0]))
					if err != nil {
						fmt.Println(err.Error())
						cx.RespondWithErrorMessage("Error loading index", http.StatusBadRequest)
						return
					}
					var size int64 = 0
					s := &streamer{rs: []io.ReadCloser{}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, filter: filterFunc}
					r, err := os.Open(node.DataPath())
					if err != nil {
						fmt.Println("Err@node_Read:Open:", err.Error())
						cx.RespondWithError(http.StatusInternalServerError)
						return
					}
					defer r.Close()
					for _, p := range query["part"] {
						pInt, err := strconv.ParseInt(p, 10, 64)
						if err != nil {
							cx.RespondWithErrorMessage("Invalid index part", http.StatusBadRequest)
							return
						}
						p, ok1 := idx.Idx[(pInt - 1)][0].(float64)
						l, ok2 := idx.Idx[(pInt - 1)][1].(float64)
						if !ok1 || !ok2 {
							cx.RespondWithErrorMessage("Malformed index", http.StatusBadRequest)
							return
						}
						pos := int64(p)
						length := int64(l)
						size += length
						s.rs = append(s.rs, NewSectionReaderCloser(r, pos, length))
					}
					s.size = size
					err = s.stream()
					if err != nil {
						fmt.Println("err", err.Error())
					}
				} else {
					cx.RespondWithErrorMessage("Index not found", http.StatusBadRequest)
					return
				}
			}
		} else {
			nf, err := os.Open(node.DataPath())
			if err != nil {
				// File not found or some sort of file read error.
				// Probably deserves more checking
				fmt.Println("err", err.Error())
				cx.RespondWithError(http.StatusBadRequest)
				return
			}
			s := &streamer{rs: []io.ReadCloser{nf}, ws: cx.ResponseWriter, contentType: "application/octet-stream", filename: node.Id, size: node.File.Size, filter: filterFunc}
			err = s.stream()
			if err != nil {
				// fix
				fmt.Println("err", err.Error())
			}
		}
		return
	} else if pipe {
		cx.RespondWithError(http.StatusNotImplemented)
	} else if list {
		cx.RespondWithError(http.StatusNotImplemented)
	} else {
		// Base case respond with node in json
		cx.RespondWithData(node)
	}
}

// GET: /node
// To do:
// - Iterate node queries
func (cr *NodeController) ReadMany(cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

	// Gather query params and setup flags
	query := cx.Request.URL.Query()
	l, hasLimit := query["limit"]
	o, hasOffset := query["skip"]
	_, hasQuery := query["query"]

	// Setup query and nodes objects
	q := bson.M{}
	nodes := new(ds.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}}
		}
	} else {
		// select on only nodes with no read rights set
		q["acl.read"] = []string{}
	}

	// Gather params to make db query. Do not include the
	// following list.
	skip := map[string]int{"limit": 1, "skip": 1, "query": 1}
	if hasQuery {
		for key, val := range query {
			_, s := skip[key]
			if !s {
				q[fmt.Sprintf("attributes.%s", key)] = val[0]
			}
		}
	}

	// Limit and skip. Set default if both are not specified
	if hasLimit || hasOffset {
		var lim, off int
		if !hasLimit {
			lim = 100
		} else {
			lim, _ = strconv.Atoi(l[0])
		}
		if !hasOffset {
			off = 0
		} else {
			off, _ = strconv.Atoi(o[0])
		}
		// Get nodes from db
		err := nodes.GetAllLimitOffset(q, lim, off)
		if err != nil {
			fmt.Println("err", err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	} else {
		// Get nodes from db
		err := nodes.GetAll(q)
		if err != nil {
			fmt.Println("err", err.Error())
			cx.RespondWithError(http.StatusBadRequest)
			return
		}
	}

	cx.RespondWithData(nodes)
	return
}

// PUT: /node/{id} -> multipart-form
func (cr *NodeController) Update(id string, cx *goweb.Context) {
	// Log Request and check for Auth
	LogRequest(cx.Request)
	u, err := AuthenticateRequest(cx.Request)
	if err != nil {
		// No Auth is not damning. Other errors are probably a dead db connection
		if err.Error() != e.NoAuth {
			if err.Error() == e.MongoDocNotFound {
				cx.RespondWithErrorMessage("Invalid username or password", http.StatusBadRequest)
				return
			} else {
				fmt.Println("Error at Auth:", err.Error())
				cx.RespondWithError(http.StatusInternalServerError)
				return
			}
		}
	}

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

	node, err := ds.LoadNode(id, u.Uuid)
	if err != nil {
		if err.Error() == e.UnAuth {
			fmt.Println("Unauthorized")
			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.
			fmt.Println("Err@node_Update:LoadNode:", err.Error())
			cx.RespondWithError(http.StatusInternalServerError)
			return
		}
	}

	params, files, err := ParseMultipartForm(cx.Request)
	if err != nil {
		fmt.Println("err", err.Error())
		cx.RespondWithError(http.StatusBadRequest)
		return
	}

	err = node.Update(params, files)
	if err != nil {
		errors := []string{"node file already set and is immutable", "node file immutable", "node attributes immutable", "node part already exists and is immutable"}
		for e := range errors {
			if err.Error() == errors[e] {
				cx.RespondWithErrorMessage(err.Error(), http.StatusBadRequest)
				return
			}
		}
		fmt.Println("err", err.Error())
		cx.RespondWithError(http.StatusBadRequest)
		return
	}
	cx.RespondWithData(node)
	return
}

// PUT: /node
func (cr *NodeController) UpdateMany(cx *goweb.Context) {
	LogRequest(cx.Request)
	cx.RespondWithError(http.StatusNotImplemented)
}
<|endoftext|>


<commit_before>package hooks

import "github.com/gernest/ngorm/engine"

//Hook is a function that is executed at a particular point in time. This allows
//doing additional transformation of any portion of the engine.Engine, and it
//can be a way to overide default behaviour.
type Hook func(e *engine.Engine) error
<commit_msg>[hooks] Start rough ideas on how hooks will look like<commit_after>package hooks

import (
	"sync"

	"github.com/gernest/ngorm/engine"
)

//Hook is a nterface that is executed at a particular point in time. This allows
//doing additional transformation of any portion of the engine.Engine, and it
//can be a way to overide default behaviour.
type Hook interface {
	Name() string
	Exec(e *engine.Engine) error
}

type Hooks struct {
	h  map[string]Hook
	mu sync.RWMutex
}

func (h *Hooks) Set(hk Hook) {
	h.mu.Lock()
	h.h[hk.Name()] = hk
	h.mu.Unlock()
}

func (h *Hooks) Get(name string) (Hook, bool) {
	h.mu.RLock()
	hk, ok := h.h[name]
	h.mu.RUnlock()
	return hk, ok
}

func NewHooks() *Hooks {
	return &Hooks{h: make(map[string]Hook)}
}

type simpleHook struct {
	name string
	e    func(*engine.Engine) error
}

func (s *simpleHook) Name() string {
	return s.name
}

func (s *simpleHook) Exec(e *engine.Engine) error {
	return s.e(e)
}

func HookFunc(name string, f func(*engine.Engine) error) Hook {
	return &simpleHook{name: name, e: f}
}
<|endoftext|>


<commit_before>package simplecsv

// AddEmptyColumn ads an empty column at the end of the csv
func (s SimpleCsv) AddEmptyColumn(columnName string) (SimpleCsv, bool) {
	var added bool

	s[0] = append(s[0], columnName)

	for i := 1; i < len(s); i++ {
		s[i] = append(s[i], "")
	}
	added = true
	return s, added
}
<commit_msg>Add RemoveColumn code<commit_after>package simplecsv

// AddEmptyColumn ads an empty column at the end of the csv
func (s SimpleCsv) AddEmptyColumn(columnName string) (SimpleCsv, bool) {
	var added bool

	s[0] = append(s[0], columnName)

	for i := 1; i < len(s); i++ {
		s[i] = append(s[i], "")
	}
	added = true
	return s, added
}

// RemoveColumn removes the column in position X
func (s SimpleCsv) RemoveColumn(columnPosition int) (SimpleCsv, bool) {
	var removed bool

	if columnPosition >= 0 && columnPosition < len(s[0]) {
		s[0] = append(s[0][:columnPosition], s[0][columnPosition+1:]...)
		for i := 1; i < len(s); i++ {
			s[i] = append(s[i][:columnPosition], s[i][columnPosition+1:]...)
		}
		removed = true
	} else {
		removed = false
	}

	return s, removed
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"

	. "github.com/eyetoe/foobarbaz/agents"
	. "github.com/eyetoe/foobarbaz/art"
	. "github.com/eyetoe/foobarbaz/colors"
	. "github.com/eyetoe/foobarbaz/simulations"
	. "github.com/eyetoe/foobarbaz/util"
)

// Fight loop where c is character and f is foe
func Fight(c *Agent, f *Agent) {

	// calculate odds for the ascii art display only once
	odds := Odds(c, f)

	// declare strings
	var charDamageOut, charAttackDetails, foeDamageOut, foeAttackDetails, healmsg string

	// declare attack winner
	var winner *Agent

	// display
	display := func() {
		c.StatusBar()
		fmt.Println()
		FoeBar(*c, *f)

		// Color Foe's name and show victory chance percentage
		switch {
		case odds >= 80:
			fmt.Printf(Green("%s\n"), f.Art)
		case odds >= 60:
			fmt.Printf(Cyan("%s\n"), f.Art)
		case odds >= 40:
			fmt.Printf(Blue("%s\n"), f.Art)
		case odds >= 20:
			fmt.Printf(Yellow("%s\n"), f.Art)
		case odds >= 0:
			fmt.Printf(Red("%s\n"), f.Art)
		}

	}

	// Fight loop start here
	for {

		// redraw and display stats
		ClearScreen()
		display()
		fmt.Printf(charAttackDetails)
		fmt.Printf(foeDamageOut)
		fmt.Printf(foeAttackDetails)
		fmt.Printf(charDamageOut)
		fmt.Printf(healmsg)

		// clear vars between runs
		charAttackDetails = ""
		foeDamageOut = ""
		foeAttackDetails = ""
		charDamageOut = ""
		healmsg = ""

		// check pulse
		if f.Dead == true {
			if f.Weap.Name != c.Weap.Name && f.DropChance >= Roll(1, 100) {
				OfferItem(c, f)
			}
			fmt.Printf(RedU("%s has died!\n"), f.Name)
			Continue()
			break
		}
		if c.Dead == true {
			fmt.Printf(RedU("%s has died!\n"), c.Name)
			Continue()
			break
		}

		// Combat Prompt
		fmt.Printf("\n:> %sight, %svade, %sescribe, %sun\n<: ", GreenU("F"), GreenU("E"), GreenU("D"), GreenU("R"))
		choice, _, _ := GetChar()

		switch choice {
		// Fight
		case "f", "F":
			ClearScreen()
			display()
			// Player Attacks First
			winner, _, charAttackDetails = Attack(c, f)
			if c.Name == winner.Name {
				foeDamageOut = Damage(c, f, odds)
				if f.Dead == true {
					healmsg = WinHeal(c)
					continue
				}
			}
			// Foe Attacks Second
			winner, _, foeAttackDetails = Attack(f, c)
			if f.Name == winner.Name {
				charDamageOut = Damage(f, c, odds)
			}
			// Evade
			continue
		case "e", "E":
			fmt.Println("Evade!\n You stall for time, looking for an opening!")
			fmt.Println("Note: should have a separate menu here where you can use items.  So you have to take a break from the fight, to be able to pull out an item or potion.  including switching weapons, drinking potions, using magic items.")
			continue
			// Describe the Foe
		case "d", "D":
			//fmt.Printf(Blue("\nYou consider the %s. %s\n"), f.Name, f.Description)
			f.Describe()
			FoeBar(*c, *f)
			fmt.Println()
			continue
			// Run from the fight
		case "r", "R":
			fmt.Println("Run!\n You have lost this battle, but may yet win the war!")
			break
			// Default back to loop
		default:
			continue
		}
		return
	}

}

// Attack takes two structs and returns two structs.
// First input struct is the 'attacker'
// Second input struct is the 'defender'
// First output struct is the 'winner'
// Second output struct is the 'loser'
func Attack(a *Agent, d *Agent) (*Agent, *Agent, string) {

	var outText string

	// roll for attacker and defender
	ar := Roll(1, 100)
	dr := Roll(1, 100)
	// bonuses
	arB := a.Str.Val + a.Weap.Attack
	drB := d.Dex.Val
	// totals
	aT := ar + arB
	dT := dr + drB

	// uncomment here to 'show your work'
	//outText = fmt.Sprintf(Black("Attack roll: %d plus Bonus: %d for Total: %d\n"), ar, arB, aT)
	//outText = outText + fmt.Sprintf(Black("Defence roll: %d plus Bonus: %d for Total: %d\n"), dr, drB, dT)

	// Attack wins if greater than Defence
	// But a tie goes to the Defence
	if aT > dT {
		outText = outText + fmt.Sprintf(Green("%s hits with %s!\n "), a.Name, a.Weap.Name)
		return a, d, outText
	} else {
		outText = outText + fmt.Sprintf(Red("%s misses!\n"), a.Name)
		return d, a, outText
	}

}

// Calculate and apply damage to Agent
func Damage(a *Agent, d *Agent, odds int) string {

	var textOut string

	hp := Roll(1, a.Weap.Damage)

	d.AdjHp(0 - hp)

	//if d.Dead == false {
	textOut = textOut + fmt.Sprintf("for %s damage. ", Red(strconv.Itoa(hp)))
	textOut = textOut + fmt.Sprintf("%s's health = %s.\n", d.Name, Red(strconv.Itoa(d.Hp.Val)))
	//}

	// Monster agents don't have a save file set
	if d.File == "" && d.Dead == true {

		// reverse the percentage
		mods := 100 - odds

		percentage := float32(mods) * .01

		// reduce the drop by the reverse percentage
		exp := float32(d.ExpDrop()) * percentage

		// int to float conversion rounds down towards zero by dropping
		// everything after the decimal point. So I add 1 to the exp here
		// so the player never gets 0 exp reward
		exp++

		// exp is a float32 so do math with exp as an int
		a.Exp = a.Exp + int(exp)

		textOut = textOut + fmt.Sprintf(Green("\nYou gain %d experience.\n"), int(exp))
		a.Save()
	}
	d.Save()
	return textOut
}

func WinHeal(c *Agent) string {
	var textOut string
	h := Roll(2, c.MxHp.Val)
	if c.MxHp.Val > c.Hp.Val && c.MxHp.Val+30 >= Roll(1, 100) {
		c.AdjHp(h)
		textOut = textOut + fmt.Sprintf(Green("\nIn victory heal %d hit points!\n\n"), h)
		c.Save()
	}
	return textOut
}

func OfferItem(c *Agent, f *Agent) {
	ClearScreen()
	fmt.Println(Yellow(Sword1()))
	fmt.Println(Blue("!! ITEM DROP !!\n"))
	fmt.Printf("%s has dropped it's %s.\n\n", Yellow(f.Name), Yellow(f.Weap.Name))
	fmt.Printf("Replace?\n	")
	c.Weap.Display()
	fmt.Printf("with..\n	")
	f.Weap.Display()
	if Confirm("\nWould you like to make this swap?") == true {
		c.Weap = f.Weap
		c.Save()
	}
}

func Spawn(c Agent) Agent {
	rand.Seed(time.Now().UTC().UnixNano())
	monsters := []Agent{
		// Add monsters here to be included in random spawn
		Spider,
		Phantom,
		Pixie,
		Kobold,
		Warlock,
		Coyote,
		Rogue,
		Minotaur,
		Lacrimosa,
		Griffon,
		Blackshuck,
	}

	// candidate is a proposed foe.  The candidate is tested with the Odds()
	// function to see if it's got >5% and <95% chance to win combat.  If it
	// does we return that candidate.   We also cap the number of candidate
	// loops at 100, so that we don't keep looping forever looking for a foe
	// we will never find.
	var candidate Agent
	for i := 0; i < 100; i++ {

		candidate = monsters[rand.Intn(len(monsters))]
		candidateOdds := Odds(&c, &candidate)

		if candidateOdds < 95 && candidateOdds > 5 {
			return candidate
		}
	}
	// we didn't find a candidate after a 100 tries, so just return one
	return candidate
}
<commit_msg>Add visual when searching for balanced foe<commit_after>package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"

	. "github.com/eyetoe/foobarbaz/agents"
	. "github.com/eyetoe/foobarbaz/art"
	. "github.com/eyetoe/foobarbaz/colors"
	. "github.com/eyetoe/foobarbaz/simulations"
	. "github.com/eyetoe/foobarbaz/util"
)

// Fight loop where c is character and f is foe
func Fight(c *Agent, f *Agent) {

	// calculate odds for the ascii art display only once
	odds := Odds(c, f)

	// declare strings
	var charDamageOut, charAttackDetails, foeDamageOut, foeAttackDetails, healmsg string

	// declare attack winner
	var winner *Agent

	// display
	display := func() {
		c.StatusBar()
		fmt.Println()
		FoeBar(*c, *f)

		// Color Foe's name and show victory chance percentage
		switch {
		case odds >= 80:
			fmt.Printf(Green("%s\n"), f.Art)
		case odds >= 60:
			fmt.Printf(Cyan("%s\n"), f.Art)
		case odds >= 40:
			fmt.Printf(Blue("%s\n"), f.Art)
		case odds >= 20:
			fmt.Printf(Yellow("%s\n"), f.Art)
		case odds >= 0:
			fmt.Printf(Red("%s\n"), f.Art)
		}

	}

	// Fight loop start here
	for {

		// redraw and display stats
		ClearScreen()
		display()
		fmt.Printf(charAttackDetails)
		fmt.Printf(foeDamageOut)
		fmt.Printf(foeAttackDetails)
		fmt.Printf(charDamageOut)
		fmt.Printf(healmsg)

		// clear vars between runs
		charAttackDetails = ""
		foeDamageOut = ""
		foeAttackDetails = ""
		charDamageOut = ""
		healmsg = ""

		// check pulse
		if f.Dead == true {
			if f.Weap.Name != c.Weap.Name && f.DropChance >= Roll(1, 100) {
				OfferItem(c, f)
			}
			fmt.Printf(RedU("%s has died!\n"), f.Name)
			Continue()
			break
		}
		if c.Dead == true {
			fmt.Printf(RedU("%s has died!\n"), c.Name)
			Continue()
			break
		}

		// Combat Prompt
		fmt.Printf("\n:> %sight, %svade, %sescribe, %sun\n<: ", GreenU("F"), GreenU("E"), GreenU("D"), GreenU("R"))
		choice, _, _ := GetChar()

		switch choice {
		// Fight
		case "f", "F":
			ClearScreen()
			display()
			// Player Attacks First
			winner, _, charAttackDetails = Attack(c, f)
			if c.Name == winner.Name {
				foeDamageOut = Damage(c, f, odds)
				if f.Dead == true {
					healmsg = WinHeal(c)
					continue
				}
			}
			// Foe Attacks Second
			winner, _, foeAttackDetails = Attack(f, c)
			if f.Name == winner.Name {
				charDamageOut = Damage(f, c, odds)
			}
			// Evade
			continue
		case "e", "E":
			fmt.Println("Evade!\n You stall for time, looking for an opening!")
			fmt.Println("Note: should have a separate menu here where you can use items.  So you have to take a break from the fight, to be able to pull out an item or potion.  including switching weapons, drinking potions, using magic items.")
			continue
			// Describe the Foe
		case "d", "D":
			//fmt.Printf(Blue("\nYou consider the %s. %s\n"), f.Name, f.Description)
			f.Describe()
			FoeBar(*c, *f)
			fmt.Println()
			continue
			// Run from the fight
		case "r", "R":
			fmt.Println("Run!\n You have lost this battle, but may yet win the war!")
			break
			// Default back to loop
		default:
			continue
		}
		return
	}

}

// Attack takes two structs and returns two structs.
// First input struct is the 'attacker'
// Second input struct is the 'defender'
// First output struct is the 'winner'
// Second output struct is the 'loser'
func Attack(a *Agent, d *Agent) (*Agent, *Agent, string) {

	var outText string

	// roll for attacker and defender
	ar := Roll(1, 100)
	dr := Roll(1, 100)
	// bonuses
	arB := a.Str.Val + a.Weap.Attack
	drB := d.Dex.Val
	// totals
	aT := ar + arB
	dT := dr + drB

	// uncomment here to 'show your work'
	//outText = fmt.Sprintf(Black("Attack roll: %d plus Bonus: %d for Total: %d\n"), ar, arB, aT)
	//outText = outText + fmt.Sprintf(Black("Defence roll: %d plus Bonus: %d for Total: %d\n"), dr, drB, dT)

	// Attack wins if greater than Defence
	// But a tie goes to the Defence
	if aT > dT {
		outText = outText + fmt.Sprintf(Green("%s hits with %s!\n "), a.Name, a.Weap.Name)
		return a, d, outText
	} else {
		outText = outText + fmt.Sprintf(Red("%s misses!\n"), a.Name)
		return d, a, outText
	}

}

// Calculate and apply damage to Agent
func Damage(a *Agent, d *Agent, odds int) string {

	var textOut string

	hp := Roll(1, a.Weap.Damage)

	d.AdjHp(0 - hp)

	//if d.Dead == false {
	textOut = textOut + fmt.Sprintf("for %s damage. ", Red(strconv.Itoa(hp)))
	textOut = textOut + fmt.Sprintf("%s's health = %s.\n", d.Name, Red(strconv.Itoa(d.Hp.Val)))
	//}

	// Monster agents don't have a save file set
	if d.File == "" && d.Dead == true {

		// reverse the percentage
		mods := 100 - odds

		percentage := float32(mods) * .01

		// reduce the drop by the reverse percentage
		exp := float32(d.ExpDrop()) * percentage

		// int to float conversion rounds down towards zero by dropping
		// everything after the decimal point. So I add 1 to the exp here
		// so the player never gets 0 exp reward
		exp++

		// exp is a float32 so do math with exp as an int
		a.Exp = a.Exp + int(exp)

		textOut = textOut + fmt.Sprintf(Green("\nYou gain %d experience.\n"), int(exp))
		a.Save()
	}
	d.Save()
	return textOut
}

func WinHeal(c *Agent) string {
	var textOut string
	h := Roll(2, c.MxHp.Val)
	if c.MxHp.Val > c.Hp.Val && c.MxHp.Val+30 >= Roll(1, 100) {
		c.AdjHp(h)
		textOut = textOut + fmt.Sprintf(Green("\nIn victory heal %d hit points!\n\n"), h)
		c.Save()
	}
	return textOut
}

func OfferItem(c *Agent, f *Agent) {
	ClearScreen()
	fmt.Println(Yellow(Sword1()))
	fmt.Println(Blue("!! ITEM DROP !!\n"))
	fmt.Printf("%s has dropped it's %s.\n\n", Yellow(f.Name), Yellow(f.Weap.Name))
	fmt.Printf("Replace?\n	")
	c.Weap.Display()
	fmt.Printf("with..\n	")
	f.Weap.Display()
	if Confirm("\nWould you like to make this swap?") == true {
		c.Weap = f.Weap
		c.Save()
	}
}

func Spawn(c Agent) Agent {
	rand.Seed(time.Now().UTC().UnixNano())
	monsters := []Agent{
		// Add monsters here to be included in random spawn
		Spider,
		Phantom,
		Pixie,
		Kobold,
		Warlock,
		Coyote,
		Rogue,
		Minotaur,
		Lacrimosa,
		Griffon,
		Blackshuck,
	}

	// candidate is a proposed foe.  The candidate is tested with the Odds()
	// function to see if it's got >5% and <95% chance to win combat.  If it
	// does we return that candidate.   We also cap the number of candidate
	// loops at 100, so that we don't keep looping forever looking for a foe
	// we will never find.
	var candidate Agent
	fmt.Println(Cyan("\n\n\nFinding opponent"))
	for i := 0; i < 100; i++ {

		fmt.Printf(".")
		candidate = monsters[rand.Intn(len(monsters))]
		candidateOdds := Odds(&c, &candidate)

		if candidateOdds < 95 && candidateOdds > 5 {
			return candidate
		}
	}
	// we didn't find a candidate after a 100 tries, so just return one
	return candidate
}
<|endoftext|>


<commit_before>package siri

import (
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/af83/edwig/api"
)

type SOAPClient struct {
	api.ClockConsumer

	url string
}

func NewSOAPClient(url string) *SOAPClient {
	return &SOAPClient{url: url}
}

// Temp
func WrapSoap(s string) string {
	soap := strings.Join([]string{
		"<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n\t<S:Body>\n",
		s,
		"\n\t</S:Body>\n</S:Envelope>"}, "")
	return soap
}

func (client *SOAPClient) CheckStatus(request *SIRICheckStatusRequest) (*XMLCheckStatusResponse, error) {
	// Wrap the request XML
	soapRequest := WrapSoap(request.BuildXML())

	// Create http request
	httpRequest, err := http.NewRequest("POST", client.url, strings.NewReader(soapRequest))
	if err != nil {
		return nil, err
	}
	httpRequest.Header.Set("Accept-Encoding", "gzip, deflate")
	httpRequest.Header.Set("Content-Type", "text/xml")

	// Send http request
	startTime := client.Clock().Now()
	response, err := http.DefaultClient.Do(httpRequest)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	responseTime := client.Clock().Since(startTime)

	// Check response status
	if response.StatusCode != http.StatusOK {
		return nil, errors.New(strings.Join([]string{"Request error, response status code: ", strconv.Itoa(response.StatusCode)}, ""))
	}

	// Check if response is gzip
	var responseReader io.ReadCloser
	if response.Header.Get("Content-Encoding") == "gzip" {
		responseReader, err = gzip.NewReader(response.Body)
		if err != nil {
			return nil, err
		}
		defer responseReader.Close()
	} else {
		responseReader = response.Body
	}

	// Create XMLCheckStatusResponse
	responseContent, err := ioutil.ReadAll(responseReader)
	if err != nil {
		return nil, err
	}
	xmlResponse, err := NewXMLCheckStatusResponseFromContent(responseContent)
	if err != nil {
		return nil, err
	}

	// Log
	if xmlResponse.Status() {
		fmt.Print("SIRI OK - status true - ")
	} else {
		fmt.Print("SIRI CRITICAL: status false - ")
		if xmlResponse.ErrorType() == "OtherError" {
			fmt.Printf("%s %d %s - ", xmlResponse.ErrorType(), xmlResponse.ErrorNumber(), xmlResponse.ErrorText())
		} else {
			fmt.Printf("%s %s - ", xmlResponse.ErrorType(), xmlResponse.ErrorText())
		}
	}
	fmt.Printf("%.3f seconds response time\n", responseTime.Seconds())

	return xmlResponse, nil
}

func CheckStatusHandler(w http.ResponseWriter, r *http.Request) {
	// Try to read and parse request body
	requestContent, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Invalid request: can't read content", 500)
		return
	}
	xmlRequest, err := NewXMLCheckStatusRequestFromContent(requestContent)
	if err != nil {
		http.Error(w, "Invalid request: can't parse content", 500)
		return
	}

	// Set Content-Type header and create a SIRICheckStatusResponse
	w.Header().Set("Content-Type", "text/xml")

	response := new(SIRICheckStatusResponse)
	response.Address = strings.Join([]string{r.URL.Host, r.URL.Path}, "")
	response.ProducerRef = "Edwig"
	response.RequestMessageRef = xmlRequest.MessageIdentifier()
	response.GenerateMessageIdentifier()
	response.Status = true // Temp
	response.SetResponseTimestamp()
	response.ServiceStartedTime = api.DefaultClock().Now() //Temp

	fmt.Fprintf(w, response.BuildXML())
}
<commit_msg>better log<commit_after>package siri

import (
	"compress/gzip"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"strings"

	"github.com/af83/edwig/api"
)

type SOAPClient struct {
	api.ClockConsumer

	url string
}

func NewSOAPClient(url string) *SOAPClient {
	return &SOAPClient{url: url}
}

// Temp
func WrapSoap(s string) string {
	soap := strings.Join([]string{
		"<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">\n\t<S:Body>\n",
		s,
		"\n\t</S:Body>\n</S:Envelope>"}, "")
	return soap
}

func (client *SOAPClient) CheckStatus(request *SIRICheckStatusRequest) (*XMLCheckStatusResponse, error) {
	// Wrap the request XML
	soapRequest := WrapSoap(request.BuildXML())

	// Create http request
	httpRequest, err := http.NewRequest("POST", client.url, strings.NewReader(soapRequest))
	if err != nil {
		return nil, err
	}
	httpRequest.Header.Set("Accept-Encoding", "gzip, deflate")
	httpRequest.Header.Set("Content-Type", "text/xml")

	// Send http request
	startTime := client.Clock().Now()
	response, err := http.DefaultClient.Do(httpRequest)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	responseTime := client.Clock().Since(startTime)

	// Check response status
	if response.StatusCode != http.StatusOK {
		return nil, errors.New(strings.Join([]string{"Request error, response status code: ", strconv.Itoa(response.StatusCode)}, ""))
	}

	// Check if response is gzip
	var responseReader io.ReadCloser
	if response.Header.Get("Content-Encoding") == "gzip" {
		responseReader, err = gzip.NewReader(response.Body)
		if err != nil {
			return nil, err
		}
		defer responseReader.Close()
	} else {
		responseReader = response.Body
	}

	// Create XMLCheckStatusResponse
	responseContent, err := ioutil.ReadAll(responseReader)
	if err != nil {
		return nil, err
	}
	xmlResponse, err := NewXMLCheckStatusResponseFromContent(responseContent)
	if err != nil {
		return nil, err
	}

	// Log
	var logMessage []byte
	if xmlResponse.Status() {
		logMessage = []byte("SIRI OK - status true - ")
	} else {
		logMessage = []byte("SIRI CRITICAL: status false - ")
		if xmlResponse.ErrorType() == "OtherError" {
			logMessage = append(logMessage, fmt.Sprintf("%s %d %s - ", xmlResponse.ErrorType(), xmlResponse.ErrorNumber(), xmlResponse.ErrorText())...)
		} else {
			logMessage = append(logMessage, fmt.Sprintf("%s %s - ", xmlResponse.ErrorType(), xmlResponse.ErrorText())...)
		}
	}
	logMessage = append(logMessage, fmt.Sprintf("%.3f seconds response time", responseTime.Seconds())...)
	log.Println(string(logMessage[:]))

	return xmlResponse, nil
}

func CheckStatusHandler(w http.ResponseWriter, r *http.Request) {
	// Try to read and parse request body
	requestContent, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Invalid request: can't read content", 500)
		return
	}
	xmlRequest, err := NewXMLCheckStatusRequestFromContent(requestContent)
	if err != nil {
		http.Error(w, "Invalid request: can't parse content", 500)
		return
	}

	// Set Content-Type header and create a SIRICheckStatusResponse
	w.Header().Set("Content-Type", "text/xml")

	response := new(SIRICheckStatusResponse)
	response.Address = strings.Join([]string{r.URL.Host, r.URL.Path}, "")
	response.ProducerRef = "Edwig"
	response.RequestMessageRef = xmlRequest.MessageIdentifier()
	response.GenerateMessageIdentifier()
	response.Status = true // Temp
	response.SetResponseTimestamp()
	response.ServiceStartedTime = api.DefaultClock().Now() //Temp

	fmt.Fprintf(w, response.BuildXML())
}
<|endoftext|>


<commit_before>package gitutil

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	log "github.com/bitrise-io/git-clone/logger"
	"github.com/bitrise-io/go-utils/cmdex"
	"github.com/bitrise-io/go-utils/errorutil"
	"github.com/bitrise-io/go-utils/pathutil"
)

// ---------------------
//	Model
// ---------------------

// Helper ...
type Helper struct {
	destinationDir string
	remoteURI      string

	checkoutParam string
	checkoutTag   bool
	pullRequestID string
	cloneDepth    string
}

// NewHelper ...
func NewHelper(destinationDir, remoteURI string) (Helper, error) {
	if destinationDir == "" {
		return Helper{}, errors.New("destination dir path is empty")
	}

	if remoteURI == "" {
		return Helper{}, errors.New("remote URI is empty")
	}

	// Expand destination dir
	fullDestinationDir, err := pathutil.AbsPath(destinationDir)
	if err != nil {
		return Helper{}, err
	}

	// Check if .git exist
	gitDirPth := filepath.Join(fullDestinationDir, ".git")
	if exist, err := pathutil.IsDirExists(gitDirPth); err != nil {
		return Helper{}, err
	} else if exist {
		return Helper{}, fmt.Errorf(".git folder already exists in the destination dir: %s", fullDestinationDir)
	}

	// Create destination dir if not exist
	if exist, err := pathutil.IsDirExists(fullDestinationDir); err != nil {
		return Helper{}, err
	} else if !exist {
		if err := os.MkdirAll(fullDestinationDir, 0777); err != nil {
			return Helper{}, err
		}
	}

	return Helper{
		destinationDir: fullDestinationDir,
		remoteURI:      remoteURI,
	}, nil
}

// ConfigureCheckoutParam ...
func (helper *Helper) ConfigureCheckoutParam(pullRequestID, commitHash, tag, branch, cloneDepth string) {
	if pullRequestID != "" {
		helper.checkoutParam = "pull/" + pullRequestID
		helper.pullRequestID = pullRequestID
	} else if commitHash != "" {
		helper.checkoutParam = commitHash
	} else if tag != "" {
		helper.checkoutParam = tag
		helper.checkoutTag = true
	} else if branch != "" {
		helper.checkoutParam = branch
	}

	helper.cloneDepth = cloneDepth
}

func runCommandInDirWithEnvs(cmdSlice []string, dir string, envs []string) error {
	cmd, err := cmdex.NewCommandFromSlice(cmdSlice)
	if err != nil {
		return err
	}

	if len(envs) > 0 {
		cmd.SetEnvs(envs)
	}

	if dir != "" {
		cmd.SetDir(dir)
	}

	log.Details("=> %s", cmdex.PrintableCommandArgs(false, cmdSlice))

	return cmd.Run()
}

func runCommandInDir(cmdSlice []string, dir string) error {
	return runCommandInDirWithEnvs(cmdSlice, dir, []string{})
}

// Init ...
func (helper Helper) Init() error {
	cmdSlice := createGitCmdSlice("init")

	return runCommandInDir(cmdSlice, helper.destinationDir)
}

// RemoteAdd ...
func (helper Helper) RemoteAdd() error {
	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass("remote", "add", "origin", helper.remoteURI)

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// Fetch ...
func (helper Helper) Fetch() error {
	params := []string{"fetch"}
	if helper.pullRequestID != "" {
		params = append(params, "origin", "pull/"+helper.pullRequestID+"/merge:"+helper.checkoutParam)
	}
	if helper.cloneDepth != "" {
		params = append(params, "--depth="+helper.cloneDepth)
	}

	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass(params...)

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// FetchTags ...
func (helper Helper) FetchTags() error {
	params := []string{"fetch", "--tags"}
	if helper.pullRequestID != "" {
		params = append(params, "origin", "pull/"+helper.pullRequestID+"/merge:"+helper.checkoutParam)
	}
	if helper.cloneDepth != "" {
		params = append(params, "--depth="+helper.cloneDepth)
	}

	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass(params...)

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// ShouldCheckout ...
func (helper Helper) ShouldCheckout() bool {
	return (helper.checkoutParam != "")
}

// ShouldCheckoutTag ...
func (helper Helper) ShouldCheckoutTag() bool {
	return helper.checkoutTag
}

// Checkout ...
func (helper Helper) Checkout() error {
	cmdSlice := createGitCmdSlice("checkout", helper.checkoutParam)

	return runCommandInDir(cmdSlice, helper.destinationDir)
}

// ShouldTryFetchUnshallow ...
func (helper Helper) ShouldTryFetchUnshallow() bool {
	return (helper.cloneDepth != "")
}

// FetchUnshallow ...
func (helper Helper) FetchUnshallow() error {
	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass("fetch", "--unshallow")

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// SubmoduleUpdate ...
func (helper Helper) SubmoduleUpdate() error {
	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass("submodule", "update", "--init", "--recursive")

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

func runLogCommand(cmdSlice []string, dir string) (string, error) {
	out, err := cmdex.NewCommand(cmdSlice[0], cmdSlice[1:]...).SetDir(dir).RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return "", err
	}
	return strings.Trim(out, `"`), nil
}

// LogCommitHash ...
func (helper Helper) LogCommitHash() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%H"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommitMessageSubject ...
func (helper Helper) LogCommitMessageSubject() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%s"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommitMessageBody ...
func (helper Helper) LogCommitMessageBody() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%b"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogAuthorName ...
func (helper Helper) LogAuthorName() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%an"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogAuthorEmail ...
func (helper Helper) LogAuthorEmail() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%ae"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommiterName ...
func (helper Helper) LogCommiterName() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%cn"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommiterEmail ...
func (helper Helper) LogCommiterEmail() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%ce"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// ---------------------
//	Methods
// ---------------------

func createGitCmdSlice(params ...string) []string {
	return append([]string{"git"}, params...)
}

func createGitCmdSliceWithGitDontAskpass(params ...string) ([]string, []string) {
	return createGitCmdSlice(params...), []string{"GIT_ASKPASS=echo"}
}

func createGitLogCmdSlice(params ...string) []string {
	return append([]string{"git", "log", "-1"}, params...)
}

func properReturn(err error, out string) error {
	if err == nil {
		return nil
	}

	if errorutil.IsExitStatusError(err) && out != "" {
		return errors.New(out)
	}
	return err
}
<commit_msg>proper error message<commit_after>package gitutil

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	log "github.com/bitrise-io/git-clone/logger"
	"github.com/bitrise-io/go-utils/cmdex"
	"github.com/bitrise-io/go-utils/errorutil"
	"github.com/bitrise-io/go-utils/pathutil"
)

// ---------------------
//	Model
// ---------------------

// Helper ...
type Helper struct {
	destinationDir string
	remoteURI      string

	checkoutParam string
	checkoutTag   bool
	pullRequestID string
	cloneDepth    string
}

// NewHelper ...
func NewHelper(destinationDir, remoteURI string) (Helper, error) {
	if destinationDir == "" {
		return Helper{}, errors.New("destination dir path is empty")
	}

	if remoteURI == "" {
		return Helper{}, errors.New("remote URI is empty")
	}

	// Expand destination dir
	fullDestinationDir, err := pathutil.AbsPath(destinationDir)
	if err != nil {
		return Helper{}, err
	}

	// Check if .git exist
	gitDirPth := filepath.Join(fullDestinationDir, ".git")
	if exist, err := pathutil.IsDirExists(gitDirPth); err != nil {
		return Helper{}, err
	} else if exist {
		return Helper{}, fmt.Errorf(".git folder already exists in the destination dir: %s", fullDestinationDir)
	}

	// Create destination dir if not exist
	if exist, err := pathutil.IsDirExists(fullDestinationDir); err != nil {
		return Helper{}, err
	} else if !exist {
		if err := os.MkdirAll(fullDestinationDir, 0777); err != nil {
			return Helper{}, err
		}
	}

	return Helper{
		destinationDir: fullDestinationDir,
		remoteURI:      remoteURI,
	}, nil
}

// ConfigureCheckoutParam ...
func (helper *Helper) ConfigureCheckoutParam(pullRequestID, commitHash, tag, branch, cloneDepth string) {
	if pullRequestID != "" {
		helper.checkoutParam = "pull/" + pullRequestID
		helper.pullRequestID = pullRequestID
	} else if commitHash != "" {
		helper.checkoutParam = commitHash
	} else if tag != "" {
		helper.checkoutParam = tag
		helper.checkoutTag = true
	} else if branch != "" {
		helper.checkoutParam = branch
	}

	helper.cloneDepth = cloneDepth
}

func runCommandInDirWithEnvs(cmdSlice []string, dir string, envs []string) error {
	cmd, err := cmdex.NewCommandFromSlice(cmdSlice)
	if err != nil {
		return err
	}

	if len(envs) > 0 {
		cmd.SetEnvs(envs)
	}

	if dir != "" {
		cmd.SetDir(dir)
	}

	log.Details("=> %s", cmdex.PrintableCommandArgs(false, cmdSlice))

	var errBuffer bytes.Buffer
	errWriter := bufio.NewWriter(&errBuffer)
	cmd.SetStderr(errWriter)

	var outBuffer bytes.Buffer
	outWriter := bufio.NewWriter(&outBuffer)
	cmd.SetStdout(outWriter)

	if err := cmd.Run(); err != nil {
		if errorutil.IsExitStatusError(err) {
			if !errorutil.IsExitStatusErrorStr(errBuffer.String()) {
				return errors.New(errBuffer.String())
			}

			if !errorutil.IsExitStatusErrorStr(outBuffer.String()) {
				return errors.New(outBuffer.String())
			}
		}

		return err
	}

	return nil
}

func runCommandInDir(cmdSlice []string, dir string) error {
	return runCommandInDirWithEnvs(cmdSlice, dir, []string{})
}

// Init ...
func (helper Helper) Init() error {
	cmdSlice := createGitCmdSlice("init")

	return runCommandInDir(cmdSlice, helper.destinationDir)
}

// RemoteAdd ...
func (helper Helper) RemoteAdd() error {
	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass("remote", "add", "origin", helper.remoteURI)

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// Fetch ...
func (helper Helper) Fetch() error {
	params := []string{"fetch"}
	if helper.pullRequestID != "" {
		params = append(params, "origin", "pull/"+helper.pullRequestID+"/merge:"+helper.checkoutParam)
	}
	if helper.cloneDepth != "" {
		params = append(params, "--depth="+helper.cloneDepth)
	}

	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass(params...)

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// FetchTags ...
func (helper Helper) FetchTags() error {
	params := []string{"fetch", "--tags"}
	if helper.pullRequestID != "" {
		params = append(params, "origin", "pull/"+helper.pullRequestID+"/merge:"+helper.checkoutParam)
	}
	if helper.cloneDepth != "" {
		params = append(params, "--depth="+helper.cloneDepth)
	}

	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass(params...)

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// ShouldCheckout ...
func (helper Helper) ShouldCheckout() bool {
	return (helper.checkoutParam != "")
}

// ShouldCheckoutTag ...
func (helper Helper) ShouldCheckoutTag() bool {
	return helper.checkoutTag
}

// Checkout ...
func (helper Helper) Checkout() error {
	cmdSlice := createGitCmdSlice("checkout", helper.checkoutParam)

	return runCommandInDir(cmdSlice, helper.destinationDir)
}

// ShouldTryFetchUnshallow ...
func (helper Helper) ShouldTryFetchUnshallow() bool {
	return (helper.cloneDepth != "")
}

// FetchUnshallow ...
func (helper Helper) FetchUnshallow() error {
	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass("fetch", "--unshallow")

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

// SubmoduleUpdate ...
func (helper Helper) SubmoduleUpdate() error {
	cmdSlice, envs := createGitCmdSliceWithGitDontAskpass("submodule", "update", "--init", "--recursive")

	return runCommandInDirWithEnvs(cmdSlice, helper.destinationDir, append(os.Environ(), envs...))
}

func runLogCommand(cmdSlice []string, dir string) (string, error) {
	out, err := cmdex.NewCommand(cmdSlice[0], cmdSlice[1:]...).SetDir(dir).RunAndReturnTrimmedCombinedOutput()
	if err != nil {
		return "", err
	}
	return strings.Trim(out, `"`), nil
}

// LogCommitHash ...
func (helper Helper) LogCommitHash() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%H"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommitMessageSubject ...
func (helper Helper) LogCommitMessageSubject() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%s"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommitMessageBody ...
func (helper Helper) LogCommitMessageBody() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%b"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogAuthorName ...
func (helper Helper) LogAuthorName() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%an"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogAuthorEmail ...
func (helper Helper) LogAuthorEmail() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%ae"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommiterName ...
func (helper Helper) LogCommiterName() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%cn"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// LogCommiterEmail ...
func (helper Helper) LogCommiterEmail() (string, error) {
	cmdSlice := createGitLogCmdSlice(`--format="%ce"`)
	return runLogCommand(cmdSlice, helper.destinationDir)
}

// ---------------------
//	Methods
// ---------------------

func createGitCmdSlice(params ...string) []string {
	return append([]string{"git"}, params...)
}

func createGitCmdSliceWithGitDontAskpass(params ...string) ([]string, []string) {
	return createGitCmdSlice(params...), []string{"GIT_ASKPASS=echo"}
}

func createGitLogCmdSlice(params ...string) []string {
	return append([]string{"git", "log", "-1"}, params...)
}

func properReturn(err error, out string) error {
	if err == nil {
		return nil
	}

	if errorutil.IsExitStatusError(err) && out != "" {
		return errors.New(out)
	}
	return err
}
<|endoftext|>


<commit_before>package sender

import analytics "github.com/segmentio/analytics-go"

var (
	// TODO: remove this; this should be sent by worker calling this
	DefaultSegmentIOKey = "kb2hfdgf20"
)

type SegementIOSender struct {
	Client *analytics.Client
}

func NewSegementIOSender(endpoint, key string, size int) *SegementIOSender {
	client := analytics.New(key)
	if endpoint != "" {
		client.Endpoint = endpoint
	}

	client.Size = size

	return &SegementIOSender{Client: client}
}

func (s *SegementIOSender) Send(event *Event) error {
	_, ok := event.Properties["body"]
	if !ok {
		if event.Body != nil {
			event.Properties["body"] = event.Body.Content
			event.Properties["bodyType"] = event.Body.Type
		}
	}

	err := s.Client.Track(&analytics.Track{
		Event:      event.Name,
		UserId:     event.User.Username,
		Properties: event.Properties,
	})

	return err
}
<commit_msg>sender: refactoring<commit_after>package sender

import analytics "github.com/segmentio/analytics-go"

var (
	// TODO: remove this; this should be sent by worker calling this
	DefaultSegmentIOKey = "kb2hfdgf20"
)

type SegementIOSender struct {
	Client *analytics.Client
}

func NewSegementIOSender(endpoint, key string, size int) *SegementIOSender {
	client := analytics.New(key)
	if endpoint != "" {
		client.Endpoint = endpoint
	}

	client.Size = size

	return &SegementIOSender{Client: client}
}

func (s *SegementIOSender) Send(event *Event) error {
	event = addBody(event)

	err := s.Client.Track(&analytics.Track{
		Event:      event.Name,
		UserId:     event.User.Username,
		Properties: event.Properties,
	})

	return err
}

func addBody(event *Event) *Event {
	_, ok := event.Properties["body"]
	if ok {
		return event
	}

	if event.Body != nil {
		event.Properties["body"] = event.Body.Content
		event.Properties["bodyType"] = event.Body.Type
	}

	return event
}
<|endoftext|>


<commit_before>// Package api provides endpoints for topic moderation system
package api

import (
	"socialapi/models"
	"socialapi/workers/common/handler"
	"socialapi/workers/common/mux"

	"github.com/koding/metrics"
)

// AddHandlers added the internal handlers to the given Muxer
func AddHandlers(m *mux.Mux, metric *metrics.Metrics) {
	m.AddHandler(
		handler.Request{
			Handler:  CreateLink,
			Name:     models.ModerationChannelCreateLink,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  DeleteLink,
			Name:     models.ModerationChannelDeleteLink,
			Type:     handler.DeleteRequest,
			Endpoint: "/moderation/channel/{rootId}/link/{leafId}",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  GetLinks,
			Name:     models.ModerationChannelGetLink,
			Type:     handler.GetRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  Blacklist,
			Name:     models.ModerationChannelBlacklist,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/blacklist",
			Metrics:  metric,
		},
	)
}
<commit_msg>socialapi: handler is added for rootId<commit_after>// Package api provides endpoints for topic moderation system
package api

import (
	"socialapi/models"
	"socialapi/workers/common/handler"
	"socialapi/workers/common/mux"

	"github.com/koding/metrics"
)

// AddHandlers added the internal handlers to the given Muxer
func AddHandlers(m *mux.Mux, metric *metrics.Metrics) {
	m.AddHandler(
		handler.Request{
			Handler:  CreateLink,
			Name:     models.ModerationChannelCreateLink,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  DeleteLink,
			Name:     models.ModerationChannelDeleteLink,
			Type:     handler.DeleteRequest,
			Endpoint: "/moderation/channel/{rootId}/link/{leafId}",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  GetLinks,
			Name:     models.ModerationChannelGetLink,
			Type:     handler.GetRequest,
			Endpoint: "/moderation/channel/{rootId}/link",
			Metrics:  metric,
		},
	)

	m.AddHandler(
		handler.Request{
			Handler:  Blacklist,
			Name:     models.ModerationChannelBlacklist,
			Type:     handler.PostRequest,
			Endpoint: "/moderation/channel/blacklist",
			Metrics:  metric,
		},
	)
	m.AddHandler(
		handler.Request{
			Handler:  GetRoot,
			Name:     models.ModerationChannelGetRoot,
			Type:     handler.GetRequest,
			Endpoint: "/moderation/channel/{leafId}/root",
			Metrics:  metric,
		},
	)
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Patrick Gundlach, speedata (Berlin, Germany)
// Copyright 2014 The Gogs Authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package git

import (
	"bytes"
)

type Commit struct {
	Author        *Signature
	Committer     *Signature
	Oid           *Oid // The id of this commit object
	CommitMessage string
	Tree          *Tree
	treeId        *Oid
	parents       []*Oid // sha1 strings
	repository    *Repository
}

// Return the commit message. Same as retrieving CommitMessage directly.
func (ci *Commit) Message() string {
	return ci.CommitMessage
}

// Get the id of the commit.
func (ci *Commit) Id() *Oid {
	return ci.Oid
}

// Return parent number n (0-based index)
func (ci *Commit) Parent(n int) *Commit {
	if n >= len(ci.parents) {
		return nil
	}
	oid := ci.parents[n]
	parent, err := ci.repository.LookupCommit(oid)
	if err != nil {
		return nil
	}
	return parent
}

// Return oid of the parent number n (0-based index). Return nil if no such parent exists.
func (ci *Commit) ParentId(n int) *Oid {
	if n >= len(ci.parents) {
		return nil
	}
	return ci.parents[n]
}

// Return the number of parents of the commit. 0 if this is the
// root commit, otherwise 1,2,...
func (ci *Commit) ParentCount() int {
	return len(ci.parents)
}

// Return oid of the (root) tree of this commit.
func (ci *Commit) TreeId() *Oid {
	return ci.treeId
}

// Parse commit information from the (uncompressed) raw
// data from the commit object.
// \n\n separate headers from message
func parseCommitData(data []byte) (*Commit, error) {
	commit := new(Commit)
	commit.parents = make([]*Oid, 0, 1)
	// we now have the contents of the commit object. Let's investigate...
	nextline := 0
l:
	for {
		eol := bytes.IndexByte(data[nextline:], '\n')
		switch {
		case eol > 0:
			line := data[nextline : nextline+eol]
			spacepos := bytes.IndexByte(line, ' ')
			reftype := line[:spacepos]
			switch string(reftype) {
			case "tree":
				oid, err := NewOidFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.treeId = oid
			case "parent":
				// A commit can have one or more parents
				oid, err := NewOidFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.parents = append(commit.parents, oid)
			case "author":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Author = sig
			case "committer":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Committer = sig
			}
			nextline += eol + 1
		case eol == 0:
			commit.CommitMessage = string(data[nextline+1:])
			break l
		default:
			break l
		}
	}
	return commit, nil
}

// Find the commit object in the repository.
func (repos *Repository) LookupCommit(oid *Oid) (*Commit, error) {
	_, _, data, err := repos.getRawObject(oid)
	if err != nil {
		return nil, err
	}
	ci, err := parseCommitData(data)
	if err != nil {
		return nil, err
	}
	ci.repository = repos
	ci.Oid = oid

	_, _, data, err = repos.getRawObject(ci.treeId)
	if err != nil {
		return nil, err
	}
	tree, err := parseTreeData(data)
	tree.Oid = ci.TreeId()
	if err != nil {
		return nil, err
	}
	tree.repository = repos
	ci.Tree = tree
	return ci, nil
}
<commit_msg>Mirror change<commit_after>// Copyright (c) 2013 Patrick Gundlach, speedata (Berlin, Germany)
// Copyright 2014 The Gogs Authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package git

import (
	"bytes"
)

// Commit represents a git commit.
type Commit struct {
	Author        *Signature
	Committer     *Signature
	Oid           *Oid // The id of this commit object
	CommitMessage string
	Tree          *Tree
	treeId        *Oid
	parents       []*Oid // sha1 strings
	repository    *Repository
}

// Return the commit message. Same as retrieving CommitMessage directly.
func (ci *Commit) Message() string {
	return ci.CommitMessage
}

// Get the id of the commit.
func (ci *Commit) Id() *Oid {
	return ci.Oid
}

// Return parent number n (0-based index)
func (ci *Commit) Parent(n int) *Commit {
	if n >= len(ci.parents) {
		return nil
	}
	oid := ci.parents[n]
	parent, err := ci.repository.LookupCommit(oid)
	if err != nil {
		return nil
	}
	return parent
}

// Return oid of the parent number n (0-based index). Return nil if no such parent exists.
func (ci *Commit) ParentId(n int) *Oid {
	if n >= len(ci.parents) {
		return nil
	}
	return ci.parents[n]
}

// Return the number of parents of the commit. 0 if this is the
// root commit, otherwise 1,2,...
func (ci *Commit) ParentCount() int {
	return len(ci.parents)
}

// Return oid of the (root) tree of this commit.
func (ci *Commit) TreeId() *Oid {
	return ci.treeId
}

// Parse commit information from the (uncompressed) raw
// data from the commit object.
// \n\n separate headers from message
func parseCommitData(data []byte) (*Commit, error) {
	commit := new(Commit)
	commit.parents = make([]*Oid, 0, 1)
	// we now have the contents of the commit object. Let's investigate...
	nextline := 0
l:
	for {
		eol := bytes.IndexByte(data[nextline:], '\n')
		switch {
		case eol > 0:
			line := data[nextline : nextline+eol]
			spacepos := bytes.IndexByte(line, ' ')
			reftype := line[:spacepos]
			switch string(reftype) {
			case "tree":
				oid, err := NewOidFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.treeId = oid
			case "parent":
				// A commit can have one or more parents
				oid, err := NewOidFromString(string(line[spacepos+1:]))
				if err != nil {
					return nil, err
				}
				commit.parents = append(commit.parents, oid)
			case "author":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Author = sig
			case "committer":
				sig, err := newSignatureFromCommitline(line[spacepos+1:])
				if err != nil {
					return nil, err
				}
				commit.Committer = sig
			}
			nextline += eol + 1
		case eol == 0:
			commit.CommitMessage = string(data[nextline+1:])
			break l
		default:
			break l
		}
	}
	return commit, nil
}

// Find the commit object in the repository.
func (repos *Repository) LookupCommit(oid *Oid) (*Commit, error) {
	_, _, data, err := repos.getRawObject(oid)
	if err != nil {
		return nil, err
	}
	ci, err := parseCommitData(data)
	if err != nil {
		return nil, err
	}
	ci.repository = repos
	ci.Oid = oid

	_, _, data, err = repos.getRawObject(ci.treeId)
	if err != nil {
		return nil, err
	}
	tree, err := parseTreeData(data)
	tree.Oid = ci.TreeId()
	if err != nil {
		return nil, err
	}
	tree.repository = repos
	ci.Tree = tree
	return ci, nil
}
<|endoftext|>


<commit_before>package fileloader

import (
	"github.com/hackform/governor"
	"github.com/labstack/echo"
	"github.com/sirupsen/logrus"
	"io"
	"mime"
	"net/http"
)

const (
	moduleID            = "fileloader"
	defaultContextField = "file"
)

type (
	// FileLoader is a service for managing file uploads
	FileLoader interface {
		Load(formField string, opt Options) echo.MiddlewareFunc
	}

	fileloaderService struct {
		log *logrus.Logger
	}

	// Options represent the options to load the file
	Options struct {
		ContextField string
		MimeType     []string
	}
)

// New returns a new fileloader service
func New(conf governor.Config, l *logrus.Logger) FileLoader {
	l.Info("initialized fileloader service")

	return &fileloaderService{
		log: l,
	}
}

const (
	moduleIDLoad = moduleID + ".Load"
)

// Load reads in a file from a form and places it into context
func (f *fileloaderService) Load(formField string, opt Options) echo.MiddlewareFunc {
	if formField == "" {
		panic("formField cannot be an empty string")
	}
	if opt.ContextField == "" {
		opt.ContextField = defaultContextField
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			file, err := c.FormFile(formField)
			if err != nil {
				return governor.NewErrorUser(moduleIDLoad, err.Error(), 0, http.StatusBadRequest)
			}

			mediaType, _, err := mime.ParseMediaType(file.Header.Get("Content-Type"))
			if err != nil {
				return governor.NewErrorUser(moduleIDLoad, err.Error(), 0, http.StatusBadRequest)
			}
			if opt.MimeType != nil && len(opt.MimeType) > 0 {
				found := false
				for _, i := range opt.MimeType {
					if i == mediaType {
						found = true
						break
					}
				}
				if !found {
					return governor.NewErrorUser(moduleIDLoad, mediaType+" is unsupported", 0, http.StatusUnsupportedMediaType)
				}
			}

			src, err := file.Open()
			if err != nil {
				return governor.NewError(moduleIDLoad, err.Error(), 0, http.StatusInternalServerError)
			}
			defer func(closer io.Closer) {
				err := closer.Close()
				if err != nil {
					gerr := governor.NewError(moduleIDLoad, err.Error(), 0, http.StatusInternalServerError)
					f.log.WithFields(logrus.Fields{
						"origin": gerr.Origin(),
						"source": gerr.Source(),
						"code":   gerr.Code(),
					}).Error(gerr.Message())
				}
			}(src)

			c.Set(opt.ContextField, src)

			return next(c)
		}
	}
}
<commit_msg>Update file loader to include filesize<commit_after>package fileloader

import (
	"github.com/hackform/governor"
	"github.com/labstack/echo"
	"github.com/sirupsen/logrus"
	"io"
	"mime"
	"net/http"
)

const (
	moduleID            = "fileloader"
	defaultContextField = "file"
	defaultContextField = "filesize"
)

type (
	// FileLoader is a service for managing file uploads
	FileLoader interface {
		Load(formField string, opt Options) echo.MiddlewareFunc
	}

	fileloaderService struct {
		log *logrus.Logger
	}

	// Options represent the options to load the file
	Options struct {
		ContextField string
		SizeField    string
		MimeType     []string
	}
)

// New returns a new fileloader service
func New(conf governor.Config, l *logrus.Logger) FileLoader {
	l.Info("initialized fileloader service")

	return &fileloaderService{
		log: l,
	}
}

const (
	moduleIDLoad = moduleID + ".Load"
)

// Load reads in a file from a form and places it into context
func (f *fileloaderService) Load(formField string, opt Options) echo.MiddlewareFunc {
	if formField == "" {
		panic("formField cannot be an empty string")
	}
	if opt.ContextField == "" {
		opt.ContextField = defaultContextField
	}
	if opt.SizeField == "" {
		opt.SizeField = defaultSizeField
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			file, err := c.FormFile(formField)
			if err != nil {
				return governor.NewErrorUser(moduleIDLoad, err.Error(), 0, http.StatusBadRequest)
			}

			mediaType, _, err := mime.ParseMediaType(file.Header.Get("Content-Type"))
			if err != nil {
				return governor.NewErrorUser(moduleIDLoad, err.Error(), 0, http.StatusBadRequest)
			}
			if opt.MimeType != nil && len(opt.MimeType) > 0 {
				found := false
				for _, i := range opt.MimeType {
					if i == mediaType {
						found = true
						break
					}
				}
				if !found {
					return governor.NewErrorUser(moduleIDLoad, mediaType+" is unsupported", 0, http.StatusUnsupportedMediaType)
				}
			}

			src, err := file.Open()
			if err != nil {
				return governor.NewError(moduleIDLoad, err.Error(), 0, http.StatusInternalServerError)
			}
			defer func(closer io.Closer) {
				err := closer.Close()
				if err != nil {
					gerr := governor.NewError(moduleIDLoad, err.Error(), 0, http.StatusInternalServerError)
					f.log.WithFields(logrus.Fields{
						"origin": gerr.Origin(),
						"source": gerr.Source(),
						"code":   gerr.Code(),
					}).Error(gerr.Message())
				}
			}(src)

			c.Set(opt.ContextField, src)
			c.Set(opt.SizeField, file.Size)

			return next(c)
		}
	}
}
<|endoftext|>