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 GetUserByUsername(username string) (*User, error) { // Get new DB connection session, collection := managers.GetMGoCollection("Users") defer session.Close() result := new(User) err := collection.Find(bson.M{"username": username}).One(&result) if err != nil { managers.LogError("Failed to retrieve User", err) return nil, err } return result, nil }
func GetFilesByProjectId(projectId string) ([]File, error) { // Get new DB connection session, collection := managers.GetMGoCollection("Files") defer session.Close() var result []File err := collection.Find(bson.M{"project": projectId}).All(&result) if err != nil { managers.LogError("Failed to retrieve Files for project "+projectId, err) return nil, err } return result, nil }
func GetFileById(id string) (*File, error) { // Get new DB connection session, collection := managers.GetMGoCollection("Files") defer session.Close() result := new(File) err := collection.Find(bson.M{"_id": id}).One(&result) if err != nil { managers.LogError("Failed to retrieve File", err) return nil, err } return result, nil }
func GetChangesByFile(fileId string) ([]FileChange, error) { // Get new DB connection session, collection := managers.GetMGoCollection("Changes") defer session.Close() var result []FileChange err := collection.Find(bson.M{"file_id": fileId}).Sort("version").All(&result) if err != nil { managers.LogError("Failed to retrieve FileChanges", err) return nil, err } return result, nil }
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)) }
// 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 CheckUserAuth(baseRequest baseRequests.BaseRequest) bool { // Get new DB connection session, collection := managers.GetMGoCollection("Users") defer session.Close() userAuthData := User{} if err := collection.Find(bson.M{"username": baseRequest.Username}).One(&userAuthData); err != nil { // Could not find user return false } for _, token := range userAuthData.Tokens { if token == baseRequest.Token { // Found matching token return true } } // No matching token found return false }
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 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) }