func PullFile(wsConn *websocket.Conn, filePullRequest fileRequests.FilePullRequest) {

	// Check that file exists
	file, err := GetFileById(filePullRequest.BaseRequest.ResId)
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-300, filePullRequest.BaseRequest.Tag, nil))
		return
	}

	// Read file from disk
	if _, err := os.Stat(file.GetPath()); os.IsNotExist(err) {
		managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(filePullRequest.BaseRequest.Tag, map[string]interface{}{"FileBytes": "", "Changes": ""}))
		return
	}
	fileBytes, err := ioutil.ReadFile(file.GetPath())
	if err != nil {
		managers.LogError("Failed to read from file", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-301, filePullRequest.BaseRequest.Tag, nil))
		return
	}

	changes, err := GetChangesByFile(file.Id)
	if err != nil {
		managers.LogError("Failed to retrieve changes", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-402, filePullRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(filePullRequest.BaseRequest.Tag, map[string]interface{}{"File": file, "FileBytes": fileBytes, "Changes": changes}))
}
func Subscribe(wsConn *websocket.Conn, subscriptionRequest projectRequests.ProjectSubscribeRequest) {

	projectId := subscriptionRequest.BaseRequest.ResId

	proj, err := GetProjectById(projectId)

	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-200, subscriptionRequest.BaseRequest.Tag, nil))
		return
	}

	hasPermission := false
	for key, value := range proj.Permissions {
		if (key == subscriptionRequest.BaseRequest.Username || key == "*") && value >= 1 {
			if !managers.WebSocketSubscribeProject(wsConn, subscriptionRequest.BaseRequest.Username, projectId) {
				managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-206, subscriptionRequest.BaseRequest.Tag, nil))
				return
			}
			hasPermission = true
		}
	}

	if !hasPermission {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-208, subscriptionRequest.BaseRequest.Tag, nil))
		return
	}

	managers.NotifyProjectClients(projectId, subscriptionRequest.GetNotification(), wsConn)
	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(subscriptionRequest.BaseRequest.Tag, nil))
}
func MoveFile(wsConn *websocket.Conn, fileMoveRequest fileRequests.FileMoveRequest) {
	session, collection := managers.GetMGoCollection("Files")
	defer session.Close()

	// Check that file exists
	file, err := GetFileById(fileMoveRequest.BaseRequest.ResId)
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-300, fileMoveRequest.BaseRequest.Tag, nil))
		return
	}

	file.Version++

	err = collection.Update(bson.M{"_id": fileMoveRequest.BaseRequest.ResId}, bson.M{"$set": bson.M{"relative_path": fileMoveRequest.NewPath, "version": file.Version}})
	if err != nil {
		if mgo.IsDup(err) {
			managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-307, fileMoveRequest.BaseRequest.Tag, nil))
			return
		}
		managers.LogError("Error renaming file", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-303, fileMoveRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(fileMoveRequest.BaseRequest.Tag, nil))
	managers.NotifyProjectClients(file.Project, fileMoveRequest.GetNotification(), wsConn)
}
func GetCollaborators(wsConn *websocket.Conn, getCollaboratorsRequest projectRequests.ProjectGetCollaboratorsRequest) {

	project, err := GetProjectById(getCollaboratorsRequest.BaseRequest.ResId)

	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-200, getCollaboratorsRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(getCollaboratorsRequest.BaseRequest.Tag, map[string]interface{}{"Collaborators": project.Permissions}))
}
func GetFiles(wsConn *websocket.Conn, projectFilesRequest projectRequests.ProjectGetFilesRequest) {

	projects, err := fileModels.GetFilesByProjectId(projectFilesRequest.BaseRequest.ResId)

	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-200, projectFilesRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(projectFilesRequest.BaseRequest.Tag, map[string]interface{}{"Files": projects}))
}
func UserProjects(wsConn *websocket.Conn, userProjectsRequest userRequests.UserProjectsRequest) {

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Projects")
	defer session.Close()

	var projects []projectModels.Project
	if err := collection.Find(bson.M{"permissions." + userProjectsRequest.BaseRequest.Username: bson.M{"$gt": 0}}).All(&projects); err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-100, userProjectsRequest.BaseRequest.Tag, nil))
		return
	}

	data := map[string]interface{}{"Projects": projects}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(userProjectsRequest.BaseRequest.Tag, data))
}
func LookupUser(wsConn *websocket.Conn, userLookupRequest userRequests.UserLookupRequest) {

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Users")
	defer session.Close()

	user := User{}
	if err := collection.Find(bson.M{"username": userLookupRequest.LookupUsername}).One(&user); err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-100, userLookupRequest.BaseRequest.Tag, nil))
		return
	}

	data := map[string]interface{}{"User": user}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(userLookupRequest.BaseRequest.Tag, data))
}
func Unsubscribe(wsConn *websocket.Conn, unsubscriptionRequest projectRequests.ProjectUnsubscribeRequest) {

	//	project := subscriptionRequest.BaseRequest.ResId
	//
	//	proj, err := GetProjectById(project)
	//
	//	if err != nil {
	//		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-200, subscriptionRequest.BaseRequest.Tag, nil))
	//		return
	//	}
	//
	//	// TODO: Add fail message if permission denied
	//	for key, _ := range proj.Permissions {
	//		if key == subscriptionRequest.BaseRequest.Username {
	//			if (!managers.WebSocketSubscribeProject(wsConn, subscriptionRequest.BaseRequest.Username, project)) {
	//				managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-206, subscriptionRequest.BaseRequest.Tag, nil))
	//				return
	//			}
	//		}
	//	}
	//
	//	managers.NotifyProjectClients(project, subscriptionRequest.GetNotification(), wsConn)
	//	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(subscriptionRequest.BaseRequest.Tag, nil))

	managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-4, unsubscriptionRequest.BaseRequest.Tag, nil))
}
// Rename project (?)
func RenameProject(wsConn *websocket.Conn, projectRenameRequest projectRequests.ProjectRenameRequest) {

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Projects")
	defer session.Close()

	// Rename the project
	err := collection.Update(bson.M{"_id": projectRenameRequest.BaseRequest.ResId}, bson.M{"$set": bson.M{"name": projectRenameRequest.NewName}})
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-202, projectRenameRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(projectRenameRequest.BaseRequest.Tag, nil))
	managers.NotifyProjectClients(projectRenameRequest.BaseRequest.ResId, projectRenameRequest.GetNotification(), wsConn)
}
// Grant permission <Level> to <User>
//  - Check if user exists
//  - Grants permission level to user, overwriting if necessary.
func GrantProjectPermissions(wsConn *websocket.Conn, projectGrantPermissionsRequest projectRequests.ProjectGrantPermissionsRequest) {

	project, err := GetProjectById(projectGrantPermissionsRequest.BaseRequest.ResId)
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-200, projectGrantPermissionsRequest.BaseRequest.Tag, nil))
		return
	}

	if !CheckUserHasPermissions(project, projectGrantPermissionsRequest.BaseRequest.Username, 5) {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-207, projectGrantPermissionsRequest.BaseRequest.Tag, nil))
		return
	}

	// Make sure that there is still an owner of the project.
	owner := ""
	for key, value := range project.Permissions {
		if value == 10 && key != projectGrantPermissionsRequest.GrantUsername {
			owner = key
		}
	}
	if owner == "" {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-205, projectGrantPermissionsRequest.BaseRequest.Tag, nil))
		return
	}

	project.Permissions[projectGrantPermissionsRequest.GrantUsername] = projectGrantPermissionsRequest.PermissionLevel

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Projects")
	defer session.Close()

	// Update permissions
	err = collection.Update(bson.M{"_id": projectGrantPermissionsRequest.BaseRequest.ResId}, bson.M{"$set": bson.M{"permissions": project.Permissions}})
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-202, projectGrantPermissionsRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(projectGrantPermissionsRequest.BaseRequest.Tag, nil))
	managers.NotifyProjectClients(projectGrantPermissionsRequest.BaseRequest.ResId, projectGrantPermissionsRequest.GetNotification(), wsConn)
}
func DeleteFile(wsConn *websocket.Conn, fileDeleteRequest fileRequests.FileDeleteRequest) {
	session, collection := managers.GetMGoCollection("Files")
	defer session.Close()

	// Check that file exists
	file, err := GetFileById(fileDeleteRequest.BaseRequest.ResId)
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-300, fileDeleteRequest.BaseRequest.Tag, nil))
		return
	}

	err = os.Remove(file.GetPath())

	err = collection.Remove(bson.M{"_id": fileDeleteRequest.BaseRequest.ResId})
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-304, fileDeleteRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(fileDeleteRequest.BaseRequest.Tag, nil))
	managers.NotifyProjectClients(file.Project, fileDeleteRequest.GetNotification(), wsConn)
}
// Create new project
func CreateProject(wsConn *websocket.Conn, projectCreateRequest projectRequests.ProjectCreateRequest) {

	// Create new Project object
	project := new(Project)
	project.Id = managers.NewObjectIdString()
	project.Name = projectCreateRequest.Name
	project.ServerPath = project.Id
	project.Permissions = map[string]int{projectCreateRequest.BaseRequest.Username: 10} // Set creator to owner permissions

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Projects")
	defer session.Close()

	// Create the project
	err := collection.Insert(project)
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-201, projectCreateRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(projectCreateRequest.BaseRequest.Tag, map[string]interface{}{"ProjectId": project.Id}))
}
func LoginUser(wsConn *websocket.Conn, loginRequest userRequests.UserLoginRequest) {

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Users")
	defer session.Close()

	user, err := GetUserByUsername(loginRequest.Username)
	if err != nil {
		// Could not find user
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-104, loginRequest.BaseRequest.Tag, nil))
		return
	}

	if err := bcrypt.CompareHashAndPassword([]byte(user.Password_Hash), []byte(loginRequest.Password)); err != nil {
		// Password did not match.
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-104, loginRequest.BaseRequest.Tag, nil))
		return
	}

	tokenBytes, err := bcrypt.GenerateFromPassword([]byte(loginRequest.Username+time.Now().String()), bcrypt.DefaultCost)
	if err != nil {
		managers.LogError("Failed to generate token", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-103, loginRequest.BaseRequest.Tag, nil))
		return
	}

	token := string(tokenBytes[:])

	err = addToken(collection, user, token)
	if err != nil {
		managers.LogError("Failed to save token", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-103, loginRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(loginRequest.BaseRequest.Tag, map[string]interface{}{"Token": token}))
}
func handleWSConn(responseWriter http.ResponseWriter, request *http.Request) {
	if request.URL.Path != "/ws/" {
		http.Error(responseWriter, "Not found", 404)
		return
	}
	if request.Method != "GET" {
		http.Error(responseWriter, "Method not allowed", 405)
		return
	}
	wsConn, err := upgrader.Upgrade(responseWriter, request, nil)
	if err != nil {
		managers.LogError("Failed to upgrade connection:", err)
		return
	}

	defer wsConn.Close()
	defer managers.WebSocketDisconnected(wsConn)
	// move above adding it to the web socket structure in case adding it fails part way through

	// subscriptions moved to User Subscribe request
	// managers.NewWebSocketConnected(wsConn)

	for {
		// messageType, message, err := wsConn.ReadMessage()
		_, message, err := wsConn.ReadMessage()
		if err != nil {
			managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(0, 0, nil))
			break
		}

		// Deserialize data from json.
		var baseRequestObj baseRequests.BaseRequest
		if err := json.Unmarshal(message, &baseRequestObj); err != nil {

			managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, map[string]interface{}{"Error:": err}))

		} else {
			if !("User" == baseRequestObj.Resource && ("Register" == baseRequestObj.Action || "Login" == baseRequestObj.Action)) && !userModels.CheckUserAuth(baseRequestObj) {
				managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-105, baseRequestObj.Tag, nil))
			} else {

				if !(baseRequestObj.Resource == "User" && ("Login" == baseRequestObj.Action || "Register" == baseRequestObj.Action)) {
					managers.LogAccess(baseRequestObj, string(message))
				}

				switch baseRequestObj.Resource {
				case "Project":
					switch baseRequestObj.Action {
					case "GetPermissionLevels":
						// {"Resource":"Project", "Action":"GetPermissionLevels", "Username":"******", "Token": "test"}
						// Deserialize from JSON
						var projectGetPermissionLevelsRequest projectRequests.ProjectGetPermissionLevelsRequest
						if err := json.Unmarshal(message, &projectGetPermissionLevelsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectGetPermissionLevelsRequest.BaseRequest = baseRequestObj
						projectModels.GetPermissionLevels(wsConn, projectGetPermissionLevelsRequest)

					case "Create":

						// {"Resource":"Project", "Action":"Create", "Username":"******", "Token": "$2a$10$kWgnc1TcG.KBaGH0cjY52OzWYt77XvkGRtOpim6ISD/W8avdujeTO", "Name":"foo"}
						// Deserialize from JSON
						var projectCreateRequest projectRequests.ProjectCreateRequest
						if err := json.Unmarshal(message, &projectCreateRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectCreateRequest.BaseRequest = baseRequestObj
						projectModels.CreateProject(wsConn, projectCreateRequest)

					case "Rename":

						// {"Resource":"Project", "Action":"Rename", "ResId": "561987174357413b14000002", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e", "NewName":"bar"}
						// Deserialize from JSON
						var projectRenameRequest projectRequests.ProjectRenameRequest
						if err := json.Unmarshal(message, &projectRenameRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectRenameRequest.BaseRequest = baseRequestObj
						projectModels.RenameProject(wsConn, projectRenameRequest)

					case "GrantPermissions":

						// {"Resource":"Project", "Action":"GrantPermissions", "ResId": "561987174357413b14000002", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e", "GrantUsername":"******", "PermissionLevel":5}
						// Deserialize from JSON
						var projectGrantPermissionsRequest projectRequests.ProjectGrantPermissionsRequest
						if err := json.Unmarshal(message, &projectGrantPermissionsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectGrantPermissionsRequest.BaseRequest = baseRequestObj

						projectModels.GrantProjectPermissions(wsConn, projectGrantPermissionsRequest)

					case "RevokePermissions":

						// {"Resource":"Project", "Action":"RevokePermissions", "ResId": "561987174357413b14000002", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e", "RevokeUsername":"******"}
						// Deserialize from JSON
						var projectRevokePermissionsRequest projectRequests.ProjectRevokePermissionsRequest
						if err := json.Unmarshal(message, &projectRevokePermissionsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectRevokePermissionsRequest.BaseRequest = baseRequestObj

						projectModels.RevokeProjectPermissions(wsConn, projectRevokePermissionsRequest)

					case "GetSubscribedClients":

						// {"Resource":"Project", "Action":"GetSubscribedClients", "ResId": "561987174357413b14000002", "Username":"******", "Token": "test"}
						// Deserialize from JSON
						var projectGetSubscribedClientsRequest projectRequests.ProjectGetSubscribedClientsRequest
						if err := json.Unmarshal(message, &projectGetSubscribedClientsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectGetSubscribedClientsRequest.BaseRequest = baseRequestObj

						managers.GetSubscribedClients(wsConn, projectGetSubscribedClientsRequest)

					case "GetCollaborators":

						// {"Resource":"Project", "Action":"GetCollaborators", "ResId": "561987174357413b14000002", "Username":"******", "Token": "test"}
						// Deserialize from JSON
						var ProjectGetCollaboratorsRequest projectRequests.ProjectGetCollaboratorsRequest
						if err := json.Unmarshal(message, &ProjectGetCollaboratorsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						ProjectGetCollaboratorsRequest.BaseRequest = baseRequestObj

						projectModels.GetCollaborators(wsConn, ProjectGetCollaboratorsRequest)

					case "GetFiles":

						// {"Resource":"Project", "Action":"GetFiles", "ResId": "561987174357413b14000002", "Username":"******", "Token": "token-fahslaj"}
						var projectFilesRequest projectRequests.ProjectGetFilesRequest
						if err := json.Unmarshal(message, &projectFilesRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectFilesRequest.BaseRequest = baseRequestObj

						projectModels.GetFiles(wsConn, projectFilesRequest)

					case "Subscribe":

						// {"Resource":"Project", "Action":"Subscribe", "Projects":["5629a063111aeb63cf000001"], "Username":"******", "Token": "token-fahslaj"}
						var projectSubscribeRequest projectRequests.ProjectSubscribeRequest
						if err := json.Unmarshal(message, &projectSubscribeRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectSubscribeRequest.BaseRequest = baseRequestObj

						projectModels.Subscribe(wsConn, projectSubscribeRequest)

					case "Unsubscribe":

						// {"Resource":"Project", "Action":"Unsubscribe", "Projects":["5629a063111aeb63cf000001"], "Username":"******", "Token": "token-fahslaj"}
						var projectUnsubscribeRequest projectRequests.ProjectUnsubscribeRequest
						if err := json.Unmarshal(message, &projectUnsubscribeRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						projectUnsubscribeRequest.BaseRequest = baseRequestObj

						projectModels.Unsubscribe(wsConn, projectUnsubscribeRequest)

					case "Delete":
					// TODO

					default:
						managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-3, baseRequestObj.Tag, nil))
						break
					}
				case "File":
					switch baseRequestObj.Action {

					case "Create":
						// {"Resource":"File", "Action":"Create", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e", "Name":"foo", "RelativePath":"test/path1/", "ProjectId":"561987174357413b14000002"}
						// Deserialize from JSON
						var fileCreateRequest fileRequests.FileCreateRequest
						if err := json.Unmarshal(message, &fileCreateRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						fileCreateRequest.BaseRequest = baseRequestObj
						fileModels.CreateFile(wsConn, fileCreateRequest)

					case "Rename":
						// {"Resource":"File", "Action":"Rename", "ResId":"561987a84357413b14000006", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e", "NewName":"foo2"}
						// Deserialize from JSON
						var fileRenameRequest fileRequests.FileRenameRequest
						if err := json.Unmarshal(message, &fileRenameRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						fileRenameRequest.BaseRequest = baseRequestObj
						fileModels.RenameFile(wsConn, fileRenameRequest)

					case "Move":
						// {"Resource":"File", "Action":"Move", "ResId":"561987a84357413b14000006", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e", "NewPath":"test/path2/"}
						// Deserialize from JSON
						var fileMoveRequest fileRequests.FileMoveRequest
						if err := json.Unmarshal(message, &fileMoveRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						fileMoveRequest.BaseRequest = baseRequestObj
						fileModels.MoveFile(wsConn, fileMoveRequest)

					case "Delete":
						// {"Resource":"File", "Action":"Delete", "ResId":"561987a84357413b14000006", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e"}
						// Deserialize from JSON
						var fileDeleteRequest fileRequests.FileDeleteRequest
						if err := json.Unmarshal(message, &fileDeleteRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						fileDeleteRequest.BaseRequest = baseRequestObj
						fileModels.DeleteFile(wsConn, fileDeleteRequest)

					case "Change":
						// {"Tag": 112, "Action": "Change", "Resource": "File", "ResId": "561987a84357413b14000006", "FileVersion":0, "Changes": "@@ -40,16 +40,17 @@\n almost i\n+t\n n shape", "Username":"******", "Token": "$2a$10$gifm6Vrfn2vBBCX7qvaQzu.Pvttotyu1pRW5V6X7RnhYYiQCUHh4e"}
						// Deserialize from JSON
						var fileChangeRequest fileRequests.FileChangeRequest
						if err := json.Unmarshal(message, &fileChangeRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						fileChangeRequest.BaseRequest = baseRequestObj

						fileModels.InsertChange(wsConn, fileChangeRequest)

					case "Pull":
						// {"Tag": 112, "Action": "Pull", "Resource": "File", "ResId": "5629a0c2111aeb63cf000002", "Username":"******", "Token": "token-fahslaj"}
						// Deserialize from JSON
						var filePullRequest fileRequests.FilePullRequest
						if err := json.Unmarshal(message, &filePullRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						filePullRequest.BaseRequest = baseRequestObj

						fileModels.PullFile(wsConn, filePullRequest)

					case "Projects":

						// {"Resource":"User", "Action":"Projects", "Username":"******", "Token": "token-fahslaj"}
						var userProjectsRequest userRequests.UserProjectsRequest
						if err := json.Unmarshal(message, &userProjectsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						userProjectsRequest.BaseRequest = baseRequestObj

						userModels.UserProjects(wsConn, userProjectsRequest)

					default:
						baseModels.NewFailResponse(-3, baseRequestObj.Tag, map[string]interface{}{"Action": baseRequestObj.Action})
						break
					}

				// // Notify success; return new version number.
				// base.NewSuccessResponse(baseRequestObj.Tag, nil)

				case "User":
					switch baseRequestObj.Action {
					case "Register":

						// {"Resource":"User", "Action":"Register", "Username":"******", "Password":"******"}
						// Deserialize from JSON
						var userRegisterRequest userRequests.UserRegisterRequest
						if err := json.Unmarshal(message, &userRegisterRequest); err != nil {

							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						userRegisterRequest.BaseRequest = baseRequestObj

						userModels.RegisterUser(wsConn, userRegisterRequest)
					case "Login":

						// {"Resource":"User", "Action":"Login", "Username":"******", "Password":"******"}
						// Deserialize from JSON
						var userLoginRequest userRequests.UserLoginRequest
						if err := json.Unmarshal(message, &userLoginRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						userLoginRequest.BaseRequest = baseRequestObj

						//Check username/pw, login if needed.
						userModels.LoginUser(wsConn, userLoginRequest)

					case "Lookup":

						// {"Resource":"User", "Action":"Lookup", "LookupUsername":"******", "Username":"******", "Token": "token-fahslaj"}
						var userLookupRequest userRequests.UserLookupRequest
						if err := json.Unmarshal(message, &userLookupRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						userLookupRequest.BaseRequest = baseRequestObj

						userModels.LookupUser(wsConn, userLookupRequest)

					case "Projects":

						// {"Resource":"User", "Action":"Projects", "Username":"******", "Token": "token-fahslaj"}
						var userProjectsRequest userRequests.UserProjectsRequest
						if err := json.Unmarshal(message, &userProjectsRequest); err != nil {
							managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-1, baseRequestObj.Tag, nil))
							break
						}
						// Add BaseRequest reference
						userProjectsRequest.BaseRequest = baseRequestObj

						userModels.UserProjects(wsConn, userProjectsRequest)

					//TODO: maybe delete?

					//TODO: Change PW

					default:
						managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-3, baseRequestObj.Tag, nil))
						break
					}
				default:
					// Invalid resource type
					managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-2, baseRequestObj.Tag, nil))
					break
				}
			}
		}
	}
}
func RegisterUser(wsConn *websocket.Conn, registrationRequest userRequests.UserRegisterRequest) {

	matched, err := regexp.MatchString("^[\\w]+$", registrationRequest.Username)
	if !matched {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-106, registrationRequest.BaseRequest.Tag, nil))
		return
	}

	// Hash password using bcrypt
	pwHashBytes, err := bcrypt.GenerateFromPassword([]byte(registrationRequest.Password), bcrypt.DefaultCost)
	if err != nil {
		managers.LogError("Failed to hash password", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-101, registrationRequest.BaseRequest.Tag, nil))
		return
	}

	// Create new UserAuthData object
	userAuthData := new(User)
	userAuthData.Id = managers.NewObjectIdString()
	userAuthData.FirstName = registrationRequest.FirstName
	userAuthData.LastName = registrationRequest.LastName
	userAuthData.Username = registrationRequest.Username
	userAuthData.Email = registrationRequest.Email
	userAuthData.Password_Hash = string(pwHashBytes[:])

	// Get new DB connection
	session, collection := managers.GetMGoCollection("Users")
	defer session.Close()

	// Make sure email is unique
	index := mgo.Index{
		Key:        []string{"email"},
		Unique:     true,
		DropDups:   true,
		Background: true,
		Sparse:     true,
	}
	err = collection.EnsureIndex(index)
	if err != nil {
		managers.LogError("Failed to ensure email index", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-101, registrationRequest.BaseRequest.Tag, nil))
		return
	}

	// Make sure username is unique
	index = mgo.Index{
		Key:        []string{"username"},
		Unique:     true,
		DropDups:   true,
		Background: true,
		Sparse:     true,
	}
	err = collection.EnsureIndex(index)
	if err != nil {
		managers.LogError("Failed to ensure username index", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-101, registrationRequest.BaseRequest.Tag, nil))
		return
	}

	// Register new user
	err = collection.Insert(userAuthData)
	if err != nil {
		// Duplicate entry
		if mgo.IsDup(err) {
			managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-102, registrationRequest.BaseRequest.Tag, nil))
			return
		}
		managers.LogError("Error registering user", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-101, registrationRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(registrationRequest.BaseRequest.Tag, nil))
}
func CreateFile(wsConn *websocket.Conn, fileCreateRequest fileRequests.FileCreateRequest) {

	file := new(File)
	file.Id = managers.NewObjectIdString()
	file.Name = fileCreateRequest.Name
	file.RelativePath = fileCreateRequest.RelativePath
	file.Version = 0
	file.Project = fileCreateRequest.ProjectId

	session, collection := managers.GetMGoCollection("Files")
	defer session.Close()

	// Create indexes
	index := mgo.Index{
		Key:        []string{"name", "relative_path"},
		Unique:     true,
		DropDups:   true,
		Background: true,
		Sparse:     true,
	}
	err := collection.EnsureIndex(index)
	if err != nil {
		managers.LogError("Failed to ensure file name/path index", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-301, fileCreateRequest.BaseRequest.Tag, nil))
		return
	}

	// Insert file record
	err = collection.Insert(file)
	if err != nil {
		if mgo.IsDup(err) {
			managers.LogError("Error creating file record", err)
			managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-305, fileCreateRequest.BaseRequest.Tag, nil))
			return
		}
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-301, fileCreateRequest.BaseRequest.Tag, nil))
		return
	}

	// Write file to disk

	fileCreateRequest.RelativePath = filepath.Clean(fileCreateRequest.RelativePath)
	if fileCreateRequest.RelativePath[0:2] == ".." || filepath.IsAbs(fileCreateRequest.RelativePath) {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-308, fileCreateRequest.BaseRequest.Tag, nil))
		return
	}

	err = os.MkdirAll("files/"+fileCreateRequest.ProjectId+"/"+fileCreateRequest.RelativePath, os.ModeExclusive)
	if err != nil {
		managers.LogError("Failed to create file directory", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-301, fileCreateRequest.BaseRequest.Tag, nil))
		return
	}
	err = ioutil.WriteFile(file.GetPath(), fileCreateRequest.FileBytes, os.ModeExclusive)
	if err != nil {
		managers.LogError("Failed to write file", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-301, fileCreateRequest.BaseRequest.Tag, nil))
		return
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(fileCreateRequest.BaseRequest.Tag, map[string]interface{}{"FileId": file.Id}))
	managers.NotifyProjectClients(file.Project, fileCreateRequest.GetNotification(file.Id), wsConn)
}
func InsertChange(wsConn *websocket.Conn, fileChangeRequest fileRequests.FileChangeRequest) {

	// Check that file exists
	file, err := GetFileById(fileChangeRequest.BaseRequest.ResId)
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-300, fileChangeRequest.BaseRequest.Tag, nil))
		return
	}

	// Check that user is on latest version, then increment. Otherwise, throw error
	if fileChangeRequest.FileVersion < file.Version {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-401, fileChangeRequest.BaseRequest.Tag, nil))
		return
	}
	fileChangeRequest.FileVersion++

	fileChange := new(FileChange)
	fileChange.Id = managers.NewObjectIdString()
	fileChange.Changes = fileChangeRequest.Changes
	fileChange.FileId = fileChangeRequest.BaseRequest.ResId
	fileChange.Version = fileChangeRequest.FileVersion
	fileChange.Username = fileChangeRequest.BaseRequest.Username
	fileChange.Date = time.Now().UTC()

	changesSession, changesCollection := managers.GetMGoCollection("Changes")
	defer changesSession.Close()

	index := mgo.Index{
		Key:        []string{"file", "version"},
		Unique:     true,
		DropDups:   true,
		Background: true,
		Sparse:     true,
	}
	err = changesCollection.EnsureIndex(index)
	if err != nil {
		managers.LogError("Failed to ensure changes index", err)
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-400, fileChangeRequest.BaseRequest.Tag, nil))
	}

	err = changesCollection.Insert(fileChange)
	if err != nil {
		if mgo.IsDup(err) {
			managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-401, fileChangeRequest.BaseRequest.Tag, nil))
			return
		}
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-400, fileChangeRequest.BaseRequest.Tag, nil))
		return
	}

	filesSession, filesCollection := managers.GetMGoCollection("Files")
	defer filesSession.Close()
	err = filesCollection.Update(bson.M{"_id": fileChangeRequest.BaseRequest.ResId}, bson.M{"$set": bson.M{"version": fileChangeRequest.FileVersion}})
	if err != nil {
		managers.SendWebSocketMessage(wsConn, baseModels.NewFailResponse(-400, fileChangeRequest.BaseRequest.Tag, nil))
		return
	}

	// TODO: Change when fileVersion is changed to atomic int
	if fileChange.Version%100 == 0 {
		scrunching.ScrunchDB(fileChange.FileId)
	}

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(fileChangeRequest.BaseRequest.Tag, map[string]interface{}{"FileVersion": fileChangeRequest.FileVersion}))
	managers.NotifyProjectClients(file.Project, fileChangeRequest.GetNotification(fileChangeRequest.FileVersion), wsConn)
}
func GetPermissionLevels(wsConn *websocket.Conn, projectGetPermissionLevelsRequest projectRequests.ProjectGetPermissionLevelsRequest) {

	managers.SendWebSocketMessage(wsConn, baseModels.NewSuccessResponse(projectGetPermissionLevelsRequest.BaseRequest.Tag, map[string]interface{}{"PermissionLevels": PermissionLevels}))
}