func TestPutNotFound(t *testing.T) { var device *doorbot.Device render := new(tests.MockRender) repo := new(tests.MockDeviceRepository) db := new(tests.MockExecutor) repositories := new(tests.MockRepositories) repositories.On("DeviceRepository").Return(repo) repositories.On("DB").Return(db) params := martini.Params{ "id": "44", } postDevice := &doorbot.Device{ Name: "Chicken Nick", } repo.On("Find", db, uint64(44)).Return(device, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified device does not exists"})).Return() Put(render, repositories, params, DeviceViewModel{Device: postDevice}) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) repositories.Mock.AssertExpectations(t) }
func TestDeleteNotFound(t *testing.T) { var door *doorbot.Door repo := new(tests.MockDoorRepository) render := new(tests.MockRender) db := new(tests.MockExecutor) repositories := new(tests.MockRepositories) repositories.On("DoorRepository").Return(repo) repositories.On("DB").Return(db) params := martini.Params{ "id": "44", } repo.On("Find", db, uint(44)).Return(door, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified door does not exists"})).Return() Delete(render, repositories, params) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) repositories.Mock.AssertExpectations(t) }
func TestGetNotFound(t *testing.T) { var device *doorbot.Device render := new(tests.MockRender) repo := new(tests.MockDeviceRepository) params := martini.Params{ "id": "33", } db := new(tests.MockExecutor) repositories := new(tests.MockRepositories) repositories.On("DeviceRepository").Return(repo) repositories.On("DB").Return(db) repositories.On("AccountScope").Return(uint(1)) repo.On("Find", db, uint64(33)).Return(device, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified device does not exists"})).Return() Get(render, repositories, params) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) repositories.Mock.AssertExpectations(t) }
func TestDeleteNotFound(t *testing.T) { var person *doorbot.Person repo := new(tests.MockPersonRepository) render := new(tests.MockRender) db := new(tests.MockExecutor) repositories := new(tests.MockRepositories) repositories.On("PersonRepository").Return(repo) repositories.On("DB").Return(db) repositories.On("AccountScope").Return(uint(1)) params := martini.Params{ "id": "44", } account := &doorbot.Account{} session := &auth.Authorization{ Type: auth.AuthorizationPerson, Person: &doorbot.Person{ AccountType: doorbot.AccountOwner, }, } repo.On("Find", db, uint(44)).Return(person, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified person does not exists"})).Return() Delete(render, repositories, params, account, session) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) repositories.Mock.AssertExpectations(t) }
func TestDeleteNotFound(t *testing.T) { var account *doorbot.Account admin := &doorbot.Administrator{} repo := new(tests.MockAccountRepository) render := new(tests.MockRender) repositories := new(tests.MockRepositories) repositories.On("AccountRepository").Return(repo) repositories.On("AccountScope").Return(1) db := new(tests.MockExecutor) repositories.On("DB").Return(db) params := martini.Params{ "id": "44", } repo.On("Find", db, uint(44)).Return(account, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified account does not exists."})).Return() Delete(render, repositories, params, admin) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) }
func TestGetNotFound(t *testing.T) { var account *doorbot.Account session := &auth.Authorization{} render := new(tests.MockRender) repo := new(tests.MockAccountRepository) db := new(tests.MockExecutor) repositories := new(tests.MockRepositories) repositories.On("DB").Return(db) repositories.On("AccountRepository").Return(repo) repositories.On("AccountScope").Return(1) params := martini.Params{ "id": "33", } repo.On("Find", db, uint(33)).Return(account, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{})).Return() Get(render, repositories, params, session) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) }
// Put updates a device func Put(render render.Render, r doorbot.Repositories, params martini.Params, vm DeviceViewModel) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } repo := r.DeviceRepository() device, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "device_id": id, "step": "device-find", }).Error("Api::Devices->Put database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if device == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified device does not exists"})) return } device.Name = vm.Device.Name device.DeviceID = vm.Device.DeviceID device.Make = vm.Device.Make device.Description = vm.Device.Description device.IsEnabled = vm.Device.IsEnabled _, err = repo.Update(r.DB(), device) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "device_id": id, "step": "device-update", }).Error("Api::Devices->Put database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } log.WithFields(log.Fields{ "account_id": r.AccountScope(), "device_id": id, }).Info("Api::Devices->Put device updated") vm.Device = device render.JSON(http.StatusOK, vm) }
// Get return a specific account func Get(render render.Render, r doorbot.Repositories, params martini.Params, session *auth.Authorization) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } repo := r.AccountRepository() account, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "account_id": id, "error": err, }).Error("Api::Accounts->Get database error.") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if account == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{})) return } // Switch the view model depending on who/what requests the information. switch session.Type { case auth.AuthorizationAdministrator: render.JSON(http.StatusOK, AccountViewModel{Account: account}) case auth.AuthorizationPerson: if session.Person.IsAccountManager() { render.JSON(http.StatusOK, AccountViewModel{Account: account}) return } // Display a reduced version of the account. public := PublicAccount{ ID: account.ID, Name: account.Name, Host: account.Host, } render.JSON(http.StatusOK, PublicAccountViewModel{Account: public}) default: render.Status(http.StatusForbidden) return } }
// Put updates a door func Put(render render.Render, r doorbot.Repositories, params martini.Params, vm DoorViewModel) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } repo := r.DoorRepository() door, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "door_id": id, "step": "door-find", }).Error("Api::Doors->Put database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if door == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified door does not exists"})) return } door.Name = vm.Door.Name _, err = repo.Update(r.DB(), door) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "door_id": id, "step": "door-update", }).Error("Api::Doors->Put database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } log.WithFields(log.Fields{ "account_id": r.AccountScope(), "door_id": vm.Door.ID, }).Error("Api::Doors->Post door updated") render.JSON(http.StatusOK, DoorViewModel{Door: door}) }
// Disable a device func Disable(render render.Render, r doorbot.Repositories, params martini.Params) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"the id must be an unsigned integer"})) return } repo := r.DeviceRepository() device, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "device_id": id, "step": "device-find", }).Error("Api::Devices->Disable database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if device == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified deevice does not exists."})) return } _, err = repo.Enable(r.DB(), device, false) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "device_id": id, "step": "device-disable", }).Error("Api::Devices->Disable database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } log.WithFields(log.Fields{ "account_id": r.AccountScope(), "device_id": id, }).Info("Api::Devices->Disabled device disabled") render.Status(http.StatusNoContent) }
// Get a specific person func Get(render render.Render, r doorbot.Repositories, params martini.Params, session *auth.Authorization) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } repo := r.PersonRepository() person, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "person_id": id, }).Error("Api::People->Get database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if person == nil { err := doorbot.NewEntityNotFoundResponse([]string{"The specified person does not exists"}) render.JSON(http.StatusNotFound, err) return } switch session.Type { case auth.AuthorizationAdministrator: render.JSON(http.StatusOK, PersonViewModel{Person: person}) case auth.AuthorizationDevice: render.JSON(http.StatusOK, PublicPersonViewModel{Person: newPublicPerson(person)}) case auth.AuthorizationPerson: // Display detailed info if the requesting user is an account manager or it is the same person if session.Person.IsAccountManager() || session.Person.ID == person.ID { render.JSON(http.StatusOK, PersonViewModel{Person: person}) return } render.JSON(http.StatusOK, PublicPersonViewModel{Person: newPublicPerson(person)}) default: render.Status(http.StatusForbidden) } }
// Delete an account ( admin panel ) func Delete(render render.Render, r doorbot.Repositories, params martini.Params, administrator *doorbot.Administrator) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } repo := r.AccountRepository() account, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "account_id": account.ID, "administrator_id": administrator.ID, }).Error("Api::Accounts->Delete database find error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if account == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified account does not exists."})) return } _, err = repo.Delete(r.DB(), account) if err != nil { log.WithFields(log.Fields{ "error": err.Error(), "administrator_id": administrator.ID, "account_id": account.ID, }).Error("Api::Accounts->Delete database delete error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } log.WithFields(log.Fields{ "administrator_id": administrator.ID, "account_id": account.ID, }).Info("Api::Accounts->Delete account deleted by administrator.") render.Status(http.StatusNoContent) }
func TestPutNotFound(t *testing.T) { var person *doorbot.Person render := new(tests.MockRender) repo := new(tests.MockPersonRepository) db := new(tests.MockExecutor) repositories := new(tests.MockRepositories) repositories.On("PersonRepository").Return(repo) repositories.On("DB").Return(db) repositories.On("AccountScope").Return(uint(1)) params := martini.Params{ "id": "44", } postPerson := &doorbot.Person{ Name: "Chicken Nick", } session := &auth.Authorization{ Type: auth.AuthorizationPerson, Person: &doorbot.Person{ ID: 3, AccountType: doorbot.AccountManager, }, } repo.On("Find", db, uint(44)).Return(person, nil) render.On("JSON", http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified person does not exists"})).Return() Put(render, repositories, params, PersonViewModel{postPerson}, session) render.Mock.AssertExpectations(t) repo.Mock.AssertExpectations(t) repositories.Mock.AssertExpectations(t) }
// Get return a specific door func Get(render render.Render, r doorbot.Repositories, params martini.Params) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } repo := r.DoorRepository() door, err := repo.Find(r.DB(), uint(id)) if door == nil || err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "door_id": id, }).Error("Api::Doors->Get database error") render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified door does not exists"})) return } render.JSON(http.StatusOK, DoorViewModel{Door: door}) }
// Delete a person func Delete(render render.Render, r doorbot.Repositories, params martini.Params, a *doorbot.Account, session *auth.Authorization) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } var logFields log.Fields var logMessage string switch session.Type { case auth.AuthorizationAdministrator: logFields = log.Fields{ "account_id": r.AccountScope(), "person_id": id, "admnistrator_id": session.Administrator.ID, } logMessage = "Api::People->Delete user deleted by administrator" case auth.AuthorizationPerson: if !session.Person.IsAccountManager() { log.WithFields(log.Fields{ "account_id": r.AccountScope(), "person_id": id, "request_person_id": session.Person.ID, }).Warn("Api::People->Delete forbidden") render.Status(http.StatusForbidden) return } logFields = log.Fields{ "account_id": r.AccountScope(), "person_id": id, "modified_by_id": session.Person.ID, } logMessage = "Api::People->Put user deleted by user" default: log.WithFields(log.Fields{ "account_id": r.AccountScope(), "person_id": id, "request_person_id": session.Person.ID, }).Warn("Api::People->Delete forbidden") render.Status(http.StatusForbidden) return } repo := r.PersonRepository() person, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "person_id": person.ID, "step": "person-find", }).Error("Api::People->Delete database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if person == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified person does not exists"})) return } _, err = repo.Delete(r.DB(), person) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "person_id": person.ID, "step": "person-delete", }).Error("Api::People->Delete database error") render.Status(http.StatusInternalServerError) return } log.WithFields(logFields).Info(logMessage) render.Status(http.StatusNoContent) }
// Put updates a person func Put(render render.Render, r doorbot.Repositories, params martini.Params, vm PersonViewModel, session *auth.Authorization) { id, err := strconv.ParseUint(params["id"], 10, 32) if err != nil { render.JSON(http.StatusBadRequest, doorbot.NewBadRequestErrorResponse([]string{"The id must be an unsigned integer"})) return } var logFields log.Fields var logMessage string canUpdateAccountType := false switch session.Type { case auth.AuthorizationAdministrator: logFields = log.Fields{ "account_id": r.AccountScope(), "person_id": id, "admnistrator_id": session.Administrator.ID, } logMessage = "Api::People->Put user updated by administrator" canUpdateAccountType = true case auth.AuthorizationPerson: if uint(id) != session.Person.ID { if session.Person.IsAccountManager() { canUpdateAccountType = true } else { log.WithFields(log.Fields{ "account_id": r.AccountScope(), "person_id": id, "request_person_id": session.Person.ID, }).Warn("Api::People->Delete forbidden") render.Status(http.StatusForbidden) return } } logFields = log.Fields{ "account_id": r.AccountScope(), "person_id": id, "request_person_id": session.Person.ID, } logMessage = "Api::People->Put user updated by user" default: log.WithFields(log.Fields{ "account_id": r.AccountScope(), "person_id": id, "request_person_id": session.Person.ID, }).Warn("Api::People->Put forbidden") render.Status(http.StatusForbidden) return } repo := r.PersonRepository() person, err := repo.Find(r.DB(), uint(id)) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "person_id": id, "step": "person-find", }).Error("Api::People->Put database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if person == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified person does not exists"})) return } person.Name = vm.Person.Name person.Email = vm.Person.Email person.PhoneNumber = vm.Person.PhoneNumber person.Title = vm.Person.Title person.IsVisible = vm.Person.IsVisible person.IsAvailable = vm.Person.IsAvailable person.NotificationsEnabled = vm.Person.NotificationsEnabled person.NotificationsAppEnabled = vm.Person.NotificationsAppEnabled person.NotificationsChatEnabled = vm.Person.NotificationsChatEnabled person.NotificationsEmailEnabled = vm.Person.NotificationsEmailEnabled person.NotificationsSMSEnabled = vm.Person.NotificationsSMSEnabled if canUpdateAccountType { person.AccountType = vm.Person.AccountType } _, err = repo.Update(r.DB(), person) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": r.AccountScope(), "person_id": person.ID, "request_person_id": session.Person.ID, "step": "person-update", }).Error("Api::People->Put database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } vm.Person = person log.WithFields(logFields).Info(logMessage) render.JSON(http.StatusOK, vm) }
// Notify someone their presence is needed at a given door. func Notify(render render.Render, account *doorbot.Account, r doorbot.Repositories, notificator notifications.Notificator, vm ViewModel) { notification := vm.Notification log.WithFields(log.Fields{ "account_id": account.ID, "person_id": notification.PersonID, "door_id": notification.DoorID, }).Info("Api::Notifications->Notify request") peopleRepo := r.PersonRepository() doorRepo := r.DoorRepository() person, err := peopleRepo.Find(r.DB(), notification.PersonID) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": account.ID, "person_id": notification.PersonID, "door_id": notification.DoorID, "step": "person-find", }).Error("Api::Notifications->Notify database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if person == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified person does not exists."})) log.WithFields(log.Fields{ "account_id": account.ID, "person_id": notification.PersonID, "door_id": notification.DoorID, }).Info("Api::Notifications->Notify person not found") return } if !person.IsVisible || !person.IsAvailable { log.WithFields(log.Fields{ "account_id": account.ID, "person_id": notification.PersonID, "door_id": notification.DoorID, "person_is_visible": person.IsVisible, "person_is_available": person.IsAvailable, }).Info("Api::Notifications->Notify person is not available/visible") //TODO Would there be a better status code? render.JSON(http.StatusForbidden, doorbot.NewForbiddenErrorResponse([]string{"The specified user is currently not available."})) return } //TODO Infer from the device token? door, err := doorRepo.Find(r.DB(), notification.DoorID) if err != nil { log.WithFields(log.Fields{ "error": err, "account_id": account.ID, "person_id": notification.PersonID, "door_id": notification.DoorID, "step": "door-find", }).Error("Api::Notifications->Notify database error") render.JSON(http.StatusInternalServerError, doorbot.NewInternalServerErrorResponse([]string{})) return } if door == nil { render.JSON(http.StatusNotFound, doorbot.NewEntityNotFoundResponse([]string{"The specified door does not exists."})) log.WithFields(log.Fields{ "account_id": account.ID, "person_id": person.ID, "door_id": notification.DoorID, }).Info("Api::Notifications->Notify door not found") return } notificator.KnockKnock(door, person) render.JSON(http.StatusAccepted, ViewModel{Notification: notification}) }